source: mainline/uspace/lib/label/src/mbr.c@ 21f1543

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

Handle dummy partition addition/removal during label destruction/creation. Handle dummy label properly in fdisk.

  • Property mode set to 100644
File size: 23.3 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 liblabel
30 * @{
31 */
32/**
33 * @file Master Boot Record label
34 */
35
36#include <block.h>
37#include <byteorder.h>
38#include <errno.h>
39#include <mem.h>
40#include <stdlib.h>
41
42#include "std/mbr.h"
43#include "mbr.h"
44
45static int mbr_open(service_id_t, label_t **);
46static int mbr_open_ext(label_t *);
47static int mbr_create(service_id_t, label_t **);
48static void mbr_close(label_t *);
49static int mbr_destroy(label_t *);
50static int mbr_get_info(label_t *, label_info_t *);
51static label_part_t *mbr_part_first(label_t *);
52static label_part_t *mbr_part_next(label_part_t *);
53static void mbr_part_get_info(label_part_t *, label_part_info_t *);
54static int mbr_part_create(label_t *, label_part_spec_t *, label_part_t **);
55static int mbr_part_destroy(label_part_t *);
56static int mbr_suggest_ptype(label_t *, label_pcnt_t, label_ptype_t *);
57
58static void mbr_unused_pte(mbr_pte_t *);
59static int mbr_part_to_pte(label_part_t *, mbr_pte_t *);
60static int mbr_pte_to_part(label_t *, mbr_pte_t *, int);
61static int mbr_pte_to_log_part(label_t *, uint64_t, mbr_pte_t *);
62static void mbr_log_part_to_ptes(label_part_t *, mbr_pte_t *, mbr_pte_t *);
63static int mbr_pte_update(label_t *, mbr_pte_t *, int);
64static int mbr_log_part_insert(label_t *, label_part_t *);
65static int mbr_ebr_create(label_t *, label_part_t *);
66static int mbr_ebr_delete(label_t *, label_part_t *);
67static int mbr_ebr_update_next(label_t *, label_part_t *);
68static void mbr_update_log_indices(label_t *);
69
70label_ops_t mbr_label_ops = {
71 .open = mbr_open,
72 .create = mbr_create,
73 .close = mbr_close,
74 .destroy = mbr_destroy,
75 .get_info = mbr_get_info,
76 .part_first = mbr_part_first,
77 .part_next = mbr_part_next,
78 .part_get_info = mbr_part_get_info,
79 .part_create = mbr_part_create,
80 .part_destroy = mbr_part_destroy,
81 .suggest_ptype = mbr_suggest_ptype
82};
83
84static int mbr_open(service_id_t sid, label_t **rlabel)
85{
86 label_t *label = NULL;
87 mbr_br_block_t *mbr = NULL;
88 mbr_pte_t *eptr;
89 uint16_t sgn;
90 size_t bsize;
91 aoff64_t nblocks;
92 uint32_t entry;
93 int rc;
94
95 rc = block_get_bsize(sid, &bsize);
96 if (rc != EOK) {
97 rc = EIO;
98 goto error;
99 }
100
101 rc = block_get_nblocks(sid, &nblocks);
102 if (rc != EOK) {
103 rc = EIO;
104 goto error;
105 }
106
107 if (bsize < 512 || (bsize % 512) != 0) {
108 rc = EINVAL;
109 goto error;
110 }
111
112 if (nblocks < mbr_ablock0) {
113 rc = EINVAL;
114 goto error;
115 }
116
117 mbr = calloc(1, bsize);
118 if (mbr == NULL) {
119 rc = ENOMEM;
120 goto error;
121 }
122
123 rc = block_read_direct(sid, mbr_ba, 1, mbr);
124 if (rc != EOK) {
125 rc = EIO;
126 goto error;
127 }
128
129 label = calloc(1, sizeof(label_t));
130 if (label == NULL)
131 return ENOMEM;
132
133 list_initialize(&label->parts);
134 list_initialize(&label->pri_parts);
135 list_initialize(&label->log_parts);
136
137 /* Verify boot record signature */
138 sgn = uint16_t_le2host(mbr->signature);
139 if (sgn != mbr_br_signature) {
140 rc = EIO;
141 goto error;
142 }
143
144
145 label->ext_part = NULL;
146 for (entry = 0; entry < mbr_nprimary; entry++) {
147 eptr = &mbr->pte[entry];
148 rc = mbr_pte_to_part(label, eptr, entry + 1);
149 if (rc != EOK)
150 goto error;
151 }
152
153 free(mbr);
154 mbr = NULL;
155
156 label->ops = &mbr_label_ops;
157 label->ltype = lt_mbr;
158 label->svc_id = sid;
159 label->block_size = bsize;
160 label->ablock0 = mbr_ablock0;
161 label->anblocks = nblocks - mbr_ablock0;
162 label->pri_entries = mbr_nprimary;
163
164 if (label->ext_part != NULL) {
165 /* Open extended partition */
166 rc = mbr_open_ext(label);
167 if (rc != EOK)
168 goto error;
169 }
170
171 *rlabel = label;
172 return EOK;
173error:
174 free(mbr);
175 mbr_close(label);
176 return rc;
177}
178
179/** Open extended partition */
180static int mbr_open_ext(label_t *label)
181{
182 mbr_br_block_t *ebr = NULL;
183 mbr_pte_t *ethis;
184 mbr_pte_t *enext;
185 uint64_t ebr_b0;
186 uint64_t ebr_nblocks_min;
187 uint64_t ebr_nblocks_max;
188 uint64_t pebr_b0;
189 uint64_t pebr_nblocks;
190 uint64_t pb0;
191 uint64_t pnblocks;
192 uint64_t ep_b0;
193 int rc;
194
195 ebr = calloc(1, label->block_size);
196 if (ebr == NULL) {
197 rc = ENOMEM;
198 goto error;
199 }
200
201 /* First block of extended partition */
202 ep_b0 = label->ext_part->block0;
203
204 /* First block of current EBR */
205 ebr_b0 = label->ext_part->block0;
206
207 /*
208 * We don't have bounds for the first EBR, so for purpose of
209 * verification let's say it contains at least one block and
210 * at most all blocks from the extended partition.
211 */
212 ebr_nblocks_min = 1;
213 ebr_nblocks_max = label->ext_part->nblocks;
214
215 while (true) {
216 /* Read EBR */
217 rc = block_read_direct(label->svc_id, ebr_b0, 1, ebr);
218 if (rc != EOK) {
219 rc = EIO;
220 goto error;
221 }
222
223 ethis = &ebr->pte[mbr_ebr_pte_this];
224 enext = &ebr->pte[mbr_ebr_pte_next];
225
226 pb0 = ebr_b0 + uint32_t_le2host(ethis->first_lba);
227 pnblocks = uint32_t_le2host(ethis->length);
228
229 if (ethis->ptype == mbr_pt_unused || pnblocks == 0)
230 break;
231
232 /* Verify partition lies within the range of EBR */
233 if (pb0 + pnblocks > ebr_b0 + ebr_nblocks_max) {
234 rc = EIO;
235 goto error;
236 }
237
238 /* Create partition structure */
239 rc = mbr_pte_to_log_part(label, ebr_b0, ethis);
240 if (rc != EOK) {
241 rc = EIO;
242 goto error;
243 }
244
245 /* Save previous EBR range */
246 pebr_b0 = ebr_b0;
247 pebr_nblocks = ebr_nblocks_min;
248
249 /* Proceed to next EBR */
250 ebr_b0 = ep_b0 + uint32_t_le2host(enext->first_lba);
251 ebr_nblocks_min = uint32_t_le2host(enext->length);
252 ebr_nblocks_max = ebr_nblocks_min;
253
254 if (enext->ptype == mbr_pt_unused || ebr_nblocks_min == 0)
255 break;
256
257 /* Verify next EBR does not overlap this EBR */
258 if (ebr_b0 < pebr_b0 + pebr_nblocks) {
259 rc = EIO;
260 goto error;
261 }
262
263 /* Verify next EBR does not extend beyond end of label */
264 if (ebr_b0 + ebr_nblocks_max > label->ablock0 + label->anblocks) {
265 rc = EIO;
266 goto error;
267 }
268 }
269
270 free(ebr);
271 return EOK;
272error:
273 /* Note that logical partitions need to be deleted by caller */
274 free(ebr);
275 return rc;
276}
277
278static int mbr_create(service_id_t sid, label_t **rlabel)
279{
280 label_t *label = NULL;
281 mbr_br_block_t *mbr = NULL;
282 aoff64_t nblocks;
283 size_t bsize;
284 int i;
285 int rc;
286
287 rc = block_get_bsize(sid, &bsize);
288 if (rc != EOK) {
289 rc = EIO;
290 goto error;
291 }
292
293 rc = block_get_nblocks(sid, &nblocks);
294 if (rc != EOK) {
295 rc = EIO;
296 goto error;
297 }
298
299 mbr = calloc(1, bsize);
300 if (mbr == NULL) {
301 rc = ENOMEM;
302 goto error;
303 }
304
305 label = calloc(1, sizeof(label_t));
306 if (label == NULL)
307 return ENOMEM;
308
309 list_initialize(&label->parts);
310 list_initialize(&label->pri_parts);
311 list_initialize(&label->log_parts);
312
313 mbr->media_id = 0;
314 mbr->pad0 = 0;
315 for (i = 0; i < mbr_nprimary; i++)
316 mbr_unused_pte(&mbr->pte[i]);
317 mbr->signature = host2uint16_t_le(mbr_br_signature);
318
319 rc = block_write_direct(sid, mbr_ba, 1, mbr);
320 if (rc != EOK) {
321 rc = EIO;
322 goto error;
323 }
324
325 free(mbr);
326 mbr = NULL;
327
328 label->ops = &mbr_label_ops;
329 label->ltype = lt_mbr;
330 label->block_size = bsize;
331 label->svc_id = sid;
332 label->ablock0 = mbr_ablock0;
333 label->anblocks = nblocks - mbr_ablock0;
334 label->pri_entries = mbr_nprimary;
335 label->ext_part = NULL;
336
337 *rlabel = label;
338 return EOK;
339error:
340 free(mbr);
341 free(label);
342 return rc;
343}
344
345static void mbr_close(label_t *label)
346{
347 label_part_t *part;
348
349 if (label == NULL)
350 return;
351
352 part = mbr_part_first(label);
353 while (part != NULL) {
354 list_remove(&part->lparts);
355 if (link_used(&part->lpri))
356 list_remove(&part->lpri);
357 if (link_used(&part->llog))
358 list_remove(&part->llog);
359 free(part);
360
361 part = mbr_part_first(label);
362 }
363
364 free(label);
365}
366
367static int mbr_destroy(label_t *label)
368{
369 mbr_br_block_t *mbr = NULL;
370 label_part_t *part;
371 int rc;
372
373 part = mbr_part_first(label);
374 if (part != NULL) {
375 rc = ENOTEMPTY;
376 goto error;
377 }
378
379 mbr = calloc(1, label->block_size);
380 if (mbr == NULL) {
381 rc = ENOMEM;
382 goto error;
383 }
384
385 rc = block_write_direct(label->svc_id, mbr_ba, 1, mbr);
386 if (rc != EOK) {
387 rc = EIO;
388 goto error;
389 }
390
391 free(mbr);
392 mbr = NULL;
393
394 free(label);
395 return EOK;
396error:
397 free(mbr);
398 return rc;
399}
400
401static bool mbr_can_delete_part(label_t *label)
402{
403 return list_count(&label->parts) > 0;
404}
405
406static int mbr_get_info(label_t *label, label_info_t *linfo)
407{
408 memset(linfo, 0, sizeof(label_info_t));
409 linfo->ltype = lt_mbr;
410
411 /* We support extended partitions */
412 linfo->flags = lf_ext_supp;
413
414 /** Can create primary if there is a free slot */
415 if (list_count(&label->pri_parts) < mbr_nprimary)
416 linfo->flags |= lf_can_create_pri;
417 /* Can create extended if there is a free slot and no extended */
418 if ((linfo->flags & lf_can_create_pri) != 0 && label->ext_part == NULL)
419 linfo->flags |= lf_can_create_ext;
420 /* Can create logical if there is an extended partition */
421 if (label->ext_part != NULL)
422 linfo->flags |= lf_can_create_log;
423 /* Can delete partition */
424 if (mbr_can_delete_part(label))
425 linfo->flags |= lf_can_delete_part;
426
427 linfo->ablock0 = label->ablock0;
428 linfo->anblocks = label->anblocks;
429
430 return EOK;
431}
432
433static label_part_t *mbr_part_first(label_t *label)
434{
435 link_t *link;
436
437 link = list_first(&label->parts);
438 if (link == NULL)
439 return NULL;
440
441 return list_get_instance(link, label_part_t, lparts);
442}
443
444static label_part_t *mbr_part_next(label_part_t *part)
445{
446 link_t *link;
447
448 link = list_next(&part->lparts, &part->label->parts);
449 if (link == NULL)
450 return NULL;
451
452 return list_get_instance(link, label_part_t, lparts);
453}
454
455static label_part_t *mbr_log_part_first(label_t *label)
456{
457 link_t *link;
458
459 link = list_first(&label->log_parts);
460 if (link == NULL)
461 return NULL;
462
463 return list_get_instance(link, label_part_t, llog);
464}
465
466static label_part_t *mbr_log_part_next(label_part_t *part)
467{
468 link_t *link;
469
470 link = list_next(&part->llog, &part->label->log_parts);
471 if (link == NULL)
472 return NULL;
473
474 return list_get_instance(link, label_part_t, llog);
475}
476
477static label_part_t *mbr_log_part_prev(label_part_t *part)
478{
479 link_t *link;
480
481 link = list_prev(&part->llog, &part->label->log_parts);
482 if (link == NULL)
483 return NULL;
484
485 return list_get_instance(link, label_part_t, llog);
486}
487
488#include <io/log.h>
489static void mbr_part_get_info(label_part_t *part, label_part_info_t *pinfo)
490{
491 pinfo->index = part->index;
492 pinfo->block0 = part->block0;
493 pinfo->nblocks = part->nblocks;
494
495 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_get_info: index=%d ptype=%d",
496 (int)part->index, (int)part->ptype.t.num);
497 if (link_used(&part->llog))
498 pinfo->pkind = lpk_logical;
499 else if (part->ptype.t.num == mbr_pt_extended)
500 pinfo->pkind = lpk_extended;
501 else
502 pinfo->pkind = lpk_primary;
503}
504
505static int mbr_part_create(label_t *label, label_part_spec_t *pspec,
506 label_part_t **rpart)
507{
508 label_part_t *part;
509 label_part_t *prev;
510 label_part_t *next;
511 mbr_pte_t pte;
512 int rc;
513
514 if (pspec->ptype.fmt != lptf_num)
515 return EINVAL;
516
517 part = calloc(1, sizeof(label_part_t));
518 if (part == NULL)
519 return ENOMEM;
520
521
522 /* XXX Check if index is used */
523
524 part->label = label;
525 part->index = pspec->index;
526 part->block0 = pspec->block0;
527 part->nblocks = pspec->nblocks;
528 part->hdr_blocks = pspec->hdr_blocks;
529
530 switch (pspec->pkind) {
531 case lpk_primary:
532 part->ptype = pspec->ptype;
533 break;
534 case lpk_extended:
535 part->ptype.fmt = lptf_num;
536 part->ptype.t.num = mbr_pt_extended;
537 if (pspec->ptype.t.num != 0) {
538 rc = EINVAL;
539 goto error;
540 }
541 if (label->ext_part != NULL) {
542 rc = EEXISTS;
543 goto error;
544 }
545 break;
546 case lpk_logical:
547 log_msg(LOG_DEFAULT, LVL_NOTE, "check index");
548 part->ptype = pspec->ptype;
549 if (pspec->index != 0) {
550 rc = EINVAL;
551 goto error;
552 }
553 break;
554 }
555
556 if (pspec->pkind != lpk_logical) {
557 /* Primary or extended partition */
558 /* XXX Verify index, block0, nblocks */
559
560 if (pspec->index < 1 || pspec->index > label->pri_entries) {
561 rc = EINVAL;
562 goto error;
563 }
564
565 if (pspec->hdr_blocks != 0) {
566 rc = EINVAL;
567 goto error;
568 }
569
570 rc = mbr_part_to_pte(part, &pte);
571 if (rc != EOK) {
572 rc = EINVAL;
573 goto error;
574 }
575
576 rc = mbr_pte_update(label, &pte, pspec->index - 1);
577 if (rc != EOK) {
578 rc = EIO;
579 goto error;
580 }
581
582 list_append(&part->lparts, &label->parts);
583 list_append(&part->lpri, &label->pri_parts);
584
585 if (pspec->pkind == lpk_extended)
586 label->ext_part = part;
587 } else {
588 /* Logical partition */
589
590 log_msg(LOG_DEFAULT, LVL_NOTE, "call mbr_log_part_insert");
591 rc = mbr_log_part_insert(label, part);
592 if (rc != EOK)
593 goto error;
594
595 log_msg(LOG_DEFAULT, LVL_NOTE, "call mbr_ebr_create");
596 /* Create EBR for new partition */
597 rc = mbr_ebr_create(label, part);
598 if (rc != EOK)
599 goto error;
600
601 prev = mbr_log_part_prev(part);
602 if (prev != NULL) {
603 log_msg(LOG_DEFAULT, LVL_NOTE, "update next");
604 /* Update 'next' PTE in EBR of previous partition */
605 rc = mbr_ebr_update_next(label, prev);
606 if (rc != EOK) {
607 log_msg(LOG_DEFAULT, LVL_NOTE, "failed to update next");
608 goto error;
609 }
610 } else {
611 log_msg(LOG_DEFAULT, LVL_NOTE, "relocate first EBR");
612 /* New partition is now the first one */
613 next = mbr_log_part_next(part);
614 if (next != NULL) {
615 /*
616 * Create new, relocated EBR for the former
617 * first partition
618 */
619 next->hdr_blocks = pspec->hdr_blocks;
620 rc = mbr_ebr_create(label, next);
621 if (rc != EOK)
622 goto error;
623 }
624 }
625
626 /* This also sets index for the new partition. */
627 mbr_update_log_indices(label);
628 }
629
630 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_create success");
631 *rpart = part;
632 return EOK;
633error:
634 free(part);
635 return rc;
636}
637
638static int mbr_part_destroy(label_part_t *part)
639{
640 mbr_pte_t pte;
641 label_part_t *prev;
642 label_part_t *next;
643 uint64_t ep_b0;
644 int rc;
645
646 if (link_used(&part->lpri)) {
647 /* Primary/extended partition */
648
649 /* Prepare unused partition table entry */
650 mbr_unused_pte(&pte);
651
652 /* Modify partition table */
653 rc = mbr_pte_update(part->label, &pte, part->index - 1);
654 if (rc != EOK)
655 return EIO;
656
657 /* If it was the extended partition, clear ext. part. pointer */
658 if (part == part->label->ext_part)
659 part->label->ext_part = NULL;
660
661 list_remove(&part->lpri);
662 } else {
663 /* Logical partition */
664
665 prev = mbr_log_part_prev(part);
666 if (prev != NULL) {
667 /* Update next link in previous EBR */
668 list_remove(&part->llog);
669
670 rc = mbr_ebr_update_next(part->label, prev);
671 if (rc != EOK) {
672 /* Roll back */
673 list_insert_after(&part->llog, &prev->llog);
674 return EIO;
675 }
676
677 /* Delete EBR */
678 rc = mbr_ebr_delete(part->label, part);
679 if (rc != EOK)
680 return EIO;
681 } else {
682 next = mbr_log_part_next(part);
683 list_remove(&part->llog);
684
685 if (next != NULL) {
686 /*
687 * Relocate next partition's EBR to the beginning
688 * of the extended partition. This also
689 * overwrites the EBR of the former first
690 * partition.
691 */
692
693 /* First block of extended partition */
694 ep_b0 = part->label->ext_part->block0;
695
696 next->hdr_blocks = next->block0 - ep_b0;
697
698 rc = mbr_ebr_create(part->label, next);
699 if (rc != EOK) {
700 list_prepend(&part->llog, &part->label->log_parts);
701 return EIO;
702 }
703 } else {
704 /* Delete EBR */
705 rc = mbr_ebr_delete(part->label, part);
706 if (rc != EOK)
707 return EIO;
708 }
709 }
710
711 /* Update indices */
712 mbr_update_log_indices(part->label);
713 }
714
715 list_remove(&part->lparts);
716 free(part);
717 return EOK;
718}
719
720static int mbr_suggest_ptype(label_t *label, label_pcnt_t pcnt,
721 label_ptype_t *ptype)
722{
723 ptype->fmt = lptf_num;
724 ptype->t.num = 0;
725
726 switch (pcnt) {
727 case lpc_exfat:
728 ptype->t.num = mbr_pt_ms_advanced;
729 break;
730 case lpc_ext4:
731 ptype->t.num = mbr_pt_linux;
732 break;
733 case lpc_fat12_16:
734 ptype->t.num = mbr_pt_fat16_lba;
735 break;
736 case lpc_fat32:
737 ptype->t.num = mbr_pt_fat32_lba;
738 break;
739 case lpc_minix:
740 ptype->t.num = mbr_pt_minix;
741 break;
742 }
743
744 if (ptype->t.num == 0)
745 return EINVAL;
746
747 return EOK;
748}
749
750
751static void mbr_unused_pte(mbr_pte_t *pte)
752{
753 memset(pte, 0, sizeof(mbr_pte_t));
754}
755
756static int mbr_part_to_pte(label_part_t *part, mbr_pte_t *pte)
757{
758 if ((part->block0 >> 32) != 0)
759 return EINVAL;
760 if ((part->nblocks >> 32) != 0)
761 return EINVAL;
762 if ((part->ptype.t.num >> 8) != 0)
763 return EINVAL;
764
765 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_to_pte: a0=%" PRIu64
766 " len=%" PRIu64 " ptype=%d", part->block0, part->nblocks,
767 (int)part->ptype.t.num);
768 memset(pte, 0, sizeof(mbr_pte_t));
769 pte->ptype = part->ptype.t.num;
770 pte->first_lba = host2uint32_t_le(part->block0);
771 pte->length = host2uint32_t_le(part->nblocks);
772 return EOK;
773}
774
775static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
776{
777 label_part_t *part;
778 uint32_t block0;
779 uint32_t nblocks;
780
781 block0 = uint32_t_le2host(pte->first_lba);
782 nblocks = uint32_t_le2host(pte->length);
783
784 /* See UEFI specification 2.0 section 5.2.1 Legacy Master Boot Record */
785 if (pte->ptype == mbr_pt_unused || nblocks == 0)
786 return EOK;
787
788 part = calloc(1, sizeof(label_part_t));
789 if (part == NULL)
790 return ENOMEM;
791
792 part->ptype.fmt = lptf_num;
793 part->ptype.t.num = pte->ptype;
794 part->index = index;
795 part->block0 = block0;
796 part->nblocks = nblocks;
797
798 /*
799 * TODO: Verify
800 * - partition must reside on disk
801 * - partition must not overlap any other partition
802 */
803
804 part->label = label;
805 list_append(&part->lparts, &label->parts);
806 list_append(&part->lpri, &label->pri_parts);
807
808 if (pte->ptype == mbr_pt_extended)
809 label->ext_part = part;
810 return EOK;
811}
812
813static int mbr_pte_to_log_part(label_t *label, uint64_t ebr_b0,
814 mbr_pte_t *pte)
815{
816 label_part_t *part;
817 uint32_t block0;
818 uint32_t nblocks;
819 size_t nlparts;
820
821 block0 = ebr_b0 + uint32_t_le2host(pte->first_lba);
822 nblocks = uint32_t_le2host(pte->length);
823
824 if (pte->ptype == mbr_pt_unused || nblocks == 0)
825 return EOK;
826
827 part = calloc(1, sizeof(label_part_t));
828 if (part == NULL)
829 return ENOMEM;
830
831 nlparts = list_count(&label->log_parts);
832
833 part->ptype.fmt = lptf_num;
834 part->ptype.t.num = pte->ptype;
835 part->index = mbr_nprimary + 1 + nlparts;
836 part->block0 = block0;
837 part->nblocks = nblocks;
838 part->hdr_blocks = block0 - ebr_b0;
839
840 part->label = label;
841 list_append(&part->lparts, &label->parts);
842 list_append(&part->llog, &label->log_parts);
843
844 return EOK;
845}
846
847static void mbr_log_part_to_ptes(label_part_t *part, mbr_pte_t *pthis,
848 mbr_pte_t *pnext)
849{
850 label_part_t *next;
851 uint64_t ep_b0;
852 uint64_t totsize;
853
854 /* First block of extended partition */
855 ep_b0 = part->label->ext_part->block0;
856
857 assert(link_used(&part->llog));
858 assert(part->block0 >= ep_b0);
859 assert(part->hdr_blocks <= part->block0 - ep_b0);
860
861 /* 'This' EBR entry */
862 if (pthis != NULL) {
863 memset(pthis, 0, sizeof(mbr_pte_t));
864 pthis->ptype = part->ptype.t.num;
865 pthis->first_lba = host2uint32_t_le(part->hdr_blocks);
866 pthis->length = host2uint32_t_le(part->nblocks);
867 }
868
869 /* 'Next' EBR entry */
870 if (pnext != NULL) {
871 next = mbr_log_part_next(part);
872
873 memset(pnext, 0, sizeof(mbr_pte_t));
874 if (next != NULL) {
875 /* Total size of EBR + partition */
876 totsize = next->hdr_blocks + next->nblocks;
877
878 pnext->ptype = mbr_pt_extended;
879 pnext->first_lba = host2uint32_t_le(next->block0 -
880 next->hdr_blocks - ep_b0);
881 pnext->length = host2uint32_t_le(totsize);
882 }
883 }
884}
885
886/** Update partition table entry at specified index.
887 *
888 * Replace partition entry at index @a index with the contents of
889 * @a pte.
890 */
891static int mbr_pte_update(label_t *label, mbr_pte_t *pte, int index)
892{
893 mbr_br_block_t *br;
894 int rc;
895
896 br = calloc(1, label->block_size);
897 if (br == NULL)
898 return ENOMEM;
899
900 rc = block_read_direct(label->svc_id, mbr_ba, 1, br);
901 if (rc != EOK) {
902 rc = EIO;
903 goto error;
904 }
905
906 br->pte[index] = *pte;
907
908 rc = block_write_direct(label->svc_id, mbr_ba, 1, br);
909 if (rc != EOK) {
910 rc = EIO;
911 goto error;
912 }
913
914 free(br);
915 return EOK;
916error:
917 free(br);
918 return rc;
919}
920
921/** Insert logical partition into logical partition list. */
922static int mbr_log_part_insert(label_t *label, label_part_t *part)
923{
924 label_part_t *cur;
925
926 cur = mbr_log_part_first(label);
927 while (cur != NULL) {
928 if (cur->block0 + cur->nblocks > part->block0)
929 break;
930 cur = mbr_log_part_next(part);
931 }
932
933 if (cur != NULL)
934 list_insert_before(&part->llog, &cur->llog);
935 else
936 list_append(&part->llog, &label->log_parts);
937
938 return EOK;
939}
940
941/** Create EBR for partition. */
942static int mbr_ebr_create(label_t *label, label_part_t *part)
943{
944 mbr_br_block_t *br;
945 uint64_t ba;
946 int rc;
947
948 br = calloc(1, label->block_size);
949 if (br == NULL)
950 return ENOMEM;
951
952 mbr_log_part_to_ptes(part, &br->pte[mbr_ebr_pte_this],
953 &br->pte[mbr_ebr_pte_next]);
954 br->signature = host2uint16_t_le(mbr_br_signature);
955
956 ba = part->block0 - part->hdr_blocks;
957
958 log_msg(LOG_DEFAULT, LVL_NOTE, "Write EBR to ba=%" PRIu64, ba);
959 rc = block_write_direct(label->svc_id, ba, 1, br);
960 if (rc != EOK) {
961 rc = EIO;
962 goto error;
963 }
964
965 free(br);
966 return EOK;
967error:
968 free(br);
969 return rc;
970}
971
972static int mbr_ebr_delete(label_t *label, label_part_t *part)
973{
974 mbr_br_block_t *br;
975 uint64_t ba;
976 int rc;
977
978 br = calloc(1, label->block_size);
979 if (br == NULL)
980 return ENOMEM;
981
982 ba = part->block0 - part->hdr_blocks;
983
984 rc = block_write_direct(label->svc_id, ba, 1, br);
985 if (rc != EOK) {
986 rc = EIO;
987 goto error;
988 }
989
990 free(br);
991 return EOK;
992error:
993 free(br);
994 return rc;
995}
996
997/** Update 'next' PTE in EBR of partition. */
998static int mbr_ebr_update_next(label_t *label, label_part_t *part)
999{
1000 mbr_br_block_t *br;
1001 uint64_t ba;
1002 uint16_t sgn;
1003 int rc;
1004
1005 ba = part->block0 - part->hdr_blocks;
1006
1007 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next ba=%" PRIu64,
1008 ba);
1009
1010 br = calloc(1, label->block_size);
1011 if (br == NULL)
1012 return ENOMEM;
1013
1014 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next read ba=%" PRIu64,
1015 ba);
1016
1017 rc = block_read_direct(label->svc_id, ba, 1, br);
1018 if (rc != EOK) {
1019 rc = EIO;
1020 goto error;
1021 }
1022
1023 /* Verify boot record signature */
1024 sgn = uint16_t_le2host(br->signature);
1025 if (sgn != mbr_br_signature) {
1026 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next signature error");
1027 rc = EIO;
1028 goto error;
1029 }
1030
1031 mbr_log_part_to_ptes(part, NULL, &br->pte[mbr_ebr_pte_next]);
1032
1033 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next write ba=%" PRIu64,
1034 ba);
1035
1036 rc = block_write_direct(label->svc_id, ba, 1, br);
1037 if (rc != EOK) {
1038 rc = EIO;
1039 goto error;
1040 }
1041
1042 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next success");
1043
1044 free(br);
1045 return EOK;
1046error:
1047 free(br);
1048 return rc;
1049}
1050
1051/** Update indices of logical partitions.
1052 *
1053 * Logical partition indices are unstable, i.e. they can change during
1054 * the lifetime of a logical partition. Since the index corresponds to the
1055 * position of the partition in order of block address, anytime a partition
1056 * is created or deleted, indices of all partitions at higher addresses
1057 * change.
1058 */
1059static void mbr_update_log_indices(label_t *label)
1060{
1061 label_part_t *part;
1062 int idx;
1063
1064 idx = mbr_nprimary + 1;
1065
1066 part = mbr_log_part_first(label);
1067 while (part != NULL) {
1068 part->index = idx++;
1069 part = mbr_log_part_next(part);
1070 }
1071}
1072
1073/** @}
1074 */
Note: See TracBrowser for help on using the repository browser.