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

Cache object: 5ac8c29657f851c5562e8177387a5551


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