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/geom/vinum/geom_vinum_drive.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) 2004, 2005, 2007 Lukas Ertl
    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  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/10.0/sys/geom/vinum/geom_vinum_drive.c 223921 2011-07-11 05:22:31Z ae $");
   29 
   30 #include <sys/types.h>
   31 #include <sys/endian.h>
   32 #include <sys/malloc.h>
   33 #include <sys/sbuf.h>
   34 #include <sys/systm.h>
   35 
   36 #include <geom/geom.h>
   37 #include <geom/vinum/geom_vinum_var.h>
   38 #include <geom/vinum/geom_vinum.h>
   39 
   40 #define GV_LEGACY_I386  0
   41 #define GV_LEGACY_AMD64 1
   42 #define GV_LEGACY_SPARC64 2
   43 #define GV_LEGACY_POWERPC 3
   44 
   45 static int      gv_legacy_header_type(uint8_t *, int);
   46 
   47 /*
   48  * Here are the "offset (size)" for the various struct gv_hdr fields,
   49  * for the legacy i386 (or 32-bit powerpc), legacy amd64 (or sparc64), and
   50  * current (cpu & endian agnostic) versions of the on-disk format of the vinum
   51  * header structure:
   52  *
   53  *       i386    amd64   current   field
   54  *     -------- -------- --------  -----
   55  *       0 ( 8)   0 ( 8)   0 ( 8)  magic
   56  *       8 ( 4)   8 ( 8)   8 ( 8)  config_length
   57  *      12 (32)  16 (32)  16 (32)  label.sysname
   58  *      44 (32)  48 (32)  48 (32)  label.name
   59  *      76 ( 4)  80 ( 8)  80 ( 8)  label.date_of_birth.tv_sec
   60  *      80 ( 4)  88 ( 8)  88 ( 8)  label.date_of_birth.tv_usec
   61  *      84 ( 4)  96 ( 8)  96 ( 8)  label.last_update.tv_sec
   62  *      88 ( 4) 104 ( 8) 104 ( 8)  label.last_update.tv_usec
   63  *      92 ( 8) 112 ( 8) 112 ( 8)  label.drive_size
   64  *     ======== ======== ========
   65  *     100      120      120       total size
   66  *
   67  * NOTE: i386 and amd64 formats are stored as little-endian; the current
   68  * format uses big-endian (network order).
   69  */
   70 
   71 
   72 /* Checks for legacy format depending on platform. */
   73 static int
   74 gv_legacy_header_type(uint8_t *hdr, int bigendian)
   75 {
   76         uint32_t *i32;
   77         int arch_32, arch_64, i;
   78 
   79         /* Set arch according to endianess. */
   80         if (bigendian) {
   81                 arch_32 = GV_LEGACY_POWERPC;
   82                 arch_64 = GV_LEGACY_SPARC64;
   83         } else {
   84                 arch_32 = GV_LEGACY_I386;
   85                 arch_64 = GV_LEGACY_AMD64;
   86         }
   87 
   88         /* if non-empty hostname overlaps 64-bit config_length */
   89         i32 = (uint32_t *)(hdr + 12);
   90         if (*i32 != 0)
   91                 return (arch_32);
   92         /* check for non-empty hostname */
   93         if (hdr[16] != 0)
   94                 return (arch_64);
   95         /* check bytes past 32-bit structure */
   96         for (i = 100; i < 120; i++)
   97                 if (hdr[i] != 0)
   98                         return (arch_32);
   99         /* check for overlapping timestamp */
  100         i32 = (uint32_t *)(hdr + 84);
  101 
  102         if (*i32 == 0)
  103                 return (arch_64);
  104         return (arch_32);
  105 }
  106 
  107 /*
  108  * Read the header while taking magic number into account, and write it to
  109  * destination pointer.
  110  */
  111 int
  112 gv_read_header(struct g_consumer *cp, struct gv_hdr *m_hdr)
  113 {
  114         struct g_provider *pp;
  115         uint64_t magic_machdep;
  116         uint8_t *d_hdr;
  117         int be, off;
  118 
  119 #define GV_GET32(endian)                                        \
  120                 endian##32toh(*((uint32_t *)&d_hdr[off]));      \
  121                 off += 4
  122 #define GV_GET64(endian)                                        \
  123                 endian##64toh(*((uint64_t *)&d_hdr[off]));      \
  124                 off += 8
  125 
  126         KASSERT(m_hdr != NULL, ("gv_read_header: null m_hdr"));
  127         KASSERT(cp != NULL, ("gv_read_header: null cp"));
  128         pp = cp->provider;
  129         KASSERT(pp != NULL, ("gv_read_header: null pp"));
  130 
  131         if ((GV_HDR_OFFSET % pp->sectorsize) != 0 ||
  132             (GV_HDR_LEN % pp->sectorsize) != 0)
  133                 return (ENODEV);
  134 
  135         d_hdr = g_read_data(cp, GV_HDR_OFFSET, pp->sectorsize, NULL);
  136         if (d_hdr == NULL)
  137                 return (-1);
  138         off = 0;
  139         m_hdr->magic = GV_GET64(be);
  140         magic_machdep = *((uint64_t *)&d_hdr[0]);
  141         /*
  142          * The big endian machines will have a reverse of GV_OLD_MAGIC, so we
  143          * need to decide if we are running on a big endian machine as well as
  144          * checking the magic against the reverse of GV_OLD_MAGIC.
  145          */
  146         be = (m_hdr->magic == magic_machdep);
  147         if (m_hdr->magic == GV_MAGIC) {
  148                 m_hdr->config_length = GV_GET64(be);
  149                 off = 16;
  150                 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  151                 off += GV_HOSTNAME_LEN;
  152                 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
  153                 off += GV_MAXDRIVENAME;
  154                 m_hdr->label.date_of_birth.tv_sec = GV_GET64(be);
  155                 m_hdr->label.date_of_birth.tv_usec = GV_GET64(be);
  156                 m_hdr->label.last_update.tv_sec = GV_GET64(be);
  157                 m_hdr->label.last_update.tv_usec = GV_GET64(be);
  158                 m_hdr->label.drive_size = GV_GET64(be);
  159         } else if (m_hdr->magic != GV_OLD_MAGIC &&
  160             m_hdr->magic != le64toh(GV_OLD_MAGIC)) {
  161                 /* Not a gvinum drive. */
  162                 g_free(d_hdr);
  163                 return (-1);
  164         } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_SPARC64) {
  165                 G_VINUM_DEBUG(1, "detected legacy sparc64 header");
  166                 m_hdr->magic = GV_MAGIC;
  167                 /* Legacy sparc64 on-disk header */
  168                 m_hdr->config_length = GV_GET64(be);
  169                 bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  170                 off += GV_HOSTNAME_LEN;
  171                 bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME);
  172                 off += GV_MAXDRIVENAME;
  173                 m_hdr->label.date_of_birth.tv_sec = GV_GET64(be);
  174                 m_hdr->label.date_of_birth.tv_usec = GV_GET64(be);
  175                 m_hdr->label.last_update.tv_sec = GV_GET64(be);
  176                 m_hdr->label.last_update.tv_usec = GV_GET64(be);
  177                 m_hdr->label.drive_size = GV_GET64(be);
  178         } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_POWERPC) {
  179                 G_VINUM_DEBUG(1, "detected legacy PowerPC header");
  180                 m_hdr->magic = GV_MAGIC;
  181                 /* legacy 32-bit big endian on-disk header */
  182                 m_hdr->config_length = GV_GET32(be);
  183                 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  184                 off += GV_HOSTNAME_LEN;
  185                 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
  186                 off += GV_MAXDRIVENAME;
  187                 m_hdr->label.date_of_birth.tv_sec = GV_GET32(be);
  188                 m_hdr->label.date_of_birth.tv_usec = GV_GET32(be);
  189                 m_hdr->label.last_update.tv_sec = GV_GET32(be);
  190                 m_hdr->label.last_update.tv_usec = GV_GET32(be);
  191                 m_hdr->label.drive_size = GV_GET64(be);
  192         } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_I386) {
  193                 G_VINUM_DEBUG(1, "detected legacy i386 header");
  194                 m_hdr->magic = GV_MAGIC;
  195                 /* legacy i386 on-disk header */
  196                 m_hdr->config_length = GV_GET32(le);
  197                 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  198                 off += GV_HOSTNAME_LEN;
  199                 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
  200                 off += GV_MAXDRIVENAME;
  201                 m_hdr->label.date_of_birth.tv_sec = GV_GET32(le);
  202                 m_hdr->label.date_of_birth.tv_usec = GV_GET32(le);
  203                 m_hdr->label.last_update.tv_sec = GV_GET32(le);
  204                 m_hdr->label.last_update.tv_usec = GV_GET32(le);
  205                 m_hdr->label.drive_size = GV_GET64(le);
  206         } else {
  207                 G_VINUM_DEBUG(1, "detected legacy amd64 header");
  208                 m_hdr->magic = GV_MAGIC;
  209                 /* legacy amd64 on-disk header */
  210                 m_hdr->config_length = GV_GET64(le);
  211                 bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  212                 off += GV_HOSTNAME_LEN;
  213                 bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME);
  214                 off += GV_MAXDRIVENAME;
  215                 m_hdr->label.date_of_birth.tv_sec = GV_GET64(le);
  216                 m_hdr->label.date_of_birth.tv_usec = GV_GET64(le);
  217                 m_hdr->label.last_update.tv_sec = GV_GET64(le);
  218                 m_hdr->label.last_update.tv_usec = GV_GET64(le);
  219                 m_hdr->label.drive_size = GV_GET64(le);
  220         }
  221 
  222         g_free(d_hdr);
  223         return (0);
  224 }
  225 
  226 /* Write out the gvinum header. */
  227 int
  228 gv_write_header(struct g_consumer *cp, struct gv_hdr *m_hdr)
  229 {
  230         uint8_t d_hdr[GV_HDR_LEN];
  231         int off, ret;
  232 
  233 #define GV_SET64BE(field)                                       \
  234         do {                                                    \
  235                 *((uint64_t *)&d_hdr[off]) = htobe64(field);    \
  236                 off += 8;                                       \
  237         } while (0)
  238 
  239         KASSERT(m_hdr != NULL, ("gv_write_header: null m_hdr"));
  240 
  241         off = 0;
  242         memset(d_hdr, 0, GV_HDR_LEN);
  243         GV_SET64BE(m_hdr->magic);
  244         GV_SET64BE(m_hdr->config_length);
  245         off = 16;
  246         bcopy(m_hdr->label.sysname, d_hdr + off, GV_HOSTNAME_LEN);
  247         off += GV_HOSTNAME_LEN;
  248         bcopy(m_hdr->label.name, d_hdr + off, GV_MAXDRIVENAME);
  249         off += GV_MAXDRIVENAME;
  250         GV_SET64BE(m_hdr->label.date_of_birth.tv_sec);
  251         GV_SET64BE(m_hdr->label.date_of_birth.tv_usec);
  252         GV_SET64BE(m_hdr->label.last_update.tv_sec);
  253         GV_SET64BE(m_hdr->label.last_update.tv_usec);
  254         GV_SET64BE(m_hdr->label.drive_size);
  255 
  256         ret = g_write_data(cp, GV_HDR_OFFSET, d_hdr, GV_HDR_LEN);
  257         return (ret);
  258 }
  259 
  260 /* Save the vinum configuration back to each involved disk. */
  261 void
  262 gv_save_config(struct gv_softc *sc)
  263 {
  264         struct g_consumer *cp;
  265         struct gv_drive *d;
  266         struct gv_hdr *vhdr, *hdr;
  267         struct sbuf *sb;
  268         struct timeval last_update;
  269         int error;
  270 
  271         KASSERT(sc != NULL, ("gv_save_config: null sc"));
  272 
  273         vhdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO);
  274         vhdr->magic = GV_MAGIC;
  275         vhdr->config_length = GV_CFG_LEN;
  276         microtime(&last_update);
  277 
  278         sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN);
  279         gv_format_config(sc, sb, 1, NULL);
  280         sbuf_finish(sb);
  281 
  282         LIST_FOREACH(d, &sc->drives, drive) {
  283                 /*
  284                  * We can't save the config on a drive that isn't up, but
  285                  * drives that were just created aren't officially up yet, so
  286                  * we check a special flag.
  287                  */
  288                 if (d->state != GV_DRIVE_UP)
  289                         continue;
  290 
  291                 cp = d->consumer;
  292                 if (cp == NULL) {
  293                         G_VINUM_DEBUG(0, "drive '%s' has no consumer!",
  294                             d->name);
  295                         continue;
  296                 }
  297 
  298                 hdr = d->hdr;
  299                 if (hdr == NULL) {
  300                         G_VINUM_DEBUG(0, "drive '%s' has no header",
  301                             d->name);
  302                         g_free(vhdr);
  303                         continue;
  304                 }
  305                 bcopy(&last_update, &hdr->label.last_update,
  306                     sizeof(struct timeval));
  307                 bcopy(&hdr->label, &vhdr->label, sizeof(struct gv_label));
  308                 g_topology_lock();
  309                 error = g_access(cp, 0, 1, 0);
  310                 if (error) {
  311                         G_VINUM_DEBUG(0, "g_access failed on "
  312                             "drive %s, errno %d", d->name, error);
  313                         g_topology_unlock();
  314                         continue;
  315                 }
  316                 g_topology_unlock();
  317 
  318                 error = gv_write_header(cp, vhdr);
  319                 if (error) {
  320                         G_VINUM_DEBUG(0, "writing vhdr failed on drive %s, "
  321                             "errno %d", d->name, error);
  322                         g_topology_lock();
  323                         g_access(cp, 0, -1, 0);
  324                         g_topology_unlock();
  325                         continue;
  326                 }
  327                 /* First config copy. */
  328                 error = g_write_data(cp, GV_CFG_OFFSET, sbuf_data(sb),
  329                     GV_CFG_LEN);
  330                 if (error) {
  331                         G_VINUM_DEBUG(0, "writing first config copy failed on "
  332                             "drive %s, errno %d", d->name, error);
  333                         g_topology_lock();
  334                         g_access(cp, 0, -1, 0);
  335                         g_topology_unlock();
  336                         continue;
  337                 }
  338                 /* Second config copy. */
  339                 error = g_write_data(cp, GV_CFG_OFFSET + GV_CFG_LEN,
  340                     sbuf_data(sb), GV_CFG_LEN);
  341                 if (error)
  342                         G_VINUM_DEBUG(0, "writing second config copy failed on "
  343                             "drive %s, errno %d", d->name, error);
  344 
  345                 g_topology_lock();
  346                 g_access(cp, 0, -1, 0);
  347                 g_topology_unlock();
  348         }
  349 
  350         sbuf_delete(sb);
  351         g_free(vhdr);
  352 }

Cache object: 77bb618d99ea9100fd216dafc9441f40


[ 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.