source: mainline/uspace/lib/fdisk/src/fdisk.c@ 68b5dd11

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

Create file system when creating partition.

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