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.3/sys/geom/vinum/geom_vinum_drive.c 222554 2011-06-01 05:03:17Z ae $");
   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         if ((GV_HDR_OFFSET % pp->sectorsize) != 0 ||
  130             (GV_HDR_LEN % pp->sectorsize) != 0)
  131                 return (ENODEV);
  132 
  133         d_hdr = g_read_data(cp, GV_HDR_OFFSET, pp->sectorsize, NULL);
  134         if (d_hdr == NULL)
  135                 return (-1);
  136         off = 0;
  137         m_hdr->magic = GV_GET64(be);
  138         magic_machdep = *((uint64_t *)&d_hdr[0]);
  139         /*
  140          * The big endian machines will have a reverse of GV_OLD_MAGIC, so we
  141          * need to decide if we are running on a big endian machine as well as
  142          * checking the magic against the reverse of GV_OLD_MAGIC.
  143          */
  144         be = (m_hdr->magic == magic_machdep);
  145         if (m_hdr->magic == GV_MAGIC) {
  146                 m_hdr->config_length = GV_GET64(be);
  147                 off = 16;
  148                 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  149                 off += GV_HOSTNAME_LEN;
  150                 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
  151                 off += GV_MAXDRIVENAME;
  152                 m_hdr->label.date_of_birth.tv_sec = GV_GET64(be);
  153                 m_hdr->label.date_of_birth.tv_usec = GV_GET64(be);
  154                 m_hdr->label.last_update.tv_sec = GV_GET64(be);
  155                 m_hdr->label.last_update.tv_usec = GV_GET64(be);
  156                 m_hdr->label.drive_size = GV_GET64(be);
  157         } else if (m_hdr->magic != GV_OLD_MAGIC &&
  158             m_hdr->magic != le64toh(GV_OLD_MAGIC)) {
  159                 /* Not a gvinum drive. */
  160                 g_free(d_hdr);
  161                 return (-1);
  162         } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_SPARC64) {
  163                 G_VINUM_DEBUG(1, "detected legacy sparc64 header");
  164                 m_hdr->magic = GV_MAGIC;
  165                 /* Legacy sparc64 on-disk header */
  166                 m_hdr->config_length = GV_GET64(be);
  167                 bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  168                 off += GV_HOSTNAME_LEN;
  169                 bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME);
  170                 off += GV_MAXDRIVENAME;
  171                 m_hdr->label.date_of_birth.tv_sec = GV_GET64(be);
  172                 m_hdr->label.date_of_birth.tv_usec = GV_GET64(be);
  173                 m_hdr->label.last_update.tv_sec = GV_GET64(be);
  174                 m_hdr->label.last_update.tv_usec = GV_GET64(be);
  175                 m_hdr->label.drive_size = GV_GET64(be);
  176         } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_POWERPC) {
  177                 G_VINUM_DEBUG(1, "detected legacy PowerPC header");
  178                 m_hdr->magic = GV_MAGIC;
  179                 /* legacy 32-bit big endian on-disk header */
  180                 m_hdr->config_length = GV_GET32(be);
  181                 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  182                 off += GV_HOSTNAME_LEN;
  183                 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
  184                 off += GV_MAXDRIVENAME;
  185                 m_hdr->label.date_of_birth.tv_sec = GV_GET32(be);
  186                 m_hdr->label.date_of_birth.tv_usec = GV_GET32(be);
  187                 m_hdr->label.last_update.tv_sec = GV_GET32(be);
  188                 m_hdr->label.last_update.tv_usec = GV_GET32(be);
  189                 m_hdr->label.drive_size = GV_GET64(be);
  190         } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_I386) {
  191                 G_VINUM_DEBUG(1, "detected legacy i386 header");
  192                 m_hdr->magic = GV_MAGIC;
  193                 /* legacy i386 on-disk header */
  194                 m_hdr->config_length = GV_GET32(le);
  195                 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  196                 off += GV_HOSTNAME_LEN;
  197                 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
  198                 off += GV_MAXDRIVENAME;
  199                 m_hdr->label.date_of_birth.tv_sec = GV_GET32(le);
  200                 m_hdr->label.date_of_birth.tv_usec = GV_GET32(le);
  201                 m_hdr->label.last_update.tv_sec = GV_GET32(le);
  202                 m_hdr->label.last_update.tv_usec = GV_GET32(le);
  203                 m_hdr->label.drive_size = GV_GET64(le);
  204         } else {
  205                 G_VINUM_DEBUG(1, "detected legacy amd64 header");
  206                 m_hdr->magic = GV_MAGIC;
  207                 /* legacy amd64 on-disk header */
  208                 m_hdr->config_length = GV_GET64(le);
  209                 bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN);
  210                 off += GV_HOSTNAME_LEN;
  211                 bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME);
  212                 off += GV_MAXDRIVENAME;
  213                 m_hdr->label.date_of_birth.tv_sec = GV_GET64(le);
  214                 m_hdr->label.date_of_birth.tv_usec = GV_GET64(le);
  215                 m_hdr->label.last_update.tv_sec = GV_GET64(le);
  216                 m_hdr->label.last_update.tv_usec = GV_GET64(le);
  217                 m_hdr->label.drive_size = GV_GET64(le);
  218         }
  219 
  220         g_free(d_hdr);
  221         return (0);
  222 }
  223 
  224 /* Write out the gvinum header. */
  225 int
  226 gv_write_header(struct g_consumer *cp, struct gv_hdr *m_hdr)
  227 {
  228         uint8_t d_hdr[GV_HDR_LEN];
  229         int off, ret;
  230 
  231 #define GV_SET64BE(field)                                       \
  232         do {                                                    \
  233                 *((uint64_t *)&d_hdr[off]) = htobe64(field);    \
  234                 off += 8;                                       \
  235         } while (0)
  236 
  237         KASSERT(m_hdr != NULL, ("gv_write_header: null m_hdr"));
  238 
  239         off = 0;
  240         memset(d_hdr, 0, GV_HDR_LEN);
  241         GV_SET64BE(m_hdr->magic);
  242         GV_SET64BE(m_hdr->config_length);
  243         off = 16;
  244         bcopy(m_hdr->label.sysname, d_hdr + off, GV_HOSTNAME_LEN);
  245         off += GV_HOSTNAME_LEN;
  246         bcopy(m_hdr->label.name, d_hdr + off, GV_MAXDRIVENAME);
  247         off += GV_MAXDRIVENAME;
  248         GV_SET64BE(m_hdr->label.date_of_birth.tv_sec);
  249         GV_SET64BE(m_hdr->label.date_of_birth.tv_usec);
  250         GV_SET64BE(m_hdr->label.last_update.tv_sec);
  251         GV_SET64BE(m_hdr->label.last_update.tv_usec);
  252         GV_SET64BE(m_hdr->label.drive_size);
  253 
  254         ret = g_write_data(cp, GV_HDR_OFFSET, d_hdr, GV_HDR_LEN);
  255         return (ret);
  256 }
  257 
  258 /* Save the vinum configuration back to each involved disk. */
  259 void
  260 gv_save_config(struct gv_softc *sc)
  261 {
  262         struct g_consumer *cp;
  263         struct gv_drive *d;
  264         struct gv_hdr *vhdr, *hdr;
  265         struct sbuf *sb;
  266         struct timeval last_update;
  267         int error;
  268 
  269         KASSERT(sc != NULL, ("gv_save_config: null sc"));
  270 
  271         vhdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO);
  272         vhdr->magic = GV_MAGIC;
  273         vhdr->config_length = GV_CFG_LEN;
  274         microtime(&last_update);
  275 
  276         sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN);
  277         gv_format_config(sc, sb, 1, NULL);
  278         sbuf_finish(sb);
  279 
  280         LIST_FOREACH(d, &sc->drives, drive) {
  281                 /*
  282                  * We can't save the config on a drive that isn't up, but
  283                  * drives that were just created aren't officially up yet, so
  284                  * we check a special flag.
  285                  */
  286                 if (d->state != GV_DRIVE_UP)
  287                         continue;
  288 
  289                 cp = d->consumer;
  290                 if (cp == NULL) {
  291                         G_VINUM_DEBUG(0, "drive '%s' has no consumer!",
  292                             d->name);
  293                         continue;
  294                 }
  295 
  296                 hdr = d->hdr;
  297                 if (hdr == NULL) {
  298                         G_VINUM_DEBUG(0, "drive '%s' has no header",
  299                             d->name);
  300                         g_free(vhdr);
  301                         continue;
  302                 }
  303                 bcopy(&last_update, &hdr->label.last_update,
  304                     sizeof(struct timeval));
  305                 bcopy(&hdr->label, &vhdr->label, sizeof(struct gv_label));
  306                 g_topology_lock();
  307                 error = g_access(cp, 0, 1, 0);
  308                 if (error) {
  309                         G_VINUM_DEBUG(0, "g_access failed on "
  310                             "drive %s, errno %d", d->name, error);
  311                         g_topology_unlock();
  312                         continue;
  313                 }
  314                 g_topology_unlock();
  315 
  316                 error = gv_write_header(cp, vhdr);
  317                 if (error) {
  318                         G_VINUM_DEBUG(0, "writing vhdr failed on drive %s, "
  319                             "errno %d", d->name, error);
  320                         g_topology_lock();
  321                         g_access(cp, 0, -1, 0);
  322                         g_topology_unlock();
  323                         continue;
  324                 }
  325                 /* First config copy. */
  326                 error = g_write_data(cp, GV_CFG_OFFSET, sbuf_data(sb),
  327                     GV_CFG_LEN);
  328                 if (error) {
  329                         G_VINUM_DEBUG(0, "writing first config copy failed on "
  330                             "drive %s, errno %d", d->name, error);
  331                         g_topology_lock();
  332                         g_access(cp, 0, -1, 0);
  333                         g_topology_unlock();
  334                         continue;
  335                 }
  336                 /* Second config copy. */
  337                 error = g_write_data(cp, GV_CFG_OFFSET + GV_CFG_LEN,
  338                     sbuf_data(sb), GV_CFG_LEN);
  339                 if (error)
  340                         G_VINUM_DEBUG(0, "writing second config copy failed on "
  341                             "drive %s, errno %d", d->name, error);
  342 
  343                 g_topology_lock();
  344                 g_access(cp, 0, -1, 0);
  345                 g_topology_unlock();
  346         }
  347 
  348         sbuf_delete(sb);
  349         g_free(vhdr);
  350 }

Cache object: 8763d7b6f7682527ee9501ca4506aafb


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