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

Cache object: 9cf17bfa7a830f814be21205ffb73ef1


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