Changeset b598460a in mainline for uspace/lib/fdisk/src/fdisk.c


Ignore:
Timestamp:
2015-10-21T09:27:06Z (9 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
852664b9
Parents:
68b5dd11
Message:

Suggest maximum available free space as the default for partition size.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/fdisk/src/fdisk.c

    r68b5dd11 rb598460a  
    6767static uint64_t fdisk_ba_align_up(fdisk_dev_t *, uint64_t);
    6868static uint64_t fdisk_ba_align_down(fdisk_dev_t *, uint64_t);
     69static int fdisk_part_get_max_free_range(fdisk_dev_t *, fdisk_spc_t, aoff64_t *,
     70    aoff64_t *);
     71static void fdisk_free_range_first(fdisk_dev_t *, fdisk_spc_t, fdisk_free_range_t *);
     72static bool fdisk_free_range_next(fdisk_free_range_t *);
     73static bool fdisk_free_range_get(fdisk_free_range_t *, aoff64_t *, aoff64_t *);
    6974
    7075static void fdisk_dev_info_delete(fdisk_dev_info_t *info)
     
    278283        }
    279284
    280         printf("vol_part_add(%zu)...\n", pinfo.svc_id);
    281         /*
    282          * Normally vol service discovers the partition asynchronously.
    283          * Here we need to make sure the partition is already known to it.
    284          */
    285         rc = vol_part_add(dev->fdisk->vol, pinfo.svc_id);
    286         printf("vol_part_add->rc = %d\n", rc);
    287         if (rc != EOK && rc != EEXIST) {
    288                 rc = EIO;
    289                 goto error;
    290         }
    291 
    292         printf("vol_part_info(%zu)\n", pinfo.svc_id);
    293         rc = vol_part_info(dev->fdisk->vol, pinfo.svc_id, &vpinfo);
    294         printf("vol_part_info->rc = %d\n", rc);
    295         if (rc != EOK) {
    296                 rc = EIO;
    297                 goto error;
     285        if (pinfo.svc_id != 0) {
     286                printf("vol_part_add(%zu)...\n", pinfo.svc_id);
     287                /*
     288                 * Normally vol service discovers the partition asynchronously.
     289                 * Here we need to make sure the partition is already known to it.
     290                 */
     291                rc = vol_part_add(dev->fdisk->vol, pinfo.svc_id);
     292                printf("vol_part_add->rc = %d\n", rc);
     293                if (rc != EOK && rc != EEXIST) {
     294                        rc = EIO;
     295                        goto error;
     296                }
     297
     298                printf("vol_part_info(%zu)\n", pinfo.svc_id);
     299                rc = vol_part_info(dev->fdisk->vol, pinfo.svc_id, &vpinfo);
     300                printf("vol_part_info->rc = %d\n", rc);
     301                if (rc != EOK) {
     302                        rc = EIO;
     303                        goto error;
     304                }
     305
     306                part->pcnt = vpinfo.pcnt;
     307                part->fstype = vpinfo.fstype;
    298308        }
    299309
     
    304314        part->pkind = pinfo.pkind;
    305315        part->svc_id = pinfo.svc_id;
    306         part->pcnt = vpinfo.pcnt;
    307         part->fstype = vpinfo.fstype;
    308316
    309317        switch (part->pkind) {
     
    620628{
    621629        vbd_disk_info_t vinfo;
     630        uint64_t b0, nb;
     631        uint64_t hdrb;
    622632        int rc;
    623633
     
    630640        info->ltype = vinfo.ltype;
    631641        info->flags = vinfo.flags;
     642
     643        if ((info->flags & lf_can_create_pri) != 0 ||
     644            (info->flags & lf_can_create_ext) != 0) {
     645                /* Verify there is enough space to create partition */
     646
     647                rc = fdisk_part_get_max_free_range(dev, spc_pri, &b0, &nb);
     648                if (rc != EOK)
     649                        info->flags &= ~(lf_can_create_pri | lf_can_create_ext);
     650        }
     651
     652        if ((info->flags & lf_can_create_log) != 0) {
     653                /* Verify there is enough space to create logical partition */
     654                hdrb = max(1, dev->align);
     655                rc = fdisk_part_get_max_free_range(dev, spc_log, &b0, &nb);
     656                if (rc != EOK || nb <= hdrb)
     657                        info->flags &= ~lf_can_create_log;
     658        }
     659
    632660        return EOK;
    633661error:
     
    735763}
    736764
    737 int fdisk_part_get_max_avail(fdisk_dev_t *dev, fdisk_cap_t *cap)
    738 {
     765int fdisk_part_get_max_avail(fdisk_dev_t *dev, fdisk_spc_t spc, fdisk_cap_t *cap)
     766{
     767        int rc;
     768        uint64_t b0;
     769        uint64_t nb;
     770        aoff64_t hdrb;
     771
     772        rc = fdisk_part_get_max_free_range(dev, spc, &b0, &nb);
     773        if (rc != EOK)
     774                return rc;
     775
     776        /* For logical partitions we need to subtract header size */
     777        if (spc == spc_log) {
     778                hdrb = max(1, dev->align);
     779                if (nb <= hdrb)
     780                        return ENOSPC;
     781                nb -= hdrb;
     782        }
     783
     784        cap->value = nb * dev->dinfo.block_size;
     785        cap->cunit = cu_byte;
    739786        return EOK;
    740787}
     
    767814        }
    768815
    769         rc = vol_part_mkfs(dev->fdisk->vol, part->svc_id, pspec->fstype);
    770         if (rc != EOK && rc != ENOTSUP) {
    771                 printf("mkfs failed\n");
    772                 fdisk_part_remove(part);
    773                 (void) vbd_part_delete(dev->fdisk->vbd, partid);
    774                 return EIO;
     816        if (part->svc_id != 0) {
     817                rc = vol_part_mkfs(dev->fdisk->vol, part->svc_id, pspec->fstype);
     818                if (rc != EOK && rc != ENOTSUP) {
     819                        printf("mkfs failed\n");
     820                        fdisk_part_remove(part);
     821                        (void) vbd_part_delete(dev->fdisk->vbd, partid);
     822                        return EIO;
     823                }
    775824        }
    776825
    777826        printf("fdisk_part_create() - done\n");
    778         part->pcnt = vpc_fs;
    779         part->fstype = pspec->fstype;
     827        if (part->svc_id != 0) {
     828                part->pcnt = vpc_fs;
     829                part->fstype = pspec->fstype;
     830        }
     831
    780832        part->capacity = pspec->capacity;
    781833
     
    9661018 */
    9671019static int fdisk_part_get_free_range(fdisk_dev_t *dev, aoff64_t nblocks,
     1020    fdisk_spc_t spc, aoff64_t *rblock0, aoff64_t *rnblocks)
     1021{
     1022        fdisk_free_range_t fr;
     1023        uint64_t b0;
     1024        uint64_t nb;
     1025
     1026        fdisk_free_range_first(dev, spc, &fr);
     1027        do {
     1028                if (fdisk_free_range_get(&fr, &b0, &nb)) {
     1029                        printf("free range: [%" PRIu64 ",+%" PRIu64 "]\n",
     1030                            b0, nb);
     1031                        if (nb >= nblocks) {
     1032                                printf("accepted.\n");
     1033                                *rblock0 = b0;
     1034                                *rnblocks = nb;
     1035                                return EOK;
     1036                        }
     1037                }
     1038        } while (fdisk_free_range_next(&fr));
     1039
     1040        /* No conforming free range found */
     1041        return ENOSPC;
     1042}
     1043
     1044/** Get largest free range of blocks.
     1045 *
     1046 * Get free range of blocks of the maximum size.
     1047 */
     1048static int fdisk_part_get_max_free_range(fdisk_dev_t *dev, fdisk_spc_t spc,
    9681049    aoff64_t *rblock0, aoff64_t *rnblocks)
    9691050{
    970         link_t *link;
    971         fdisk_part_t *part;
    972         uint64_t avail;
    973         uint64_t pb0;
    974         uint64_t nba;
    975 
    976         printf("fdisk_part_get_free_range: align=%" PRIu64 "\n",
    977             dev->align);
    978 
    979         link = list_first(&dev->pri_ba);
    980         nba = fdisk_ba_align_up(dev, dev->dinfo.ablock0);
    981         while (link != NULL) {
    982                 part = list_get_instance(link, fdisk_part_t, lpri_ba);
    983                 pb0 = fdisk_ba_align_down(dev, part->block0);
    984                 if (pb0 >= nba && pb0 - nba >= nblocks)
    985                         break;
    986                 nba = fdisk_ba_align_up(dev, part->block0 + part->nblocks);
    987                 link = list_next(link, &dev->pri_ba);
    988         }
    989 
    990         if (link != NULL) {
    991                 printf("nba=%" PRIu64 " pb0=%" PRIu64 "\n",
    992                     nba, pb0);
    993                 /* Free range before a partition */
    994                 avail = pb0 - nba;
    995         } else {
    996                 /* Free range at the end */
    997                 pb0 = fdisk_ba_align_down(dev, dev->dinfo.ablock0 +
    998                     dev->dinfo.anblocks);
    999                 if (pb0 < nba)
    1000                         return ELIMIT;
    1001                 avail = pb0 - nba;
    1002                 printf("nba=%" PRIu64 " avail=%" PRIu64 "\n",
    1003                     nba, avail);
    1004 
    1005         }
    1006 
    1007         /* Verify that the range is large enough */
    1008         if (avail < nblocks)
    1009                 return ELIMIT;
    1010 
    1011         *rblock0 = nba;
    1012         *rnblocks = avail;
    1013         return EOK;
    1014 }
    1015 
    1016 /** Get free range of blocks in extended partition.
    1017  *
    1018  * Get free range of blocks in extended partition that can accomodate
    1019  * a partition of at least the specified size plus the header (EBR + padding).
    1020  * Returns the header size in blocks, the start and length of the partition.
    1021  */
    1022 static int fdisk_part_get_log_free_range(fdisk_dev_t *dev, aoff64_t nblocks,
    1023     aoff64_t *rhdrb, aoff64_t *rblock0, aoff64_t *rnblocks)
    1024 {
    1025         link_t *link;
    1026         fdisk_part_t *part;
    1027         uint64_t avail;
    1028         uint64_t hdrb;
    1029         uint64_t pb0;
    1030         uint64_t nba;
    1031 
    1032         printf("fdisk_part_get_log_free_range\n");
    1033         /* Number of header blocks */
    1034         hdrb = max(1, dev->align);
    1035 
    1036         link = list_first(&dev->log_ba);
    1037         nba = fdisk_ba_align_up(dev, dev->ext_part->block0);
    1038         while (link != NULL) {
    1039                 part = list_get_instance(link, fdisk_part_t, llog_ba);
    1040                 pb0 = fdisk_ba_align_down(dev, part->block0);
    1041                 if (pb0 >= nba && pb0 - nba >= nblocks)
    1042                         break;
    1043                 nba = fdisk_ba_align_up(dev, part->block0 + part->nblocks);
    1044                 link = list_next(link, &dev->log_ba);
    1045         }
    1046 
    1047         if (link != NULL) {
    1048                 /* Free range before a partition */
    1049                 avail = pb0 - nba;
    1050         } else {
    1051                 /* Free range at the end */
    1052                 pb0 = fdisk_ba_align_down(dev, dev->ext_part->block0 +
    1053                     dev->ext_part->nblocks);
    1054                 if (pb0 < nba) {
    1055                         printf("not enough space\n");
    1056                         return ELIMIT;
     1051        fdisk_free_range_t fr;
     1052        uint64_t b0;
     1053        uint64_t nb;
     1054        uint64_t best_b0;
     1055        uint64_t best_nb;
     1056
     1057        best_b0 = best_nb = 0;
     1058        fdisk_free_range_first(dev, spc, &fr);
     1059        do {
     1060                if (fdisk_free_range_get(&fr, &b0, &nb)) {
     1061                        if (nb > best_nb) {
     1062                                best_b0 = b0;
     1063                                best_nb = nb;
     1064                        }
    10571065                }
    1058 
    1059                 avail = pb0 - nba;
    1060 
    1061                 printf("nba=%" PRIu64 " pb0=%" PRIu64" avail=%" PRIu64 "\n",
    1062                     nba, pb0, avail);
    1063         }
    1064         /* Verify that the range is large enough */
    1065         if (avail < hdrb + nblocks) {
    1066                 printf("not enough space\n");
    1067                 return ELIMIT;
    1068         }
    1069 
    1070         *rhdrb = hdrb;
    1071         *rblock0 = nba + hdrb;
    1072         *rnblocks = avail;
    1073         printf("hdrb=%" PRIu64 " block0=%" PRIu64" avail=%" PRIu64 "\n",
    1074             hdrb, nba + hdrb, avail);
     1066        } while (fdisk_free_range_next(&fr));
     1067
     1068        if (best_nb == 0)
     1069                return ENOSPC;
     1070
     1071        *rblock0 = best_b0;
     1072        *rnblocks = best_nb;
    10751073        return EOK;
    10761074}
     
    10821080        uint64_t cbytes;
    10831081        aoff64_t req_blocks;
    1084         aoff64_t fhdr;
    10851082        aoff64_t fblock0;
    10861083        aoff64_t fnblocks;
     1084        aoff64_t hdrb;
    10871085        uint64_t block_size;
    10881086        label_pcnt_t pcnt;
     
    11361134
    11371135                printf("fdisk_part_spec_prepare() - get free range\n");
    1138                 rc = fdisk_part_get_free_range(dev, req_blocks, &fblock0, &fnblocks);
     1136                rc = fdisk_part_get_free_range(dev, req_blocks, spc_pri,
     1137                    &fblock0, &fnblocks);
    11391138                if (rc != EOK)
    11401139                        return EIO;
     
    11491148        case lpk_logical:
    11501149                printf("fdisk_part_spec_prepare() - log\n");
    1151                 rc = fdisk_part_get_log_free_range(dev, req_blocks, &fhdr,
     1150                hdrb = max(1, dev->align);
     1151                rc = fdisk_part_get_free_range(dev, hdrb + req_blocks, spc_log,
    11521152                    &fblock0, &fnblocks);
    11531153                if (rc != EOK)
     
    11551155
    11561156                memset(vpspec, 0, sizeof(vbd_part_spec_t));
    1157                 vpspec->hdr_blocks = fhdr;
    1158                 vpspec->block0 = fblock0;
     1157                vpspec->hdr_blocks = hdrb;
     1158                vpspec->block0 = fblock0 + hdrb;
    11591159                vpspec->nblocks = req_blocks;
    11601160                vpspec->pkind = lpk_logical;
    1161                 vpspec->ptype.fmt = lptf_num;
    1162                 vpspec->ptype.t.num = 42;
    11631161                break;
    11641162        }
     
    12091207}
    12101208
     1209static void fdisk_free_range_first(fdisk_dev_t *dev, fdisk_spc_t spc,
     1210    fdisk_free_range_t *fr)
     1211{
     1212        link_t *link;
     1213
     1214        fr->dev = dev;
     1215        fr->spc = spc;
     1216
     1217        if (fr->spc == spc_pri) {
     1218                /* Primary partitions */
     1219                fr->b0 = fdisk_ba_align_up(fr->dev, fr->dev->dinfo.ablock0);
     1220
     1221                link = list_first(&dev->pri_ba);
     1222                if (link != NULL)
     1223                        fr->npart = list_get_instance(link, fdisk_part_t, lpri_ba);
     1224                else
     1225                        fr->npart = NULL;
     1226        } else { /* fr->spc == spc_log */
     1227                /* Logical partitions */
     1228                fr->b0 = fdisk_ba_align_up(fr->dev, fr->dev->ext_part->block0);
     1229
     1230                link = list_first(&dev->log_ba);
     1231                if (link != NULL)
     1232                        fr->npart = list_get_instance(link, fdisk_part_t, llog_ba);
     1233                else
     1234                        fr->npart = NULL;
     1235        }
     1236}
     1237
     1238static bool fdisk_free_range_next(fdisk_free_range_t *fr)
     1239{
     1240        link_t *link;
     1241
     1242        if (fr->npart == NULL)
     1243                return false;
     1244
     1245        fr->b0 = fdisk_ba_align_up(fr->dev, fr->npart->block0 +
     1246            fr->npart->nblocks);
     1247
     1248        if (fr->spc == spc_pri) {
     1249                /* Primary partitions */
     1250                link = list_next(&fr->npart->lpri_ba, &fr->dev->pri_ba);
     1251                if (link != NULL)
     1252                        fr->npart = list_get_instance(link, fdisk_part_t, lpri_ba);
     1253                else
     1254                        fr->npart = NULL;
     1255        } else { /* fr->spc == spc_log */
     1256                /* Logical partitions */
     1257                link = list_next(&fr->npart->llog_ba, &fr->dev->log_ba);
     1258                if (link != NULL)
     1259                        fr->npart = list_get_instance(link, fdisk_part_t, llog_ba);
     1260                else
     1261                        fr->npart = NULL;
     1262        }
     1263
     1264        return true;
     1265}
     1266
     1267static bool fdisk_free_range_get(fdisk_free_range_t *fr,
     1268    aoff64_t *b0, aoff64_t *nb)
     1269{
     1270        aoff64_t b1;
     1271
     1272        if (fr->npart != NULL) {
     1273                b1 = fdisk_ba_align_down(fr->dev, fr->npart->block0);
     1274        } else {
     1275                if (fr->spc == spc_pri) {
     1276                        b1 = fdisk_ba_align_down(fr->dev,
     1277                            fr->dev->dinfo.ablock0 + fr->dev->dinfo.anblocks);
     1278                } else { /* fr->spc == spc_log */
     1279                        b1 = fdisk_ba_align_down(fr->dev,
     1280                            fr->dev->ext_part->block0 + fr->dev->ext_part->nblocks);
     1281                }
     1282        }
     1283
     1284        if (b1 < fr->b0)
     1285                return false;
     1286
     1287        *b0 = fr->b0;
     1288        *nb = b1 - fr->b0;
     1289
     1290        return true;
     1291}
     1292
    12111293/** @}
    12121294 */
Note: See TracChangeset for help on using the changeset viewer.