source: mainline/uspace/lib/label/src/mbr.c@ 1b23e33

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

Fix comment.

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