source: mainline/uspace/lib/fdisk/src/fdisk.c@ f57ccb5

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

Set partition type based on selected filesystem type.

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