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/vinumrevive.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, 1999
    3  *      Nan Yang Computer Services Limited.  All rights reserved.
    4  *
    5  *  Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
    6  *
    7  *  Written by Greg Lehey
    8  *
    9  *  This software is distributed under the so-called ``Berkeley
   10  *  License'':
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by Nan Yang Computer
   23  *      Services Limited.
   24  * 4. Neither the name of the Company nor the names of its contributors
   25  *    may be used to endorse or promote products derived from this software
   26  *    without specific prior written permission.
   27  *
   28  * This software is provided ``as is'', and any express or implied
   29  * warranties, including, but not limited to, the implied warranties of
   30  * merchantability and fitness for a particular purpose are disclaimed.
   31  * In no event shall the company or contributors be liable for any
   32  * direct, indirect, incidental, special, exemplary, or consequential
   33  * damages (including, but not limited to, procurement of substitute
   34  * goods or services; loss of use, data, or profits; or business
   35  * interruption) however caused and on any theory of liability, whether
   36  * in contract, strict liability, or tort (including negligence or
   37  * otherwise) arising in any way out of the use of this software, even if
   38  * advised of the possibility of such damage.
   39  *
   40  * $Id: vinumrevive.c,v 1.19 2003/05/08 04:34:47 grog Exp grog $
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 
   45 __FBSDID("$FreeBSD$");
   46 #include <dev/vinum/vinumhdr.h>
   47 #include <dev/vinum/request.h>
   48 
   49 /*
   50  * Revive a block of a subdisk.  Return an error
   51  * indication.  EAGAIN means successful copy, but
   52  * that more blocks remain to be copied.  EINVAL
   53  * means that the subdisk isn't associated with a
   54  * plex (which means a programming error if we get
   55  * here at all; FIXME).
   56  */
   57 
   58 int
   59 revive_block(int sdno)
   60 {
   61     int s;                                                  /* priority level */
   62     struct sd *sd;
   63     struct plex *plex;
   64     struct volume *vol;
   65     struct buf *bp;
   66     int error = EAGAIN;
   67     int size;                                               /* size of revive block, bytes */
   68     daddr_t plexblkno;                                      /* lblkno in plex */
   69     int psd;                                                /* parity subdisk number */
   70     u_int64_t stripe;                                       /* stripe number */
   71     int paritysd = 0;                                       /* set if this is the parity stripe */
   72     struct rangelock *lock;                                 /* for locking */
   73     daddr_t stripeoffset;                                   /* offset in stripe */
   74 
   75     plexblkno = 0;                                          /* to keep the compiler happy */
   76     sd = &SD[sdno];
   77     lock = NULL;
   78     if (sd->plexno < 0)                                     /* no plex? */
   79         return EINVAL;
   80     plex = &PLEX[sd->plexno];                               /* point to plex */
   81     if (plex->volno >= 0)
   82         vol = &VOL[plex->volno];
   83     else
   84         vol = NULL;
   85 
   86     if ((sd->revive_blocksize == 0)                         /* no block size */
   87     ||(sd->revive_blocksize & ((1 << DEV_BSHIFT) - 1)))     /* or invalid block size */
   88         sd->revive_blocksize = DEFAULT_REVIVE_BLOCKSIZE;
   89     else if (sd->revive_blocksize > MAX_REVIVE_BLOCKSIZE)
   90         sd->revive_blocksize = MAX_REVIVE_BLOCKSIZE;
   91     size = min(sd->revive_blocksize >> DEV_BSHIFT, sd->sectors - sd->revived) << DEV_BSHIFT;
   92     sd->reviver = curproc->p_pid;                           /* note who last had a bash at it */
   93 
   94     /* Now decide where to read from */
   95     switch (plex->organization) {
   96     case plex_concat:
   97         plexblkno = sd->revived + sd->plexoffset;           /* corresponding address in plex */
   98         break;
   99 
  100     case plex_striped:
  101         stripeoffset = sd->revived % plex->stripesize;      /* offset from beginning of stripe */
  102         if (stripeoffset + (size >> DEV_BSHIFT) > plex->stripesize)
  103             size = (plex->stripesize - stripeoffset) << DEV_BSHIFT;
  104         plexblkno = sd->plexoffset                          /* base */
  105             + (sd->revived - stripeoffset) * plex->subdisks /* offset to beginning of stripe */
  106             + stripeoffset;                                 /* offset from beginning of stripe */
  107         break;
  108 
  109     case plex_raid4:
  110     case plex_raid5:
  111         stripeoffset = sd->revived % plex->stripesize;      /* offset from beginning of stripe */
  112         plexblkno = sd->plexoffset                          /* base */
  113             + (sd->revived - stripeoffset) * (plex->subdisks - 1) /* offset to beginning of stripe */
  114             +stripeoffset;                                  /* offset from beginning of stripe */
  115         stripe = (sd->revived / plex->stripesize);          /* stripe number */
  116 
  117         /* Make sure we don't go beyond the end of the band. */
  118         size = min(size, (plex->stripesize - stripeoffset) << DEV_BSHIFT);
  119         if (plex->organization == plex_raid4)
  120             psd = plex->subdisks - 1;                       /* parity subdisk for this stripe */
  121         else
  122             psd = plex->subdisks - 1 - stripe % plex->subdisks; /* parity subdisk for this stripe */
  123         paritysd = plex->sdnos[psd] == sdno;                /* note if it's the parity subdisk */
  124 
  125         /*
  126          * Now adjust for the strangenesses
  127          * in RAID-4 and RAID-5 striping.
  128          */
  129         if (sd->plexsdno > psd)                             /* beyond the parity stripe, */
  130             plexblkno -= plex->stripesize;                  /* one stripe less */
  131         else if (paritysd)
  132             plexblkno -= plex->stripesize * sd->plexsdno;   /* go back to the beginning of the band */
  133         break;
  134 
  135     case plex_disorg:                                       /* to keep the compiler happy */
  136         break;                                              /* to keep the pedants happy */
  137     }
  138 
  139     if (paritysd) {                                         /* we're reviving a parity block, */
  140         bp = parityrebuild(plex, sd->revived, size, rebuildparity, &lock, NULL); /* do the grunt work */
  141         if (bp == NULL)                                     /* no buffer space */
  142             return ENOMEM;                                  /* chicken out */
  143     } else {                                                /* data block */
  144         s = splbio();
  145         bp = geteblk(size);                                 /* Get a buffer */
  146         splx(s);
  147         if (bp == NULL)
  148             return ENOMEM;
  149 
  150         /*
  151          * Amount to transfer: block size, unless it
  152          * would overlap the end.
  153          */
  154         bp->b_bcount = size;
  155         bp->b_resid = bp->b_bcount;
  156         bp->b_blkno = plexblkno;                            /* start here */
  157         if (isstriped(plex))                                /* we need to lock striped plexes */
  158             lock = lockrange(plexblkno << DEV_BSHIFT, bp, plex); /* lock it */
  159         if (vol != NULL)                                    /* it's part of a volume, */
  160             /*
  161                * First, read the data from the volume.  We
  162                * don't care which plex, that's bre's job.
  163              */
  164             bp->b_dev = VOL[plex->volno].dev;               /* create the device number */
  165         else                                                /* it's an unattached plex */
  166             bp->b_dev = PLEX[sd->plexno].dev;               /* create the device number */
  167 
  168         bp->b_iocmd = BIO_READ;                             /* either way, read it */
  169         bp->b_flags = 0;
  170         vinumstart(bp, 1);
  171         bufwait(bp);
  172     }
  173 
  174     if (bp->b_ioflags & BIO_ERROR) {
  175         error = bp->b_error;
  176         if (lock)                                           /* we took a lock, */
  177             unlockrange(sd->plexno, lock);                  /* give it back */
  178     } else
  179         /* Now write to the subdisk */
  180     {
  181         bp->b_dev = SD[sdno].dev;                           /* create the device number */
  182         bp->b_flags &= ~B_DONE;                             /* no longer done */
  183         bp->b_ioflags = 0;
  184         bp->b_iocmd = BIO_WRITE;
  185         bp->b_resid = bp->b_bcount;
  186         bp->b_blkno = sd->revived;                          /* write it to here */
  187         sdio(bp);                                           /* perform the I/O */
  188         bufwait(bp);
  189         if (bp->b_ioflags & BIO_ERROR)
  190             error = bp->b_error;
  191         else {
  192             sd->revived += bp->b_bcount >> DEV_BSHIFT;      /* moved this much further down */
  193             if (sd->revived >= sd->sectors) {               /* finished */
  194                 sd->revived = 0;
  195                 set_sd_state(sdno, sd_up, setstate_force);  /* bring the sd up */
  196                 log(LOG_INFO, "vinum: %s is %s\n", sd->name, sd_state(sd->state));
  197                 save_config();                              /* and save the updated configuration */
  198                 error = 0;                                  /* we're done */
  199             }
  200         }
  201         if (lock)                                           /* we took a lock, */
  202             unlockrange(sd->plexno, lock);                  /* give it back */
  203         while (sd->waitlist) {                              /* we have waiting requests */
  204 #ifdef VINUMDEBUG
  205             struct request *rq = sd->waitlist;
  206 
  207             if (debug & DEBUG_REVIVECONFLICT)
  208                 log(LOG_DEBUG,
  209                     "Relaunch revive conflict sd %d: %p\n%s dev %d.%d, offset 0x%jx, length %ld\n",
  210                     rq->sdno,
  211                     rq,
  212                     rq->bp->b_iocmd == BIO_READ ? "Read" : "Write",
  213                     major(rq->bp->b_dev),
  214                     minor(rq->bp->b_dev),
  215                     (intmax_t) rq->bp->b_blkno,
  216                     rq->bp->b_bcount);
  217 #endif
  218             launch_requests(sd->waitlist, 1);               /* do them now */
  219             sd->waitlist = sd->waitlist->next;              /* and move on to the next */
  220         }
  221     }
  222     if (bp->b_qindex == 0) {                                /* not on a queue, */
  223         bp->b_flags |= B_INVAL;
  224         bp->b_ioflags &= ~BIO_ERROR;
  225         brelse(bp);                                         /* is this kosher? */
  226     }
  227     return error;
  228 }
  229 
  230 /*
  231  * Check or rebuild the parity blocks of a RAID-4
  232  * or RAID-5 plex.
  233  *
  234  * The variables plex->checkblock and
  235  * plex->rebuildblock represent the
  236  * subdisk-relative address of the stripe we're
  237  * looking at, not the plex-relative address.  We
  238  * store it in the plex and not as a local
  239  * variable because this function could be
  240  * stopped, and we don't want to repeat the part
  241  * we've already done.  This is also the reason
  242  * why we don't initialize it here except at the
  243  * end.  It gets initialized with the plex on
  244  * creation.
  245  *
  246  * Each call to this function processes at most
  247  * one stripe.  We can't loop in this function,
  248  * because we're unstoppable, so we have to be
  249  * called repeatedly from userland.
  250  */
  251 void
  252 parityops(struct vinum_ioctl_msg *data)
  253 {
  254     int plexno;
  255     struct plex *plex;
  256     int size;                                               /* I/O transfer size, bytes */
  257     int stripe;                                             /* stripe number in plex */
  258     int psd;                                                /* parity subdisk number */
  259     struct rangelock *lock;                                 /* lock on stripe */
  260     struct _ioctl_reply *reply;
  261     off_t pstripe;                                          /* pointer to our stripe counter */
  262     struct buf *pbp;
  263     off_t errorloc;                                         /* offset of parity error */
  264     enum parityop op;                                       /* operation to perform */
  265 
  266     plexno = data->index;
  267     op = data->op;
  268     pbp = NULL;
  269     reply = (struct _ioctl_reply *) data;
  270     reply->error = EAGAIN;                                  /* expect to repeat this call */
  271     plex = &PLEX[plexno];
  272     if (!isparity(plex)) {                                  /* not RAID-4 or RAID-5 */
  273         reply->error = EINVAL;
  274         return;
  275     } else if (plex->state < plex_flaky) {
  276         reply->error = EIO;
  277         strcpy(reply->msg, "Plex is not completely accessible\n");
  278         return;
  279     }
  280     pstripe = data->offset;
  281     stripe = pstripe / plex->stripesize;                    /* stripe number */
  282     psd = plex->subdisks - 1 - stripe % plex->subdisks;     /* parity subdisk for this stripe */
  283     size = min(DEFAULT_REVIVE_BLOCKSIZE,                    /* one block at a time */
  284         plex->stripesize << DEV_BSHIFT);
  285 
  286     pbp = parityrebuild(plex, pstripe, size, op, &lock, &errorloc); /* do the grunt work */
  287     if (pbp == NULL) {                                      /* no buffer space */
  288         reply->error = ENOMEM;
  289         return;                                             /* chicken out */
  290     }
  291     /*
  292      * Now we have a result in the data buffer of
  293      * the parity buffer header, which we have kept.
  294      * Decide what to do with it.
  295      */
  296     reply->msg[0] = '\0';                                   /* until shown otherwise */
  297     if ((pbp->b_ioflags & BIO_ERROR) == 0) {                /* no error */
  298         if ((op == rebuildparity)
  299             || (op == rebuildandcheckparity)) {
  300             pbp->b_iocmd = BIO_WRITE;
  301             pbp->b_resid = pbp->b_bcount;
  302             sdio(pbp);                                      /* write the parity block */
  303             bufwait(pbp);
  304         }
  305         if (((op == checkparity)
  306                 || (op == rebuildandcheckparity))
  307             && (errorloc != -1)) {
  308             if (op == checkparity)
  309                 reply->error = EIO;
  310             sprintf(reply->msg,
  311                 "Parity incorrect at offset 0x%jx\n",
  312                 (intmax_t) errorloc);
  313         }
  314         if (reply->error == EAGAIN) {                       /* still OK, */
  315             plex->checkblock = pstripe + (pbp->b_bcount >> DEV_BSHIFT); /* moved this much further down */
  316             if (plex->checkblock >= SD[plex->sdnos[0]].sectors) { /* finished */
  317                 plex->checkblock = 0;
  318                 reply->error = 0;
  319             }
  320         }
  321     }
  322     if (pbp->b_ioflags & BIO_ERROR)
  323         reply->error = pbp->b_error;
  324     pbp->b_flags |= B_INVAL;
  325     pbp->b_ioflags &= ~BIO_ERROR;
  326     brelse(pbp);
  327     unlockrange(plexno, lock);
  328 }
  329 
  330 /*
  331  * Rebuild a parity stripe.  Return pointer to
  332  * parity bp.  On return,
  333  *
  334  * 1.  The band is locked.  The caller must unlock
  335  *     the band and release the buffer header.
  336  *
  337  * 2.  All buffer headers except php have been
  338  *     released.  The caller must release pbp.
  339  *
  340  * 3.  For checkparity and rebuildandcheckparity,
  341  *     the parity is compared with the current
  342  *     parity block.  If it's different, the
  343  *     offset of the error is returned to
  344  *     errorloc.  The caller can set the value of
  345  *     the pointer to NULL if this is called for
  346  *     rebuilding parity.
  347  *
  348  * pstripe is the subdisk-relative base address of
  349  * the data to be reconstructed, size is the size
  350  * of the transfer in bytes.
  351  */
  352 struct buf *
  353 parityrebuild(struct plex *plex,
  354     u_int64_t pstripe,
  355     int size,
  356     enum parityop op,
  357     struct rangelock **lockp,
  358     off_t * errorloc)
  359 {
  360     int error;
  361     int s;
  362     int sdno;
  363     u_int64_t stripe;                                       /* stripe number */
  364     int *parity_buf;                                        /* buffer address for current parity block */
  365     int *newparity_buf;                                     /* and for new parity block */
  366     int mysize;                                             /* I/O transfer size for this transfer */
  367     int isize;                                              /* mysize in ints */
  368     int i;
  369     int psd;                                                /* parity subdisk number */
  370     int newpsd;                                             /* and "subdisk number" of new parity */
  371     struct buf **bpp;                                       /* pointers to our bps */
  372     struct buf *pbp;                                        /* buffer header for parity stripe */
  373     int *sbuf;
  374     int bufcount;                                           /* number of buffers we need */
  375 
  376     stripe = pstripe / plex->stripesize;                    /* stripe number */
  377     psd = plex->subdisks - 1 - stripe % plex->subdisks;     /* parity subdisk for this stripe */
  378     parity_buf = NULL;                                      /* to keep the compiler happy */
  379     error = 0;
  380 
  381     /*
  382      * It's possible that the default transfer size
  383      * we chose is not a factor of the stripe size.
  384      * We *must* limit this operation to a single
  385      * stripe, at least for RAID-5 rebuild, since
  386      * the parity subdisk changes between stripes,
  387      * so in this case we need to perform a short
  388      * transfer.  Set variable mysize to reflect
  389      * this.
  390      */
  391     mysize = min(size, (plex->stripesize * (stripe + 1) - pstripe) << DEV_BSHIFT);
  392     isize = mysize / (sizeof(int));                         /* number of ints in the buffer */
  393     bufcount = plex->subdisks + 1;                          /* sd buffers plus result buffer */
  394     newpsd = plex->subdisks;
  395     bpp = (struct buf **) Malloc(bufcount * sizeof(struct buf *)); /* array of pointers to bps */
  396 
  397     /* First, build requests for all subdisks */
  398     for (sdno = 0; sdno < bufcount; sdno++) {               /* for each subdisk */
  399         if ((sdno != psd) || (op != rebuildparity)) {
  400             /* Get a buffer header and initialize it. */
  401             s = splbio();
  402             bpp[sdno] = geteblk(mysize);                    /* Get a buffer */
  403             if (bpp[sdno] == NULL) {
  404                 while (sdno-- > 0) {                        /* release the ones we got */
  405                     bpp[sdno]->b_flags |= B_INVAL;
  406                     brelse(bpp[sdno]);                      /* give back our resources */
  407                 }
  408                 splx(s);
  409                 printf("vinum: can't allocate buffer space for parity op.\n");
  410                 return NULL;                                /* no bpps */
  411             }
  412             splx(s);
  413             if (sdno == psd)
  414                 parity_buf = (int *) bpp[sdno]->b_data;
  415             if (sdno == newpsd)                             /* the new one? */
  416                 bpp[sdno]->b_dev = SD[plex->sdnos[psd]].dev; /* write back to the parity SD */
  417             else
  418                 bpp[sdno]->b_dev = SD[plex->sdnos[sdno]].dev; /* device number */
  419             bpp[sdno]->b_iocmd = BIO_READ;                  /* either way, read it */
  420             bpp[sdno]->b_flags = 0;
  421             bpp[sdno]->b_bcount = mysize;
  422             bpp[sdno]->b_resid = bpp[sdno]->b_bcount;
  423             bpp[sdno]->b_blkno = pstripe;                   /* transfer from here */
  424         }
  425     }
  426 
  427     /* Initialize result buffer */
  428     pbp = bpp[newpsd];
  429     newparity_buf = (int *) bpp[newpsd]->b_data;
  430     bzero(newparity_buf, mysize);
  431 
  432     /*
  433      * Now lock the stripe with the first non-parity
  434      * bp as locking bp.
  435      */
  436     *lockp = lockrange(pstripe * plex->stripesize * (plex->subdisks - 1),
  437         bpp[psd ? 0 : 1],
  438         plex);
  439 
  440     /*
  441      * Then issue requests for all subdisks in
  442      * parallel.  Don't transfer the parity stripe
  443      * if we're rebuilding parity, unless we also
  444      * want to check it.
  445      */
  446     for (sdno = 0; sdno < plex->subdisks; sdno++) {         /* for each real subdisk */
  447         if ((sdno != psd) || (op != rebuildparity)) {
  448             sdio(bpp[sdno]);
  449         }
  450     }
  451 
  452     /*
  453      * Next, wait for the requests to complete.
  454      * We wait in the order in which they were
  455      * issued, which isn't necessarily the order in
  456      * which they complete, but we don't have a
  457      * convenient way of doing the latter, and the
  458      * delay is minimal.
  459      */
  460     for (sdno = 0; sdno < plex->subdisks; sdno++) {         /* for each subdisk */
  461         if ((sdno != psd) || (op != rebuildparity)) {
  462             bufwait(bpp[sdno]);
  463             if (bpp[sdno]->b_ioflags & BIO_ERROR)           /* can't read, */
  464                 error = bpp[sdno]->b_error;
  465             else if (sdno != psd) {                         /* update parity */
  466                 sbuf = (int *) bpp[sdno]->b_data;
  467                 for (i = 0; i < isize; i++)
  468                     ((int *) newparity_buf)[i] ^= sbuf[i];  /* xor in the buffer */
  469             }
  470         }
  471         if (sdno != psd) {                                  /* release all bps except parity */
  472             bpp[sdno]->b_flags |= B_INVAL;
  473             brelse(bpp[sdno]);                              /* give back our resources */
  474         }
  475     }
  476 
  477     /*
  478      * If we're checking, compare the calculated
  479      * and the read parity block.  If they're
  480      * different, return the plex-relative offset;
  481      * otherwise return -1.
  482      */
  483     if ((op == checkparity)
  484         || (op == rebuildandcheckparity)) {
  485         *errorloc = -1;                                     /* no error yet */
  486         for (i = 0; i < isize; i++) {
  487             if (parity_buf[i] != newparity_buf[i]) {
  488                 *errorloc = (off_t) (pstripe << DEV_BSHIFT) * (plex->subdisks - 1)
  489                     + i * sizeof(int);
  490                 break;
  491             }
  492         }
  493         bpp[psd]->b_flags |= B_INVAL;
  494         brelse(bpp[psd]);                                   /* give back our resources */
  495     }
  496     /* release our resources */
  497     Free(bpp);
  498     if (error) {
  499         pbp->b_ioflags |= BIO_ERROR;
  500         pbp->b_error = error;
  501     }
  502     return pbp;
  503 }
  504 
  505 /*
  506  * Initialize a subdisk by writing zeroes to the
  507  * complete address space.  If verify is set,
  508  * check each transfer for correctness.
  509  *
  510  * Each call to this function writes (and maybe
  511  * checks) a single block.
  512  */
  513 int
  514 initsd(int sdno, int verify)
  515 {
  516     int s;                                                  /* priority level */
  517     struct sd *sd;
  518     struct plex *plex;
  519     struct volume *vol;
  520     struct buf *bp;
  521     int error;
  522     int size;                                               /* size of init block, bytes */
  523     daddr_t plexblkno;                                      /* lblkno in plex */
  524     int verified;                                           /* set when we're happy with what we wrote */
  525 
  526     error = 0;
  527     plexblkno = 0;                                          /* to keep the compiler happy */
  528     sd = &SD[sdno];
  529     if (sd->plexno < 0)                                     /* no plex? */
  530         return EINVAL;
  531     plex = &PLEX[sd->plexno];                               /* point to plex */
  532     if (plex->volno >= 0)
  533         vol = &VOL[plex->volno];
  534     else
  535         vol = NULL;
  536 
  537     if (sd->init_blocksize == 0) {
  538         sd->init_blocksize = DEFAULT_REVIVE_BLOCKSIZE;
  539     } else if (sd->init_blocksize > MAX_REVIVE_BLOCKSIZE)
  540         sd->init_blocksize = MAX_REVIVE_BLOCKSIZE;
  541 
  542     size = min(sd->init_blocksize >> DEV_BSHIFT, sd->sectors - sd->initialized) << DEV_BSHIFT;
  543 
  544     verified = 0;
  545     while (!verified) {                                     /* until we're happy with it, */
  546         s = splbio();
  547         bp = geteblk(size);                                 /* Get a buffer */
  548         splx(s);
  549         if (bp == NULL)
  550             return ENOMEM;
  551 
  552         bp->b_bcount = size;
  553         bp->b_resid = bp->b_bcount;
  554         bp->b_blkno = sd->initialized;                      /* write it to here */
  555         bzero(bp->b_data, bp->b_bcount);
  556         bp->b_dev = SD[sdno].dev;                           /* create the device number */
  557         bp->b_iocmd = BIO_WRITE;
  558         sdio(bp);                                           /* perform the I/O */
  559         bufwait(bp);
  560         if (bp->b_ioflags & BIO_ERROR)
  561             error = bp->b_error;
  562         if (bp->b_qindex == 0) {                            /* not on a queue, */
  563             bp->b_flags |= B_INVAL;
  564             bp->b_ioflags &= ~BIO_ERROR;
  565             brelse(bp);                                     /* is this kosher? */
  566         }
  567         if ((error == 0) && verify) {                       /* check that it got there */
  568             s = splbio();
  569             bp = geteblk(size);                             /* get a buffer */
  570             if (bp == NULL) {
  571                 splx(s);
  572                 error = ENOMEM;
  573             } else {
  574                 bp->b_bcount = size;
  575                 bp->b_resid = bp->b_bcount;
  576                 bp->b_blkno = sd->initialized;              /* read from here */
  577                 bp->b_dev = SD[sdno].dev;                   /* create the device number */
  578                 bp->b_iocmd = BIO_READ;                     /* read it back */
  579                 splx(s);
  580                 sdio(bp);
  581                 bufwait(bp);
  582                 /*
  583                  * XXX Bug fix code.  This is hopefully no
  584                  * longer needed (21 February 2000).
  585                  */
  586                 if (bp->b_ioflags & BIO_ERROR)
  587                     error = bp->b_error;
  588                 else if ((*bp->b_data != 0)                 /* first word spammed */
  589                 ||(bcmp(bp->b_data, &bp->b_data[1], bp->b_bcount - 1))) { /* or one of the others */
  590                     printf("vinum: init error on %s, offset 0x%llx sectors\n",
  591                         sd->name,
  592                         (long long) sd->initialized);
  593                     verified = 0;
  594                 } else
  595                     verified = 1;
  596                 if (bp->b_qindex == 0) {                    /* not on a queue, */
  597                     bp->b_flags |= B_INVAL;
  598                     bp->b_ioflags &= ~BIO_ERROR;
  599                     brelse(bp);                             /* is this kosher? */
  600                 }
  601             }
  602         } else
  603             verified = 1;
  604     }
  605     if (error == 0) {                                       /* did it, */
  606         sd->initialized += size >> DEV_BSHIFT;              /* moved this much further down */
  607         if (sd->initialized >= sd->sectors) {               /* finished */
  608             sd->initialized = 0;
  609             set_sd_state(sdno, sd_initialized, setstate_force); /* bring the sd up */
  610             log(LOG_INFO, "vinum: %s is %s\n", sd->name, sd_state(sd->state));
  611             save_config();                                  /* and save the updated configuration */
  612         } else                                              /* more to go, */
  613             error = EAGAIN;                                 /* ya'll come back, see? */
  614     }
  615     return error;
  616 }
  617 
  618 /* Local Variables: */
  619 /* fill-column: 50 */
  620 /* End: */

Cache object: 19b4b8774a6c11a620ce9ecc05c583dc


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