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/dev/vinum/vinumio.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) 1997, 1998
    3  *      Nan Yang Computer Services Limited.  All rights reserved.
    4  *
    5  *  This software is distributed under the so-called ``Berkeley
    6  *  License'':
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   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 the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by Nan Yang Computer
   19  *      Services Limited.
   20  * 4. Neither the name of the Company nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * This software is provided ``as is'', and any express or implied
   25  * warranties, including, but not limited to, the implied warranties of
   26  * merchantability and fitness for a particular purpose are disclaimed.
   27  * In no event shall the company or contributors be liable for any
   28  * direct, indirect, incidental, special, exemplary, or consequential
   29  * damages (including, but not limited to, procurement of substitute
   30  * goods or services; loss of use, data, or profits; or business
   31  * interruption) however caused and on any theory of liability, whether
   32  * in contract, strict liability, or tort (including negligence or
   33  * otherwise) arising in any way out of the use of this software, even if
   34  * advised of the possibility of such damage.
   35  *
   36  * $Id: vinumio.c,v 1.1.1.1 2003/10/10 03:08:25 grog Exp $
   37  * $FreeBSD$
   38  */
   39 
   40 #include <dev/vinum/vinumhdr.h>
   41 #include <dev/vinum/request.h>
   42 
   43 static char *sappend(char *txt, char *s);
   44 static int drivecmp(const void *va, const void *vb);
   45 
   46 /* Open the device associated with the drive, and set drive's vp.
   47  * Return an error number */
   48 int
   49 open_drive(struct drive *drive, struct proc *p, int verbose)
   50 {
   51     struct nameidata nd;
   52     struct vattr va;
   53     int error;
   54 
   55     if (drive->devicename[0] == '\0')                       /* no device name */
   56         sprintf(drive->devicename, "/dev/%s", drive->label.name); /* get it from the drive name */
   57     NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, drive->devicename, p);
   58     error = vn_open(&nd, FREAD | FWRITE, 0);                /* open the device */
   59     if (error != 0) {                                       /* can't open? */
   60         set_drive_state(drive->driveno, drive_down, setstate_force);
   61         drive->lasterror = error;
   62         if (verbose)
   63             printf("vinum open_drive %s: failed with error %d\n", drive->devicename, error); /* XXX */
   64         return error;
   65     }
   66     drive->flags |= VF_OPEN;                                /* mark the drive as open */
   67     drive->vp = nd.ni_vp;
   68     drive->p = p;
   69 
   70     error = VOP_GETATTR(drive->vp, &va, NOCRED, drive->p);
   71     if (error) {
   72         VOP_UNLOCK(drive->vp, 0);
   73         close_drive(drive);
   74         set_drive_state(drive->driveno, drive_down, setstate_force);
   75         drive->lasterror = error;
   76         if (verbose)
   77             printf("vinum open_drive %s: GETAATTR returns error %d\n", drive->devicename, error); /* XXX */
   78         return error;
   79     }
   80     drive->dev = va.va_rdev;                                /* device */
   81 
   82     if (va.va_type != VBLK) {                               /* only consider block devices */
   83         VOP_UNLOCK(drive->vp, 0);
   84         close_drive(drive);
   85         set_drive_state(drive->driveno, drive_down, setstate_force); /* this also closes the drive */
   86         drive->lasterror = ENOTBLK;
   87         if (verbose)
   88             printf("vinum open_drive %s: Not a block device\n", drive->devicename); /* XXX */
   89         return ENOTBLK;
   90     }
   91     drive->vp->v_numoutput = 0;
   92     VOP_UNLOCK(drive->vp, 0);
   93     return 0;
   94 }
   95 
   96 
   97 /*
   98  * Set some variables in the drive struct in more
   99  * convenient form.  Return error indication.
  100  */
  101 int
  102 set_drive_parms(struct drive *drive)
  103 {
  104     drive->blocksize = BLKDEV_IOSIZE;                       /* do we need this? */
  105     drive->secsperblock = drive->blocksize                  /* number of sectors per block */
  106         / drive->partinfo.disklab->d_secsize;
  107 
  108     /* Now update the label part */
  109     bcopy(hostname, drive->label.sysname, VINUMHOSTNAMELEN); /* put in host name */
  110     microtime(&drive->label.date_of_birth);                 /* and current time */
  111     drive->label.drive_size = ((u_int64_t) drive->partinfo.part->p_size) /* size of the drive in bytes */
  112     *((u_int64_t) drive->partinfo.disklab->d_secsize);
  113 #ifdef VINUMDEBUG
  114     if (debug & DEBUG_BIGDRIVE)                             /* pretend we're 100 times as big */
  115         drive->label.drive_size *= 100;
  116 #endif
  117 
  118     /* number of sectors available for subdisks */
  119     drive->sectors_available = drive->label.drive_size / DEV_BSIZE - DATASTART;
  120 
  121     /*
  122      * Bug in 3.0 as of January 1998: you can open
  123      * non-existent slices.  They have a length of 0.
  124      */
  125     if (drive->label.drive_size < MINVINUMSLICE) {          /* too small to worry about */
  126         set_drive_state(drive->driveno, drive_down, setstate_force);
  127         drive->lasterror = ENOSPC;
  128         return ENOSPC;
  129     }
  130     drive->freelist_size = INITIAL_DRIVE_FREELIST;          /* initial number of entries */
  131     drive->freelist = (struct drive_freelist *)
  132         Malloc(INITIAL_DRIVE_FREELIST * sizeof(struct drive_freelist));
  133     if (drive->freelist == NULL)                            /* can't malloc, dammit */
  134         return ENOSPC;
  135     drive->freelist_entries = 1;                            /* just (almost) the complete drive */
  136     drive->freelist[0].offset = DATASTART;                  /* starts here */
  137     drive->freelist[0].sectors = (drive->label.drive_size >> DEV_BSHIFT) - DATASTART; /* and it's this long */
  138     if (drive->label.name[0] != '\0')                       /* got a name */
  139         set_drive_state(drive->driveno, drive_up, setstate_force); /* our drive is accessible */
  140     else                                                    /* we know about it, but that's all */
  141         drive->state = drive_referenced;
  142     return 0;
  143 }
  144 
  145 /*
  146  * Initialize a drive: open the device and add
  147  * device information.
  148  */
  149 int
  150 init_drive(struct drive *drive, int verbose)
  151 {
  152     int error;
  153     struct disklabel label;
  154     const struct bdevsw *bdev;
  155 
  156     if (drive->devicename[0] != '/') {
  157         drive->lasterror = EINVAL;
  158         log(LOG_ERR, "vinum: Can't open drive without drive name\n");
  159         return EINVAL;
  160     }
  161     drive->lasterror = open_drive(drive, curproc, verbose); /* open the drive */
  162     if (drive->lasterror)
  163         return drive->lasterror;
  164 
  165     bdev = bdevsw_lookup(drive->dev);
  166     if (bdev == NULL)
  167         return ENXIO;
  168     drive->lasterror = (*bdev->d_ioctl) (drive->dev,
  169         DIOCGDINFO,
  170         (caddr_t) & label,
  171         FREAD,
  172         curproc);
  173     if (drive->lasterror == 0) {
  174         if (label.d_type == DTYPE_FLOPPY) {
  175             drive->partinfo.disklab->d_secsize = label.d_secsize;
  176             drive->partinfo.part->p_size = label.d_secsize * label.d_secperunit;
  177             drive->partinfo.part->p_fstype = FS_VINUM;      /* force Vinum */
  178         } else
  179             /* XXX should use VOP interface, like FreeBSD */
  180             drive->lasterror = (*bdev->d_ioctl) (drive->dev, /* get the partition information */
  181                 DIOCGPART,
  182                 (caddr_t) & drive->partinfo,
  183                 FREAD,
  184                 curproc);
  185     }
  186     if (drive->lasterror) {
  187         if (verbose)
  188             log(LOG_WARNING,
  189                 "vinum open_drive %s: Can't get partition information, drive->lasterror %d\n",
  190                 drive->devicename,
  191                 drive->lasterror);
  192         error = drive->lasterror;                           /* clobbered by close_drive */
  193         close_drive(drive);
  194         return error;
  195     }
  196     if (drive->partinfo.part->p_fstype != FS_VINUM) {       /* not Vinum */
  197         drive->lasterror = EFTYPE;
  198         if (verbose)
  199             log(LOG_WARNING,
  200                 "vinum open_drive %s: Wrong partition type for vinum\n",
  201                 drive->devicename);
  202         close_drive(drive);
  203         return EFTYPE;
  204     }
  205     return set_drive_parms(drive);                          /* set various odds and ends */
  206 }
  207 
  208 /* Close a drive if it's open. */
  209 void
  210 close_drive(struct drive *drive)
  211 {
  212     LOCKDRIVE(drive);                                       /* keep the daemon out */
  213     if (drive->flags & VF_OPEN)
  214         close_locked_drive(drive);                          /* and close it */
  215     if (drive->state > drive_down)                          /* if it's up */
  216         drive->state = drive_down;                          /* make sure it's down */
  217     unlockdrive(drive);
  218 }
  219 
  220 /*
  221  * Real drive close code, called with drive already locked.
  222  * We have also checked that the drive is open.  No errors.
  223  */
  224 void
  225 close_locked_drive(struct drive *drive)
  226 {
  227     /*
  228      * If we can't access the drive, we can't flush
  229      * the queues, which spec_close() will try to
  230      * do.  Get rid of them here first.
  231      */
  232 
  233     const struct bdevsw *bdev = bdevsw_lookup(drive->dev);
  234 
  235     if (bdev == NULL)
  236         panic("no bdevsw");                                 /* XXX */
  237     drive->lasterror = (*bdev->d_close) (drive->dev, 0, 0, NULL);
  238     drive->flags &= ~VF_OPEN;                               /* no longer open */
  239 }
  240 
  241 /*
  242  * Remove drive from the configuration.
  243  * Caller must ensure that it isn't active.
  244  */
  245 void
  246 remove_drive(int driveno)
  247 {
  248     struct drive *drive = &vinum_conf.drive[driveno];
  249     struct vinum_hdr *vhdr;                                 /* buffer for header */
  250     int error;
  251 
  252     if (drive->state > drive_referenced) {                  /* real drive */
  253         if (drive->state == drive_up) {
  254             vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN); /* allocate buffer */
  255             CHECKALLOC(vhdr, "Can't allocate memory");
  256             error = read_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET);
  257             if (error)
  258                 drive->lasterror = error;
  259             else {
  260                 vhdr->magic = VINUM_NOMAGIC;                /* obliterate the magic, but leave the rest */
  261                 write_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET);
  262             }
  263             Free(vhdr);
  264         }
  265         free_drive(drive);                                  /* close it and free resources */
  266         save_config();                                      /* and save the updated configuration */
  267     }
  268 }
  269 
  270 /*
  271  * Transfer drive data.  Usually called from one of these defines;
  272  * #define read_drive(a, b, c, d) driveio (a, b, c, d, B_READ)
  273  * #define write_drive(a, b, c, d) driveio (a, b, c, d, B_WRITE)
  274  *
  275  * length and offset are in bytes, but must be multiples of sector
  276  * size.  The function *does not check* for this condition, and
  277  * truncates ruthlessly.
  278  * Return error number.
  279  */
  280 int
  281 driveio(struct drive *drive, char *buf, size_t length, off_t offset, int flag)
  282 {
  283     int error;
  284     struct buf *bp;
  285     const struct bdevsw *bdev;
  286 
  287     error = 0;                                              /* to keep the compiler happy */
  288     while (length) {                                        /* divide into small enough blocks */
  289         int len = min(length, MAXBSIZE);                    /* maximum block device transfer is MAXBSIZE */
  290 
  291         bp = geteblk(len);                                  /* get a buffer header */
  292         bp->b_flags = flag | B_BUSY;
  293         bp->b_dev = drive->dev;                             /* device */
  294         bp->b_blkno = offset / drive->partinfo.disklab->d_secsize; /* block number */
  295         bp->b_saveaddr = bp->b_data;
  296         bp->b_data = buf;
  297         bp->b_bcount = len;
  298         bdev = bdevsw_lookup(bp->b_dev);
  299         if (bdev == NULL)
  300             return ENXIO;
  301         (*bdev->d_strategy) (bp);
  302         error = biowait(bp);
  303         bp->b_data = bp->b_saveaddr;
  304         bp->b_flags |= B_INVAL | B_AGE;
  305         bp->b_flags &= ~B_ERROR;
  306         brelse(bp);
  307         if (error)
  308             break;
  309         length -= len;                                      /* update pointers */
  310         buf += len;
  311         offset += len;
  312     }
  313     return error;
  314 }
  315 
  316 /*
  317  * Check a drive for a vinum header.  If found,
  318  * update the drive information.  We come here
  319  * with a partially populated drive structure
  320  * which includes the device name.
  321  *
  322  * Return information on what we found.
  323  *
  324  * This function is called from two places: check_drive,
  325  * which wants to find out whether the drive is a
  326  * Vinum drive, and config_drive, which asserts that
  327  * it is a vinum drive.  In the first case, we don't
  328  * print error messages (verbose==0), in the second
  329  * we do (verbose==1).
  330  */
  331 enum drive_label_info
  332 read_drive_label(struct drive *drive, int verbose)
  333 {
  334     int error;
  335     int result;                                             /* result of our search */
  336     struct vinum_hdr *vhdr;                                 /* and as header */
  337 
  338     error = init_drive(drive, 0);                           /* find the drive */
  339     if (error)                                              /* find the drive */
  340         return DL_CANT_OPEN;                                /* not ours */
  341 
  342     vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN);     /* allocate buffers */
  343     CHECKALLOC(vhdr, "Can't allocate memory");
  344 
  345     drive->state = drive_up;                                /* be optimistic */
  346     error = read_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET);
  347     if (vhdr->magic == VINUM_MAGIC) {                       /* ours! */
  348         if (drive->label.name[0]                            /* we have a name for this drive */
  349         &&(strcmp(drive->label.name, vhdr->label.name))) {  /* but it doesn't match the real name */
  350             drive->lasterror = EINVAL;
  351             result = DL_WRONG_DRIVE;                        /* it's the wrong drive */
  352             drive->state = drive_unallocated;               /* put it back, it's not ours */
  353         } else
  354             result = DL_OURS;
  355         /*
  356          * We copy the drive anyway so that we have
  357          * the correct name in the drive info.  This
  358          * may not be the name specified
  359          */
  360         drive->label = vhdr->label;                         /* put in the label information */
  361     } else if (vhdr->magic == VINUM_NOMAGIC)                /* was ours, but we gave it away */
  362         result = DL_DELETED_LABEL;                          /* and return the info */
  363     else
  364         result = DL_NOT_OURS;                               /* we could have it, but we don't yet */
  365     Free(vhdr);                                             /* that's all. */
  366     return result;
  367 }
  368 
  369 /*
  370  * Check a drive for a vinum header.  If found,
  371  * read configuration information from the drive and
  372  * incorporate the data into the configuration.
  373  *
  374  * Return drive number.
  375  */
  376 struct drive *
  377 check_drive(char *devicename)
  378 {
  379     int driveno;
  380     int i;
  381     struct drive *drive;
  382 
  383     driveno = find_drive_by_name(devicename, 1);            /* if entry doesn't exist, create it */
  384     drive = &vinum_conf.drive[driveno];                     /* and get a pointer */
  385 
  386     if (read_drive_label(drive, 0) == DL_OURS) {            /* one of ours */
  387         for (i = 0; i < vinum_conf.drives_allocated; i++) { /* see if the name already exists */
  388             if ((i != driveno)                              /* not this drive */
  389             &&(DRIVE[i].state != drive_unallocated)         /* and it's allocated */
  390             &&(strcmp(DRIVE[i].label.name,
  391                         DRIVE[driveno].label.name) == 0)) { /* and it has the same name */
  392                 struct drive *mydrive = &DRIVE[i];
  393 
  394                 if (mydrive->devicename[0] == '/') {        /* we know a device name for it */
  395                     /*
  396                      * set an error, but don't take the
  397                      * drive down: that would cause unneeded
  398                      * error messages.
  399                      */
  400                     drive->lasterror = EEXIST;
  401                     break;
  402                 } else {                                    /* it's just a place holder, */
  403                     int sdno;
  404 
  405                     for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) { /* look at each subdisk */
  406                         if ((SD[sdno].driveno == i)         /* it's pointing to this one, */
  407                         &&(SD[sdno].state != sd_unallocated)) { /* and it's a real subdisk */
  408                             SD[sdno].driveno = drive->driveno; /* point to the one we found */
  409                             update_sd_state(sdno);          /* and update its state */
  410                         }
  411                     }
  412                     bzero(mydrive, sizeof(struct drive));   /* don't deallocate it, just remove it */
  413                 }
  414             }
  415         }
  416     } else {
  417         if (drive->lasterror == 0)
  418             drive->lasterror = ENODEV;
  419         close_drive(drive);
  420         drive->state = drive_down;
  421     }
  422     return drive;
  423 }
  424 
  425 static char *
  426 sappend(char *txt, char *s)
  427 {
  428     while ((*s++ = *txt++) != 0);
  429     return s - 1;
  430 }
  431 
  432 /* Kludge: kernel printf doesn't handle quads correctly XXX */
  433 static char *lltoa(long long l, char *s);
  434 
  435 static char *
  436 lltoa(long long l, char *s)
  437 {
  438     if (l < 0) {
  439         *s++ = '-';
  440         l = -l;
  441     }
  442     if (l > 9) {
  443         s = lltoa(l / 10, s);
  444         l %= 10;
  445     }
  446     *s++ = l + '';
  447     return s;
  448 }
  449 /*
  450  * Format the configuration in text form into the buffer
  451  * at config.  Don't go beyond len bytes
  452  * XXX this stinks.  Fix soon.
  453  */
  454 void
  455 format_config(char *config, int len)
  456 {
  457     int i;
  458     int j;
  459     char *s = config;
  460 
  461     bzero(config, len);
  462 
  463     /* First, the volume configuration */
  464     for (i = 0; i < vinum_conf.volumes_allocated; i++) {
  465         struct volume *vol;
  466 
  467         vol = &vinum_conf.volume[i];
  468         if ((vol->state > volume_uninit)
  469             && (vol->name[0] != '\0')) {                    /* paranoia */
  470             if (vol->preferred_plex >= 0)                   /* preferences, */
  471                 sprintf(s,
  472                     "volume %s state %s readpol prefer %s",
  473                     vol->name,
  474                     volume_state(vol->state),
  475                     vinum_conf.plex[vol->preferred_plex].name);
  476             else                                            /* default round-robin */
  477                 sprintf(s,
  478                     "volume %s state %s",
  479                     vol->name,
  480                     volume_state(vol->state));
  481             while (*s)
  482                 s++;                                        /* find the end */
  483             s = sappend("\n", s);
  484             if (s > &config[len - 80]) {
  485                 log(LOG_ERR, "vinum: configuration data overflow\n");
  486                 return;
  487             }
  488         }
  489     }
  490 
  491     /* Then the plex configuration */
  492     for (i = 0; i < vinum_conf.plexes_allocated; i++) {
  493         struct plex *plex;
  494 
  495         plex = &vinum_conf.plex[i];
  496         if ((plex->state != plex_referenced)
  497             && (plex->name[0] != '\0')) {                   /* paranoia */
  498             sprintf(s, "plex name %s state %s org %s ",
  499                 plex->name,
  500                 plex_state(plex->state),
  501                 plex_org(plex->organization));
  502             while (*s)
  503                 s++;                                        /* find the end */
  504             if ((plex->organization == plex_striped)
  505                 || (plex->organization == plex_raid5)) {
  506                 sprintf(s, "%db ", (int) plex->stripesize);
  507                 while (*s)
  508                     s++;                                    /* find the end */
  509             }
  510             if (plex->volno >= 0)                           /* we have a volume */
  511                 sprintf(s, "vol %s ", vinum_conf.volume[plex->volno].name);
  512             while (*s)
  513                 s++;                                        /* find the end */
  514             for (j = 0; j < plex->subdisks; j++) {
  515                 sprintf(s, " sd %s", vinum_conf.sd[plex->sdnos[j]].name);
  516             }
  517             s = sappend("\n", s);
  518             if (s > &config[len - 80]) {
  519                 log(LOG_ERR, "vinum: configuration data overflow\n");
  520                 return;
  521             }
  522         }
  523     }
  524 
  525     /* And finally the subdisk configuration */
  526     for (i = 0; i < vinum_conf.subdisks_allocated; i++) {
  527         struct sd *sd;
  528 
  529         sd = &SD[i];
  530         if ((sd->state != sd_referenced)
  531             && (sd->name[0] != '\0')) {                     /* paranoia */
  532             sprintf(s,
  533                 "sd name %s drive %s plex %s state %s len ",
  534                 sd->name,
  535                 vinum_conf.drive[sd->driveno].label.name,
  536                 vinum_conf.plex[sd->plexno].name,
  537                 sd_state(sd->state));
  538             while (*s)
  539                 s++;                                        /* find the end */
  540             s = lltoa(sd->sectors, s);
  541             s = sappend("b driveoffset ", s);
  542             s = lltoa(sd->driveoffset, s);
  543             s = sappend("b plexoffset ", s);
  544             s = lltoa(sd->plexoffset, s);
  545             s = sappend("b\n", s);
  546             if (s > &config[len - 80]) {
  547                 log(LOG_ERR, "vinum: configuration data overflow\n");
  548                 return;
  549             }
  550         }
  551     }
  552 }
  553 
  554 /*
  555  * issue a save config request to the dæmon.  The actual work
  556  * is done in process context by daemon_save_config.
  557  */
  558 void
  559 save_config(void)
  560 {
  561     queue_daemon_request(daemonrq_saveconfig, (union daemoninfo) 0);
  562 }
  563 
  564 /*
  565  * Write the configuration to all vinum slices.  This
  566  * is performed by the daemon only.
  567  */
  568 void
  569 daemon_save_config(void)
  570 {
  571     int error;
  572     int written_config;                                     /* set when we first write the config to disk */
  573     int driveno;
  574     struct drive *drive;                                    /* point to current drive info */
  575     struct vinum_hdr *vhdr;                                 /* and as header */
  576     char *config;                                           /* point to config data */
  577     int wlabel_on;                                          /* to set writing label on/off */
  578     const struct bdevsw *bdev;
  579 
  580     /* don't save the configuration while we're still working on it */
  581     if (vinum_conf.flags & VF_CONFIGURING)
  582         return;
  583     written_config = 0;                                     /* no config written yet */
  584     /* Build a volume header */
  585     vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN);     /* get space for the config data */
  586     CHECKALLOC(vhdr, "Can't allocate config data");
  587     vhdr->magic = VINUM_MAGIC;                              /* magic number */
  588     vhdr->config_length = MAXCONFIG;                        /* length of following config info */
  589 
  590     config = Malloc(MAXCONFIG);                             /* get space for the config data */
  591     CHECKALLOC(config, "Can't allocate config data");
  592 
  593     format_config(config, MAXCONFIG);
  594     error = 0;                                              /* no errors yet */
  595     for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
  596         drive = &vinum_conf.drive[driveno];                 /* point to drive */
  597         if (drive->state > drive_referenced) {
  598             LOCKDRIVE(drive);                               /* don't let it change */
  599 
  600             /*
  601              * First, do some drive consistency checks.  Some
  602              * of these are kludges, others require a process
  603              * context and couldn't be done before.
  604              */
  605             if ((drive->devicename[0] == '\0')
  606                 || (drive->label.name[0] == '\0')) {
  607                 unlockdrive(drive);
  608                 free_drive(drive);                          /* get rid of it */
  609                 break;
  610             }
  611             if (((drive->flags & VF_OPEN) == 0)             /* drive not open */
  612             &&(drive->state > drive_down)) {                /* and it thinks it's not down */
  613                 unlockdrive(drive);
  614                 set_drive_state(driveno, drive_down, setstate_force); /* tell it what's what */
  615                 continue;
  616             }
  617             if ((drive->state == drive_down)                /* it's down */
  618             &&(drive->flags & VF_OPEN)) {                   /* but open, */
  619                 unlockdrive(drive);
  620                 close_drive(drive);                         /* close it */
  621             } else if (drive->state > drive_down) {
  622                 microtime(&drive->label.last_update);       /* time of last update is now */
  623                 bcopy((char *) &drive->label,               /* and the label info from the drive structure */
  624                     (char *) &vhdr->label,
  625                     sizeof(vhdr->label));
  626                 if ((drive->state != drive_unallocated)
  627                     && (drive->state != drive_referenced)) { /* and it's a real drive */
  628                     wlabel_on = 1;                          /* enable writing the label */
  629                     bdev = bdevsw_lookup(drive->dev);
  630                     if (bdev == NULL)
  631                                                             /* XXX log this */
  632                         error = ENXIO;
  633                     else
  634                         error = (*bdev->d_ioctl) (drive->dev, /* make the label writeable */
  635                             DIOCWLABEL,
  636                             (caddr_t) & wlabel_on,
  637                             FWRITE,
  638                             curproc);
  639                     if (error == 0)
  640                         error = write_drive(drive, (char *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET);
  641                     if (error == 0)
  642                         error = write_drive(drive, config, MAXCONFIG, VINUM_CONFIG_OFFSET); /* first config copy */
  643                     if (error == 0)
  644                         error = write_drive(drive, config, MAXCONFIG, VINUM_CONFIG_OFFSET + MAXCONFIG); /* second copy */
  645                     wlabel_on = 0;                          /* enable writing the label */
  646                     if (error == 0)
  647                                                             /* make the label non-writeable again */
  648                         error = (*bdev->d_ioctl) (drive->dev,
  649                             DIOCWLABEL,
  650                             (caddr_t) & wlabel_on,
  651                             FWRITE,
  652                             curproc);
  653                     unlockdrive(drive);
  654                     if (error) {
  655                         log(LOG_ERR,
  656                             "vinum: Can't write config to %s, error %d\n",
  657                             drive->devicename,
  658                             error);
  659                         set_drive_state(drive->driveno, drive_down, setstate_force);
  660                     } else
  661                         written_config = 1;                 /* we've written it on at least one drive */
  662                 }
  663             } else                                          /* not worth looking at, */
  664                 unlockdrive(drive);                         /* just unlock it again */
  665         }
  666     }
  667     Free(vhdr);
  668     Free(config);
  669 }
  670 
  671 /*
  672  * Disk labels are a mess.  The correct way to
  673  * access them is with the DIOC[GSW]DINFO ioctls,
  674  * but some programs, such as newfs, access the
  675  * disk directly, so we have to write things
  676  * there.  We do this only on request.  If a user
  677  * request tries to read it directly, we fake up
  678  * one on the fly.
  679  */
  680 
  681 /*
  682  * get_volume_label returns a label structure to
  683  * lp, which is allocated by the caller.
  684  */
  685 void
  686 get_volume_label(char *name, int plexes, u_int64_t size, struct disklabel *lp)
  687 {
  688     bzero(lp, sizeof(struct disklabel));
  689 
  690     strncpy(lp->d_typename, "vinum", sizeof(lp->d_typename));
  691     lp->d_type = DTYPE_VINUM;
  692     strncpy(lp->d_packname, name, min(sizeof(lp->d_packname), sizeof(name)));
  693     lp->d_rpm = 14400 * plexes;                             /* to keep them guessing */
  694     lp->d_interleave = 1;
  695     lp->d_flags = 0;
  696 
  697     /*
  698      * A Vinum volume has a single track with all
  699      * its sectors.
  700      */
  701     lp->d_secsize = DEV_BSIZE;                              /* bytes per sector */
  702     lp->d_nsectors = size;                                  /* data sectors per track */
  703     lp->d_ntracks = 1;                                      /* tracks per cylinder */
  704     lp->d_ncylinders = 1;                                   /* data cylinders per unit */
  705     lp->d_secpercyl = size;                                 /* data sectors per cylinder */
  706     lp->d_secperunit = size;                                /* data sectors per unit */
  707 
  708     lp->d_bbsize = 8192;                                    /* fake boot block size */
  709     lp->d_sbsize = 1024;                                    /* NetBSD doesn't seem to have an SBSIZE XXX */
  710     lp->d_magic = DISKMAGIC;
  711     lp->d_magic2 = DISKMAGIC;
  712 
  713     /*
  714      * Set up partitions a, b and c to be identical
  715      * and the size of the volume.  a is UFS, b is
  716      * swap, c is nothing.
  717      */
  718     lp->d_partitions[0].p_size = size;
  719     lp->d_partitions[0].p_fsize = 1024;
  720     lp->d_partitions[0].p_fstype = FS_BSDFFS;               /* FreeBSD File System :-) */
  721     lp->d_partitions[0].p_fsize = 1024;                     /* FS fragment size */
  722     lp->d_partitions[0].p_frag = 8;                         /* and fragments per block */
  723     lp->d_partitions[SWAP_PART].p_size = size;
  724     lp->d_partitions[SWAP_PART].p_fstype = FS_SWAP;         /* swap partition */
  725     lp->d_partitions[LABEL_PART].p_size = size;
  726     lp->d_npartitions = LABEL_PART + 1;
  727     strncpy(lp->d_packname, name, min(sizeof(lp->d_packname), sizeof(name)));
  728     lp->d_checksum = dkcksum(lp);
  729 }
  730 
  731 /* Write a volume label.  This implements the VINUM_LABEL ioctl. */
  732 int
  733 write_volume_label(int volno)
  734 {
  735     struct disklabel *lp;
  736     struct buf *bp;
  737     struct disklabel *dlp;
  738     struct volume *vol;
  739     int error;
  740 
  741     lp = (struct disklabel *) Malloc((sizeof(struct disklabel) + (DEV_BSIZE - 1)) & (DEV_BSIZE - 1));
  742     if (lp == 0)
  743         return ENOMEM;
  744 
  745     if ((unsigned) (volno) >= (unsigned) vinum_conf.volumes_allocated) /* invalid volume */
  746         return ENOENT;
  747 
  748     vol = &VOL[volno];                                      /* volume in question */
  749     if (vol->state <= volume_uninit)                        /* nothing there */
  750         return ENXIO;
  751     else if (vol->state < volume_up)                        /* not accessible */
  752         return EIO;                                         /* I/O error */
  753 
  754     get_volume_label(vol->name, vol->plexes, vol->size, lp); /* get the label */
  755 
  756     /*
  757      * Now write to disk.  This code is derived from the
  758      * system writedisklabel (), which does silly things
  759      * like reading the label and refusing to write
  760      * unless it's already there.
  761      */
  762     bp = geteblk((int) lp->d_secsize);                      /* get a buffer */
  763     bp->b_dev = makedev(VINUM_CDEV_MAJOR, vol->volno);      /* our own raw volume */
  764     bp->b_blkno = LABELSECTOR * ((int) lp->d_secsize / DEV_BSIZE);
  765     bp->b_bcount = lp->d_secsize;
  766     bzero(bp->b_data, lp->d_secsize);
  767     dlp = (struct disklabel *) bp->b_data;
  768     *dlp = *lp;
  769     bp->b_flags &= ~B_INVAL;
  770     bp->b_flags |= B_BUSY | B_WRITE;
  771     vinumstrategy(bp);
  772     error = biowait(bp);
  773     bp->b_flags |= B_INVAL | B_AGE;
  774     bp->b_flags &= ~B_ERROR;
  775 
  776     brelse(bp);
  777     return error;
  778 }
  779 
  780 /* Look at all disks on the system for vinum slices. */
  781 int
  782 vinum_scandisk(char *devicename[], int drives)
  783 {
  784     struct drive *volatile drive;
  785     volatile int driveno;
  786     int firstdrive;                                         /* first drive in this list */
  787     volatile int gooddrives;                                /* number of usable drives found */
  788     int firsttime;                                          /* set if we have never configured before */
  789     int error;
  790     char *config_text;                                      /* read the config info from disk into here */
  791     char *volatile cptr;                                    /* pointer into config information */
  792     char *eptr;                                             /* end pointer into config information */
  793     char *config_line;                                      /* copy the config line to */
  794     volatile int status;
  795     int *volatile drivelist;                                /* list of drive indices */
  796 #define DRIVENAMELEN 64
  797 #define DRIVEPARTS   35                                     /* max partitions per drive, excluding c */
  798     char partname[DRIVENAMELEN];                            /* for creating partition names */
  799 
  800     status = 0;                                             /* success indication */
  801     vinum_conf.flags |= VF_READING_CONFIG;                  /* reading config from disk */
  802 
  803     gooddrives = 0;                                         /* number of usable drives found */
  804     firstdrive = vinum_conf.drives_used;                    /* the first drive */
  805     firsttime = vinum_conf.drives_used == 0;                /* are we a virgin? */
  806 
  807     /* allocate a drive pointer list */
  808     drivelist = (int *) Malloc(drives * DRIVEPARTS * sizeof(int));
  809     CHECKALLOC(drivelist, "Can't allocate memory");
  810 
  811     /* Open all drives and find which was modified most recently */
  812     for (driveno = 0; driveno < drives; driveno++) {
  813         char part;                                          /* UNIX partition */
  814         int slice;
  815         int founddrive;                                     /* flag when we find a vinum drive */
  816 
  817         founddrive = 0;                                     /* no vinum drive found yet on this spindle */
  818         /* first try the partition table */
  819         for (slice = 1; slice < 5; slice++)
  820             for (part = 'a'; part < 'i'; part++) {
  821                 if (part != 'c') {                          /* don't do the c partition */
  822                     snprintf(partname,
  823                         DRIVENAMELEN,
  824                         "%ss%d%c",
  825                         devicename[driveno],
  826                         slice,
  827                         part);
  828                     drive = check_drive(partname);          /* try to open it */
  829                     if ((drive->lasterror != 0)             /* didn't work, */
  830                     ||(drive->state != drive_up))
  831                         free_drive(drive);                  /* get rid of it */
  832                     else if (drive->flags & VF_CONFIGURED)  /* already read this config, */
  833                         log(LOG_WARNING,
  834                             "vinum: already read config from %s\n", /* say so */
  835                             drive->label.name);
  836                     else {
  837                         drivelist[gooddrives] = drive->driveno; /* keep the drive index */
  838                         drive->flags &= ~VF_NEWBORN;        /* which is no longer newly born */
  839                         gooddrives++;
  840                         founddrive++;
  841                     }
  842                 }
  843             }
  844         if (founddrive == 0) {                              /* didn't find anything, */
  845             for (part = 'a'; part < 'i'; part++)            /* try the compatibility partition */
  846                 if (part != 'c') {                          /* don't do the c partition */
  847                     snprintf(partname,                      /* /dev/sd0a */
  848                         DRIVENAMELEN,
  849                         "%s%c",
  850                         devicename[driveno],
  851                         part);
  852                     drive = check_drive(partname);          /* try to open it */
  853                     if ((drive->lasterror != 0)             /* didn't work, */
  854                     ||(drive->state != drive_up))
  855                         free_drive(drive);                  /* get rid of it */
  856                     else if (drive->flags & VF_CONFIGURED)  /* already read this config, */
  857                         log(LOG_WARNING,
  858                             "vinum: already read config from %s\n", /* say so */
  859                             drive->label.name);
  860                     else {
  861                         drivelist[gooddrives] = drive->driveno; /* keep the drive index */
  862                         drive->flags &= ~VF_NEWBORN;        /* which is no longer newly born */
  863                         gooddrives++;
  864                     }
  865                 }
  866         }
  867     }
  868 
  869     if (gooddrives == 0) {
  870         if (firsttime)
  871             log(LOG_WARNING, "vinum: no drives found\n");
  872         else
  873             log(LOG_INFO, "vinum: no additional drives found\n");
  874         return ENOENT;
  875     }
  876     /*
  877      * We now have at least one drive open.  Sort
  878      * them in order of config time and merge the
  879      * config info with what we have already.
  880      */
  881     qsort(drivelist, gooddrives, sizeof(int), drivecmp);
  882     config_text = (char *) Malloc(MAXCONFIG * 2);           /* allocate buffers */
  883     CHECKALLOC(config_text, "Can't allocate memory");
  884     config_line = (char *) Malloc(MAXCONFIGLINE * 2);       /* allocate buffers */
  885     CHECKALLOC(config_line, "Can't allocate memory");
  886     for (driveno = 0; driveno < gooddrives; driveno++) {    /* now include the config */
  887         drive = &DRIVE[drivelist[driveno]];                 /* point to the drive */
  888 
  889         if (firsttime && (driveno == 0))                    /* we've never configured before, */
  890             log(LOG_INFO, "vinum: reading configuration from %s\n", drive->devicename);
  891         else
  892             log(LOG_INFO, "vinum: updating configuration from %s\n", drive->devicename);
  893 
  894         if (drive->state == drive_up)
  895             /* Read in both copies of the configuration information */
  896             error = read_drive(drive, config_text, MAXCONFIG * 2, VINUM_CONFIG_OFFSET);
  897         else {
  898             error = EIO;
  899             printf("vinum_scandisk: %s is %s\n", drive->devicename, drive_state(drive->state));
  900         }
  901 
  902         if (error != 0) {
  903             log(LOG_ERR, "vinum: Can't read device %s, error %d\n", drive->devicename, error);
  904             free_drive(drive);                              /* give it back */
  905             status = error;
  906         }
  907         /*
  908          * At this point, check that the two copies
  909          * are the same, and do something useful if
  910          * not.  In particular, consider which is
  911          * newer, and what this means for the
  912          * integrity of the data on the drive.
  913          */
  914         else {
  915             vinum_conf.drives_used++;                       /* another drive in use */
  916             /* Parse the configuration, and add it to the global configuration */
  917             for (cptr = config_text; *cptr != '\0';) {      /* love this style(9) */
  918                 volatile int parse_status;                  /* return value from parse_config */
  919 
  920                 for (eptr = config_line; (*cptr != '\n') && (*cptr != '\0');) /* until the end of the line */
  921                     *eptr++ = *cptr++;
  922                 *eptr = '\0';                               /* and delimit */
  923                 if (setjmp(&command_fail) == 0) {           /* come back here on error and continue */
  924                     parse_status = parse_config(config_line, &keyword_set, 1); /* parse the config line */
  925                     if (parse_status < 0) {                 /* error in config */
  926                         /*
  927                            * This config should have been parsed
  928                            * in user space.  If we run into
  929                            * problems here, something serious is
  930                            * afoot.  Complain and let the user
  931                            * snarf the config to see what's
  932                            * wrong.
  933                          */
  934                         log(LOG_ERR,
  935                             "vinum: Config error on %s, aborting integration\n",
  936                             drive->devicename);
  937                         free_drive(drive);                  /* give it back */
  938                         status = EINVAL;
  939                     }
  940                 }
  941                 while (*cptr == '\n')
  942                     cptr++;                                 /* skip to next line */
  943             }
  944         }
  945         drive->flags |= VF_CONFIGURED;                      /* read this drive's configuration */
  946     }
  947 
  948     Free(config_text);
  949     Free(drivelist);
  950     vinum_conf.flags &= ~VF_READING_CONFIG;                 /* no longer reading from disk */
  951     if (status != 0)
  952         printf("vinum: couldn't read configuration");
  953     else
  954         updateconfig(VF_READING_CONFIG);                    /* update from disk config */
  955     return status;
  956 }
  957 
  958 /*
  959  * Compare the modification dates of the drives, for qsort.
  960  * Return 1 if a < b, 0 if a == b, 01 if a > b: in other
  961  * words, sort backwards.
  962  */
  963 int
  964 drivecmp(const void *va, const void *vb)
  965 {
  966     const struct drive *a = &DRIVE[*(const int *) va];
  967     const struct drive *b = &DRIVE[*(const int *) vb];
  968 
  969     if ((a->label.last_update.tv_sec == b->label.last_update.tv_sec)
  970         && (a->label.last_update.tv_usec == b->label.last_update.tv_usec))
  971         return 0;
  972     else if ((a->label.last_update.tv_sec > b->label.last_update.tv_sec)
  973             || ((a->label.last_update.tv_sec == b->label.last_update.tv_sec)
  974             && (a->label.last_update.tv_usec > b->label.last_update.tv_usec)))
  975         return -1;
  976     else
  977         return 1;
  978 }
  979 /* Local Variables: */
  980 /* fill-column: 50 */
  981 /* End: */

Cache object: 2bda8c639bfc6e2bb109feb0e78892e8


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