source: mainline/uspace/lib/label/src/mbr.c@ 100b1d1

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

Compute hdr_blocks when opening logical partition. Update logical partition indices when deleting logical partition.

  • Property mode set to 100644
File size: 21.8 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 int rc;
630
631 if (link_used(&part->lpri)) {
632 /* Primary/extended partition */
633
634 /* Prepare unused partition table entry */
635 mbr_unused_pte(&pte);
636
637 /* Modify partition table */
638 rc = mbr_pte_update(part->label, &pte, part->index - 1);
639 if (rc != EOK)
640 return EIO;
641
642 /* If it was the extended partition, clear ext. part. pointer */
643 if (part == part->label->ext_part)
644 part->label->ext_part = NULL;
645
646 list_remove(&part->lpri);
647 } else {
648 /* Logical partition */
649
650 prev = mbr_log_part_prev(part);
651 if (prev != NULL) {
652 /* Update next link in previous EBR */
653 list_remove(&part->llog);
654
655 rc = mbr_ebr_update_next(part->label, prev);
656 if (rc != EOK) {
657 /* Roll back */
658 list_insert_after(&part->llog, &prev->llog);
659 return EIO;
660 }
661 } else {
662 list_remove(&part->llog);
663 }
664
665 /* Delete EBR */
666 mbr_ebr_delete(part->label, part);
667
668 /* Update indices */
669 mbr_update_log_indices(part->label);
670 }
671
672 list_remove(&part->lparts);
673 free(part);
674 return EOK;
675}
676
677static void mbr_unused_pte(mbr_pte_t *pte)
678{
679 memset(pte, 0, sizeof(mbr_pte_t));
680}
681
682static int mbr_part_to_pte(label_part_t *part, mbr_pte_t *pte)
683{
684 if ((part->block0 >> 32) != 0)
685 return EINVAL;
686 if ((part->nblocks >> 32) != 0)
687 return EINVAL;
688 if ((part->ptype >> 8) != 0)
689 return EINVAL;
690
691 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_part_to_pte: a0=%" PRIu64
692 " len=%" PRIu64 " ptype=%d", part->block0, part->nblocks,
693 (int)part->ptype);
694 memset(pte, 0, sizeof(mbr_pte_t));
695 pte->ptype = part->ptype;
696 pte->first_lba = host2uint32_t_le(part->block0);
697 pte->length = host2uint32_t_le(part->nblocks);
698 return EOK;
699}
700
701static int mbr_pte_to_part(label_t *label, mbr_pte_t *pte, int index)
702{
703 label_part_t *part;
704 uint32_t block0;
705 uint32_t nblocks;
706
707 block0 = uint32_t_le2host(pte->first_lba);
708 nblocks = uint32_t_le2host(pte->length);
709
710 /* See UEFI specification 2.0 section 5.2.1 Legacy Master Boot Record */
711 if (pte->ptype == mbr_pt_unused || nblocks == 0)
712 return EOK;
713
714 part = calloc(1, sizeof(label_part_t));
715 if (part == NULL)
716 return ENOMEM;
717
718 part->ptype = pte->ptype;
719 part->index = index;
720 part->block0 = block0;
721 part->nblocks = nblocks;
722
723 /*
724 * TODO: Verify
725 * - partition must reside on disk
726 * - partition must not overlap any other partition
727 */
728
729 part->label = label;
730 list_append(&part->lparts, &label->parts);
731 list_append(&part->lpri, &label->pri_parts);
732
733 if (pte->ptype == mbr_pt_extended)
734 label->ext_part = part;
735 return EOK;
736}
737
738static int mbr_pte_to_log_part(label_t *label, uint64_t ebr_b0,
739 mbr_pte_t *pte)
740{
741 label_part_t *part;
742 uint32_t block0;
743 uint32_t nblocks;
744 size_t nlparts;
745
746 block0 = ebr_b0 + uint32_t_le2host(pte->first_lba);
747 nblocks = uint32_t_le2host(pte->length);
748
749 if (pte->ptype == mbr_pt_unused || nblocks == 0)
750 return EOK;
751
752 part = calloc(1, sizeof(label_part_t));
753 if (part == NULL)
754 return ENOMEM;
755
756 nlparts = list_count(&label->log_parts);
757
758 part->ptype = pte->ptype;
759 part->index = mbr_nprimary + 1 + nlparts;
760 part->block0 = block0;
761 part->nblocks = nblocks;
762 part->hdr_blocks = block0 - ebr_b0;
763
764 part->label = label;
765 list_append(&part->lparts, &label->parts);
766 list_append(&part->llog, &label->log_parts);
767
768 return EOK;
769}
770#include <stdio.h>
771static void mbr_log_part_to_ptes(label_part_t *part, mbr_pte_t *pthis,
772 mbr_pte_t *pnext)
773{
774 label_part_t *next;
775 uint64_t ep_b0;
776 uint64_t totsize;
777
778 /* First block of extended partition */
779 ep_b0 = part->label->ext_part->block0;
780
781 assert(link_used(&part->llog));
782 assert(part->block0 >= ep_b0);
783 printf("part->hdr_blocks = %" PRIu64 "\n", part->hdr_blocks);
784 printf("part->block0 = %" PRIu64 "\n", part->block0);
785 printf("ep_b0 = %" PRIu64 "\n", ep_b0);
786 assert(part->hdr_blocks <= part->block0 - ep_b0);
787
788 /* 'This' EBR entry */
789 if (pthis != NULL) {
790 memset(pthis, 0, sizeof(mbr_pte_t));
791 pthis->ptype = part->ptype;
792 pthis->first_lba = host2uint32_t_le(part->hdr_blocks);
793 pthis->length = host2uint32_t_le(part->nblocks);
794 }
795
796 /* 'Next' EBR entry */
797 if (pnext != NULL) {
798 next = mbr_part_next(part);
799
800 memset(pnext, 0, sizeof(mbr_pte_t));
801 if (next != NULL) {
802 /* Total size of EBR + partition */
803 totsize = next->hdr_blocks + next->nblocks;
804
805 pnext->ptype = mbr_pt_extended;
806 pnext->first_lba = host2uint32_t_le(next->block0 -
807 next->hdr_blocks - ep_b0);
808 pnext->length = host2uint32_t_le(totsize);
809 }
810 }
811}
812
813/** Update partition table entry at specified index.
814 *
815 * Replace partition entry at index @a index with the contents of
816 * @a pte.
817 */
818static int mbr_pte_update(label_t *label, mbr_pte_t *pte, int index)
819{
820 mbr_br_block_t *br;
821 int rc;
822
823 br = calloc(1, label->block_size);
824 if (br == NULL)
825 return ENOMEM;
826
827 rc = block_read_direct(label->svc_id, mbr_ba, 1, br);
828 if (rc != EOK) {
829 rc = EIO;
830 goto error;
831 }
832
833 br->pte[index] = *pte;
834
835 rc = block_write_direct(label->svc_id, mbr_ba, 1, br);
836 if (rc != EOK) {
837 rc = EIO;
838 goto error;
839 }
840
841 free(br);
842 return EOK;
843error:
844 free(br);
845 return rc;
846}
847
848/** Insert logical partition into logical partition list. */
849static int mbr_log_part_insert(label_t *label, label_part_t *part)
850{
851 label_part_t *cur;
852
853 cur = mbr_log_part_first(label);
854 while (cur != NULL) {
855 if (cur->block0 + cur->nblocks > part->block0)
856 break;
857 cur = mbr_log_part_next(part);
858 }
859
860 if (cur != NULL)
861 list_insert_before(&part->llog, &cur->llog);
862 else
863 list_append(&part->llog, &label->log_parts);
864
865 return EOK;
866}
867
868/** Create EBR for partition. */
869static int mbr_ebr_create(label_t *label, label_part_t *part)
870{
871 mbr_br_block_t *br;
872 uint64_t ba;
873 int rc;
874
875 br = calloc(1, label->block_size);
876 if (br == NULL)
877 return ENOMEM;
878
879 mbr_log_part_to_ptes(part, &br->pte[mbr_ebr_pte_this],
880 &br->pte[mbr_ebr_pte_next]);
881 br->signature = host2uint16_t_le(mbr_br_signature);
882
883 ba = part->block0 - part->hdr_blocks;
884
885 log_msg(LOG_DEFAULT, LVL_NOTE, "Write EBR to ba=%" PRIu64, ba);
886 rc = block_write_direct(label->svc_id, ba, 1, br);
887 if (rc != EOK) {
888 rc = EIO;
889 goto error;
890 }
891
892 free(br);
893 return EOK;
894error:
895 free(br);
896 return rc;
897}
898
899static int mbr_ebr_delete(label_t *label, label_part_t *part)
900{
901 mbr_br_block_t *br;
902 uint64_t ba;
903 int rc;
904
905 br = calloc(1, label->block_size);
906 if (br == NULL)
907 return ENOMEM;
908
909 ba = part->block0 - part->hdr_blocks;
910
911 rc = block_write_direct(label->svc_id, ba, 1, br);
912 if (rc != EOK) {
913 rc = EIO;
914 goto error;
915 }
916
917 free(br);
918 return EOK;
919error:
920 free(br);
921 return rc;
922}
923
924/** Update 'next' PTE in EBR of partition. */
925static int mbr_ebr_update_next(label_t *label, label_part_t *part)
926{
927 mbr_br_block_t *br;
928 uint64_t ba;
929 uint16_t sgn;
930 int rc;
931
932 ba = part->block0 - part->hdr_blocks;
933
934 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next ba=%" PRIu64,
935 ba);
936
937 br = calloc(1, label->block_size);
938 if (br == NULL)
939 return ENOMEM;
940
941 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next read ba=%" PRIu64,
942 ba);
943
944 rc = block_read_direct(label->svc_id, ba, 1, br);
945 if (rc != EOK) {
946 rc = EIO;
947 goto error;
948 }
949
950 /* Verify boot record signature */
951 sgn = uint16_t_le2host(br->signature);
952 if (sgn != mbr_br_signature) {
953 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next signature error");
954 rc = EIO;
955 goto error;
956 }
957
958 mbr_log_part_to_ptes(part, NULL, &br->pte[mbr_ebr_pte_next]);
959
960 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next write ba=%" PRIu64,
961 ba);
962
963 rc = block_write_direct(label->svc_id, ba, 1, br);
964 if (rc != EOK) {
965 rc = EIO;
966 goto error;
967 }
968
969 log_msg(LOG_DEFAULT, LVL_NOTE, "mbr_ebr_update_next success");
970
971 free(br);
972 return EOK;
973error:
974 free(br);
975 return rc;
976}
977
978/** Update indices of logical partitions.
979 *
980 * Logical partition indices are unstable, i.e. they can change during
981 * the lifetime of a logical partition. Since the index corresponds to the
982 * position of the partition in order of block address, anytime a partition
983 * is created or deleted, indices of all partitions at higher addresses
984 * change.
985 */
986static void mbr_update_log_indices(label_t *label)
987{
988 label_part_t *part;
989 int idx;
990
991 idx = mbr_nprimary + 1;
992
993 part = mbr_log_part_first(label);
994 while (part != NULL) {
995 part->index = idx++;
996 part = mbr_log_part_next(part);
997 }
998}
999
1000/** @}
1001 */
Note: See TracBrowser for help on using the repository browser.