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
RevLine 
[e96047c]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>
[8227d63]41#include <mem.h>
[e96047c]42#include <stdio.h>
43#include <stdlib.h>
44#include <str.h>
[28ed0d95]45#include <vbd.h>
[22fb7ab]46#include <vol.h>
[e96047c]47
[8227d63]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
[6bc542b]60static int fdisk_part_spec_prepare(fdisk_dev_t *, fdisk_part_spec_t *,
61 vbd_part_spec_t *);
[c02d098]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 *);
[1b23e33]65static uint64_t fdisk_ba_align_up(fdisk_dev_t *, uint64_t);
66static uint64_t fdisk_ba_align_down(fdisk_dev_t *, uint64_t);
[6bc542b]67
[e96047c]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
[22fb7ab]80int fdisk_create(fdisk_t **rfdisk)
81{
[28ed0d95]82 fdisk_t *fdisk = NULL;
[22fb7ab]83 int rc;
84
85 fdisk = calloc(1, sizeof(fdisk_t));
[28ed0d95]86 if (fdisk == NULL) {
87 rc = ENOMEM;
88 goto error;
89 }
[22fb7ab]90
91 rc = vol_create(&fdisk->vol);
92 if (rc != EOK) {
[28ed0d95]93 rc = EIO;
94 goto error;
95 }
96
97 rc = vbd_create(&fdisk->vbd);
98 if (rc != EOK) {
99 rc = EIO;
100 goto error;
[22fb7ab]101 }
102
103 *rfdisk = fdisk;
104 return EOK;
[28ed0d95]105error:
106 fdisk_destroy(fdisk);
107
108 return rc;
[22fb7ab]109}
110
111void fdisk_destroy(fdisk_t *fdisk)
112{
[28ed0d95]113 if (fdisk == NULL)
114 return;
115
[22fb7ab]116 vol_destroy(fdisk->vol);
[28ed0d95]117 vbd_destroy(fdisk->vbd);
[22fb7ab]118 free(fdisk);
119}
120
121int fdisk_dev_list_get(fdisk_t *fdisk, fdisk_dev_list_t **rdevlist)
[e96047c]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
[372df8f]135 printf("vbd_get_disks()\n");
136 rc = vbd_get_disks(fdisk->vbd, &svcs, &count);
137 printf(" -> %d\n", rc);
[e96047c]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
[8227d63]205void fdisk_dev_info_get_svcid(fdisk_dev_info_t *info, service_id_t *rsid)
[e96047c]206{
207 *rsid = info->svcid;
208}
209
[8227d63]210int fdisk_dev_info_get_svcname(fdisk_dev_info_t *info, char **rname)
[e96047c]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
[8227d63]230int fdisk_dev_info_capacity(fdisk_dev_info_t *info, fdisk_cap_t *cap)
[e96047c]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;
[8227d63]240
241 info->blk_inited = true;
[e96047c]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
[1626cd4]258static int fdisk_part_add(fdisk_dev_t *dev, vbd_part_id_t partid,
259 fdisk_part_t **rpart)
260{
[c02d098]261 fdisk_part_t *part;
[1626cd4]262 vbd_part_info_t pinfo;
[4b6635a7]263 vol_part_info_t vpinfo;
[1626cd4]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
[4b6635a7]276 rc = vol_part_info(dev->fdisk->vol, pinfo.svc_id, &vpinfo);
277 if (rc != EOK) {
278 rc = EIO;
279 goto error;
280 }
281
[1626cd4]282 part->dev = dev;
283 part->index = pinfo.index;
284 part->block0 = pinfo.block0;
285 part->nblocks = pinfo.nblocks;
[b7a4d06]286 part->pkind = pinfo.pkind;
[4b6635a7]287 part->svc_id = pinfo.svc_id;
288 part->pcnt = vpinfo.pcnt;
289 part->fstype = vpinfo.fstype;
[1626cd4]290
[c02d098]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
[1626cd4]323 /* Insert to list by block address */
[c02d098]324 link = list_first(&dev->pri_ba);
[1626cd4]325 while (link != NULL) {
[c02d098]326 p = list_get_instance(link, fdisk_part_t, lpri_ba);
[1626cd4]327 if (p->block0 > part->block0) {
[c02d098]328 list_insert_before(&part->lpri_ba, &p->lpri_ba);
[1626cd4]329 break;
330 }
331
[c02d098]332 link = list_next(link, &dev->pri_ba);
[1626cd4]333 }
334
335 if (link == NULL)
[c02d098]336 list_append(&part->lpri_ba, &dev->pri_ba);
[1626cd4]337
338 /* Insert to list by index */
[c02d098]339 link = list_first(&dev->pri_idx);
[1626cd4]340 while (link != NULL) {
[c02d098]341 p = list_get_instance(link, fdisk_part_t, lpri_idx);
[1626cd4]342 if (p->index > part->index) {
[c02d098]343 list_insert_before(&part->lpri_idx, &p->lpri_idx);
[1626cd4]344 break;
345 }
346
[c02d098]347 link = list_next(link, &dev->pri_idx);
[1626cd4]348 }
349
350 if (link == NULL)
[c02d098]351 list_append(&part->lpri_idx, &dev->pri_idx);
352}
[1626cd4]353
[c02d098]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;
[1626cd4]358
[c02d098]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 }
[1626cd4]367
[c02d098]368 link = list_next(link, &dev->log_ba);
369 }
370
371 if (link == NULL)
372 list_append(&part->llog_ba, &dev->log_ba);
373}
[1626cd4]374
[22fb7ab]375int fdisk_dev_open(fdisk_t *fdisk, service_id_t sid, fdisk_dev_t **rdev)
[e96047c]376{
[372df8f]377 vbd_disk_info_t vinfo;
[1626cd4]378 fdisk_dev_t *dev = NULL;
379 service_id_t *psids = NULL;
380 size_t nparts, i;
381 int rc;
[e96047c]382
383 dev = calloc(1, sizeof(fdisk_dev_t));
384 if (dev == NULL)
385 return ENOMEM;
386
[22fb7ab]387 dev->fdisk = fdisk;
[8227d63]388 dev->sid = sid;
[c02d098]389 list_initialize(&dev->parts);
390 list_initialize(&dev->pri_idx);
391 list_initialize(&dev->pri_ba);
392 list_initialize(&dev->log_ba);
[1626cd4]393
[372df8f]394 rc = vbd_disk_info(fdisk->vbd, sid, &vinfo);
[603c1d1f]395 if (rc != EOK) {
396 rc = EIO;
397 goto error;
398 }
399
400 printf("get label info\n");
[c02d098]401 rc = fdisk_update_dev_info(dev);
[1626cd4]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);
[e96047c]430 *rdev = dev;
431 return EOK;
[1626cd4]432error:
433 fdisk_dev_close(dev);
434 return rc;
[e96047c]435}
436
437void fdisk_dev_close(fdisk_dev_t *dev)
438{
[1626cd4]439 if (dev == NULL)
440 return;
441
442 /* XXX Clean up partitions */
[e96047c]443 free(dev);
444}
445
[8227d63]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
[e96047c]485int fdisk_label_get_info(fdisk_dev_t *dev, fdisk_label_info_t *info)
486{
[372df8f]487 vbd_disk_info_t vinfo;
[22fb7ab]488 int rc;
489
[372df8f]490 rc = vbd_disk_info(dev->fdisk->vbd, dev->sid, &vinfo);
[22fb7ab]491 if (rc != EOK) {
492 rc = EIO;
493 goto error;
494 }
495
496 info->ltype = vinfo.ltype;
[b7a4d06]497 info->flags = vinfo.flags;
[e96047c]498 return EOK;
[22fb7ab]499error:
500 return rc;
[e96047c]501}
502
[22fb7ab]503int fdisk_label_create(fdisk_dev_t *dev, label_type_t ltype)
[e96047c]504{
[c02d098]505 int rc;
506
[372df8f]507 rc = vbd_label_create(dev->fdisk->vbd, dev->sid, ltype);
[c02d098]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;
[e96047c]516}
517
518int fdisk_label_destroy(fdisk_dev_t *dev)
519{
[8227d63]520 fdisk_part_t *part;
[22fb7ab]521 int rc;
[e96047c]522
[8227d63]523 part = fdisk_part_first(dev);
524 while (part != NULL) {
[372df8f]525 rc = fdisk_part_destroy(part);
526 if (rc != EOK)
527 return EIO;
[8227d63]528 part = fdisk_part_first(dev);
529 }
530
[372df8f]531 rc = vbd_label_delete(dev->fdisk->vbd, dev->sid);
[22fb7ab]532 if (rc != EOK)
533 return EIO;
534
[e96047c]535 return EOK;
536}
537
538fdisk_part_t *fdisk_part_first(fdisk_dev_t *dev)
539{
[8227d63]540 link_t *link;
541
[c02d098]542 link = list_first(&dev->parts);
[8227d63]543 if (link == NULL)
544 return NULL;
545
[c02d098]546 return list_get_instance(link, fdisk_part_t, lparts);
[e96047c]547}
548
549fdisk_part_t *fdisk_part_next(fdisk_part_t *part)
550{
[8227d63]551 link_t *link;
552
[c02d098]553 link = list_next(&part->lparts, &part->dev->parts);
[8227d63]554 if (link == NULL)
555 return NULL;
556
[c02d098]557 return list_get_instance(link, fdisk_part_t, lparts);
[8227d63]558}
559
560int fdisk_part_get_info(fdisk_part_t *part, fdisk_part_info_t *info)
561{
562 info->capacity = part->capacity;
[4b6635a7]563 info->pcnt = part->pcnt;
[8227d63]564 info->fstype = part->fstype;
[b7a4d06]565 info->pkind = part->pkind;
[8227d63]566 return EOK;
[e96047c]567}
568
569int fdisk_part_get_max_avail(fdisk_dev_t *dev, fdisk_cap_t *cap)
570{
571 return EOK;
572}
573
[8227d63]574int fdisk_part_create(fdisk_dev_t *dev, fdisk_part_spec_t *pspec,
[e96047c]575 fdisk_part_t **rpart)
576{
[8227d63]577 fdisk_part_t *part;
[28ed0d95]578 vbd_part_spec_t vpspec;
579 vbd_part_id_t partid;
580 int rc;
[8227d63]581
[6bc542b]582 printf("fdisk_part_create()\n");
[8227d63]583
[6bc542b]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");
[28ed0d95]589 rc = vbd_part_create(dev->fdisk->vbd, dev->sid, &vpspec, &partid);
[6bc542b]590 if (rc != EOK)
[28ed0d95]591 return EIO;
592
[6bc542b]593 printf("fdisk_part_create() - call fdisk_part_add\n");
594 rc = fdisk_part_add(dev, partid, &part);
[1626cd4]595 if (rc != EOK) {
596 /* Try rolling back */
597 (void) vbd_part_delete(dev->fdisk->vbd, partid);
598 return EIO;
599 }
600
[6bc542b]601 printf("fdisk_part_create() - done\n");
[4b6635a7]602 part->pcnt = vpc_fs;
[6bc542b]603 part->fstype = pspec->fstype;
604 part->capacity = pspec->capacity;
[8227d63]605
[6bc542b]606 if (rpart != NULL)
607 *rpart = part;
[e96047c]608 return EOK;
609}
610
611int fdisk_part_destroy(fdisk_part_t *part)
612{
[28ed0d95]613 int rc;
614
615 rc = vbd_part_delete(part->dev->fdisk->vbd, part->part_id);
616 if (rc != EOK)
617 return EIO;
618
[c02d098]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);
[8227d63]626 free(part);
[e96047c]627 return EOK;
628}
629
[8227d63]630void fdisk_pspec_init(fdisk_part_spec_t *pspec)
631{
632 memset(pspec, 0, sizeof(fdisk_part_spec_t));
633}
634
[e96047c]635int fdisk_cap_format(fdisk_cap_t *cap, char **rstr)
636{
637 int rc;
[8227d63]638 const char *sunit;
639
640 sunit = NULL;
[e96047c]641
[8227d63]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);
[e96047c]647 if (rc < 0)
648 return ENOMEM;
649
650 return EOK;
651}
652
[8227d63]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
[22fb7ab]688int fdisk_ltype_format(label_type_t ltype, char **rstr)
[e96047c]689{
690 const char *sltype;
691 char *s;
692
693 sltype = NULL;
694 switch (ltype) {
[372df8f]695 case lt_none:
696 sltype = "None";
697 break;
[22fb7ab]698 case lt_mbr:
[e96047c]699 sltype = "MBR";
700 break;
[22fb7ab]701 case lt_gpt:
[e96047c]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
[4b6635a7]714int fdisk_fstype_format(vol_fstype_t fstype, char **rstr)
[8227d63]715{
716 const char *sfstype;
717 char *s;
718
719 sfstype = NULL;
720 switch (fstype) {
[4b6635a7]721 case fs_exfat:
[8227d63]722 sfstype = "ExFAT";
723 break;
[4b6635a7]724 case fs_fat:
[8227d63]725 sfstype = "FAT";
726 break;
[4b6635a7]727 case fs_minix:
[8227d63]728 sfstype = "MINIX";
729 break;
[4b6635a7]730 case fs_ext4:
[8227d63]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
[b7a4d06]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
[6bc542b]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
[c02d098]776 link = list_first(&dev->pri_idx);
[6bc542b]777 nidx = 1;
778 while (link != NULL) {
[c02d098]779 part = list_get_instance(link, fdisk_part_t, lpri_idx);
[6bc542b]780 if (part->index > nidx)
781 break;
[99c23405]782 nidx = part->index + 1;
[c02d098]783 link = list_next(link, &dev->pri_idx);
[6bc542b]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;
[1b23e33]804 uint64_t pb0;
805 uint64_t nba;
806
807 printf("fdisk_part_get_free_range: align=%" PRIu64 "\n",
808 dev->align);
[6bc542b]809
[c02d098]810 link = list_first(&dev->pri_ba);
[1b23e33]811 nba = fdisk_ba_align_up(dev, dev->dinfo.ablock0);
[6bc542b]812 while (link != NULL) {
[c02d098]813 part = list_get_instance(link, fdisk_part_t, lpri_ba);
[1b23e33]814 pb0 = fdisk_ba_align_down(dev, part->block0);
815 if (pb0 >= nba && pb0 - nba >= nblocks)
[6bc542b]816 break;
[1b23e33]817 nba = fdisk_ba_align_up(dev, part->block0 + part->nblocks);
[c02d098]818 link = list_next(link, &dev->pri_ba);
[6bc542b]819 }
820
821 if (link != NULL) {
[1b23e33]822 printf("nba=%" PRIu64 " pb0=%" PRIu64 "\n",
823 nba, pb0);
[6bc542b]824 /* Free range before a partition */
[1b23e33]825 avail = pb0 - nba;
[6bc542b]826 } else {
827 /* Free range at the end */
[1b23e33]828 pb0 = fdisk_ba_align_down(dev, dev->dinfo.ablock0 +
829 dev->dinfo.anblocks);
830 if (pb0 < nba)
[6bc542b]831 return ELIMIT;
[1b23e33]832 avail = pb0 - nba;
833 printf("nba=%" PRIu64 " avail=%" PRIu64 "\n",
834 nba, avail);
835
[6bc542b]836 }
837
[1b23e33]838 /* Verify that the range is large enough */
839 if (avail < nblocks)
840 return ELIMIT;
841
[6bc542b]842 *rblock0 = nba;
843 *rnblocks = avail;
844 return EOK;
845}
846
[c02d098]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;
[1b23e33]860 uint64_t pb0;
861 uint64_t nba;
[c02d098]862
[1b23e33]863 printf("fdisk_part_get_log_free_range\n");
[c02d098]864 /* Number of header blocks */
865 hdrb = max(1, dev->align);
866
867 link = list_first(&dev->log_ba);
[1b23e33]868 nba = fdisk_ba_align_up(dev, dev->ext_part->block0);
[c02d098]869 while (link != NULL) {
870 part = list_get_instance(link, fdisk_part_t, llog_ba);
[1b23e33]871 pb0 = fdisk_ba_align_down(dev, part->block0);
872 if (pb0 >= nba && pb0 - nba >= nblocks)
[c02d098]873 break;
[1b23e33]874 nba = fdisk_ba_align_up(dev, part->block0 + part->nblocks);
[c02d098]875 link = list_next(link, &dev->log_ba);
876 }
877
878 if (link != NULL) {
879 /* Free range before a partition */
[1b23e33]880 avail = pb0 - nba;
[c02d098]881 } else {
882 /* Free range at the end */
[1b23e33]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");
[c02d098]887 return ELIMIT;
[1b23e33]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;
[c02d098]899 }
900
901 *rhdrb = hdrb;
902 *rblock0 = nba + hdrb;
903 *rnblocks = avail;
[1b23e33]904 printf("hdrb=%" PRIu64 " block0=%" PRIu64" avail=%" PRIu64 "\n",
905 hdrb, nba + hdrb, avail);
[c02d098]906 return EOK;
907}
908
[6bc542b]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;
[c02d098]915 aoff64_t fhdr;
[6bc542b]916 aoff64_t fblock0;
917 aoff64_t fnblocks;
918 uint64_t block_size;
[f57ccb5]919 label_pcnt_t pcnt;
[6bc542b]920 unsigned i;
921 int index;
922 int rc;
923
[c02d098]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");
[6bc542b]927 block_size = dev->dinfo.block_size;
[c02d098]928 printf("fdisk_part_spec_prepare() - cbytes\n");
[6bc542b]929 cbytes = pspec->capacity.value;
[c02d098]930 printf("fdisk_part_spec_prepare() - cunit\n");
[6bc542b]931 for (i = 0; i < pspec->capacity.cunit; i++)
932 cbytes = cbytes * 1000;
933
[c02d098]934 printf("fdisk_part_spec_prepare() - req_blocks block_size=%zu\n",
935 block_size);
[6bc542b]936 req_blocks = (cbytes + block_size - 1) / block_size;
[1b23e33]937 req_blocks = fdisk_ba_align_up(dev, req_blocks);
[6bc542b]938
[f57ccb5]939 pcnt = -1;
940
941 switch (pspec->fstype) {
[4b6635a7]942 case fs_exfat:
[f57ccb5]943 pcnt = lpc_exfat;
944 break;
[4b6635a7]945 case fs_fat:
[f57ccb5]946 pcnt = lpc_fat32; /* XXX Detect FAT12/16 vs FAT32 */
947 break;
[4b6635a7]948 case fs_minix:
[f57ccb5]949 pcnt = lpc_minix;
950 break;
[4b6635a7]951 case fs_ext4:
[f57ccb5]952 pcnt = lpc_ext4;
953 break;
954 }
955
956 if (pcnt < 0)
957 return EINVAL;
958
[c02d098]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;
[6bc542b]967
[c02d098]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;
[6bc542b]986
[c02d098]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;
[f57ccb5]992 vpspec->ptype.fmt = lptf_num;
993 vpspec->ptype.t.num = 42;
[c02d098]994 break;
995 }
996
[f57ccb5]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
[c02d098]1004 return EOK;
1005}
1006
1007static int fdisk_update_dev_info(fdisk_dev_t *dev)
1008{
1009 int rc;
1010 size_t align_bytes;
[1b23e33]1011 uint64_t avail_cap;
[c02d098]1012
1013 rc = vbd_disk_info(dev->fdisk->vbd, dev->sid, &dev->dinfo);
1014 if (rc != EOK)
1015 return EIO;
[b7a4d06]1016
[1b23e33]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
[c02d098]1026 dev->align = align_bytes / dev->dinfo.block_size;
1027 if (dev->align < 1)
1028 dev->align = 1;
[6bc542b]1029 return EOK;
1030}
1031
[1b23e33]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
[e96047c]1042/** @}
1043 */
Note: See TracBrowser for help on using the repository browser.