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

Cache object: f20721dfd06e8502bc4550e36768eeb1


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