source: mainline/uspace/lib/label/src/mbr.c@ 03661d19

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

Handle simplified capacity entry.

  • Property mode set to 100644
File size: 23.0 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 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_create");
515 if (pspec->ptype.fmt != lptf_num)
516 return EINVAL;
517
518 part = calloc(1, sizeof(label_part_t));
519 if (part == NULL)
520 return ENOMEM;
521
522
523 /* XXX Check if index is used */
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 part->ptype = pspec->ptype;
548 if (pspec->index != 0) {
549 rc = EINVAL;
550 goto error;
551 }
552 break;
553 }
554
555 if (pspec->pkind != lpk_logical) {
556 /* Primary or extended partition */
557 /* XXX Verify index, block0, nblocks */
558
559 if (pspec->index < 1 || pspec->index > label->pri_entries) {
560 rc = EINVAL;
561 goto error;
562 }
563
564 if (pspec->hdr_blocks != 0) {
565 rc = EINVAL;
566 goto error;
567 }
568
569 rc = mbr_part_to_pte(part, &pte);
570 if (rc != EOK) {
571 rc = EINVAL;
572 goto error;
573 }
574
575 rc = mbr_pte_update(label, &pte, pspec->index - 1);
576 if (rc != EOK) {
577 rc = EIO;
578 goto error;
579 }
580
581 list_append(&part->lparts, &label->parts);
582 list_append(&part->lpri, &label->pri_parts);
583
584 if (pspec->pkind == lpk_extended)
585 label->ext_part = part;
586 } else {
587 /* Logical partition */
588 rc = mbr_log_part_insert(label, part);
589 if (rc != EOK)
590 goto error;
591
592 /* Create EBR for new partition */
593 rc = mbr_ebr_create(label, part);
594 if (rc != EOK)
595 goto error;
596
597 prev = mbr_log_part_prev(part);
598 if (prev != NULL) {
599 /* Update 'next' PTE in EBR of previous partition */
600 rc = mbr_ebr_update_next(label, prev);
601 if (rc != EOK) {
602 goto error;
603 }
604 } else {
605 /* New partition is now the first one */
606 next = mbr_log_part_next(part);
607 if (next != NULL) {
608 /*
609 * Create new, relocated EBR for the former
610 * first partition
611 */
612 next->hdr_blocks = pspec->hdr_blocks;
613 rc = mbr_ebr_create(label, next);
614 if (rc != EOK)
615 goto error;
616 }
617 }
618
619 /* This also sets index for the new partition. */
620 mbr_update_log_indices(label);
621 }
622
623 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_create success");
624 *rpart = part;
625 return EOK;
626error:
627 free(part);
628 return rc;
629}
630
631static int mbr_part_destroy(label_part_t *part)
632{
633 mbr_pte_t pte;
634 label_part_t *prev;
635 label_part_t *next;
636 uint64_t ep_b0;
637 int rc;
638
639 if (link_used(&part->lpri)) {
640 /* Primary/extended partition */
641
642 /* Prepare unused partition table entry */
643 mbr_unused_pte(&pte);
644
645 /* Modify partition table */
646 rc = mbr_pte_update(part->label, &pte, part->index - 1);
647 if (rc != EOK)
648 return EIO;
649
650 /* If it was the extended partition, clear ext. part. pointer */
651 if (part == part->label->ext_part)
652 part->label->ext_part = NULL;
653
654 list_remove(&part->lpri);
655 } else {
656 /* Logical partition */
657
658 prev = mbr_log_part_prev(part);
659 if (prev != NULL) {
660 /* Update next link in previous EBR */
661 list_remove(&part->llog);
662
663 rc = mbr_ebr_update_next(part->label, prev);
664 if (rc != EOK) {
665 /* Roll back */
666 list_insert_after(&part->llog, &prev->llog);
667 return EIO;
668 }
669
670 /* Delete EBR */
671 rc = mbr_ebr_delete(part->label, part);
672 if (rc != EOK)
673 return EIO;
674 } else {
675 next = mbr_log_part_next(part);
676 list_remove(&part->llog);
677
678 if (next != NULL) {
679 /*
680 * Relocate next partition's EBR to the beginning
681 * of the extended partition. This also
682 * overwrites the EBR of the former first
683 * partition.
684 */
685
686 /* First block of extended partition */
687 ep_b0 = part->label->ext_part->block0;
688
689 next->hdr_blocks = next->block0 - ep_b0;
690
691 rc = mbr_ebr_create(part->label, next);
692 if (rc != EOK) {
693 list_prepend(&part->llog, &part->label->log_parts);
694 return EIO;
695 }
696 } else {
697 /* Delete EBR */
698 rc = mbr_ebr_delete(part->label, part);
699 if (rc != EOK)
700 return EIO;
701 }
702 }
703
704 /* Update indices */
705 mbr_update_log_indices(part->label);
706 }
707
708 list_remove(&part->lparts);
709 free(part);
710 return EOK;
711}
712
713static int mbr_suggest_ptype(label_t *label, label_pcnt_t pcnt,
714 label_ptype_t *ptype)
715{
716 ptype->fmt = lptf_num;
717 ptype->t.num = 0;
718
719 switch (pcnt) {
720 case lpc_exfat:
721 ptype->t.num = mbr_pt_ms_advanced;
722 break;
723 case lpc_ext4:
724 ptype->t.num = mbr_pt_linux;
725 break;
726 case lpc_fat12_16:
727 ptype->t.num = mbr_pt_fat16_lba;
728 break;
729 case lpc_fat32:
730 ptype->t.num = mbr_pt_fat32_lba;
731 break;
732 case lpc_minix:
733 ptype->t.num = mbr_pt_minix;
734 break;
735 }
736
737 if (ptype->t.num == 0)
738 return EINVAL;
739
740 return EOK;
741}
742
743
744static void mbr_unused_pte(mbr_pte_t *pte)
745{
746 memset(pte, 0, sizeof(mbr_pte_t));
747}
748
749static int mbr_part_to_pte(label_part_t *part, mbr_pte_t *pte)
750{
751 if ((part->block0 >> 32) != 0)
752 return EINVAL;
753 if ((part->nblocks >> 32) != 0)
754 return EINVAL;
755 if ((part->ptype.t.num >> 8) != 0)
756 return EINVAL;
757
758 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_to_pte: a0=%" PRIu64
759 " len=%" PRIu64 " ptype=%d", part->block0, part->nblocks,
760 (int)part->ptype.t.num);
761 memset(pte, 0, sizeof(mbr_pte_t));
762 pte->ptype = part->ptype.t.num;
763 pte->first_lba = host2uint32_t_le(part->block0);
764 pte->length = host2uint32_t_le(part->nblocks);
765 return EOK;
766}
767
768static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
769{
770 label_part_t *part;
771 uint32_t block0;
772 uint32_t nblocks;
773
774 block0 = uint32_t_le2host(pte->first_lba);
775 nblocks = uint32_t_le2host(pte->length);
776
777 /* See UEFI specification 2.0 section 5.2.1 Legacy Master Boot Record */
778 if (pte->ptype == mbr_pt_unused || nblocks == 0)
779 return EOK;
780
781 part = calloc(1, sizeof(label_part_t));
782 if (part == NULL)
783 return ENOMEM;
784
785 part->ptype.fmt = lptf_num;
786 part->ptype.t.num = pte->ptype;
787 part->index = index;
788 part->block0 = block0;
789 part->nblocks = nblocks;
790
791 /*
792 * TODO: Verify
793 * - partition must reside on disk
794 * - partition must not overlap any other partition
795 */
796
797 part->label = label;
798 list_append(&part->lparts, &label->parts);
799 list_append(&part->lpri, &label->pri_parts);
800
801 if (pte->ptype == mbr_pt_extended)
802 label->ext_part = part;
803 return EOK;
804}
805
806static int mbr_pte_to_log_part(label_t *label, uint64_t ebr_b0,
807 mbr_pte_t *pte)
808{
809 label_part_t *part;
810 uint32_t block0;
811 uint32_t nblocks;
812 size_t nlparts;
813
814 block0 = ebr_b0 + uint32_t_le2host(pte->first_lba);
815 nblocks = uint32_t_le2host(pte->length);
816
817 if (pte->ptype == mbr_pt_unused || nblocks == 0)
818 return EOK;
819
820 part = calloc(1, sizeof(label_part_t));
821 if (part == NULL)
822 return ENOMEM;
823
824 nlparts = list_count(&label->log_parts);
825
826 part->ptype.fmt = lptf_num;
827 part->ptype.t.num = pte->ptype;
828 part->index = mbr_nprimary + 1 + nlparts;
829 part->block0 = block0;
830 part->nblocks = nblocks;
831 part->hdr_blocks = block0 - ebr_b0;
832
833 part->label = label;
834 list_append(&part->lparts, &label->parts);
835 list_append(&part->llog, &label->log_parts);
836
837 return EOK;
838}
839
840static void mbr_log_part_to_ptes(label_part_t *part, mbr_pte_t *pthis,
841 mbr_pte_t *pnext)
842{
843 label_part_t *next;
844 uint64_t ep_b0;
845 uint64_t totsize;
846
847 /* First block of extended partition */
848 ep_b0 = part->label->ext_part->block0;
849
850 assert(link_used(&part->llog));
851 assert(part->block0 >= ep_b0);
852 assert(part->hdr_blocks <= part->block0 - ep_b0);
853
854 /* 'This' EBR entry */
855 if (pthis != NULL) {
856 memset(pthis, 0, sizeof(mbr_pte_t));
857 pthis->ptype = part->ptype.t.num;
858 pthis->first_lba = host2uint32_t_le(part->hdr_blocks);
859 pthis->length = host2uint32_t_le(part->nblocks);
860 }
861
862 /* 'Next' EBR entry */
863 if (pnext != NULL) {
864 next = mbr_log_part_next(part);
865
866 memset(pnext, 0, sizeof(mbr_pte_t));
867 if (next != NULL) {
868 /* Total size of EBR + partition */
869 totsize = next->hdr_blocks + next->nblocks;
870
871 pnext->ptype = mbr_pt_extended;
872 pnext->first_lba = host2uint32_t_le(next->block0 -
873 next->hdr_blocks - ep_b0);
874 pnext->length = host2uint32_t_le(totsize);
875 }
876 }
877}
878
879/** Update partition table entry at specified index.
880 *
881 * Replace partition entry at index @a index with the contents of
882 * @a pte.
883 */
884static int mbr_pte_update(label_t *label, mbr_pte_t *pte, int index)
885{
886 mbr_br_block_t *br;
887 int rc;
888
889 br = calloc(1, label->block_size);
890 if (br == NULL)
891 return ENOMEM;
892
893 rc = block_read_direct(label->svc_id, mbr_ba, 1, br);
894 if (rc != EOK) {
895 rc = EIO;
896 goto error;
897 }
898
899 br->pte[index] = *pte;
900
901 rc = block_write_direct(label->svc_id, mbr_ba, 1, br);
902 if (rc != EOK) {
903 rc = EIO;
904 goto error;
905 }
906
907 free(br);
908 return EOK;
909error:
910 free(br);
911 return rc;
912}
913
914/** Insert logical partition into logical partition list. */
915static int mbr_log_part_insert(label_t *label, label_part_t *part)
916{
917 label_part_t *cur;
918
919 cur = mbr_log_part_first(label);
920 while (cur != NULL) {
921 if (cur->block0 + cur->nblocks > part->block0)
922 break;
923 cur = mbr_log_part_next(part);
924 }
925
926 if (cur != NULL)
927 list_insert_before(&part->llog, &cur->llog);
928 else
929 list_append(&part->llog, &label->log_parts);
930
931 return EOK;
932}
933
934/** Create EBR for partition. */
935static int mbr_ebr_create(label_t *label, label_part_t *part)
936{
937 mbr_br_block_t *br;
938 uint64_t ba;
939 int rc;
940
941 br = calloc(1, label->block_size);
942 if (br == NULL)
943 return ENOMEM;
944
945 mbr_log_part_to_ptes(part, &br->pte[mbr_ebr_pte_this],
946 &br->pte[mbr_ebr_pte_next]);
947 br->signature = host2uint16_t_le(mbr_br_signature);
948
949 ba = part->block0 - part->hdr_blocks;
950
951 log_msg(LOG_DEFAULT, LVL_NOTE, "Write EBR to ba=%" PRIu64, ba);
952 rc = block_write_direct(label->svc_id, ba, 1, br);
953 if (rc != EOK) {
954 rc = EIO;
955 goto error;
956 }
957
958 free(br);
959 return EOK;
960error:
961 free(br);
962 return rc;
963}
964
965static int mbr_ebr_delete(label_t *label, label_part_t *part)
966{
967 mbr_br_block_t *br;
968 uint64_t ba;
969 int rc;
970
971 br = calloc(1, label->block_size);
972 if (br == NULL)
973 return ENOMEM;
974
975 ba = part->block0 - part->hdr_blocks;
976
977 rc = block_write_direct(label->svc_id, ba, 1, br);
978 if (rc != EOK) {
979 rc = EIO;
980 goto error;
981 }
982
983 free(br);
984 return EOK;
985error:
986 free(br);
987 return rc;
988}
989
990/** Update 'next' PTE in EBR of partition. */
991static int mbr_ebr_update_next(label_t *label, label_part_t *part)
992{
993 mbr_br_block_t *br;
994 uint64_t ba;
995 uint16_t sgn;
996 int rc;
997
998 ba = part->block0 - part->hdr_blocks;
999
1000 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next ba=%" PRIu64,
1001 ba);
1002
1003 br = calloc(1, label->block_size);
1004 if (br == NULL)
1005 return ENOMEM;
1006
1007 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next read ba=%" PRIu64,
1008 ba);
1009
1010 rc = block_read_direct(label->svc_id, ba, 1, br);
1011 if (rc != EOK) {
1012 rc = EIO;
1013 goto error;
1014 }
1015
1016 /* Verify boot record signature */
1017 sgn = uint16_t_le2host(br->signature);
1018 if (sgn != mbr_br_signature) {
1019 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next signature error");
1020 rc = EIO;
1021 goto error;
1022 }
1023
1024 mbr_log_part_to_ptes(part, NULL, &br->pte[mbr_ebr_pte_next]);
1025
1026 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next write ba=%" PRIu64,
1027 ba);
1028
1029 rc = block_write_direct(label->svc_id, ba, 1, br);
1030 if (rc != EOK) {
1031 rc = EIO;
1032 goto error;
1033 }
1034
1035 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next success");
1036
1037 free(br);
1038 return EOK;
1039error:
1040 free(br);
1041 return rc;
1042}
1043
1044/** Update indices of logical partitions.
1045 *
1046 * Logical partition indices are unstable, i.e. they can change during
1047 * the lifetime of a logical partition. Since the index corresponds to the
1048 * position of the partition in order of block address, anytime a partition
1049 * is created or deleted, indices of all partitions at higher addresses
1050 * change.
1051 */
1052static void mbr_update_log_indices(label_t *label)
1053{
1054 label_part_t *part;
1055 int idx;
1056
1057 idx = mbr_nprimary + 1;
1058
1059 part = mbr_log_part_first(label);
1060 while (part != NULL) {
1061 part->index = idx++;
1062 part = mbr_log_part_next(part);
1063 }
1064}
1065
1066/** @}
1067 */
Note: See TracBrowser for help on using the repository browser.