[BACK]Return to rf_copyback.c CVS log [TXT][DIR] Up to [local] / sys / dev / raidframe

Annotation of sys/dev/raidframe/rf_copyback.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: rf_copyback.c,v 1.8 2007/06/05 00:38:22 deraadt Exp $ */
        !             2: /*     $NetBSD: rf_copyback.c,v 1.14 2000/03/07 02:59:50 oster Exp $   */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1995 Carnegie-Mellon University.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Author: Mark Holland
        !             9:  *
        !            10:  * Permission to use, copy, modify and distribute this software and
        !            11:  * its documentation is hereby granted, provided that both the copyright
        !            12:  * notice and this permission notice appear in all copies of the
        !            13:  * software, derivative works or modified versions, and any portions
        !            14:  * thereof, and that both notices appear in supporting documentation.
        !            15:  *
        !            16:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            17:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
        !            18:  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            19:  *
        !            20:  * Carnegie Mellon requests users of this software to return to
        !            21:  *
        !            22:  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
        !            23:  *  School of Computer Science
        !            24:  *  Carnegie Mellon University
        !            25:  *  Pittsburgh PA 15213-3890
        !            26:  *
        !            27:  * any improvements or extensions that they make and grant Carnegie the
        !            28:  * rights to redistribute these changes.
        !            29:  */
        !            30:
        !            31:
        !            32: /*****************************************************************************
        !            33:  *
        !            34:  * copyback.c -- Code to copy reconstructed data back from spare space to
        !            35:  *              the replaced disk.
        !            36:  *
        !            37:  * The code operates using callbacks on the I/Os to continue with the next
        !            38:  * unit to be copied back. We do this because a simple loop containing
        !            39:  * blocking I/Os will not work in the simulator.
        !            40:  *
        !            41:  *****************************************************************************/
        !            42:
        !            43: #include "rf_types.h"
        !            44:
        !            45: #include <sys/time.h>
        !            46: #include <sys/buf.h>
        !            47: #include "rf_raid.h"
        !            48: #include "rf_mcpair.h"
        !            49: #include "rf_acctrace.h"
        !            50: #include "rf_etimer.h"
        !            51: #include "rf_general.h"
        !            52: #include "rf_utils.h"
        !            53: #include "rf_copyback.h"
        !            54: #include "rf_decluster.h"
        !            55: #include "rf_driver.h"
        !            56: #include "rf_shutdown.h"
        !            57: #include "rf_kintf.h"
        !            58:
        !            59: #define        RF_COPYBACK_DATA        0
        !            60: #define        RF_COPYBACK_PARITY      1
        !            61:
        !            62: int    rf_copyback_in_progress;
        !            63:
        !            64: int  rf_CopybackReadDoneProc(RF_CopybackDesc_t *, int);
        !            65: int  rf_CopybackWriteDoneProc(RF_CopybackDesc_t *, int);
        !            66: void rf_CopybackOne(RF_CopybackDesc_t *, int, RF_RaidAddr_t,
        !            67:        RF_RowCol_t, RF_RowCol_t, RF_SectorNum_t);
        !            68: void rf_CopybackComplete(RF_CopybackDesc_t *, int);
        !            69:
        !            70: int
        !            71: rf_ConfigureCopyback(RF_ShutdownList_t **listp)
        !            72: {
        !            73:        rf_copyback_in_progress = 0;
        !            74:        return (0);
        !            75: }
        !            76:
        !            77: #include <sys/types.h>
        !            78: #include <sys/param.h>
        !            79: #include <sys/systm.h>
        !            80: #include <sys/proc.h>
        !            81: #include <sys/ioctl.h>
        !            82: #include <sys/fcntl.h>
        !            83: #ifdef __NETBSD__
        !            84: #include <sys/vnode.h>
        !            85: #endif
        !            86:
        !            87:
        !            88: /* Do a complete copyback. */
        !            89: void
        !            90: rf_CopybackReconstructedData(RF_Raid_t *raidPtr)
        !            91: {
        !            92:        RF_ComponentLabel_t c_label;
        !            93:        int done, retcode;
        !            94:        RF_CopybackDesc_t *desc;
        !            95:        RF_RowCol_t frow, fcol;
        !            96:        RF_RaidDisk_t *badDisk;
        !            97:        char *databuf;
        !            98:
        !            99:        struct partinfo dpart;
        !           100:        struct vnode *vp;
        !           101:        struct vattr va;
        !           102:        struct proc *proc;
        !           103:
        !           104:        int ac;
        !           105:
        !           106:        done = 0;
        !           107:        fcol = 0;
        !           108:        for (frow = 0; frow < raidPtr->numRow; frow++) {
        !           109:                for (fcol = 0; fcol < raidPtr->numCol; fcol++) {
        !           110:                        if (raidPtr->Disks[frow][fcol].status ==
        !           111:                             rf_ds_dist_spared ||
        !           112:                            raidPtr->Disks[frow][fcol].status ==
        !           113:                             rf_ds_spared) {
        !           114:                                done = 1;
        !           115:                                break;
        !           116:                        }
        !           117:                }
        !           118:                if (done)
        !           119:                        break;
        !           120:        }
        !           121:
        !           122:        if (frow == raidPtr->numRow) {
        !           123:                printf("COPYBACK: No disks need copyback.\n");
        !           124:                return;
        !           125:        }
        !           126:        badDisk = &raidPtr->Disks[frow][fcol];
        !           127:
        !           128:        proc = raidPtr->engine_thread;
        !           129:
        !           130:        /*
        !           131:         * This device may have been opened successfully the first time.
        !           132:         * Close it before trying to open it again.
        !           133:         */
        !           134:
        !           135:        if (raidPtr->raid_cinfo[frow][fcol].ci_vp != NULL) {
        !           136:                printf("Close the opened device: %s.\n",
        !           137:                    raidPtr->Disks[frow][fcol].devname);
        !           138:                vp = raidPtr->raid_cinfo[frow][fcol].ci_vp;
        !           139:                ac = raidPtr->Disks[frow][fcol].auto_configured;
        !           140:                rf_close_component(raidPtr, vp, ac);
        !           141:                raidPtr->raid_cinfo[frow][fcol].ci_vp = NULL;
        !           142:
        !           143:        }
        !           144:        /* Note that this disk was *not* auto_configured (any longer). */
        !           145:        raidPtr->Disks[frow][fcol].auto_configured = 0;
        !           146:
        !           147:        printf("About to (re-)open the device: %s.\n",
        !           148:            raidPtr->Disks[frow][fcol].devname);
        !           149:
        !           150:        retcode = raidlookup(raidPtr->Disks[frow][fcol].devname, proc, &vp);
        !           151:
        !           152:        if (retcode) {
        !           153:                printf("COPYBACK: raidlookup on device: %s failed: %d !\n",
        !           154:                    raidPtr->Disks[frow][fcol].devname, retcode);
        !           155:
        !           156:                /*
        !           157:                 * XXX The component isn't responding properly... Must be
        !           158:                 * still dead :-(
        !           159:                 */
        !           160:                return;
        !           161:
        !           162:        } else {
        !           163:
        !           164:                /*
        !           165:                 * Ok, so we can at least do a lookup...
        !           166:                 * How about actually getting a vp for it ?
        !           167:                 */
        !           168:
        !           169:                if ((retcode = VOP_GETATTR(vp, &va, proc->p_ucred, proc)) != 0)
        !           170:                {
        !           171:                        return;
        !           172:                }
        !           173:                retcode = VOP_IOCTL(vp, DIOCGPART, (caddr_t) &dpart, FREAD,
        !           174:                    proc->p_ucred, proc);
        !           175:                if (retcode) {
        !           176:                        return;
        !           177:                }
        !           178:                raidPtr->Disks[frow][fcol].blockSize = dpart.disklab->d_secsize;
        !           179:
        !           180:                raidPtr->Disks[frow][fcol].numBlocks = DL_GETPSIZE(dpart.part) -
        !           181:                    rf_protectedSectors;
        !           182:
        !           183:                raidPtr->raid_cinfo[frow][fcol].ci_vp = vp;
        !           184:                raidPtr->raid_cinfo[frow][fcol].ci_dev = va.va_rdev;
        !           185:
        !           186:                /* XXX Or the above ? */
        !           187:                raidPtr->Disks[frow][fcol].dev = va.va_rdev;
        !           188:
        !           189:                /*
        !           190:                 * We allow the user to specify that only a fraction of the
        !           191:                 * disks should be used this is just for debug: it speeds up
        !           192:                 * the parity scan.
        !           193:                 */
        !           194:                raidPtr->Disks[frow][fcol].numBlocks =
        !           195:                    raidPtr->Disks[frow][fcol].numBlocks *
        !           196:                    rf_sizePercentage / 100;
        !           197:        }
        !           198: #if 0
        !           199:        /* This is the way it was done before the CAM stuff was removed. */
        !           200:
        !           201:        if (rf_extract_ids(badDisk->devname, &bus, &targ, &lun)) {
        !           202:                printf("COPYBACK: unable to extract bus, target, lun from"
        !           203:                    " devname %s.\n", badDisk->devname);
        !           204:                return;
        !           205:        }
        !           206:        /*
        !           207:         * TUR the disk that's marked as bad to be sure that it's actually
        !           208:         * alive.
        !           209:         */
        !           210:        rf_SCSI_AllocTUR(&tur_op);
        !           211:        retcode = rf_SCSI_DoTUR(tur_op, bus, targ, lun, badDisk->dev);
        !           212:        rf_SCSI_FreeDiskOp(tur_op, 0);
        !           213: #endif
        !           214:
        !           215:        if (retcode) {
        !           216:                printf("COPYBACK: target disk failed TUR.\n");
        !           217:                return;
        !           218:        }
        !           219:        /* Get a buffer to hold one SU. */
        !           220:        RF_Malloc(databuf, rf_RaidAddressToByte(raidPtr,
        !           221:            raidPtr->Layout.sectorsPerStripeUnit), (char *));
        !           222:
        !           223:        /* Create a descriptor. */
        !           224:        RF_Malloc(desc, sizeof(*desc), (RF_CopybackDesc_t *));
        !           225:        desc->raidPtr = raidPtr;
        !           226:        desc->status = 0;
        !           227:        desc->frow = frow;
        !           228:        desc->fcol = fcol;
        !           229:        desc->spRow = badDisk->spareRow;
        !           230:        desc->spCol = badDisk->spareCol;
        !           231:        desc->stripeAddr = 0;
        !           232:        desc->sectPerSU = raidPtr->Layout.sectorsPerStripeUnit;
        !           233:        desc->sectPerStripe = raidPtr->Layout.sectorsPerStripeUnit *
        !           234:            raidPtr->Layout.numDataCol;
        !           235:        desc->databuf = databuf;
        !           236:        desc->mcpair = rf_AllocMCPair();
        !           237:
        !           238:        printf("COPYBACK: Quiescing the array.\n");
        !           239:        /*
        !           240:         * Quiesce the array, since we don't want to code support for user
        !           241:         * accs here.
        !           242:         */
        !           243:        rf_SuspendNewRequestsAndWait(raidPtr);
        !           244:
        !           245:        /* Adjust state of the array and of the disks. */
        !           246:        RF_LOCK_MUTEX(raidPtr->mutex);
        !           247:        raidPtr->Disks[desc->frow][desc->fcol].status = rf_ds_optimal;
        !           248:        raidPtr->status[desc->frow] = rf_rs_optimal;
        !           249:        rf_copyback_in_progress = 1;    /* Debug only. */
        !           250:        RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           251:
        !           252:        printf("COPYBACK: Beginning\n");
        !           253:        RF_GETTIME(desc->starttime);
        !           254:        rf_ContinueCopyback(desc);
        !           255:
        !           256:        /*
        !           257:         * Data has been restored.
        !           258:         * Fix up the component label.
        !           259:         * Don't actually need the read here.
        !           260:         */
        !           261:        raidread_component_label(raidPtr->raid_cinfo[frow][fcol].ci_dev,
        !           262:                                 raidPtr->raid_cinfo[frow][fcol].ci_vp,
        !           263:                                 &c_label);
        !           264:
        !           265:        raid_init_component_label(raidPtr, &c_label);
        !           266:
        !           267:        c_label.row = frow;
        !           268:        c_label.column = fcol;
        !           269:
        !           270:        raidwrite_component_label(raidPtr->raid_cinfo[frow][fcol].ci_dev,
        !           271:                                  raidPtr->raid_cinfo[frow][fcol].ci_vp,
        !           272:                                  &c_label);
        !           273: }
        !           274:
        !           275:
        !           276: /*
        !           277:  * Invoked via callback after a copyback I/O has completed to
        !           278:  * continue on with the next one.
        !           279:  */
        !           280: void
        !           281: rf_ContinueCopyback(RF_CopybackDesc_t *desc)
        !           282: {
        !           283:        RF_SectorNum_t testOffs, stripeAddr;
        !           284:        RF_Raid_t *raidPtr = desc->raidPtr;
        !           285:        RF_RaidAddr_t addr;
        !           286:        RF_RowCol_t testRow, testCol;
        !           287:        int old_pctg, new_pctg, done;
        !           288:        struct timeval t, diff;
        !           289:
        !           290:        old_pctg = (-1);
        !           291:        while (1) {
        !           292:                stripeAddr = desc->stripeAddr;
        !           293:                desc->raidPtr->copyback_stripes_done = stripeAddr /
        !           294:                    desc->sectPerStripe;
        !           295:                if (rf_prReconSched) {
        !           296:                        old_pctg = 100 * desc->stripeAddr /
        !           297:                            raidPtr->totalSectors;
        !           298:                }
        !           299:                desc->stripeAddr += desc->sectPerStripe;
        !           300:                if (rf_prReconSched) {
        !           301:                        new_pctg = 100 * desc->stripeAddr /
        !           302:                            raidPtr->totalSectors;
        !           303:                        if (new_pctg != old_pctg) {
        !           304:                                RF_GETTIME(t);
        !           305:                                RF_TIMEVAL_DIFF(&desc->starttime, &t, &diff);
        !           306:                                printf("%d %d.%06d\n", new_pctg,
        !           307:                                    (int) diff.tv_sec, (int) diff.tv_usec);
        !           308:                        }
        !           309:                }
        !           310:                if (stripeAddr >= raidPtr->totalSectors) {
        !           311:                        rf_CopybackComplete(desc, 0);
        !           312:                        return;
        !           313:                }
        !           314:                /* Walk through the current stripe, su-by-su. */
        !           315:                for (done = 0, addr = stripeAddr;
        !           316:                     addr < stripeAddr + desc->sectPerStripe;
        !           317:                     addr += desc->sectPerSU) {
        !           318:
        !           319:                        /* Map the SU, disallowing remap to spare space. */
        !           320:                        (raidPtr->Layout.map->MapSector) (raidPtr, addr,
        !           321:                            &testRow, &testCol, &testOffs, RF_DONT_REMAP);
        !           322:
        !           323:                        if (testRow == desc->frow && testCol == desc->fcol) {
        !           324:                                rf_CopybackOne(desc, RF_COPYBACK_DATA, addr,
        !           325:                                    testRow, testCol, testOffs);
        !           326:                                done = 1;
        !           327:                                break;
        !           328:                        }
        !           329:                }
        !           330:
        !           331:                if (!done) {
        !           332:                        /*
        !           333:                         * We didn't find the failed disk in the data part,
        !           334:                         * check parity.
        !           335:                         */
        !           336:
        !           337:                        /*
        !           338:                         * Map the parity for this stripe, disallowing remap
        !           339:                         * to spare space.
        !           340:                         */
        !           341:                        (raidPtr->Layout.map->MapParity) (raidPtr, stripeAddr,
        !           342:                            &testRow, &testCol, &testOffs, RF_DONT_REMAP);
        !           343:
        !           344:                        if (testRow == desc->frow && testCol == desc->fcol) {
        !           345:                                rf_CopybackOne(desc, RF_COPYBACK_PARITY,
        !           346:                                    stripeAddr, testRow, testCol, testOffs);
        !           347:                        }
        !           348:                }
        !           349:                /* Check to see if the last read/write pair failed. */
        !           350:                if (desc->status) {
        !           351:                        rf_CopybackComplete(desc, 1);
        !           352:                        return;
        !           353:                }
        !           354:                /*
        !           355:                 * We didn't find any units to copy back in this stripe.
        !           356:                 * Continue with the next one.
        !           357:                 */
        !           358:        }
        !           359: }
        !           360:
        !           361:
        !           362: /* Copyback one unit. */
        !           363: void
        !           364: rf_CopybackOne(RF_CopybackDesc_t *desc, int typ, RF_RaidAddr_t addr,
        !           365:     RF_RowCol_t testRow, RF_RowCol_t testCol, RF_SectorNum_t testOffs)
        !           366: {
        !           367:        RF_SectorCount_t sectPerSU = desc->sectPerSU;
        !           368:        RF_Raid_t *raidPtr = desc->raidPtr;
        !           369:        RF_RowCol_t spRow = desc->spRow;
        !           370:        RF_RowCol_t spCol = desc->spCol;
        !           371:        RF_SectorNum_t spOffs;
        !           372:
        !           373:        /* Find the spare location for this SU. */
        !           374:        if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
        !           375:                if (typ == RF_COPYBACK_DATA)
        !           376:                        raidPtr->Layout.map->MapSector(raidPtr, addr, &spRow,
        !           377:                            &spCol, &spOffs, RF_REMAP);
        !           378:                else
        !           379:                        raidPtr->Layout.map->MapParity(raidPtr, addr, &spRow,
        !           380:                            &spCol, &spOffs, RF_REMAP);
        !           381:        } else {
        !           382:                spOffs = testOffs;
        !           383:        }
        !           384:
        !           385:        /* Create reqs to read the old location & write the new. */
        !           386:        desc->readreq = rf_CreateDiskQueueData(RF_IO_TYPE_READ, spOffs,
        !           387:            sectPerSU, desc->databuf, 0L, 0, (int (*) (void *, int))
        !           388:            rf_CopybackReadDoneProc, desc, NULL, NULL, (void *) raidPtr,
        !           389:            RF_DISKQUEUE_DATA_FLAGS_NONE, NULL);
        !           390:        desc->writereq = rf_CreateDiskQueueData(RF_IO_TYPE_WRITE, testOffs,
        !           391:            sectPerSU, desc->databuf, 0L, 0, (int (*) (void *, int))
        !           392:            rf_CopybackWriteDoneProc, desc, NULL, NULL, (void *) raidPtr,
        !           393:            RF_DISKQUEUE_DATA_FLAGS_NONE, NULL);
        !           394:        desc->frow = testRow;
        !           395:        desc->fcol = testCol;
        !           396:
        !           397:        /*
        !           398:         * Enqueue the read. The write will go out as part of the callback on
        !           399:         * the read. At user-level & in the kernel, wait for the read-write
        !           400:         * pair to complete. In the simulator, just return, since everything
        !           401:         * will happen as callbacks.
        !           402:         */
        !           403:
        !           404:        RF_LOCK_MUTEX(desc->mcpair->mutex);
        !           405:        desc->mcpair->flag = 0;
        !           406:
        !           407:        rf_DiskIOEnqueue(&raidPtr->Queues[spRow][spCol], desc->readreq,
        !           408:            RF_IO_NORMAL_PRIORITY);
        !           409:
        !           410:        while (!desc->mcpair->flag) {
        !           411:                RF_WAIT_MCPAIR(desc->mcpair);
        !           412:        }
        !           413:        RF_UNLOCK_MUTEX(desc->mcpair->mutex);
        !           414:        rf_FreeDiskQueueData(desc->readreq);
        !           415:        rf_FreeDiskQueueData(desc->writereq);
        !           416:
        !           417: }
        !           418:
        !           419:
        !           420: /*
        !           421:  * Called at interrupt context when the read has completed.
        !           422:  * Just send out the write.
        !           423:  */
        !           424: int
        !           425: rf_CopybackReadDoneProc(RF_CopybackDesc_t *desc, int status)
        !           426: {
        !           427:        if (status) {           /* Invoke the callback with bad status. */
        !           428:                printf("COPYBACK: copyback read failed. Aborting.\n");
        !           429:                (desc->writereq->CompleteFunc) (desc, -100);
        !           430:        } else {
        !           431:                rf_DiskIOEnqueue(&(desc->raidPtr
        !           432:                    ->Queues[desc->frow][desc->fcol]),
        !           433:                    desc->writereq, RF_IO_NORMAL_PRIORITY);
        !           434:        }
        !           435:        return (0);
        !           436: }
        !           437:
        !           438:
        !           439: /*
        !           440:  * Called at interrupt context when the write has completed.
        !           441:  * At user level & in the kernel, wake up the copyback thread.
        !           442:  * In the simulator, invoke the next copyback directly.
        !           443:  * Can't free diskqueuedata structs in the kernel because we're at
        !           444:  * interrupt context.
        !           445:  */
        !           446: int
        !           447: rf_CopybackWriteDoneProc(RF_CopybackDesc_t *desc, int status)
        !           448: {
        !           449:        if (status && status != -100) {
        !           450:                printf("COPYBACK: copyback write failed. Aborting.\n");
        !           451:        }
        !           452:        desc->status = status;
        !           453:        rf_MCPairWakeupFunc(desc->mcpair);
        !           454:        return (0);
        !           455: }
        !           456:
        !           457:
        !           458: /* Invoked when the copyback has completed. */
        !           459: void
        !           460: rf_CopybackComplete(RF_CopybackDesc_t *desc, int status)
        !           461: {
        !           462:        RF_Raid_t *raidPtr = desc->raidPtr;
        !           463:        struct timeval t, diff;
        !           464:
        !           465:        if (!status) {
        !           466:                RF_LOCK_MUTEX(raidPtr->mutex);
        !           467:                if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
        !           468:                        RF_ASSERT(raidPtr->Layout.map->parityConfig == 'D');
        !           469:                        rf_FreeSpareTable(raidPtr);
        !           470:                } else {
        !           471:                        raidPtr->Disks[desc->spRow][desc->spCol].status =
        !           472:                            rf_ds_spare;
        !           473:                }
        !           474:                RF_UNLOCK_MUTEX(raidPtr->mutex);
        !           475:
        !           476:                RF_GETTIME(t);
        !           477:                RF_TIMEVAL_DIFF(&desc->starttime, &t, &diff);
        !           478:                printf("Copyback time was %d.%06d seconds.\n",
        !           479:                    (int) diff.tv_sec, (int) diff.tv_usec);
        !           480:        } else
        !           481:                printf("COPYBACK: Failure.\n");
        !           482:
        !           483:        RF_Free(desc->databuf, rf_RaidAddressToByte(raidPtr, desc->sectPerSU));
        !           484:        rf_FreeMCPair(desc->mcpair);
        !           485:        RF_Free(desc, sizeof(*desc));
        !           486:
        !           487:        rf_copyback_in_progress = 0;
        !           488:        rf_ResumeNewRequests(raidPtr);
        !           489: }

CVSweb