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.39 2003/05/23 00:59:53 grog Exp grog $
   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 /*
   47  * Open the device associated with the drive, and
   48  * set drive's vp.  Return an error number.
   49  */
   50 int
   51 open_drive(struct drive *drive, struct thread *td, int verbose)
   52 {
   53     struct cdevsw *dsw;                                     /* pointer to cdevsw entry */
   54 
   55     if (drive->flags & VF_OPEN)                             /* open already, */
   56         return EBUSY;                                       /* don't do it again */
   57 
   58     drive->dev = getdiskbyname(drive->devicename);
   59     if (drive->dev == NULL)                                 /* didn't find anything */
   60         return ENOENT;
   61     dev_ref(drive->dev);
   62 
   63     drive->dev->si_iosize_max = DFLTPHYS;
   64     dsw = devsw(drive->dev);
   65     if (dsw == NULL)                                        /* sanity, should not happen */
   66         drive->lasterror = ENOENT;
   67     else if ((dsw->d_flags & D_DISK) == 0)
   68         drive->lasterror = ENOTBLK;
   69     else {
   70         DROP_GIANT();
   71         drive->lasterror = (dsw->d_open) (drive->dev, FWRITE | FREAD, 0, td);
   72         PICKUP_GIANT();
   73     }
   74 
   75     if (drive->lasterror != 0) {                            /* failed */
   76         drive->state = drive_down;                          /* just force it down */
   77         if (verbose)
   78             log(LOG_WARNING,
   79                 "vinum open_drive %s: failed with error %d\n",
   80                 drive->devicename, drive->lasterror);
   81     } else
   82         drive->flags |= VF_OPEN;                            /* we're open now */
   83 
   84     return drive->lasterror;
   85 }
   86 
   87 /*
   88  * Set some variables in the drive struct in more
   89  * convenient form.  Return error indication.
   90  */
   91 int
   92 set_drive_parms(struct drive *drive)
   93 {
   94     drive->blocksize = BLKDEV_IOSIZE;                       /* do we need this? */
   95     drive->secsperblock = drive->blocksize                  /* number of sectors per block */
   96         / drive->sectorsize;
   97 
   98     /* Now update the label part */
   99     bcopy(hostname, drive->label.sysname, VINUMHOSTNAMELEN); /* put in host name */
  100     microtime(&drive->label.date_of_birth);                 /* and current time */
  101     drive->label.drive_size = drive->mediasize;             /* size of the drive in bytes */
  102 #ifdef VINUMDEBUG
  103     if (debug & DEBUG_BIGDRIVE)                             /* pretend we're 100 times as big */
  104         drive->label.drive_size *= 100;
  105 #endif
  106 
  107     /* number of sectors available for subdisks */
  108     drive->sectors_available = drive->label.drive_size / DEV_BSIZE - DATASTART;
  109 
  110     /*
  111      * Bug in 3.0 as of January 1998: you can open
  112      * non-existent slices.  They have a length of 0.
  113      */
  114     if (drive->label.drive_size < MINVINUMSLICE) {          /* too small to worry about */
  115         set_drive_state(drive->driveno, drive_down, setstate_force);
  116         drive->lasterror = ENOSPC;
  117         return ENOSPC;
  118     }
  119     drive->freelist_size = INITIAL_DRIVE_FREELIST;          /* initial number of entries */
  120     drive->freelist = (struct drive_freelist *)
  121         Malloc(INITIAL_DRIVE_FREELIST * sizeof(struct drive_freelist));
  122     if (drive->freelist == NULL)                            /* can't malloc, dammit */
  123         return ENOSPC;
  124     drive->freelist_entries = 1;                            /* just (almost) the complete drive */
  125     drive->freelist[0].offset = DATASTART;                  /* starts here */
  126     drive->freelist[0].sectors = (drive->label.drive_size >> DEV_BSHIFT) - DATASTART; /* and it's this long */
  127     if (drive->label.name[0] != '\0')                       /* got a name */
  128         set_drive_state(drive->driveno, drive_up, setstate_force); /* our drive is accessible */
  129     else                                                    /* we know about it, but that's all */
  130         drive->state = drive_referenced;
  131     return 0;
  132 }
  133 
  134 /*
  135  * Initialize a drive: open the device and add
  136  * device information.
  137  */
  138 int
  139 init_drive(struct drive *drive, int verbose)
  140 {
  141 
  142     drive->lasterror = open_drive(drive, curthread, verbose); /* open the drive */
  143     if (drive->lasterror)
  144         return drive->lasterror;
  145 
  146     DROP_GIANT();
  147     drive->lasterror = (*devsw(drive->dev)->d_ioctl) (drive->dev,
  148         DIOCGSECTORSIZE,
  149         (caddr_t) & drive->sectorsize,
  150         FREAD,
  151         curthread);
  152     if (drive->lasterror == 0)
  153         drive->lasterror = (*devsw(drive->dev)->d_ioctl) (drive->dev,
  154             DIOCGMEDIASIZE,
  155             (caddr_t) & drive->mediasize,
  156             FREAD,
  157             curthread);
  158     PICKUP_GIANT();
  159     if (drive->lasterror) {
  160         if (verbose)
  161             log(LOG_ERR,
  162                 "vinum: Can't get drive dimensions for %s: error %d\n",
  163                 drive->devicename,
  164                 drive->lasterror);
  165         close_drive(drive);
  166         return drive->lasterror;
  167     }
  168     return set_drive_parms(drive);                          /* set various odds and ends */
  169 }
  170 
  171 /* Close a drive if it's open. */
  172 void
  173 close_drive(struct drive *drive)
  174 {
  175     LOCKDRIVE(drive);                                       /* keep the daemon out */
  176     if (drive->flags & VF_OPEN)
  177         close_locked_drive(drive);                          /* and close it */
  178     if (drive->state > drive_down)                          /* if it's up */
  179         drive->state = drive_down;                          /* make sure it's down */
  180     unlockdrive(drive);
  181 }
  182 
  183 /*
  184  * Real drive close code, called with drive already locked.
  185  * We have also checked that the drive is open.  No errors.
  186  */
  187 void
  188 close_locked_drive(struct drive *drive)
  189 {
  190     int error;
  191 
  192     /*
  193      * If we can't access the drive, we can't flush
  194      * the queues, which spec_close() will try to
  195      * do.  Get rid of them here first.
  196      */
  197     DROP_GIANT();
  198     error = (*devsw(drive->dev)->d_close) (drive->dev, FWRITE | FREAD, 0, NULL);
  199     PICKUP_GIANT();
  200     drive->flags &= ~VF_OPEN;                               /* no longer open */
  201     if (drive->lasterror == 0)
  202         drive->lasterror = error;
  203 }
  204 
  205 /*
  206  * Remove drive from the configuration.
  207  * Caller must ensure that it isn't active.
  208  */
  209 void
  210 remove_drive(int driveno)
  211 {
  212     struct drive *drive = &vinum_conf.drive[driveno];
  213     struct vinum_hdr *vhdr;                                 /* buffer for header */
  214     int error;
  215 
  216     if (drive->state > drive_referenced) {                  /* real drive */
  217         if (drive->state == drive_up) {
  218             vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN); /* allocate buffer */
  219             CHECKALLOC(vhdr, "Can't allocate memory");
  220             error = read_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET);
  221             if (error)
  222                 drive->lasterror = error;
  223             else {
  224                 vhdr->magic = VINUM_NOMAGIC;                /* obliterate the magic, but leave the rest */
  225                 write_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET);
  226             }
  227             Free(vhdr);
  228         }
  229         free_drive(drive);                                  /* close it and free resources */
  230         save_config();                                      /* and save the updated configuration */
  231     }
  232 }
  233 
  234 /*
  235  * Transfer drive data.  Usually called from one of these defines;
  236  * #define read_drive(a, b, c, d) driveio (a, b, c, d, B_READ)
  237  * #define write_drive(a, b, c, d) driveio (a, b, c, d, B_WRITE)
  238  *
  239  * length and offset are in bytes, but must be multiples of sector
  240  * size.  The function *does not check* for this condition, and
  241  * truncates ruthlessly.
  242  * Return error number.
  243  */
  244 int
  245 driveio(struct drive *drive, char *buf, size_t length, off_t offset, int flag)
  246 {
  247     int error;
  248     struct buf *bp;
  249 
  250     error = 0;                                              /* to keep the compiler happy */
  251     while (length) {                                        /* divide into small enough blocks */
  252         int len = min(length, MAXBSIZE);                    /* maximum block device transfer is MAXBSIZE */
  253 
  254         bp = geteblk(len);                                  /* get a buffer header */
  255         bp->b_flags = 0;
  256         bp->b_iocmd = flag;
  257         bp->b_dev = drive->dev;                             /* device */
  258         bp->b_blkno = offset / drive->sectorsize;           /* block number */
  259         bp->b_offset = offset;
  260         bp->b_iooffset = offset;
  261         bp->b_saveaddr = bp->b_data;
  262         bp->b_data = buf;
  263         bp->b_bcount = len;
  264         DEV_STRATEGY(bp);                                   /* initiate the transfer */
  265         error = bufwait(bp);
  266         bp->b_data = bp->b_saveaddr;
  267         bp->b_flags |= B_INVAL | B_AGE;
  268         bp->b_ioflags &= ~BIO_ERROR;
  269         brelse(bp);
  270         if (error)
  271             break;
  272         length -= len;                                      /* update pointers */
  273         buf += len;
  274         offset += len;
  275     }
  276     return error;
  277 }
  278 
  279 /*
  280  * Check a drive for a vinum header.  If found,
  281  * update the drive information.  We come here
  282  * with a partially populated drive structure
  283  * which includes the device name.
  284  *
  285  * Return information on what we found.
  286  *
  287  * This function is called from two places: check_drive,
  288  * which wants to find out whether the drive is a
  289  * Vinum drive, and config_drive, which asserts that
  290  * it is a vinum drive.  In the first case, we don't
  291  * print error messages (verbose==0), in the second
  292  * we do (verbose==1).
  293  */
  294 enum drive_label_info
  295 read_drive_label(struct drive *drive, int verbose)
  296 {
  297     int error;
  298     int result;                                             /* result of our search */
  299     struct vinum_hdr *vhdr;                                 /* and as header */
  300 
  301     error = init_drive(drive, 0);                           /* find the drive */
  302     if (error)                                              /* find the drive */
  303         return DL_CANT_OPEN;                                /* not ours */
  304 
  305     vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN);     /* allocate buffers */
  306     CHECKALLOC(vhdr, "Can't allocate memory");
  307 
  308     drive->state = drive_up;                                /* be optimistic */
  309     error = read_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET);
  310     if (vhdr->magic == VINUM_MAGIC) {                       /* ours! */
  311         if (drive->label.name[0]                            /* we have a name for this drive */
  312         &&(strcmp(drive->label.name, vhdr->label.name))) {  /* but it doesn't match the real name */
  313             drive->lasterror = EINVAL;
  314             result = DL_WRONG_DRIVE;                        /* it's the wrong drive */
  315             drive->state = drive_unallocated;               /* put it back, it's not ours */
  316         } else
  317             result = DL_OURS;
  318         /*
  319          * We copy the drive anyway so that we have
  320          * the correct name in the drive info.  This
  321          * may not be the name specified
  322          */
  323         drive->label = vhdr->label;                         /* put in the label information */
  324     } else if (vhdr->magic == VINUM_NOMAGIC)                /* was ours, but we gave it away */
  325         result = DL_DELETED_LABEL;                          /* and return the info */
  326     else
  327         result = DL_NOT_OURS;                               /* we could have it, but we don't yet */
  328     Free(vhdr);                                             /* that's all. */
  329     return result;
  330 }
  331 
  332 /*
  333  * Check a drive for a vinum header.  If found,
  334  * read configuration information from the drive and
  335  * incorporate the data into the configuration.
  336  *
  337  * Return drive number.
  338  */
  339 struct drive *
  340 check_drive(char *devicename)
  341 {
  342     int driveno;
  343     int i;
  344     struct drive *drive;
  345 
  346     driveno = find_drive_by_name(devicename, 1);            /* if entry doesn't exist, create it */
  347     drive = &vinum_conf.drive[driveno];                     /* and get a pointer */
  348 
  349     if (drive->state >= drive_down)                         /* up or down, we know it */
  350         return drive;
  351     if (read_drive_label(drive, 0) == DL_OURS) {            /* one of ours */
  352         for (i = 0; i < vinum_conf.drives_allocated; i++) { /* see if the name already exists */
  353             if ((i != driveno)                              /* not this drive */
  354             &&(DRIVE[i].state != drive_unallocated)         /* and it's allocated */
  355             &&(strcmp(DRIVE[i].label.name,
  356                         DRIVE[driveno].label.name) == 0)) { /* and it has the same name */
  357                 struct drive *mydrive = &DRIVE[i];
  358 
  359                 if (mydrive->devicename[0] == '/') {        /* we know a device name for it */
  360                     /*
  361                      * set an error, but don't take the
  362                      * drive down: that would cause unneeded
  363                      * error messages.
  364                      */
  365                     drive->lasterror = EEXIST;
  366                     break;
  367                 } else {                                    /* it's just a place holder, */
  368                     int sdno;
  369 
  370                     for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) { /* look at each subdisk */
  371                         if ((SD[sdno].driveno == i)         /* it's pointing to this one, */
  372                         &&(SD[sdno].state != sd_unallocated)) { /* and it's a real subdisk */
  373                             SD[sdno].driveno = drive->driveno; /* point to the one we found */
  374                             update_sd_state(sdno);          /* and update its state */
  375                         }
  376                     }
  377                     bzero(mydrive, sizeof(struct drive));   /* don't deallocate it, just remove it */
  378                 }
  379             }
  380         }
  381         return drive;
  382     } else {                                                /* not ours, */
  383         close_drive(drive);
  384         free_drive(drive);                                  /* get rid of it */
  385         return NULL;
  386     }
  387 }
  388 
  389 static char *
  390 sappend(char *txt, char *s)
  391 {
  392     while ((*s++ = *txt++) != 0);
  393     return s - 1;
  394 }
  395 
  396 void
  397 format_config(char *config, int len)
  398 {
  399     int i;
  400     int j;
  401     char *s = config;
  402     char *configend = &config[len];
  403 
  404     bzero(config, len);
  405 
  406     /* First write the volume configuration */
  407     for (i = 0; i < vinum_conf.volumes_allocated; i++) {
  408         struct volume *vol;
  409 
  410         vol = &vinum_conf.volume[i];
  411         if ((vol->state > volume_uninit)
  412             && (vol->name[0] != '\0')) {                    /* paranoia */
  413             snprintf(s,
  414                 configend - s,
  415                 "volume %s state %s",
  416                 vol->name,
  417                 volume_state(vol->state));
  418             while (*s)
  419                 s++;                                        /* find the end */
  420             s = sappend("\n", s);
  421         }
  422     }
  423 
  424     /* Then the plex configuration */
  425     for (i = 0; i < vinum_conf.plexes_allocated; i++) {
  426         struct plex *plex;
  427         struct volume *vol;
  428 
  429         plex = &vinum_conf.plex[i];
  430         if ((plex->state > plex_referenced)
  431             && (plex->name[0] != '\0')) {                   /* paranoia */
  432             snprintf(s,
  433                 configend - s,
  434                 "plex name %s state %s org %s ",
  435                 plex->name,
  436                 plex_state(plex->state),
  437                 plex_org(plex->organization));
  438             while (*s)
  439                 s++;                                        /* find the end */
  440             if (isstriped(plex)) {
  441                 snprintf(s,
  442                     configend - s,
  443                     "%ds ",
  444                     (int) plex->stripesize);
  445                 while (*s)
  446                     s++;                                    /* find the end */
  447             }
  448             if (plex->volno >= 0) {                         /* we have a volume */
  449                 vol = &VOL[plex->volno];
  450                 snprintf(s,
  451                     configend - s,
  452                     "vol %s ",
  453                     vol->name);
  454                 while (*s)
  455                     s++;                                    /* find the end */
  456                 if ((vol->preferred_plex >= 0)              /* has a preferred plex */
  457                 &&vol->plex[vol->preferred_plex] == i)      /* and it's us */
  458                     snprintf(s, configend - s, "preferred ");
  459                 while (*s)
  460                     s++;                                    /* find the end */
  461             }
  462             for (j = 0; j < plex->subdisks; j++) {
  463                 snprintf(s,
  464                     configend - s,
  465                     " sd %s",
  466                     vinum_conf.sd[plex->sdnos[j]].name);
  467             }
  468             s = sappend("\n", s);
  469         }
  470     }
  471 
  472     /* And finally the subdisk configuration */
  473     for (i = 0; i < vinum_conf.subdisks_allocated; i++) {
  474         struct sd *sd;
  475         char *drivename;
  476 
  477         sd = &SD[i];
  478         if ((sd->state != sd_referenced)
  479             && (sd->state != sd_unallocated)
  480             && (sd->name[0] != '\0')) {                     /* paranoia */
  481             drivename = vinum_conf.drive[sd->driveno].label.name;
  482             /*
  483              * XXX We've seen cases of dead subdisks
  484              * which don't have a drive.  If we let them
  485              * through here, the drive name is null, so
  486              * they get the drive named 'plex'.
  487              *
  488              * This is a breakage limiter, not a fix.
  489              */
  490             if (drivename[0] == '\0')
  491                 drivename = "*invalid*";
  492             snprintf(s,
  493                 configend - s,
  494                 "sd name %s drive %s len %llus driveoffset %llus state %s",
  495                 sd->name,
  496                 drivename,
  497                 (unsigned long long) sd->sectors,
  498                 (unsigned long long) sd->driveoffset,
  499                 sd_state(sd->state));
  500             while (*s)
  501                 s++;                                        /* find the end */
  502             if (sd->plexno >= 0)
  503                 snprintf(s,
  504                     configend - s,
  505                     " plex %s plexoffset %llds",
  506                     vinum_conf.plex[sd->plexno].name,
  507                     (long long) sd->plexoffset);
  508             else
  509                 snprintf(s, configend - s, " detached");
  510             while (*s)
  511                 s++;                                        /* find the end */
  512             if (sd->flags & VF_RETRYERRORS) {
  513                 snprintf(s, configend - s, " retryerrors");
  514                 while (*s)
  515                     s++;                                    /* find the end */
  516             }
  517             snprintf(s, configend - s, " \n");
  518             while (*s)
  519                 s++;                                        /* find the end */
  520         }
  521     }
  522     if (s > &config[len - 2])
  523         panic("vinum: configuration data overflow");
  524 }
  525 
  526 /*
  527  * issue a save config request to the dæmon.  The actual work
  528  * is done in process context by daemon_save_config.
  529  */
  530 void
  531 save_config(void)
  532 {
  533     queue_daemon_request(daemonrq_saveconfig, (union daemoninfo) 0);
  534 }
  535 
  536 /*
  537  * Write the configuration to all vinum slices.  This
  538  * is performed by the daemon only.
  539  */
  540 void
  541 daemon_save_config(void)
  542 {
  543     int error;
  544     int written_config;                                     /* set when we first write the config to disk */
  545     int driveno;
  546     struct drive *drive;                                    /* point to current drive info */
  547     struct vinum_hdr *vhdr;                                 /* and as header */
  548     char *config;                                           /* point to config data */
  549 
  550     /* don't save the configuration while we're still working on it */
  551     if (vinum_conf.flags & VF_CONFIGURING)
  552         return;
  553     written_config = 0;                                     /* no config written yet */
  554     /* Build a volume header */
  555     vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN);     /* get space for the config data */
  556     CHECKALLOC(vhdr, "Can't allocate config data");
  557     vhdr->magic = VINUM_MAGIC;                              /* magic number */
  558     vhdr->config_length = MAXCONFIG;                        /* length of following config info */
  559 
  560     config = Malloc(MAXCONFIG);                             /* get space for the config data */
  561     CHECKALLOC(config, "Can't allocate config data");
  562 
  563     format_config(config, MAXCONFIG);
  564     error = 0;                                              /* no errors yet */
  565     for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
  566         drive = &vinum_conf.drive[driveno];                 /* point to drive */
  567         if (drive->state > drive_referenced) {
  568             LOCKDRIVE(drive);                               /* don't let it change */
  569 
  570             /*
  571              * First, do some drive consistency checks.  Some
  572              * of these are kludges, others require a process
  573              * context and couldn't be done before.
  574              */
  575             if ((drive->devicename[0] == '\0')
  576                 || (drive->label.name[0] == '\0')) {
  577                 unlockdrive(drive);
  578                 free_drive(drive);                          /* get rid of it */
  579                 break;
  580             }
  581             if (((drive->flags & VF_OPEN) == 0)             /* drive not open */
  582             &&(drive->state > drive_down)) {                /* and it thinks it's not down */
  583                 unlockdrive(drive);
  584                 set_drive_state(driveno, drive_down, setstate_force); /* tell it what's what */
  585                 continue;
  586             }
  587             if ((drive->state == drive_down)                /* it's down */
  588             &&(drive->flags & VF_OPEN)) {                   /* but open, */
  589                 unlockdrive(drive);
  590                 close_drive(drive);                         /* close it */
  591             } else if (drive->state > drive_down) {
  592                 microtime(&drive->label.last_update);       /* time of last update is now */
  593                 bcopy((char *) &drive->label,               /* and the label info from the drive structure */
  594                     (char *) &vhdr->label,
  595                     sizeof(vhdr->label));
  596                 if ((drive->state != drive_unallocated)
  597                     && (drive->state != drive_referenced)) { /* and it's a real drive */
  598                     error = write_drive(drive,
  599                         (char *) vhdr,
  600                         VINUMHEADERLEN,
  601                         VINUM_LABEL_OFFSET);
  602                     if (error == 0)                         /* first config copy */
  603                         error = write_drive(drive,
  604                             config,
  605                             MAXCONFIG,
  606                             VINUM_CONFIG_OFFSET);
  607                     if (error == 0)
  608                         error = write_drive(drive,          /* second copy */
  609                             config,
  610                             MAXCONFIG,
  611                             VINUM_CONFIG_OFFSET + MAXCONFIG);
  612                     unlockdrive(drive);
  613                     if (error) {
  614                         log(LOG_ERR,
  615                             "vinum: Can't write config to %s, error %d\n",
  616                             drive->devicename,
  617                             error);
  618                         set_drive_state(drive->driveno, drive_down, setstate_force);
  619                     } else
  620                         written_config = 1;                 /* we've written it on at least one drive */
  621                 }
  622             } else                                          /* not worth looking at, */
  623                 unlockdrive(drive);                         /* just unlock it again */
  624         }
  625     }
  626     Free(vhdr);
  627     Free(config);
  628 }
  629 
  630 /*
  631  * Search disks on system for vinum slices and add
  632  * them to the configuuration if they're not
  633  * there already.  devicename is a blank-separate
  634  * list of device names.  If not provided, use
  635  * sysctl to get a list of all disks on the
  636  * system.
  637  *
  638  * Return an error indication.
  639  */
  640 int
  641 vinum_scandisk(char *devicename)
  642 {
  643     struct drive *volatile drive;
  644     volatile int driveno;
  645     int firstdrive;                                         /* first drive in this list */
  646     volatile int gooddrives;                                /* number of usable drives found */
  647     int firsttime;                                          /* set if we have never configured before */
  648     int error;
  649     char *config_text;                                      /* read the config info from disk into here */
  650     char *volatile cptr;                                    /* pointer into config information */
  651     char *eptr;                                             /* end pointer into config information */
  652     char *config_line;                                      /* copy the config line to */
  653     volatile int status;
  654     int *drivelist;                                         /* list of drive indices */
  655     char *partname;                                         /* for creating partition names */
  656     char *cp;                                               /* pointer to start of disk name */
  657     char *ep;                                               /* and to first char after name */
  658     char *np;                                               /* name pointer in naem we build */
  659     size_t alloclen;
  660     int malloced;
  661     int partnamelen;                                        /* length of partition name */
  662     int drives;
  663     int goodpart;                                           /* good vinum drives on this disk */
  664 
  665     malloced = 0;                                           /* devicename not malloced */
  666     if (devicename == NULL) {                               /* no devices specified, */
  667         /* get a list of all disks in the system */
  668         /* Get size of disk list */
  669         error = kernel_sysctlbyname(&thread0, "kern.disks", NULL,
  670             NULL, NULL, 0, &alloclen);
  671         if (error) {
  672             log(LOG_ERR, "vinum: can't get disk list: %d\n", error);
  673             return EINVAL;
  674         }
  675         devicename = Malloc(alloclen);
  676         if (devicename == NULL) {
  677             printf("vinum: can't allocate memory for drive list");
  678             return ENOMEM;
  679         } else
  680             malloced = 1;
  681         /* Now get the list of disks */
  682         kernel_sysctlbyname(&thread0, "kern.disks", devicename,
  683             &alloclen, NULL, 0, NULL);
  684     }
  685     status = 0;                                             /* success indication */
  686     vinum_conf.flags |= VF_READING_CONFIG;                  /* reading config from disk */
  687     partname = Malloc(MAXPATHLEN);                          /* extract name of disk here */
  688     if (partname == NULL) {
  689         printf("vinum_scandisk: can't allocate memory for drive name");
  690         return ENOMEM;
  691     }
  692     gooddrives = 0;                                         /* number of usable drives found */
  693     firstdrive = vinum_conf.drives_used;                    /* the first drive */
  694     firsttime = vinum_conf.drives_used == 0;                /* are we a virgin? */
  695 
  696     /* allocate a drive pointer list */
  697     drives = 256;                                           /* should be enough for most cases */
  698     drivelist = (int *) Malloc(drives * sizeof(int));
  699     CHECKALLOC(drivelist, "Can't allocate memory");
  700     error = lock_config();                                  /* make sure we're alone here */
  701     if (error)
  702         return error;
  703     error = setjmp(command_fail);                           /* come back here on error */
  704     if (error)                                              /* longjmped out */
  705         return error;
  706 
  707     /* Open all drives and find which was modified most recently */
  708     for (cp = devicename; *cp; cp = ep) {
  709         char part;                                          /* UNIX partition */
  710 #if defined(__i386__) || defined(__amd64__)
  711         int slice;
  712 #endif
  713 
  714         while (*cp == ' ')
  715             cp++;                                           /* find start of name */
  716         if (*cp == '\0')                                    /* done, */
  717             break;
  718         ep = cp;
  719         while (*ep && (*ep != ' '))                         /* find end of name */
  720             ep++;
  721 
  722         np = partname;                                      /* start building up a name here */
  723         if (*cp != '/') {                                   /* name doesn't start with /, */
  724             strcpy(np, "/dev/");                            /* assume /dev */
  725             np += strlen("/dev/");
  726         }
  727         memcpy(np, cp, ep - cp);                            /* put in name */
  728         np += ep - cp;                                      /* and point past */
  729 
  730         goodpart = 0;                                       /* no partitions on this disk yet */
  731         partnamelen = MAXPATHLEN + np - partname;           /* remaining length in partition name */
  732 #if defined(__i386__) || defined(__amd64__)
  733         /* first try the partition table */
  734         for (slice = 1; slice < 5; slice++)
  735             for (part = 'a'; part < 'i'; part++) {
  736                 if (part != 'c') {                          /* don't do the c partition */
  737                     snprintf(np,
  738                         partnamelen,
  739                         "s%d%c",
  740                         slice,
  741                         part);
  742                     drive = check_drive(partname);          /* try to open it */
  743                     if (drive) {                            /* got something, */
  744                         if (drive->flags & VF_CONFIGURED)   /* already read this config, */
  745                             log(LOG_WARNING,
  746                                 "vinum: already read config from %s\n", /* say so */
  747                                 drive->label.name);
  748                         else {
  749                             if (gooddrives == drives)       /* ran out of entries */
  750                                 EXPAND(drivelist, int, drives, drives); /* double the size */
  751                             drivelist[gooddrives] = drive->driveno; /* keep the drive index */
  752                             drive->flags &= ~VF_NEWBORN;    /* which is no longer newly born */
  753                             gooddrives++;
  754                             goodpart++;
  755                         }
  756                     }
  757                 }
  758             }
  759 #endif
  760         /*
  761          * If the machine doesn't have a BIOS
  762          * partition table, try normal devices.
  763          */
  764         if (goodpart == 0) {                                /* didn't find anything, */
  765             for (part = 'a'; part < 'i'; part++)            /* try the compatibility partition */
  766                 if (part != 'c') {                          /* don't do the c partition */
  767                     snprintf(np,
  768                         partnamelen,
  769                         "%c",
  770                         part);
  771                     drive = check_drive(partname);          /* try to open it */
  772                     if (drive) {                            /* got something, */
  773                         if (drive->flags & VF_CONFIGURED)   /* already read this config, */
  774                             log(LOG_WARNING,
  775                                 "vinum: already read config from %s\n", /* say so */
  776                                 drive->label.name);
  777                         else {
  778                             if (gooddrives == drives)       /* ran out of entries */
  779                                 EXPAND(drivelist, int, drives, drives); /* double the size */
  780                             drivelist[gooddrives] = drive->driveno; /* keep the drive index */
  781                             drive->flags &= ~VF_NEWBORN;    /* which is no longer newly born */
  782                             gooddrives++;
  783                             goodpart++;
  784                         }
  785                     }
  786                 }
  787         }
  788     }
  789     Free(partname);
  790 
  791     if (gooddrives == 0) {
  792         if (firsttime)
  793             log(LOG_WARNING, "vinum: no drives found\n");
  794         else
  795             log(LOG_INFO, "vinum: no additional drives found\n");
  796         if (malloced)
  797             Free(devicename);
  798         unlock_config();
  799         return ENOENT;
  800     }
  801     /*
  802      * We now have at least one drive open.  Sort
  803      * them in order of config time and merge the
  804      * config info with what we have already.
  805      */
  806     qsort(drivelist, gooddrives, sizeof(int), drivecmp);
  807     config_text = (char *) Malloc(MAXCONFIG * 2);           /* allocate buffers */
  808     CHECKALLOC(config_text, "Can't allocate memory");
  809     config_line = (char *) Malloc(MAXCONFIGLINE * 2);       /* allocate buffers */
  810     CHECKALLOC(config_line, "Can't allocate memory");
  811     for (driveno = 0; driveno < gooddrives; driveno++) {    /* now include the config */
  812         drive = &DRIVE[drivelist[driveno]];                 /* point to the drive */
  813 
  814         if (firsttime && (driveno == 0))                    /* we've never configured before, */
  815             log(LOG_INFO, "vinum: reading configuration from %s\n", drive->devicename);
  816         else
  817             log(LOG_INFO, "vinum: updating configuration from %s\n", drive->devicename);
  818 
  819         if (drive->state == drive_up)
  820             /* Read in both copies of the configuration information */
  821             error = read_drive(drive, config_text, MAXCONFIG * 2, VINUM_CONFIG_OFFSET);
  822         else {
  823             error = EIO;
  824             printf("vinum_scandisk: %s is %s\n", drive->devicename, drive_state(drive->state));
  825         }
  826 
  827         if (error != 0) {
  828             log(LOG_ERR, "vinum: Can't read device %s, error %d\n", drive->devicename, error);
  829             free_drive(drive);                              /* give it back */
  830             status = error;
  831         }
  832         /*
  833          * At this point, check that the two copies
  834          * are the same, and do something useful if
  835          * not.  In particular, consider which is
  836          * newer, and what this means for the
  837          * integrity of the data on the drive.
  838          */
  839         else {
  840             vinum_conf.drives_used++;                       /* another drive in use */
  841             /* Parse the configuration, and add it to the global configuration */
  842             for (cptr = config_text; *cptr != '\0';) {      /* love this style(9) */
  843                 volatile int parse_status;                  /* return value from parse_config */
  844 
  845                 for (eptr = config_line; (*cptr != '\n') && (*cptr != '\0');) /* until the end of the line */
  846                     *eptr++ = *cptr++;
  847                 *eptr = '\0';                               /* and delimit */
  848                 if (setjmp(command_fail) == 0) {            /* come back here on error and continue */
  849                     parse_status = parse_config(config_line, &keyword_set, 1); /* parse the config line */
  850                     /*
  851                      * parse_config recognizes referenced
  852                      * drives and builds a drive entry for
  853                      * them.  This may expand the drive
  854                      * table, thus invalidating the pointer.
  855                      */
  856                     drive = &DRIVE[drivelist[driveno]];     /* point to the drive */
  857 
  858                     if (parse_status < 0) {                 /* error in config */
  859                         /*
  860                            * This config should have been parsed
  861                            * in user space.  If we run into
  862                            * problems here, something serious is
  863                            * afoot.  Complain and let the user
  864                            * snarf the config to see what's
  865                            * wrong.
  866                          */
  867                         log(LOG_ERR,
  868                             "vinum: Config error on %s, aborting integration\n",
  869                             drive->devicename);
  870                         free_drive(drive);                  /* give it back */
  871                         status = EINVAL;
  872                     }
  873                 }
  874                 while (*cptr == '\n')
  875                     cptr++;                                 /* skip to next line */
  876             }
  877         }
  878         drive->flags |= VF_CONFIGURED;                      /* this drive's configuration is complete */
  879     }
  880 
  881     Free(config_line);
  882     Free(config_text);
  883     Free(drivelist);
  884     vinum_conf.flags &= ~VF_READING_CONFIG;                 /* no longer reading from disk */
  885     if (status != 0)
  886         printf("vinum: couldn't read configuration");
  887     else
  888         updateconfig(VF_READING_CONFIG);                    /* update from disk config */
  889     if (malloced)
  890         Free(devicename);
  891     unlock_config();
  892     return status;
  893 }
  894 
  895 /*
  896  * Compare the modification dates of the drives, for qsort.
  897  * Return 1 if a < b, 0 if a == b, 01 if a > b: in other
  898  * words, sort backwards.
  899  */
  900 int
  901 drivecmp(const void *va, const void *vb)
  902 {
  903     const struct drive *a = &DRIVE[*(const int *) va];
  904     const struct drive *b = &DRIVE[*(const int *) vb];
  905 
  906     if ((a->label.last_update.tv_sec == b->label.last_update.tv_sec)
  907         && (a->label.last_update.tv_usec == b->label.last_update.tv_usec))
  908         return 0;
  909     else if ((a->label.last_update.tv_sec > b->label.last_update.tv_sec)
  910             || ((a->label.last_update.tv_sec == b->label.last_update.tv_sec)
  911             && (a->label.last_update.tv_usec > b->label.last_update.tv_usec)))
  912         return -1;
  913     else
  914         return 1;
  915 }
  916 /* Local Variables: */
  917 /* fill-column: 50 */
  918 /* End: */

Cache object: 6518d46f3230d2e96d013c0bb590bb6d


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