source: mainline/uspace/lib/fdisk/src/fdisk.c@ 0ecfc62

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

Information structures need updating to new model.

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