2 * Copyright (c) 2024 Jiri Svoboda
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup libfdisk
33 * @file Disk management library.
48 static errno_t
fdisk_dev_add_parts(fdisk_dev_t
*);
49 static void fdisk_dev_remove_parts(fdisk_dev_t
*);
50 static errno_t
fdisk_part_spec_prepare(fdisk_dev_t
*, fdisk_part_spec_t
*,
52 static void fdisk_pri_part_insert_lists(fdisk_dev_t
*, fdisk_part_t
*);
53 static void fdisk_log_part_insert_lists(fdisk_dev_t
*, fdisk_part_t
*);
54 static errno_t
fdisk_update_dev_info(fdisk_dev_t
*);
55 static uint64_t fdisk_ba_align_up(fdisk_dev_t
*, uint64_t);
56 static uint64_t fdisk_ba_align_down(fdisk_dev_t
*, uint64_t);
57 static errno_t
fdisk_part_get_max_free_range(fdisk_dev_t
*, fdisk_spc_t
, aoff64_t
*,
59 static void fdisk_free_range_first(fdisk_dev_t
*, fdisk_spc_t
, fdisk_free_range_t
*);
60 static bool fdisk_free_range_next(fdisk_free_range_t
*);
61 static bool fdisk_free_range_get(fdisk_free_range_t
*, aoff64_t
*, aoff64_t
*);
63 static void fdisk_dev_info_delete(fdisk_dev_info_t
*info
)
72 errno_t
fdisk_create(fdisk_t
**rfdisk
)
74 fdisk_t
*fdisk
= NULL
;
77 fdisk
= calloc(1, sizeof(fdisk_t
));
83 rc
= vol_create(&fdisk
->vol
);
89 rc
= vbd_create(&fdisk
->vbd
);
103 void fdisk_destroy(fdisk_t
*fdisk
)
108 vol_destroy(fdisk
->vol
);
109 vbd_destroy(fdisk
->vbd
);
113 errno_t
fdisk_dev_list_get(fdisk_t
*fdisk
, fdisk_dev_list_t
**rdevlist
)
115 fdisk_dev_list_t
*devlist
= NULL
;
116 fdisk_dev_info_t
*info
;
117 service_id_t
*svcs
= NULL
;
121 devlist
= calloc(1, sizeof(fdisk_dev_list_t
));
125 devlist
->fdisk
= fdisk
;
126 list_initialize(&devlist
->devinfos
);
128 rc
= vbd_get_disks(fdisk
->vbd
, &svcs
, &count
);
134 for (i
= 0; i
< count
; i
++) {
135 info
= calloc(1, sizeof(fdisk_dev_info_t
));
141 info
->svcid
= svcs
[i
];
142 info
->devlist
= devlist
;
143 list_append(&info
->ldevlist
, &devlist
->devinfos
);
151 fdisk_dev_list_free(devlist
);
155 void fdisk_dev_list_free(fdisk_dev_list_t
*devlist
)
157 fdisk_dev_info_t
*info
;
162 while (!list_empty(&devlist
->devinfos
)) {
163 info
= list_get_instance(list_first(
164 &devlist
->devinfos
), fdisk_dev_info_t
,
167 list_remove(&info
->ldevlist
);
168 fdisk_dev_info_delete(info
);
174 fdisk_dev_info_t
*fdisk_dev_first(fdisk_dev_list_t
*devlist
)
176 if (list_empty(&devlist
->devinfos
))
179 return list_get_instance(list_first(&devlist
->devinfos
),
180 fdisk_dev_info_t
, ldevlist
);
183 fdisk_dev_info_t
*fdisk_dev_next(fdisk_dev_info_t
*devinfo
)
187 lnext
= list_next(&devinfo
->ldevlist
,
188 &devinfo
->devlist
->devinfos
);
192 return list_get_instance(lnext
, fdisk_dev_info_t
,
196 void fdisk_dev_info_get_svcid(fdisk_dev_info_t
*info
, service_id_t
*rsid
)
201 errno_t
fdisk_dev_info_get_svcname(fdisk_dev_info_t
*info
, char **rname
)
206 if (info
->svcname
== NULL
) {
207 rc
= loc_service_get_name(info
->svcid
,
213 name
= str_dup(info
->svcname
);
221 errno_t
fdisk_dev_info_capacity(fdisk_dev_info_t
*info
, capa_spec_t
*capa
)
223 vbd_disk_info_t vinfo
;
226 rc
= vbd_disk_info(info
->devlist
->fdisk
->vbd
, info
->svcid
, &vinfo
);
230 capa_from_blocks(vinfo
.nblocks
, vinfo
.block_size
, capa
);
234 /** Add partition to our inventory. */
235 static errno_t
fdisk_part_add(fdisk_dev_t
*dev
, vbd_part_id_t partid
,
236 fdisk_part_t
**rpart
)
239 vbd_part_info_t pinfo
;
240 vol_part_info_t vpinfo
;
243 part
= calloc(1, sizeof(fdisk_part_t
));
247 rc
= vbd_part_get_info(dev
->fdisk
->vbd
, partid
, &pinfo
);
253 if (pinfo
.svc_id
!= 0) {
255 * Normally vol service discovers the partition asynchronously.
256 * Here we need to make sure the partition is already known to it.
258 rc
= vol_part_add(dev
->fdisk
->vol
, pinfo
.svc_id
);
259 if (rc
!= EOK
&& rc
!= EEXIST
) {
264 rc
= vol_part_info(dev
->fdisk
->vol
, pinfo
.svc_id
, &vpinfo
);
270 part
->pcnt
= vpinfo
.pcnt
;
271 part
->fstype
= vpinfo
.fstype
;
272 part
->label
= str_dup(vpinfo
.label
);
276 part
->index
= pinfo
.index
;
277 part
->block0
= pinfo
.block0
;
278 part
->nblocks
= pinfo
.nblocks
;
279 part
->pkind
= pinfo
.pkind
;
280 part
->svc_id
= pinfo
.svc_id
;
282 switch (part
->pkind
) {
285 fdisk_pri_part_insert_lists(dev
, part
);
288 fdisk_log_part_insert_lists(dev
, part
);
292 list_append(&part
->lparts
, &dev
->parts
);
294 if (part
->pkind
== lpk_extended
)
295 dev
->ext_part
= part
;
297 capa_from_blocks(part
->nblocks
, dev
->dinfo
.block_size
,
299 part
->part_id
= partid
;
311 /** Remove partition from our inventory. */
312 static void fdisk_part_remove(fdisk_part_t
*part
)
314 list_remove(&part
->lparts
);
315 if (link_used(&part
->lpri_ba
))
316 list_remove(&part
->lpri_ba
);
317 if (link_used(&part
->lpri_idx
))
318 list_remove(&part
->lpri_idx
);
319 if (link_used(&part
->llog_ba
))
320 list_remove(&part
->llog_ba
);
326 static void fdisk_pri_part_insert_lists(fdisk_dev_t
*dev
, fdisk_part_t
*part
)
331 /* Insert to list by block address */
332 link
= list_first(&dev
->pri_ba
);
333 while (link
!= NULL
) {
334 p
= list_get_instance(link
, fdisk_part_t
, lpri_ba
);
335 if (p
->block0
> part
->block0
) {
336 list_insert_before(&part
->lpri_ba
, &p
->lpri_ba
);
340 link
= list_next(link
, &dev
->pri_ba
);
344 list_append(&part
->lpri_ba
, &dev
->pri_ba
);
346 /* Insert to list by index */
347 link
= list_first(&dev
->pri_idx
);
348 while (link
!= NULL
) {
349 p
= list_get_instance(link
, fdisk_part_t
, lpri_idx
);
350 if (p
->index
> part
->index
) {
351 list_insert_before(&part
->lpri_idx
, &p
->lpri_idx
);
355 link
= list_next(link
, &dev
->pri_idx
);
359 list_append(&part
->lpri_idx
, &dev
->pri_idx
);
362 static void fdisk_log_part_insert_lists(fdisk_dev_t
*dev
, fdisk_part_t
*part
)
367 /* Insert to list by block address */
368 link
= list_first(&dev
->log_ba
);
369 while (link
!= NULL
) {
370 p
= list_get_instance(link
, fdisk_part_t
, llog_ba
);
371 if (p
->block0
> part
->block0
) {
372 list_insert_before(&part
->llog_ba
, &p
->llog_ba
);
376 link
= list_next(link
, &dev
->log_ba
);
380 list_append(&part
->llog_ba
, &dev
->log_ba
);
383 static errno_t
fdisk_dev_add_parts(fdisk_dev_t
*dev
)
385 service_id_t
*psids
= NULL
;
389 rc
= fdisk_update_dev_info(dev
);
395 rc
= vbd_label_get_parts(dev
->fdisk
->vbd
, dev
->sid
, &psids
, &nparts
);
401 for (i
= 0; i
< nparts
; i
++) {
402 rc
= fdisk_part_add(dev
, psids
[i
], NULL
);
411 fdisk_dev_remove_parts(dev
);
415 static void fdisk_dev_remove_parts(fdisk_dev_t
*dev
)
419 part
= fdisk_part_first(dev
);
420 while (part
!= NULL
) {
421 fdisk_part_remove(part
);
422 part
= fdisk_part_first(dev
);
426 errno_t
fdisk_dev_open(fdisk_t
*fdisk
, service_id_t sid
, fdisk_dev_t
**rdev
)
428 fdisk_dev_t
*dev
= NULL
;
429 service_id_t
*psids
= NULL
;
433 dev
= calloc(1, sizeof(fdisk_dev_t
));
439 list_initialize(&dev
->parts
);
440 list_initialize(&dev
->pri_idx
);
441 list_initialize(&dev
->pri_ba
);
442 list_initialize(&dev
->log_ba
);
444 rc
= fdisk_update_dev_info(dev
);
450 rc
= vbd_label_get_parts(fdisk
->vbd
, sid
, &psids
, &nparts
);
456 for (i
= 0; i
< nparts
; i
++) {
457 rc
= fdisk_part_add(dev
, psids
[i
], NULL
);
467 fdisk_dev_close(dev
);
471 void fdisk_dev_close(fdisk_dev_t
*dev
)
476 fdisk_dev_remove_parts(dev
);
480 /** Erase contents of unlabeled disk. */
481 errno_t
fdisk_dev_erase(fdisk_dev_t
*dev
)
486 if (dev
->dinfo
.ltype
!= lt_none
)
489 part
= fdisk_part_first(dev
);
490 assert(part
!= NULL
);
491 if (part
->pcnt
== vpc_empty
)
494 rc
= vol_part_empty(dev
->fdisk
->vol
, part
->svc_id
);
499 part
->pcnt
= vpc_empty
;
503 void fdisk_dev_get_flags(fdisk_dev_t
*dev
, fdisk_dev_flags_t
*rflags
)
505 fdisk_dev_flags_t flags
;
510 /* fdf_can_create_label */
511 if (dev
->dinfo
.ltype
== lt_none
) {
512 part
= fdisk_part_first(dev
);
513 assert(part
!= NULL
);
514 if (part
->pcnt
== vpc_empty
)
515 flags
|= fdf_can_create_label
;
517 flags
|= fdf_can_erase_dev
;
519 flags
|= fdf_can_delete_label
;
525 errno_t
fdisk_dev_get_svcname(fdisk_dev_t
*dev
, char **rname
)
530 rc
= loc_service_get_name(dev
->sid
, &name
);
538 errno_t
fdisk_dev_capacity(fdisk_dev_t
*dev
, capa_spec_t
*capa
)
540 capa_from_blocks(dev
->dinfo
.nblocks
, dev
->dinfo
.block_size
, capa
);
544 errno_t
fdisk_label_get_info(fdisk_dev_t
*dev
, fdisk_label_info_t
*info
)
546 vbd_disk_info_t vinfo
;
551 rc
= vbd_disk_info(dev
->fdisk
->vbd
, dev
->sid
, &vinfo
);
557 info
->ltype
= vinfo
.ltype
;
558 info
->flags
= vinfo
.flags
;
560 if ((info
->flags
& lf_can_create_pri
) != 0 ||
561 (info
->flags
& lf_can_create_ext
) != 0) {
562 /* Verify there is enough space to create partition */
564 rc
= fdisk_part_get_max_free_range(dev
, spc_pri
, &b0
, &nb
);
566 info
->flags
&= ~(lf_can_create_pri
| lf_can_create_ext
);
569 if ((info
->flags
& lf_can_create_log
) != 0) {
570 /* Verify there is enough space to create logical partition */
571 hdrb
= max(1, dev
->align
);
572 rc
= fdisk_part_get_max_free_range(dev
, spc_log
, &b0
, &nb
);
573 if (rc
!= EOK
|| nb
<= hdrb
)
574 info
->flags
&= ~lf_can_create_log
;
582 errno_t
fdisk_label_create(fdisk_dev_t
*dev
, label_type_t ltype
)
587 /* Disk must not contain a label. */
588 if (dev
->dinfo
.ltype
!= lt_none
)
591 /* Dummy partition spanning entire disk must be considered empty */
592 part
= fdisk_part_first(dev
);
593 assert(part
!= NULL
);
594 if (part
->pcnt
!= vpc_empty
)
597 /* Remove dummy partition */
598 fdisk_dev_remove_parts(dev
);
600 rc
= vbd_label_create(dev
->fdisk
->vbd
, dev
->sid
, ltype
);
602 /* Re-add dummy partition */
603 (void) fdisk_dev_add_parts(dev
);
607 rc
= fdisk_update_dev_info(dev
);
614 errno_t
fdisk_label_destroy(fdisk_dev_t
*dev
)
617 fdisk_dev_flags_t dflags
;
620 part
= fdisk_part_first(dev
);
621 while (part
!= NULL
) {
622 rc
= fdisk_part_destroy(part
);
625 part
= fdisk_part_first(dev
);
628 rc
= vbd_label_delete(dev
->fdisk
->vbd
, dev
->sid
);
632 rc
= fdisk_dev_add_parts(dev
);
636 /* Make sure device is considered empty */
637 fdisk_dev_get_flags(dev
, &dflags
);
638 if ((dflags
& fdf_can_erase_dev
) != 0) {
639 rc
= fdisk_dev_erase(dev
);
647 fdisk_part_t
*fdisk_part_first(fdisk_dev_t
*dev
)
651 link
= list_first(&dev
->parts
);
655 return list_get_instance(link
, fdisk_part_t
, lparts
);
658 fdisk_part_t
*fdisk_part_next(fdisk_part_t
*part
)
662 link
= list_next(&part
->lparts
, &part
->dev
->parts
);
666 return list_get_instance(link
, fdisk_part_t
, lparts
);
669 errno_t
fdisk_part_get_info(fdisk_part_t
*part
, fdisk_part_info_t
*info
)
671 info
->capacity
= part
->capacity
;
672 info
->pcnt
= part
->pcnt
;
673 info
->fstype
= part
->fstype
;
674 info
->pkind
= part
->pkind
;
675 info
->label
= part
->label
;
676 info
->svc_id
= part
->svc_id
;
680 /** Get size of largest free block. */
681 errno_t
fdisk_part_get_max_avail(fdisk_dev_t
*dev
, fdisk_spc_t spc
,
689 rc
= fdisk_part_get_max_free_range(dev
, spc
, &b0
, &nb
);
693 /* For logical partitions we need to subtract header size */
694 if (spc
== spc_log
) {
695 hdrb
= max(1, dev
->align
);
701 capa_from_blocks(nb
, dev
->dinfo
.block_size
, capa
);
705 /** Get total free space capacity. */
706 errno_t
fdisk_part_get_tot_avail(fdisk_dev_t
*dev
, fdisk_spc_t spc
,
709 fdisk_free_range_t fr
;
716 hdrb
= max(1, dev
->align
);
721 fdisk_free_range_first(dev
, spc
, &fr
);
723 if (fdisk_free_range_get(&fr
, &b0
, &nb
)) {
727 } while (fdisk_free_range_next(&fr
));
729 capa_from_blocks(totb
, dev
->dinfo
.block_size
, capa
);
733 /** Create partition.
735 * Create new partition based on a specification.
737 * @param dev Fdisk device
738 * @param pspec Partition specification
739 * @param rpart Place to store pointer to new partition
741 * @return EOK on success or error code
743 errno_t
fdisk_part_create(fdisk_dev_t
*dev
, fdisk_part_spec_t
*pspec
,
744 fdisk_part_t
**rpart
)
746 fdisk_part_t
*part
= NULL
;
747 vbd_part_spec_t vpspec
;
748 vbd_part_id_t partid
= 0;
749 vol_part_info_t vpinfo
;
754 label
= pspec
->label
!= NULL
? pspec
->label
: "";
755 mountp
= pspec
->mountp
!= NULL
? pspec
->mountp
: "";
757 rc
= fdisk_part_spec_prepare(dev
, pspec
, &vpspec
);
763 rc
= vbd_part_create(dev
->fdisk
->vbd
, dev
->sid
, &vpspec
, &partid
);
769 rc
= fdisk_part_add(dev
, partid
, &part
);
775 if (part
->svc_id
!= 0) {
776 rc
= vol_part_mkfs(dev
->fdisk
->vol
, part
->svc_id
, pspec
->fstype
,
778 if (rc
!= EOK
&& rc
!= ENOTSUP
) {
783 /* Get the real label value */
784 rc
= vol_part_info(dev
->fdisk
->vol
, part
->svc_id
, &vpinfo
);
790 part
->pcnt
= vpinfo
.pcnt
;
791 part
->fstype
= vpinfo
.fstype
;
792 part
->label
= str_dup(vpinfo
.label
);
794 if (part
->label
== NULL
) {
804 /* Try rolling back */
806 fdisk_part_remove(part
);
808 (void) vbd_part_delete(dev
->fdisk
->vbd
, partid
);
812 /** Destroy partition.
814 * @param part Partition
815 * @return EOK on success or error code
817 errno_t
fdisk_part_destroy(fdisk_part_t
*part
)
821 rc
= vol_part_eject(part
->dev
->fdisk
->vol
, part
->svc_id
);
825 rc
= vbd_part_delete(part
->dev
->fdisk
->vbd
, part
->part_id
);
829 fdisk_part_remove(part
);
833 /** Set partition mount point.
835 * @param part Fdisk partition
836 * @param mountp Mount point
838 * @return EOK on success or error code
840 errno_t
fdisk_part_set_mountp(fdisk_part_t
*part
, const char *mountp
)
842 return vol_part_set_mountp(part
->dev
->fdisk
->vol
,
843 part
->svc_id
, mountp
);
846 void fdisk_pspec_init(fdisk_part_spec_t
*pspec
)
848 memset(pspec
, 0, sizeof(fdisk_part_spec_t
));
851 /** Get free partition index. */
852 static errno_t
fdisk_part_get_free_idx(fdisk_dev_t
*dev
, int *rindex
)
858 link
= list_first(&dev
->pri_idx
);
860 while (link
!= NULL
) {
861 part
= list_get_instance(link
, fdisk_part_t
, lpri_idx
);
862 if (part
->index
> nidx
)
864 nidx
= part
->index
+ 1;
865 link
= list_next(link
, &dev
->pri_idx
);
868 if (nidx
> 4 /* XXXX actual number of slots */) {
876 /** Get free range of blocks.
878 * Get free range of blocks of at least the specified size (first fit).
880 static errno_t
fdisk_part_get_free_range(fdisk_dev_t
*dev
, aoff64_t nblocks
,
881 fdisk_spc_t spc
, aoff64_t
*rblock0
, aoff64_t
*rnblocks
)
883 fdisk_free_range_t fr
;
887 fdisk_free_range_first(dev
, spc
, &fr
);
889 if (fdisk_free_range_get(&fr
, &b0
, &nb
)) {
896 } while (fdisk_free_range_next(&fr
));
898 /* No conforming free range found */
902 /** Get largest free range of blocks.
904 * Get free range of blocks of the maximum size.
906 static errno_t
fdisk_part_get_max_free_range(fdisk_dev_t
*dev
, fdisk_spc_t spc
,
907 aoff64_t
*rblock0
, aoff64_t
*rnblocks
)
909 fdisk_free_range_t fr
;
915 best_b0
= best_nb
= 0;
916 fdisk_free_range_first(dev
, spc
, &fr
);
918 if (fdisk_free_range_get(&fr
, &b0
, &nb
)) {
924 } while (fdisk_free_range_next(&fr
));
934 /** Prepare new partition specification for VBD. */
935 static errno_t
fdisk_part_spec_prepare(fdisk_dev_t
*dev
, fdisk_part_spec_t
*pspec
,
936 vbd_part_spec_t
*vpspec
)
950 rc
= capa_to_blocks(&pspec
->capacity
, cv_nom
, dev
->dinfo
.block_size
,
955 rc
= capa_to_blocks(&pspec
->capacity
, cv_min
, dev
->dinfo
.block_size
,
960 rc
= capa_to_blocks(&pspec
->capacity
, cv_max
, dev
->dinfo
.block_size
,
965 nom_blocks
= fdisk_ba_align_up(dev
, nom_blocks
);
966 min_blocks
= fdisk_ba_align_up(dev
, min_blocks
);
967 max_blocks
= fdisk_ba_align_up(dev
, max_blocks
);
971 switch (pspec
->fstype
) {
976 pcnt
= lpc_fat32
; /* XXX Detect FAT12/16 vs FAT32 */
985 return EINVAL
; /* You cannot create an ISO partition */
988 if (pcnt
== LPC_LIMIT
)
991 if (pspec
->pkind
== lpk_logical
) {
992 hdrb
= max(1, dev
->align
);
999 rc
= fdisk_part_get_free_range(dev
, hdrb
+ nom_blocks
, spc
,
1000 &fblock0
, &fnblocks
);
1004 * If the size of the free range would still give the same capacity
1005 * when rounded, allocate entire range. Otherwise allocate exactly
1006 * what we were asked for.
1008 if (fnblocks
<= max_blocks
) {
1009 act_blocks
= fnblocks
;
1011 act_blocks
= hdrb
+ nom_blocks
;
1014 assert(rc
== ENOSPC
);
1017 * There is no free range that can contain exactly the requested
1018 * capacity. Try to allocate at least such number of blocks
1019 * that would still fullfill the request within the limits
1020 * of the precision with witch the capacity was specified
1021 * (i.e. when rounded up).
1023 rc
= fdisk_part_get_free_range(dev
, hdrb
+ min_blocks
, spc
,
1024 &fblock0
, &fnblocks
);
1028 assert(fnblocks
< hdrb
+ nom_blocks
);
1029 act_blocks
= fnblocks
;
1032 if (pspec
->pkind
!= lpk_logical
) {
1033 rc
= fdisk_part_get_free_idx(dev
, &index
);
1040 memset(vpspec
, 0, sizeof(vbd_part_spec_t
));
1041 vpspec
->index
= index
;
1042 vpspec
->hdr_blocks
= hdrb
;
1043 vpspec
->block0
= fblock0
+ hdrb
;
1044 vpspec
->nblocks
= act_blocks
- hdrb
;
1045 vpspec
->pkind
= pspec
->pkind
;
1047 if (pspec
->pkind
!= lpk_extended
) {
1048 rc
= vbd_suggest_ptype(dev
->fdisk
->vbd
, dev
->sid
, pcnt
,
1057 static errno_t
fdisk_update_dev_info(fdisk_dev_t
*dev
)
1063 rc
= vbd_disk_info(dev
->fdisk
->vbd
, dev
->sid
, &dev
->dinfo
);
1067 /* Capacity available for partition in bytes */
1068 avail_cap
= dev
->dinfo
.anblocks
* dev
->dinfo
.block_size
;
1070 /* Determine optimum alignment */
1071 align_bytes
= 1024 * 1024; /* 1 MiB */
1072 while (align_bytes
> 1 && avail_cap
/ align_bytes
< 256) {
1073 align_bytes
= align_bytes
/ 16;
1076 dev
->align
= align_bytes
/ dev
->dinfo
.block_size
;
1082 static uint64_t fdisk_ba_align_up(fdisk_dev_t
*dev
, uint64_t ba
)
1084 return ((ba
+ dev
->align
- 1) / dev
->align
) * dev
->align
;
1087 static uint64_t fdisk_ba_align_down(fdisk_dev_t
*dev
, uint64_t ba
)
1089 return ba
- (ba
% dev
->align
);
1092 static void fdisk_free_range_first(fdisk_dev_t
*dev
, fdisk_spc_t spc
,
1093 fdisk_free_range_t
*fr
)
1100 if (fr
->spc
== spc_pri
) {
1101 /* Primary partitions */
1102 fr
->b0
= fdisk_ba_align_up(fr
->dev
, fr
->dev
->dinfo
.ablock0
);
1104 link
= list_first(&dev
->pri_ba
);
1106 fr
->npart
= list_get_instance(link
, fdisk_part_t
, lpri_ba
);
1109 } else { /* fr->spc == spc_log */
1110 /* Logical partitions */
1111 fr
->b0
= fdisk_ba_align_up(fr
->dev
, fr
->dev
->ext_part
->block0
);
1113 link
= list_first(&dev
->log_ba
);
1115 fr
->npart
= list_get_instance(link
, fdisk_part_t
, llog_ba
);
1121 static bool fdisk_free_range_next(fdisk_free_range_t
*fr
)
1125 if (fr
->npart
== NULL
)
1128 fr
->b0
= fdisk_ba_align_up(fr
->dev
, fr
->npart
->block0
+
1129 fr
->npart
->nblocks
);
1131 if (fr
->spc
== spc_pri
) {
1132 /* Primary partitions */
1133 link
= list_next(&fr
->npart
->lpri_ba
, &fr
->dev
->pri_ba
);
1135 fr
->npart
= list_get_instance(link
, fdisk_part_t
, lpri_ba
);
1138 } else { /* fr->spc == spc_log */
1139 /* Logical partitions */
1140 link
= list_next(&fr
->npart
->llog_ba
, &fr
->dev
->log_ba
);
1142 fr
->npart
= list_get_instance(link
, fdisk_part_t
, llog_ba
);
1150 static bool fdisk_free_range_get(fdisk_free_range_t
*fr
,
1151 aoff64_t
*b0
, aoff64_t
*nb
)
1155 if (fr
->npart
!= NULL
) {
1156 b1
= fdisk_ba_align_down(fr
->dev
, fr
->npart
->block0
);
1158 if (fr
->spc
== spc_pri
) {
1159 b1
= fdisk_ba_align_down(fr
->dev
,
1160 fr
->dev
->dinfo
.ablock0
+ fr
->dev
->dinfo
.anblocks
);
1161 } else { /* fr->spc == spc_log */
1162 b1
= fdisk_ba_align_down(fr
->dev
,
1163 fr
->dev
->ext_part
->block0
+ fr
->dev
->ext_part
->nblocks
);
1176 /** Get volume label support. */
1177 errno_t
fdisk_get_vollabel_support(fdisk_dev_t
*dev
, vol_fstype_t fstype
,
1178 vol_label_supp_t
*vlsupp
)
1180 return vol_part_get_lsupp(dev
->fdisk
->vol
, fstype
, vlsupp
);