source: mainline/uspace/lib/fdisk/src/fdisk.c@ 4b6635a7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4b6635a7 was 4b6635a7, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Volsrv empty partition detection.

  • Property mode set to 100644
File size: 21.1 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
16 *
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.
27 */
28
29/** @addtogroup libfdisk
30 * @{
31 */
32/**
33 * @file Disk management library.
34 */
35
36#include <adt/list.h>
37#include <block.h>
38#include <errno.h>
39#include <fdisk.h>
40#include <loc.h>
41#include <mem.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <str.h>
45#include <vbd.h>
46#include <vol.h>
47
48static const char *cu_str[] = {
49 [cu_byte] = "B",
50 [cu_kbyte] = "kB",
51 [cu_mbyte] = "MB",
52 [cu_gbyte] = "GB",
53 [cu_tbyte] = "TB",
54 [cu_pbyte] = "PB",
55 [cu_ebyte] = "EB",
56 [cu_zbyte] = "ZB",
57 [cu_ybyte] = "YB"
58};
59
60static int fdisk_part_spec_prepare(fdisk_dev_t *, fdisk_part_spec_t *,
61 vbd_part_spec_t *);
62static void fdisk_pri_part_insert_lists(fdisk_dev_t *, fdisk_part_t *);
63static void fdisk_log_part_insert_lists(fdisk_dev_t *, fdisk_part_t *);
64static int fdisk_update_dev_info(fdisk_dev_t *);
65static uint64_t fdisk_ba_align_up(fdisk_dev_t *, uint64_t);
66static uint64_t fdisk_ba_align_down(fdisk_dev_t *, uint64_t);
67
68static void fdisk_dev_info_delete(fdisk_dev_info_t *info)
69{
70 if (info == NULL)
71 return;
72
73 if (info->blk_inited)
74 block_fini(info->svcid);
75
76 free(info->svcname);
77 free(info);
78}
79
80int fdisk_create(fdisk_t **rfdisk)
81{
82 fdisk_t *fdisk = NULL;
83 int rc;
84
85 fdisk = calloc(1, sizeof(fdisk_t));
86 if (fdisk == NULL) {
87 rc = ENOMEM;
88 goto error;
89 }
90
91 rc = vol_create(&fdisk->vol);
92 if (rc != EOK) {
93 rc = EIO;
94 goto error;
95 }
96
97 rc = vbd_create(&fdisk->vbd);
98 if (rc != EOK) {
99 rc = EIO;
100 goto error;
101 }
102
103 *rfdisk = fdisk;
104 return EOK;
105error:
106 fdisk_destroy(fdisk);
107
108 return rc;
109}
110
111void fdisk_destroy(fdisk_t *fdisk)
112{
113 if (fdisk == NULL)
114 return;
115
116 vol_destroy(fdisk->vol);
117 vbd_destroy(fdisk->vbd);
118 free(fdisk);
119}
120
121int fdisk_dev_list_get(fdisk_t *fdisk, fdisk_dev_list_t **rdevlist)
122{
123 fdisk_dev_list_t *devlist = NULL;
124 fdisk_dev_info_t *info;
125 service_id_t *svcs = NULL;
126 size_t count, i;
127 int rc;
128
129 devlist = calloc(1, sizeof(fdisk_dev_list_t));
130 if (devlist == NULL)
131 return ENOMEM;
132
133 list_initialize(&devlist->devinfos);
134
135 printf("vbd_get_disks()\n");
136 rc = vbd_get_disks(fdisk->vbd, &svcs, &count);
137 printf(" -> %d\n", rc);
138 if (rc != EOK) {
139 rc = EIO;
140 goto error;
141 }
142
143 for (i = 0; i < count; i++) {
144 info = calloc(1, sizeof(fdisk_dev_info_t));
145 if (info == NULL) {
146 rc = ENOMEM;
147 goto error;
148 }
149
150 info->svcid = svcs[i];
151 info->devlist = devlist;
152 list_append(&info->ldevlist, &devlist->devinfos);
153 }
154
155 *rdevlist = devlist;
156 free(svcs);
157 return EOK;
158error:
159 free(svcs);
160 fdisk_dev_list_free(devlist);
161 return rc;
162}
163
164void fdisk_dev_list_free(fdisk_dev_list_t *devlist)
165{
166 fdisk_dev_info_t *info;
167
168 if (devlist == NULL)
169 return;
170
171 while (!list_empty(&devlist->devinfos)) {
172 info = list_get_instance(list_first(
173 &devlist->devinfos), fdisk_dev_info_t,
174 ldevlist);
175
176 list_remove(&info->ldevlist);
177 fdisk_dev_info_delete(info);
178 }
179
180 free(devlist);
181}
182
183fdisk_dev_info_t *fdisk_dev_first(fdisk_dev_list_t *devlist)
184{
185 if (list_empty(&devlist->devinfos))
186 return NULL;
187
188 return list_get_instance(list_first(&devlist->devinfos),
189 fdisk_dev_info_t, ldevlist);
190}
191
192fdisk_dev_info_t *fdisk_dev_next(fdisk_dev_info_t *devinfo)
193{
194 link_t *lnext;
195
196 lnext = list_next(&devinfo->ldevlist,
197 &devinfo->devlist->devinfos);
198 if (lnext == NULL)
199 return NULL;
200
201 return list_get_instance(lnext, fdisk_dev_info_t,
202 ldevlist);
203}
204
205void fdisk_dev_info_get_svcid(fdisk_dev_info_t *info, service_id_t *rsid)
206{
207 *rsid = info->svcid;
208}
209
210int fdisk_dev_info_get_svcname(fdisk_dev_info_t *info, char **rname)
211{
212 char *name;
213 int rc;
214
215 if (info->svcname == NULL) {
216 rc = loc_service_get_name(info->svcid,
217 &info->svcname);
218 if (rc != EOK)
219 return rc;
220 }
221
222 name = str_dup(info->svcname);
223 if (name == NULL)
224 return ENOMEM;
225
226 *rname = name;
227 return EOK;
228}
229
230int fdisk_dev_info_capacity(fdisk_dev_info_t *info, fdisk_cap_t *cap)
231{
232 size_t bsize;
233 aoff64_t nblocks;
234 int rc;
235
236 if (!info->blk_inited) {
237 rc = block_init(EXCHANGE_SERIALIZE, info->svcid, 2048);
238 if (rc != EOK)
239 return rc;
240
241 info->blk_inited = true;
242 }
243
244 rc = block_get_bsize(info->svcid, &bsize);
245 if (rc != EOK)
246 return EIO;
247
248 rc = block_get_nblocks(info->svcid, &nblocks);
249 if (rc != EOK)
250 return EIO;
251
252 cap->value = bsize * nblocks;
253 cap->cunit = cu_byte;
254
255 return EOK;
256}
257
258static int fdisk_part_add(fdisk_dev_t *dev, vbd_part_id_t partid,
259 fdisk_part_t **rpart)
260{
261 fdisk_part_t *part;
262 vbd_part_info_t pinfo;
263 vol_part_info_t vpinfo;
264 int rc;
265
266 part = calloc(1, sizeof(fdisk_part_t));
267 if (part == NULL)
268 return ENOMEM;
269
270 rc = vbd_part_get_info(dev->fdisk->vbd, partid, &pinfo);
271 if (rc != EOK) {
272 rc = EIO;
273 goto error;
274 }
275
276 rc = vol_part_info(dev->fdisk->vol, pinfo.svc_id, &vpinfo);
277 if (rc != EOK) {
278 rc = EIO;
279 goto error;
280 }
281
282 part->dev = dev;
283 part->index = pinfo.index;
284 part->block0 = pinfo.block0;
285 part->nblocks = pinfo.nblocks;
286 part->pkind = pinfo.pkind;
287 part->svc_id = pinfo.svc_id;
288 part->pcnt = vpinfo.pcnt;
289 part->fstype = vpinfo.fstype;
290
291 switch (part->pkind) {
292 case lpk_primary:
293 case lpk_extended:
294 fdisk_pri_part_insert_lists(dev, part);
295 break;
296 case lpk_logical:
297 fdisk_log_part_insert_lists(dev, part);
298 break;
299 }
300
301 list_append(&part->lparts, &dev->parts);
302
303 if (part->pkind == lpk_extended)
304 dev->ext_part = part;
305
306 part->capacity.cunit = cu_byte;
307 part->capacity.value = part->nblocks * dev->dinfo.block_size;
308 part->part_id = partid;
309
310 if (rpart != NULL)
311 *rpart = part;
312 return EOK;
313error:
314 free(part);
315 return rc;
316}
317
318static void fdisk_pri_part_insert_lists(fdisk_dev_t *dev, fdisk_part_t *part)
319{
320 link_t *link;
321 fdisk_part_t *p;
322
323 /* Insert to list by block address */
324 link = list_first(&dev->pri_ba);
325 while (link != NULL) {
326 p = list_get_instance(link, fdisk_part_t, lpri_ba);
327 if (p->block0 > part->block0) {
328 list_insert_before(&part->lpri_ba, &p->lpri_ba);
329 break;
330 }
331
332 link = list_next(link, &dev->pri_ba);
333 }
334
335 if (link == NULL)
336 list_append(&part->lpri_ba, &dev->pri_ba);
337
338 /* Insert to list by index */
339 link = list_first(&dev->pri_idx);
340 while (link != NULL) {
341 p = list_get_instance(link, fdisk_part_t, lpri_idx);
342 if (p->index > part->index) {
343 list_insert_before(&part->lpri_idx, &p->lpri_idx);
344 break;
345 }
346
347 link = list_next(link, &dev->pri_idx);
348 }
349
350 if (link == NULL)
351 list_append(&part->lpri_idx, &dev->pri_idx);
352}
353
354static void fdisk_log_part_insert_lists(fdisk_dev_t *dev, fdisk_part_t *part)
355{
356 link_t *link;
357 fdisk_part_t *p;
358
359 /* Insert to list by block address */
360 link = list_first(&dev->log_ba);
361 while (link != NULL) {
362 p = list_get_instance(link, fdisk_part_t, llog_ba);
363 if (p->block0 > part->block0) {
364 list_insert_before(&part->llog_ba, &p->llog_ba);
365 break;
366 }
367
368 link = list_next(link, &dev->log_ba);
369 }
370
371 if (link == NULL)
372 list_append(&part->llog_ba, &dev->log_ba);
373}
374
375int fdisk_dev_open(fdisk_t *fdisk, service_id_t sid, fdisk_dev_t **rdev)
376{
377 vbd_disk_info_t vinfo;
378 fdisk_dev_t *dev = NULL;
379 service_id_t *psids = NULL;
380 size_t nparts, i;
381 int rc;
382
383 dev = calloc(1, sizeof(fdisk_dev_t));
384 if (dev == NULL)
385 return ENOMEM;
386
387 dev->fdisk = fdisk;
388 dev->sid = sid;
389 list_initialize(&dev->parts);
390 list_initialize(&dev->pri_idx);
391 list_initialize(&dev->pri_ba);
392 list_initialize(&dev->log_ba);
393
394 rc = vbd_disk_info(fdisk->vbd, sid, &vinfo);
395 if (rc != EOK) {
396 rc = EIO;
397 goto error;
398 }
399
400 printf("get label info\n");
401 rc = fdisk_update_dev_info(dev);
402 if (rc != EOK) {
403 printf("failed\n");
404 rc = EIO;
405 goto error;
406 }
407
408 printf("block size: %zu\n", dev->dinfo.block_size);
409 printf("get partitions\n");
410 rc = vbd_label_get_parts(fdisk->vbd, sid, &psids, &nparts);
411 if (rc != EOK) {
412 printf("failed\n");
413 rc = EIO;
414 goto error;
415 }
416 printf("OK\n");
417
418 printf("found %zu partitions.\n", nparts);
419 for (i = 0; i < nparts; i++) {
420 printf("add partition sid=%zu\n", psids[i]);
421 rc = fdisk_part_add(dev, psids[i], NULL);
422 if (rc != EOK) {
423 printf("failed\n");
424 goto error;
425 }
426 printf("OK\n");
427 }
428
429 free(psids);
430 *rdev = dev;
431 return EOK;
432error:
433 fdisk_dev_close(dev);
434 return rc;
435}
436
437void fdisk_dev_close(fdisk_dev_t *dev)
438{
439 if (dev == NULL)
440 return;
441
442 /* XXX Clean up partitions */
443 free(dev);
444}
445
446int fdisk_dev_get_svcname(fdisk_dev_t *dev, char **rname)
447{
448 char *name;
449 int rc;
450
451 rc = loc_service_get_name(dev->sid, &name);
452 if (rc != EOK)
453 return rc;
454
455 *rname = name;
456 return EOK;
457}
458
459int fdisk_dev_capacity(fdisk_dev_t *dev, fdisk_cap_t *cap)
460{
461 size_t bsize;
462 aoff64_t nblocks;
463 int rc;
464
465 rc = block_init(EXCHANGE_SERIALIZE, dev->sid, 2048);
466 if (rc != EOK)
467 return rc;
468
469 rc = block_get_bsize(dev->sid, &bsize);
470 if (rc != EOK)
471 return EIO;
472
473 rc = block_get_nblocks(dev->sid, &nblocks);
474 if (rc != EOK)
475 return EIO;
476
477 block_fini(dev->sid);
478
479 cap->value = bsize * nblocks;
480 cap->cunit = cu_byte;
481
482 return EOK;
483}
484
485int fdisk_label_get_info(fdisk_dev_t *dev, fdisk_label_info_t *info)
486{
487 vbd_disk_info_t vinfo;
488 int rc;
489
490 rc = vbd_disk_info(dev->fdisk->vbd, dev->sid, &vinfo);
491 if (rc != EOK) {
492 rc = EIO;
493 goto error;
494 }
495
496 info->ltype = vinfo.ltype;
497 info->flags = vinfo.flags;
498 return EOK;
499error:
500 return rc;
501}
502
503int fdisk_label_create(fdisk_dev_t *dev, label_type_t ltype)
504{
505 int rc;
506
507 rc = vbd_label_create(dev->fdisk->vbd, dev->sid, ltype);
508 if (rc != EOK)
509 return rc;
510
511 rc = fdisk_update_dev_info(dev);
512 if (rc != EOK)
513 return rc;
514
515 return EOK;
516}
517
518int fdisk_label_destroy(fdisk_dev_t *dev)
519{
520 fdisk_part_t *part;
521 int rc;
522
523 part = fdisk_part_first(dev);
524 while (part != NULL) {
525 rc = fdisk_part_destroy(part);
526 if (rc != EOK)
527 return EIO;
528 part = fdisk_part_first(dev);
529 }
530
531 rc = vbd_label_delete(dev->fdisk->vbd, dev->sid);
532 if (rc != EOK)
533 return EIO;
534
535 return EOK;
536}
537
538fdisk_part_t *fdisk_part_first(fdisk_dev_t *dev)
539{
540 link_t *link;
541
542 link = list_first(&dev->parts);
543 if (link == NULL)
544 return NULL;
545
546 return list_get_instance(link, fdisk_part_t, lparts);
547}
548
549fdisk_part_t *fdisk_part_next(fdisk_part_t *part)
550{
551 link_t *link;
552
553 link = list_next(&part->lparts, &part->dev->parts);
554 if (link == NULL)
555 return NULL;
556
557 return list_get_instance(link, fdisk_part_t, lparts);
558}
559
560int fdisk_part_get_info(fdisk_part_t *part, fdisk_part_info_t *info)
561{
562 info->capacity = part->capacity;
563 info->pcnt = part->pcnt;
564 info->fstype = part->fstype;
565 info->pkind = part->pkind;
566 return EOK;
567}
568
569int fdisk_part_get_max_avail(fdisk_dev_t *dev, fdisk_cap_t *cap)
570{
571 return EOK;
572}
573
574int fdisk_part_create(fdisk_dev_t *dev, fdisk_part_spec_t *pspec,
575 fdisk_part_t **rpart)
576{
577 fdisk_part_t *part;
578 vbd_part_spec_t vpspec;
579 vbd_part_id_t partid;
580 int rc;
581
582 printf("fdisk_part_create()\n");
583
584 rc = fdisk_part_spec_prepare(dev, pspec, &vpspec);
585 if (rc != EOK)
586 return EIO;
587
588 printf("fdisk_part_create() - call vbd_part_create\n");
589 rc = vbd_part_create(dev->fdisk->vbd, dev->sid, &vpspec, &partid);
590 if (rc != EOK)
591 return EIO;
592
593 printf("fdisk_part_create() - call fdisk_part_add\n");
594 rc = fdisk_part_add(dev, partid, &part);
595 if (rc != EOK) {
596 /* Try rolling back */
597 (void) vbd_part_delete(dev->fdisk->vbd, partid);
598 return EIO;
599 }
600
601 printf("fdisk_part_create() - done\n");
602 part->pcnt = vpc_fs;
603 part->fstype = pspec->fstype;
604 part->capacity = pspec->capacity;
605
606 if (rpart != NULL)
607 *rpart = part;
608 return EOK;
609}
610
611int fdisk_part_destroy(fdisk_part_t *part)
612{
613 int rc;
614
615 rc = vbd_part_delete(part->dev->fdisk->vbd, part->part_id);
616 if (rc != EOK)
617 return EIO;
618
619 list_remove(&part->lparts);
620 if (link_used(&part->lpri_ba))
621 list_remove(&part->lpri_ba);
622 if (link_used(&part->lpri_idx))
623 list_remove(&part->lpri_idx);
624 if (link_used(&part->llog_ba))
625 list_remove(&part->llog_ba);
626 free(part);
627 return EOK;
628}
629
630void fdisk_pspec_init(fdisk_part_spec_t *pspec)
631{
632 memset(pspec, 0, sizeof(fdisk_part_spec_t));
633}
634
635int fdisk_cap_format(fdisk_cap_t *cap, char **rstr)
636{
637 int rc;
638 const char *sunit;
639
640 sunit = NULL;
641
642 if (cap->cunit < 0 || cap->cunit >= CU_LIMIT)
643 assert(false);
644
645 sunit = cu_str[cap->cunit];
646 rc = asprintf(rstr, "%" PRIu64 " %s", cap->value, sunit);
647 if (rc < 0)
648 return ENOMEM;
649
650 return EOK;
651}
652
653int fdisk_cap_parse(const char *str, fdisk_cap_t *cap)
654{
655 char *eptr;
656 char *p;
657 unsigned long val;
658 int i;
659
660 val = strtoul(str, &eptr, 10);
661
662 while (*eptr == ' ')
663 ++eptr;
664
665 if (*eptr == '\0') {
666 cap->cunit = cu_byte;
667 } else {
668 for (i = 0; i < CU_LIMIT; i++) {
669 if (str_lcasecmp(eptr, cu_str[i],
670 str_length(cu_str[i])) == 0) {
671 p = eptr + str_size(cu_str[i]);
672 while (*p == ' ')
673 ++p;
674 if (*p == '\0')
675 goto found;
676 }
677 }
678
679 return EINVAL;
680found:
681 cap->cunit = i;
682 }
683
684 cap->value = val;
685 return EOK;
686}
687
688int fdisk_ltype_format(label_type_t ltype, char **rstr)
689{
690 const char *sltype;
691 char *s;
692
693 sltype = NULL;
694 switch (ltype) {
695 case lt_none:
696 sltype = "None";
697 break;
698 case lt_mbr:
699 sltype = "MBR";
700 break;
701 case lt_gpt:
702 sltype = "GPT";
703 break;
704 }
705
706 s = str_dup(sltype);
707 if (s == NULL)
708 return ENOMEM;
709
710 *rstr = s;
711 return EOK;
712}
713
714int fdisk_fstype_format(vol_fstype_t fstype, char **rstr)
715{
716 const char *sfstype;
717 char *s;
718
719 sfstype = NULL;
720 switch (fstype) {
721 case fs_exfat:
722 sfstype = "ExFAT";
723 break;
724 case fs_fat:
725 sfstype = "FAT";
726 break;
727 case fs_minix:
728 sfstype = "MINIX";
729 break;
730 case fs_ext4:
731 sfstype = "Ext4";
732 break;
733 }
734
735 s = str_dup(sfstype);
736 if (s == NULL)
737 return ENOMEM;
738
739 *rstr = s;
740 return EOK;
741}
742
743int fdisk_pkind_format(label_pkind_t pkind, char **rstr)
744{
745 const char *spkind;
746 char *s;
747
748 spkind = NULL;
749 switch (pkind) {
750 case lpk_primary:
751 spkind = "Primary";
752 break;
753 case lpk_extended:
754 spkind = "Extended";
755 break;
756 case lpk_logical:
757 spkind = "Logical";
758 break;
759 }
760
761 s = str_dup(spkind);
762 if (s == NULL)
763 return ENOMEM;
764
765 *rstr = s;
766 return EOK;
767}
768
769/** Get free partition index. */
770static int fdisk_part_get_free_idx(fdisk_dev_t *dev, int *rindex)
771{
772 link_t *link;
773 fdisk_part_t *part;
774 int nidx;
775
776 link = list_first(&dev->pri_idx);
777 nidx = 1;
778 while (link != NULL) {
779 part = list_get_instance(link, fdisk_part_t, lpri_idx);
780 if (part->index > nidx)
781 break;
782 nidx = part->index + 1;
783 link = list_next(link, &dev->pri_idx);
784 }
785
786 if (nidx > 4 /* XXXX actual number of slots*/) {
787 return ELIMIT;
788 }
789
790 *rindex = nidx;
791 return EOK;
792}
793
794/** Get free range of blocks.
795 *
796 * Get free range of blocks of at least the specified size (first fit).
797 */
798static int fdisk_part_get_free_range(fdisk_dev_t *dev, aoff64_t nblocks,
799 aoff64_t *rblock0, aoff64_t *rnblocks)
800{
801 link_t *link;
802 fdisk_part_t *part;
803 uint64_t avail;
804 uint64_t pb0;
805 uint64_t nba;
806
807 printf("fdisk_part_get_free_range: align=%" PRIu64 "\n",
808 dev->align);
809
810 link = list_first(&dev->pri_ba);
811 nba = fdisk_ba_align_up(dev, dev->dinfo.ablock0);
812 while (link != NULL) {
813 part = list_get_instance(link, fdisk_part_t, lpri_ba);
814 pb0 = fdisk_ba_align_down(dev, part->block0);
815 if (pb0 >= nba && pb0 - nba >= nblocks)
816 break;
817 nba = fdisk_ba_align_up(dev, part->block0 + part->nblocks);
818 link = list_next(link, &dev->pri_ba);
819 }
820
821 if (link != NULL) {
822 printf("nba=%" PRIu64 " pb0=%" PRIu64 "\n",
823 nba, pb0);
824 /* Free range before a partition */
825 avail = pb0 - nba;
826 } else {
827 /* Free range at the end */
828 pb0 = fdisk_ba_align_down(dev, dev->dinfo.ablock0 +
829 dev->dinfo.anblocks);
830 if (pb0 < nba)
831 return ELIMIT;
832 avail = pb0 - nba;
833 printf("nba=%" PRIu64 " avail=%" PRIu64 "\n",
834 nba, avail);
835
836 }
837
838 /* Verify that the range is large enough */
839 if (avail < nblocks)
840 return ELIMIT;
841
842 *rblock0 = nba;
843 *rnblocks = avail;
844 return EOK;
845}
846
847/** Get free range of blocks in extended partition.
848 *
849 * Get free range of blocks in extended partition that can accomodate
850 * a partition of at least the specified size plus the header (EBR + padding).
851 * Returns the header size in blocks, the start and length of the partition.
852 */
853static int fdisk_part_get_log_free_range(fdisk_dev_t *dev, aoff64_t nblocks,
854 aoff64_t *rhdrb, aoff64_t *rblock0, aoff64_t *rnblocks)
855{
856 link_t *link;
857 fdisk_part_t *part;
858 uint64_t avail;
859 uint64_t hdrb;
860 uint64_t pb0;
861 uint64_t nba;
862
863 printf("fdisk_part_get_log_free_range\n");
864 /* Number of header blocks */
865 hdrb = max(1, dev->align);
866
867 link = list_first(&dev->log_ba);
868 nba = fdisk_ba_align_up(dev, dev->ext_part->block0);
869 while (link != NULL) {
870 part = list_get_instance(link, fdisk_part_t, llog_ba);
871 pb0 = fdisk_ba_align_down(dev, part->block0);
872 if (pb0 >= nba && pb0 - nba >= nblocks)
873 break;
874 nba = fdisk_ba_align_up(dev, part->block0 + part->nblocks);
875 link = list_next(link, &dev->log_ba);
876 }
877
878 if (link != NULL) {
879 /* Free range before a partition */
880 avail = pb0 - nba;
881 } else {
882 /* Free range at the end */
883 pb0 = fdisk_ba_align_down(dev, dev->ext_part->block0 +
884 dev->ext_part->nblocks);
885 if (pb0 < nba) {
886 printf("not enough space\n");
887 return ELIMIT;
888 }
889
890 avail = pb0 - nba;
891
892 printf("nba=%" PRIu64 " pb0=%" PRIu64" avail=%" PRIu64 "\n",
893 nba, pb0, avail);
894 }
895 /* Verify that the range is large enough */
896 if (avail < hdrb + nblocks) {
897 printf("not enough space\n");
898 return ELIMIT;
899 }
900
901 *rhdrb = hdrb;
902 *rblock0 = nba + hdrb;
903 *rnblocks = avail;
904 printf("hdrb=%" PRIu64 " block0=%" PRIu64" avail=%" PRIu64 "\n",
905 hdrb, nba + hdrb, avail);
906 return EOK;
907}
908
909/** Prepare new partition specification for VBD. */
910static int fdisk_part_spec_prepare(fdisk_dev_t *dev, fdisk_part_spec_t *pspec,
911 vbd_part_spec_t *vpspec)
912{
913 uint64_t cbytes;
914 aoff64_t req_blocks;
915 aoff64_t fhdr;
916 aoff64_t fblock0;
917 aoff64_t fnblocks;
918 uint64_t block_size;
919 label_pcnt_t pcnt;
920 unsigned i;
921 int index;
922 int rc;
923
924 printf("fdisk_part_spec_prepare() - dev=%p pspec=%p vpspec=%p\n", dev, pspec,
925 vpspec);
926 printf("fdisk_part_spec_prepare() - block size\n");
927 block_size = dev->dinfo.block_size;
928 printf("fdisk_part_spec_prepare() - cbytes\n");
929 cbytes = pspec->capacity.value;
930 printf("fdisk_part_spec_prepare() - cunit\n");
931 for (i = 0; i < pspec->capacity.cunit; i++)
932 cbytes = cbytes * 1000;
933
934 printf("fdisk_part_spec_prepare() - req_blocks block_size=%zu\n",
935 block_size);
936 req_blocks = (cbytes + block_size - 1) / block_size;
937 req_blocks = fdisk_ba_align_up(dev, req_blocks);
938
939 pcnt = -1;
940
941 switch (pspec->fstype) {
942 case fs_exfat:
943 pcnt = lpc_exfat;
944 break;
945 case fs_fat:
946 pcnt = lpc_fat32; /* XXX Detect FAT12/16 vs FAT32 */
947 break;
948 case fs_minix:
949 pcnt = lpc_minix;
950 break;
951 case fs_ext4:
952 pcnt = lpc_ext4;
953 break;
954 }
955
956 if (pcnt < 0)
957 return EINVAL;
958
959 printf("fdisk_part_spec_prepare() - switch\n");
960 switch (pspec->pkind) {
961 case lpk_primary:
962 case lpk_extended:
963 printf("fdisk_part_spec_prepare() - pri/ext\n");
964 rc = fdisk_part_get_free_idx(dev, &index);
965 if (rc != EOK)
966 return EIO;
967
968 printf("fdisk_part_spec_prepare() - get free range\n");
969 rc = fdisk_part_get_free_range(dev, req_blocks, &fblock0, &fnblocks);
970 if (rc != EOK)
971 return EIO;
972
973 printf("fdisk_part_spec_prepare() - memset\n");
974 memset(vpspec, 0, sizeof(vbd_part_spec_t));
975 vpspec->index = index;
976 vpspec->block0 = fblock0;
977 vpspec->nblocks = req_blocks;
978 vpspec->pkind = pspec->pkind;
979 break;
980 case lpk_logical:
981 printf("fdisk_part_spec_prepare() - log\n");
982 rc = fdisk_part_get_log_free_range(dev, req_blocks, &fhdr,
983 &fblock0, &fnblocks);
984 if (rc != EOK)
985 return EIO;
986
987 memset(vpspec, 0, sizeof(vbd_part_spec_t));
988 vpspec->hdr_blocks = fhdr;
989 vpspec->block0 = fblock0;
990 vpspec->nblocks = req_blocks;
991 vpspec->pkind = lpk_logical;
992 vpspec->ptype.fmt = lptf_num;
993 vpspec->ptype.t.num = 42;
994 break;
995 }
996
997 if (pspec->pkind != lpk_extended) {
998 rc = vbd_suggest_ptype(dev->fdisk->vbd, dev->sid, pcnt,
999 &vpspec->ptype);
1000 if (rc != EOK)
1001 return EIO;
1002 }
1003
1004 return EOK;
1005}
1006
1007static int fdisk_update_dev_info(fdisk_dev_t *dev)
1008{
1009 int rc;
1010 size_t align_bytes;
1011 uint64_t avail_cap;
1012
1013 rc = vbd_disk_info(dev->fdisk->vbd, dev->sid, &dev->dinfo);
1014 if (rc != EOK)
1015 return EIO;
1016
1017 /* Capacity available for partition in bytes */
1018 avail_cap = dev->dinfo.anblocks * dev->dinfo.block_size;
1019
1020 /* Determine optimum alignment */
1021 align_bytes = 1024 * 1024; /* 1 MiB */
1022 while (align_bytes > 1 && avail_cap / align_bytes < 256) {
1023 align_bytes = align_bytes / 16;
1024 }
1025
1026 dev->align = align_bytes / dev->dinfo.block_size;
1027 if (dev->align < 1)
1028 dev->align = 1;
1029 return EOK;
1030}
1031
1032static uint64_t fdisk_ba_align_up(fdisk_dev_t *dev, uint64_t ba)
1033{
1034 return ((ba + dev->align - 1) / dev->align) * dev->align;
1035}
1036
1037static uint64_t fdisk_ba_align_down(fdisk_dev_t *dev, uint64_t ba)
1038{
1039 return ba - (ba % dev->align);
1040}
1041
1042/** @}
1043 */
Note: See TracBrowser for help on using the repository browser.