The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_diskgpt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
    3  * 
    4  * This code is derived from software contributed to The DragonFly Project
    5  * by Matthew Dillon <dillon@backplane.com>
    6  * 
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in
   15  *    the documentation and/or other materials provided with the
   16  *    distribution.
   17  * 3. Neither the name of The DragonFly Project nor the names of its
   18  *    contributors may be used to endorse or promote products derived
   19  *    from this software without specific, prior written permission.
   20  * 
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/conf.h>
   38 #include <sys/endian.h>
   39 #include <sys/diskslice.h>
   40 #include <sys/diskmbr.h>
   41 #include <sys/disk.h>
   42 #include <sys/buf.h>
   43 #include <sys/malloc.h>
   44 #include <sys/syslog.h>
   45 #include <sys/bus.h>
   46 #include <sys/device.h>
   47 #include <sys/gpt.h>
   48 
   49 static void gpt_setslice(const char *sname, struct disk_info *info,
   50                          struct diskslice *sp, struct gpt_ent *sent);
   51 
   52 /*
   53  * Handle GPT on raw disk.  Note that GPTs are not recursive.  The MBR is
   54  * ignored once a GPT has been detected.
   55  *
   56  * GPTs always start at block #1, regardless of how the MBR has been set up.
   57  * In fact, the MBR's starting block might be pointing to the boot partition
   58  * in the GPT rather then to the start of the GPT.
   59  *
   60  * This routine is called from mbrinit() when a GPT has been detected.
   61  */
   62 int
   63 gptinit(cdev_t dev, struct disk_info *info, struct diskslices **sspp)
   64 {
   65         struct buf *bp1 = NULL;
   66         struct buf *bp2 = NULL;
   67         struct gpt_hdr *gpt;
   68         struct gpt_ent *ent;
   69         struct diskslice *sp;
   70         struct diskslices *ssp;
   71         cdev_t wdev;
   72         int error;
   73         uint32_t len;
   74         uint32_t entries;
   75         uint32_t entsz;
   76         uint32_t crc;
   77         uint32_t table_lba;
   78         uint32_t table_blocks;
   79         int i = 0, j;
   80         const char *dname;
   81 
   82         /*
   83          * The GPT starts in sector 1.
   84          */
   85         wdev = dev;
   86         dname = dev_dname(wdev);
   87         bp1 = geteblk((int)info->d_media_blksize);
   88         bp1->b_bio1.bio_offset = info->d_media_blksize;
   89         bp1->b_bio1.bio_done = biodone_sync;
   90         bp1->b_bio1.bio_flags |= BIO_SYNC;
   91         bp1->b_bcount = info->d_media_blksize;
   92         bp1->b_cmd = BUF_CMD_READ;
   93         dev_dstrategy(wdev, &bp1->b_bio1);
   94         if (biowait(&bp1->b_bio1, "gptrd") != 0) {
   95                 kprintf("%s: reading GPT @ block 1: error %d\n",
   96                         dname, bp1->b_error);
   97                 error = EIO;
   98                 goto done;
   99         }
  100 
  101         /*
  102          * Header sanity check
  103          */
  104         gpt = (void *)bp1->b_data;
  105         len = le32toh(gpt->hdr_size);
  106         if (len < GPT_MIN_HDR_SIZE || len > info->d_media_blksize) {
  107                 kprintf("%s: Illegal GPT header size %d\n", dname, len);
  108                 error = EINVAL;
  109                 goto done;
  110         }
  111 
  112         crc = le32toh(gpt->hdr_crc_self);
  113         gpt->hdr_crc_self = 0;
  114         if (crc32(gpt, len) != crc) {
  115                 kprintf("%s: GPT CRC32 did not match\n", dname);
  116                 error = EINVAL;
  117                 goto done;
  118         }
  119 
  120         /*
  121          * Validate the partition table and its location, then read it
  122          * into a buffer.
  123          */
  124         entries = le32toh(gpt->hdr_entries);
  125         entsz = le32toh(gpt->hdr_entsz);
  126         table_lba = le32toh(gpt->hdr_lba_table);
  127         table_blocks = (entries * entsz + info->d_media_blksize - 1) /
  128                        info->d_media_blksize;
  129         if (entries < 1 || entries > 128 ||
  130             entsz < 128 || (entsz & 7) || entsz > MAXBSIZE / entries ||
  131             table_lba < 2 || table_lba + table_blocks > info->d_media_blocks) {
  132                 kprintf("%s: GPT partition table is out of bounds\n", dname);
  133                 error = EINVAL;
  134                 goto done;
  135         }
  136 
  137         /*
  138          * XXX subject to device dma size limitations
  139          */
  140         bp2 = geteblk((int)(table_blocks * info->d_media_blksize));
  141         bp2->b_bio1.bio_offset = (off_t)table_lba * info->d_media_blksize;
  142         bp2->b_bio1.bio_done = biodone_sync;
  143         bp2->b_bio1.bio_flags |= BIO_SYNC;
  144         bp2->b_bcount = table_blocks * info->d_media_blksize;
  145         bp2->b_cmd = BUF_CMD_READ;
  146         dev_dstrategy(wdev, &bp2->b_bio1);
  147         if (biowait(&bp2->b_bio1, "gptrd") != 0) {
  148                 kprintf("%s: reading GPT partition table @ %lld: error %d\n",
  149                         dname,
  150                         (long long)bp2->b_bio1.bio_offset,
  151                         bp2->b_error);
  152                 error = EIO;
  153                 goto done;
  154         }
  155 
  156         /*
  157          * We are passed a pointer to a minimal slices struct.  Replace
  158          * it with a maximal one (128 slices + special slices).  Well,
  159          * really there is only one special slice (the WHOLE_DISK_SLICE)
  160          * since we use the compatibility slice for s0, but don't quibble.
  161          * 
  162          */
  163         kfree(*sspp, M_DEVBUF);
  164         ssp = *sspp = dsmakeslicestruct(BASE_SLICE+128, info);
  165 
  166         /*
  167          * Create a slice for each partition.
  168          */
  169         for (i = 0; i < (int)entries && i < 128; ++i) {
  170                 struct gpt_ent sent;
  171                 char partname[2];
  172                 char *sname;
  173 
  174                 ent = (void *)((char *)bp2->b_data + i * entsz);
  175                 le_uuid_dec(&ent->ent_type, &sent.ent_type);
  176                 le_uuid_dec(&ent->ent_uuid, &sent.ent_uuid);
  177                 sent.ent_lba_start = le64toh(ent->ent_lba_start);
  178                 sent.ent_lba_end = le64toh(ent->ent_lba_end);
  179                 sent.ent_attr = le64toh(ent->ent_attr);
  180 
  181                 for (j = 0; j < NELEM(ent->ent_name); ++j)
  182                         sent.ent_name[j] = le16toh(ent->ent_name[j]);
  183 
  184                 /*
  185                  * The COMPATIBILITY_SLICE is actually slice 0 (s0).  This
  186                  * is a bit weird becaue the whole-disk slice is #1, so
  187                  * slice 1 (s1) starts at BASE_SLICE.
  188                  */
  189                 if (i == 0)
  190                         sp = &ssp->dss_slices[COMPATIBILITY_SLICE];
  191                 else
  192                         sp = &ssp->dss_slices[BASE_SLICE+i-1];
  193                 sname = dsname(dev, dkunit(dev), WHOLE_DISK_SLICE,
  194                                WHOLE_SLICE_PART, partname);
  195 
  196                 if (kuuid_is_nil(&sent.ent_type))
  197                         continue;
  198 
  199                 if (sent.ent_lba_start < table_lba + table_blocks ||
  200                     sent.ent_lba_end >= info->d_media_blocks ||
  201                     sent.ent_lba_start >= sent.ent_lba_end) {
  202                         kprintf("%s part %d: unavailable, bad start or "
  203                                 "ending lba\n",
  204                                 sname, i);
  205                 } else {
  206                         gpt_setslice(sname, info, sp, &sent);
  207                 }
  208         }
  209         ssp->dss_nslices = BASE_SLICE + i;
  210 
  211         error = 0;
  212 done:
  213         if (bp1) {
  214                 bp1->b_flags |= B_INVAL | B_AGE;
  215                 brelse(bp1);
  216         }
  217         if (bp2) {
  218                 bp2->b_flags |= B_INVAL | B_AGE;
  219                 brelse(bp2);
  220         }
  221         if (error == EINVAL)
  222                 error = 0;
  223         return (error);
  224 }
  225 
  226 static
  227 void
  228 gpt_setslice(const char *sname, struct disk_info *info, struct diskslice *sp,
  229              struct gpt_ent *sent)
  230 {
  231         sp->ds_offset = sent->ent_lba_start;
  232         sp->ds_size   = sent->ent_lba_end + 1 - sent->ent_lba_start;
  233         sp->ds_type   = 1;      /* XXX */
  234         sp->ds_type_uuid = sent->ent_type;
  235         sp->ds_stor_uuid = sent->ent_uuid;
  236         sp->ds_reserved = 0;    /* no reserved sectors */
  237 }
  238 

Cache object: 26342db74144d44f296a4ae278d260ee


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.