diff options
| author | oster <oster@NetBSD.org> | 1999-03-02 03:18:48 +0000 |
|---|---|---|
| committer | oster <oster@NetBSD.org> | 1999-03-02 03:18:48 +0000 |
| commit | 98d8c12355f52f3ed7bb6937988cd6edfe5bf052 (patch) | |
| tree | 604cc4b606cc49d12d9a70328bade5ff863955eb /sys/dev/raidframe | |
| parent | d17a319fc82e1f9937c07a376714ed64bf4eb61d (diff) | |
Update for recent changes including component label support, clean
bits, rebuilding components in-place, adding hot spares, shutdownhooks, etc.
Diffstat (limited to 'sys/dev/raidframe')
| -rw-r--r-- | sys/dev/raidframe/rf_configure.h | 9 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_copyback.c | 26 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_disks.c | 370 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_driver.c | 174 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_netbsd.h | 15 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_netbsdkintf.c | 229 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_raid.h | 7 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_raidframe.h | 7 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_reconstruct.c | 267 | ||||
| -rw-r--r-- | sys/dev/raidframe/rf_reconstruct.h | 5 |
10 files changed, 997 insertions, 112 deletions
diff --git a/sys/dev/raidframe/rf_configure.h b/sys/dev/raidframe/rf_configure.h index 4baa9cc3756..2577d4eaf88 100644 --- a/sys/dev/raidframe/rf_configure.h +++ b/sys/dev/raidframe/rf_configure.h @@ -1,4 +1,4 @@ -/* $NetBSD: rf_configure.h,v 1.3 1999/02/05 00:06:06 oster Exp $ */ +/* $NetBSD: rf_configure.h,v 1.4 1999/03/02 03:18:49 oster Exp $ */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. @@ -75,6 +75,13 @@ struct RF_Config_s { * layout-specific info */ void *layoutSpecific; /* a pointer to a layout-specific structure to * be copied in */ + int force; /* if !0, ignore many fatal + configuration conditions */ + /* + "force" is used to override cases where the component labels would + indicate that configuration should not proceed without user + intervention + */ }; #ifndef _KERNEL int rf_MakeConfig(char *configname, RF_Config_t * cfgPtr); diff --git a/sys/dev/raidframe/rf_copyback.c b/sys/dev/raidframe/rf_copyback.c index 7a4b269405d..42e52122be6 100644 --- a/sys/dev/raidframe/rf_copyback.c +++ b/sys/dev/raidframe/rf_copyback.c @@ -1,4 +1,4 @@ -/* $NetBSD: rf_copyback.c,v 1.6 1999/02/27 03:43:20 oster Exp $ */ +/* $NetBSD: rf_copyback.c,v 1.7 1999/03/02 03:18:49 oster Exp $ */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. @@ -82,13 +82,17 @@ rf_ConfigureCopyback(listp) #include <sys/fcntl.h> #include <sys/vnode.h> +/* XXX these should be in a .h file somewhere */ int raidlookup __P((char *, struct proc *, struct vnode **)); +int raidwrite_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *); +int raidread_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *); /* do a complete copyback */ void rf_CopybackReconstructedData(raidPtr) RF_Raid_t *raidPtr; { + RF_ComponentLabel_t c_label; int done, retcode; RF_CopybackDesc_t *desc; RF_RowCol_t frow, fcol; @@ -227,6 +231,26 @@ rf_CopybackReconstructedData(raidPtr) printf("COPYBACK: Beginning\n"); RF_GETTIME(desc->starttime); rf_ContinueCopyback(desc); + + /* Data has been restored. Fix up the component label. */ + /* Don't actually need the read here.. */ + raidread_component_label( raidPtr->raid_cinfo[frow][fcol].ci_dev, + raidPtr->raid_cinfo[frow][fcol].ci_vp, + &c_label); + + c_label.version = RF_COMPONENT_LABEL_VERSION; + c_label.mod_counter = raidPtr->mod_counter; + c_label.serial_number = raidPtr->serial_number; + c_label.row = frow; + c_label.column = fcol; + c_label.num_rows = raidPtr->numRow; + c_label.num_columns = raidPtr->numCol; + c_label.clean = RF_RAID_DIRTY; + c_label.status = rf_ds_optimal; + + raidwrite_component_label( raidPtr->raid_cinfo[frow][fcol].ci_dev, + raidPtr->raid_cinfo[frow][fcol].ci_vp, + &c_label); } diff --git a/sys/dev/raidframe/rf_disks.c b/sys/dev/raidframe/rf_disks.c index 914b35f01e2..af717290dbd 100644 --- a/sys/dev/raidframe/rf_disks.c +++ b/sys/dev/raidframe/rf_disks.c @@ -1,4 +1,4 @@ -/* $NetBSD: rf_disks.c,v 1.6 1999/02/24 00:00:03 oster Exp $ */ +/* $NetBSD: rf_disks.c,v 1.7 1999/03/02 03:18:49 oster Exp $ */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. @@ -119,9 +119,11 @@ rf_ConfigureDisks( listp, raidPtr, cfgPtr ) int bs, ret; unsigned i, count, foundone = 0, numFailuresThisRow; int num_rows_done, num_cols_done; + int force; num_rows_done = 0; num_cols_done = 0; + force = cfgPtr->force; RF_CallocAndAdd(disks, raidPtr->numRow, sizeof(RF_RaidDisk_t *), (RF_RaidDisk_t **), raidPtr->cleanupList); @@ -166,14 +168,14 @@ rf_ConfigureDisks( listp, raidPtr, cfgPtr ) &disks[r][c], r, c); if (ret) goto fail; -#ifdef NOT_YET_BOYS_AND_GIRLS + if (disks[r][c].status == rf_ds_optimal) { raidread_component_label( raidPtr->raid_cinfo[r][c].ci_dev, raidPtr->raid_cinfo[r][c].ci_vp, &raidPtr->raid_cinfo[r][c].ci_label); } -#endif + if (disks[r][c].status != rf_ds_optimal) { numFailuresThisRow++; } else { @@ -221,11 +223,17 @@ rf_ConfigureDisks( listp, raidPtr, cfgPtr ) goto fail; } -#if NOT_YET_BOYS_AND_GIRLS if (rf_CheckLabels( raidPtr, cfgPtr )) { - printf("There were fatal errors (ignored for now)\n"); + printf("raid%d: There were fatal errors\n", raidPtr->raidid); + if (force != 0) { + printf("raid%d: Fatal errors being ignored.\n", + raidPtr->raidid); + } else { + ret = EINVAL; + goto fail; + } } -#endif + for (r = 0; r < raidPtr->numRow; r++) { for (c = 0; c < raidPtr->numCol; c++) { if (disks[r][c].status == rf_ds_optimal) { @@ -417,6 +425,78 @@ rf_ConfigureDisk(raidPtr, buf, diskPtr, row, col) return (0); } +static void rf_print_label_status( RF_Raid_t *, int, int, char *, + RF_ComponentLabel_t *); + +static void +rf_print_label_status( raidPtr, row, column, dev_name, ci_label ) + RF_Raid_t *raidPtr; + int row; + int column; + char *dev_name; + RF_ComponentLabel_t *ci_label; +{ + + printf("raid%d: Component %s being configured at row: %d col: %d\n", + raidPtr->raidid, dev_name, row, column ); + printf(" Row: %d Column: %d Num Rows: %d Num Columns: %d\n", + ci_label->row, ci_label->column, + ci_label->num_rows, ci_label->num_columns); + printf(" Version: %d Serial Number: %d Mod Counter: %d\n", + ci_label->version, ci_label->serial_number, + ci_label->mod_counter); + printf(" Clean: %d Status: %d\n", + ci_label->clean, ci_label->status ); +} + +static int rf_check_label_vitals( RF_Raid_t *, int, int, char *, + RF_ComponentLabel_t *, int, int ); +static int rf_check_label_vitals( raidPtr, row, column, dev_name, ci_label, + serial_number, mod_counter ) + RF_Raid_t *raidPtr; + int row; + int column; + char *dev_name; + RF_ComponentLabel_t *ci_label; + int serial_number; + int mod_counter; +{ + int fatal_error = 0; + + if (serial_number != ci_label->serial_number) { + printf("%s has a different serial number: %d %d\n", + dev_name, serial_number, ci_label->serial_number); + fatal_error = 1; + } + if (mod_counter != ci_label->mod_counter) { + printf("%s has a different modfication count: %d %d\n", + dev_name, mod_counter, ci_label->mod_counter); + } + + if (row != ci_label->row) { + printf("Row out of alignment for: %s\n", dev_name); + fatal_error = 1; + } + if (column != ci_label->column) { + printf("Column out of alignment for: %s\n", dev_name); + fatal_error = 1; + } + if (raidPtr->numRow != ci_label->num_rows) { + printf("Number of rows do not match for: %s\n", dev_name); + fatal_error = 1; + } + if (raidPtr->numCol != ci_label->num_columns) { + printf("Number of columns do not match for: %s\n", dev_name); + fatal_error = 1; + } + if (ci_label->clean == 0) { + /* it's not clean, but that's not fatal */ + printf("%s is not clean!\n", dev_name); + } + return(fatal_error); +} + + /* rf_CheckLabels() - check all the component labels for consistency. @@ -432,80 +512,252 @@ rf_CheckLabels( raidPtr, cfgPtr ) int r,c; char *dev_name; RF_ComponentLabel_t *ci_label; - int version = 0; int serial_number = 0; - int mod_counter = 0; + int mod_number = 0; int fatal_error = 0; - int disk_num = 0; + int mod_values[4]; + int mod_count[4]; + int ser_values[4]; + int ser_count[4]; + int num_ser; + int num_mod; + int i; + int found; + int hosed_row; + int hosed_column; + int too_fatal; + int parity_good; + int force; + + hosed_row = -1; + hosed_column = -1; + too_fatal = 0; + force = cfgPtr->force; + + /* + We're going to try to be a little intelligent here. If one + component's label is bogus, and we can identify that it's the + *only* one that's gone, we'll mark it as "failed" and allow + the configuration to proceed. This will be the *only* case + that we'll proceed if there would be (otherwise) fatal errors. + + Basically we simply keep a count of how many components had + what serial number. If all but one agree, we simply mark + the disagreeing component as being failed, and allow + things to come up "normally". + + We do this first for serial numbers, and then for "mod_counter". - for (r = 0; r < raidPtr->numRow; r++) { + */ + + num_ser = 0; + num_mod = 0; + for (r = 0; r < raidPtr->numRow && !fatal_error ; r++) { for (c = 0; c < raidPtr->numCol; c++) { - dev_name = &cfgPtr->devnames[r][c][0]; ci_label = &raidPtr->raid_cinfo[r][c].ci_label; - - printf("Component label for %s being configured at row: %d col: %d\n", dev_name, r, c ); - printf(" Row: %d Column: %d Num Rows: %d Num Columns: %d\n", ci_label->row, ci_label->column, - ci_label->num_rows, ci_label->num_columns); - printf(" Version: %d Serial Number: %d Clean: %d Status: %d\n", ci_label->version, ci_label->serial_number, - ci_label->clean, ci_label->status ); - - if ( r !=0 && c != 0) { - if (serial_number != ci_label->serial_number) { - printf("%s has a different %s\n", - dev_name, "serial number!"); - fatal_error = 1; + found=0; + for(i=0;i<num_ser;i++) { + if (ser_values[i] == ci_label->serial_number) { + ser_count[i]++; + found=1; + break; } - if (version != ci_label->version) { - printf("%s has a different %s\n", - dev_name, "version!"); + } + if (!found) { + ser_values[num_ser] = ci_label->serial_number; + ser_count[num_ser] = 1; + num_ser++; + if (num_ser>2) { fatal_error = 1; + break; } - if (mod_counter != ci_label->mod_counter) { - printf("%s has a different modfication count!\n",dev_name); + } + found=0; + for(i=0;i<num_mod;i++) { + if (mod_values[i] == ci_label->mod_counter) { + mod_count[i]++; + found=1; + break; } - } else { - serial_number = ci_label->serial_number; - version = ci_label->version; - mod_counter = ci_label->mod_counter; } - - if (r != ci_label->row) { - printf("Row out of alignment for: %s\n", - dev_name); - fatal_error = 1; + if (!found) { + mod_values[num_mod] = ci_label->mod_counter; + mod_count[num_mod] = 1; + num_mod++; + if (num_mod>2) { + fatal_error = 1; + break; + } } - if (c != ci_label->column) { - printf("Column out of alignment for: %s\n", - dev_name); - fatal_error = 1; + } + } +#if DEBUG + printf("raid%d: Summary of serial numbers:\n", raidPtr->raidid); + for(i=0;i<num_ser;i++) { + printf("%d %d\n", ser_values[i], ser_count[i]); + } + printf("raid%d: Summary of mod counters:\n", raidPtr->raidid); + for(i=0;i<num_mod;i++) { + printf("%d %d\n", mod_values[i], mod_count[i]); + } +#endif + serial_number = ser_values[0]; + if (num_ser == 2) { + if ((ser_count[0] == 1) || (ser_count[1] == 1)) { + /* Locate the maverick component */ + if (ser_count[1] > ser_count[0]) { + serial_number = ser_values[1]; + } + for (r = 0; r < raidPtr->numRow; r++) { + for (c = 0; c < raidPtr->numCol; c++) { + ci_label = &raidPtr->raid_cinfo[r][c].ci_label; + if (serial_number != + ci_label->serial_number) { + hosed_row = r; + hosed_column = c; + break; + } + } } - if (raidPtr->numRow != ci_label->num_rows) { - printf("Number of rows do not match for: %s\n", - dev_name); - fatal_error = 1; + printf("Hosed component: %s\n", + &cfgPtr->devnames[hosed_row][hosed_column][0]); + if (!force) { + /* we'll fail this component, as if there are + other major errors, we arn't forcing things + and we'll abort the config anyways */ + raidPtr->Disks[hosed_row][hosed_column].status + = rf_ds_failed; + raidPtr->numFailures++; + raidPtr->status[hosed_row] = rf_rs_degraded; } - if (raidPtr->numCol != ci_label->num_columns) { - printf("Number of columns do not match for: %s\n", - dev_name); - fatal_error = 1; + } else { + too_fatal = 1; + } + if (cfgPtr->parityConfig == '0') { + /* We've identified two different serial numbers. + RAID 0 can't cope with that, so we'll punt */ + too_fatal = 1; + } + + } + + /* record the serial number for later. If we bail later, setting + this doesn't matter, otherwise we've got the best guess at the + correct serial number */ + raidPtr->serial_number = serial_number; + + mod_number = mod_values[0]; + if (num_mod == 2) { + if ((mod_count[0] == 1) || (mod_count[1] == 1)) { + /* Locate the maverick component */ + if (mod_count[1] > mod_count[0]) { + mod_number = mod_values[1]; + } + for (r = 0; r < raidPtr->numRow && !too_fatal ; r++) { + for (c = 0; c < raidPtr->numCol; c++) { + ci_label = &raidPtr->raid_cinfo[r][c].ci_label; + if (mod_number != + ci_label->mod_counter) { + if ( ( hosed_row == r ) && + ( hosed_column == c )) { + /* same one. Can + deal with it. */ + } else { + hosed_row = r; + hosed_column = c; + if (num_ser != 1) { + too_fatal = 1; + break; + } + } + } + } } - if (ci_label->clean == 0) { - /* it's not clean, but it's not fatal */ - printf("%s is not clean!\n", dev_name); + printf("Hosed component: %s\n", + &cfgPtr->devnames[hosed_row][hosed_column][0]); + if (!force) { + /* we'll fail this component, as if there are + other major errors, we arn't forcing things + and we'll abort the config anyways */ + raidPtr->Disks[hosed_row][hosed_column].status + = rf_ds_failed; + raidPtr->numFailures++; + raidPtr->status[hosed_row] = rf_rs_degraded; } - disk_num++; + } else { + too_fatal = 1; + } + if (cfgPtr->parityConfig == '0') { + /* We've identified two different mod counters. + RAID 0 can't cope with that, so we'll punt */ + too_fatal = 1; } + } + + raidPtr->mod_counter = mod_number; + + if (too_fatal) { + /* we've had both a serial number mismatch, and a mod_counter + mismatch -- and they involved two different components!! + Bail -- make things fail so that the user must force + the issue... */ + hosed_row = -1; + hosed_column = -1; } + if (num_ser > 2) { + printf("raid%d: Too many different serial numbers!\n", + raidPtr->raidid); + } + + if (num_mod > 2) { + printf("raid%d: Too many different mod counters!\n", + raidPtr->raidid); + } + + /* we start by assuming the parity will be good, and flee from + that notion at the slightest sign of trouble */ + + parity_good = RF_RAID_CLEAN; + for (r = 0; r < raidPtr->numRow; r++) { + for (c = 0; c < raidPtr->numCol; c++) { + dev_name = &cfgPtr->devnames[r][c][0]; + ci_label = &raidPtr->raid_cinfo[r][c].ci_label; + + if ((r == hosed_row) && (c == hosed_column)) { + printf("raid%d: Ignoring %s\n", + raidPtr->raidid, dev_name); + } else { + rf_print_label_status( raidPtr, r, c, + dev_name, ci_label ); + if (rf_check_label_vitals( raidPtr, r, c, + dev_name, ci_label, + serial_number, + mod_number )) { + fatal_error = 1; + } + if (ci_label->clean != RF_RAID_CLEAN) { + parity_good = RF_RAID_DIRTY; + } + } + } + } + if (fatal_error) { + parity_good = RF_RAID_DIRTY; + } + + /* we note the state of the parity */ + raidPtr->parity_good = parity_good; + return(fatal_error); } -int rf_add_hot_spare(RF_Raid_t *, RF_HotSpare_t *); +int rf_add_hot_spare(RF_Raid_t *, RF_SingleComponent_t *); int rf_add_hot_spare(raidPtr, sparePtr) RF_Raid_t *raidPtr; - RF_HotSpare_t *sparePtr; + RF_SingleComponent_t *sparePtr; { RF_RaidDisk_t *disks; int ret; @@ -524,7 +776,7 @@ rf_add_hot_spare(raidPtr, sparePtr) spare_number = raidPtr->numSpare; - ret = rf_ConfigureDisk(raidPtr, sparePtr->spare_name, + ret = rf_ConfigureDisk(raidPtr, sparePtr->component_name, &disks[spare_number], 0, raidPtr->numCol + spare_number); @@ -532,7 +784,7 @@ rf_add_hot_spare(raidPtr, sparePtr) goto fail; if (disks[spare_number].status != rf_ds_optimal) { RF_ERRORMSG1("Warning: spare disk %s failed TUR\n", - sparePtr->spare_name); + sparePtr->component_name); ret=EINVAL; goto fail; } else { @@ -581,7 +833,7 @@ fail: int rf_remove_hot_spare(raidPtr,sparePtr) RF_Raid_t *raidPtr; - RF_HotSpare_t *sparePtr; + RF_SingleComponent_t *sparePtr; { int spare_number; @@ -591,7 +843,7 @@ rf_remove_hot_spare(raidPtr,sparePtr) return(EINVAL); } - spare_number = sparePtr->spare_number; + spare_number = sparePtr->column; return(EINVAL); /* XXX not implemented yet */ #if 0 diff --git a/sys/dev/raidframe/rf_driver.c b/sys/dev/raidframe/rf_driver.c index 37db07c8798..b836c9f1f71 100644 --- a/sys/dev/raidframe/rf_driver.c +++ b/sys/dev/raidframe/rf_driver.c @@ -1,4 +1,40 @@ -/* $NetBSD: rf_driver.c,v 1.8 1999/02/27 03:43:20 oster Exp $ */ +/* $NetBSD: rf_driver.c,v 1.9 1999/03/02 03:18:49 oster Exp $ */ +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Greg Oster + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. @@ -113,6 +149,10 @@ static void rf_ShutdownRDFreeList(void *); static int rf_ConfigureRDFreeList(RF_ShutdownList_t **); void rf_UnconfigureVnodes( RF_Raid_t * ); +/* XXX move these to their own .h file! */ +int raidwrite_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *); +int raidread_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *); +int raidmarkclean(dev_t dev, struct vnode *b_vp,int); RF_DECLARE_MUTEX(rf_printf_mutex) /* debug only: avoids interleaved * printfs by different stripes */ @@ -141,15 +181,15 @@ RF_DECLARE_GLOBAL_THREADID /* declarations for threadid.h */ } #endif /* DKUSAGE > 0 */ - static int configureCount = 0; /* number of active configurations */ - static int isconfigged = 0; /* is basic raidframe (non per-array) - * stuff configged */ +static int configureCount = 0; /* number of active configurations */ +static int isconfigged = 0; /* is basic raidframe (non per-array) + * stuff configged */ RF_DECLARE_STATIC_MUTEX(configureMutex) /* used to lock the configuration * stuff */ - static RF_ShutdownList_t *globalShutdown; /* non array-specific - * stuff */ +static RF_ShutdownList_t *globalShutdown; /* non array-specific + * stuff */ - static int rf_ConfigureRDFreeList(RF_ShutdownList_t ** listp); +static int rf_ConfigureRDFreeList(RF_ShutdownList_t ** listp); /* called at system boot time */ int @@ -236,6 +276,125 @@ rf_UnconfigureArray() } RF_UNLOCK_MUTEX(configureMutex); } + + +static void rf_update_component_labels( RF_Raid_t *); +static void +rf_update_component_labels( raidPtr ) + RF_Raid_t *raidPtr; +{ + RF_ComponentLabel_t c_label; + int sparecol; + int r,c; + int i,j; + int srow, scol; + + srow = -1; + scol = -1; + + /* XXX should do extra checks to make sure things really are clean, + rather than blindly setting the clean bit... */ + + raidPtr->mod_counter++; + + for (r = 0; r < raidPtr->numRow; r++) { + for (c = 0; c < raidPtr->numCol; c++) { + if (raidPtr->Disks[r][c].status == rf_ds_optimal) { + raidread_component_label( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + &c_label); + /* make sure status is noted */ + c_label.status = rf_ds_optimal; + raidwrite_component_label( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + &c_label); + if (raidPtr->parity_good == RF_RAID_CLEAN) { + raidmarkclean( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + raidPtr->mod_counter); + } + } + /* else we don't touch it.. */ +#if 0 + else if (raidPtr->Disks[r][c].status != + rf_ds_failed) { + raidread_component_label( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + &c_label); + /* make sure status is noted */ + c_label.status = + raidPtr->Disks[r][c].status; + raidwrite_component_label( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + &c_label); + if (raidPtr->parity_good == RF_RAID_CLEAN) { + raidmarkclean( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + raidPtr->mod_counter); + } + } +#endif + } + } + + for( c = 0; c < raidPtr->numSpare ; c++) { + sparecol = raidPtr->numCol + c; + if (raidPtr->Disks[0][sparecol].status == rf_ds_used_spare) { + /* + + we claim this disk is "optimal" if it's + rf_ds_used_spare, as that means it should be + directly substitutable for the disk it replaced. + We note that too... + + */ + + for(i=0;i<raidPtr->numRow;i++) { + for(j=0;j<raidPtr->numCol;j++) { + if ((raidPtr->Disks[i][j].spareRow == + 0) && + (raidPtr->Disks[i][j].spareCol == + sparecol)) { + srow = i; + scol = j; + break; + } + } + } + + raidread_component_label( + raidPtr->Disks[0][sparecol].dev, + raidPtr->raid_cinfo[0][sparecol].ci_vp, + &c_label); + /* make sure status is noted */ + c_label.version = RF_COMPONENT_LABEL_VERSION; + c_label.mod_counter = raidPtr->mod_counter; + c_label.serial_number = raidPtr->serial_number; + c_label.row = srow; + c_label.column = scol; + c_label.num_rows = raidPtr->numRow; + c_label.num_columns = raidPtr->numCol; + c_label.clean = RF_RAID_DIRTY; /* changed in a bit*/ + c_label.status = rf_ds_optimal; + raidwrite_component_label( + raidPtr->Disks[0][sparecol].dev, + raidPtr->raid_cinfo[0][sparecol].ci_vp, + &c_label); + if (raidPtr->parity_good == RF_RAID_CLEAN) { + raidmarkclean( raidPtr->Disks[0][sparecol].dev, + raidPtr->raid_cinfo[0][sparecol].ci_vp, + raidPtr->mod_counter); + } + } + } +} + /* * Called to shut down an array. */ @@ -269,6 +428,7 @@ rf_Shutdown(raidPtr) raidPtr->valid = 0; + rf_update_component_labels(raidPtr); rf_UnconfigureVnodes(raidPtr); diff --git a/sys/dev/raidframe/rf_netbsd.h b/sys/dev/raidframe/rf_netbsd.h index a5b0ed86d26..b6d2b512d62 100644 --- a/sys/dev/raidframe/rf_netbsd.h +++ b/sys/dev/raidframe/rf_netbsd.h @@ -1,4 +1,4 @@ -/* $NetBSD: rf_netbsd.h,v 1.4 1999/02/23 23:57:54 oster Exp $ */ +/* $NetBSD: rf_netbsd.h,v 1.5 1999/03/02 03:18:48 oster Exp $ */ /*- * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. * All rights reserved. @@ -106,16 +106,17 @@ typedef struct RF_ComponentLabel_s { int status; /* rf_ds_optimal, rf_ds_dist_spared, whatever. */ } RF_ComponentLabel_t; -typedef struct RF_HotSpare_s { - int spare_number; - char spare_name[50]; /* name of the spare disk */ -} RF_HotSpare_t; +typedef struct RF_SingleComponent_s { + int row; + int column; + char component_name[50]; /* name of the component */ +} RF_SingleComponent_t; #ifdef _KERNEL /* XXX this is *not* the place for these... */ -int rf_add_hot_spare(RF_Raid_t *raidPtr, RF_HotSpare_t *sparePtr); -int rf_remove_hot_spare(RF_Raid_t *raidPtr, RF_HotSpare_t *sparePtr); +int rf_add_hot_spare(RF_Raid_t *raidPtr, RF_SingleComponent_t *sparePtr); +int rf_remove_hot_spare(RF_Raid_t *raidPtr, RF_SingleComponent_t *sparePtr); struct raidcinfo { diff --git a/sys/dev/raidframe/rf_netbsdkintf.c b/sys/dev/raidframe/rf_netbsdkintf.c index d41ec9f5320..be2aaddfdbc 100644 --- a/sys/dev/raidframe/rf_netbsdkintf.c +++ b/sys/dev/raidframe/rf_netbsdkintf.c @@ -1,4 +1,4 @@ -/* $NetBSD: rf_netbsdkintf.c,v 1.11 1999/02/23 23:57:53 oster Exp $ */ +/* $NetBSD: rf_netbsdkintf.c,v 1.12 1999/03/02 03:18:49 oster Exp $ */ /*- * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. * All rights reserved. @@ -210,8 +210,10 @@ static void InitBP(struct buf * bp, struct vnode *, unsigned rw_flag, #define Dprintf3(s,a,b,c) if (rf_queueDebug) \ rf_debug_printf(s,a,b,c,NULL,NULL,NULL,NULL,NULL) -static int raidmarkclean(dev_t dev, struct vnode *b_vp); +int raidmarkclean(dev_t dev, struct vnode *b_vp, int); +int raidmarkdirty(dev_t dev, struct vnode *b_vp, int); +void raid_shutdown(void *); void raidattach __P((int)); int raidsize __P((dev_t)); @@ -254,6 +256,7 @@ struct raid_softc { int sc_cflags; /* configuration flags */ size_t sc_size; /* size of the raid device */ dev_t sc_dev; /* our device.. */ + void * sc_sdhook; /* our shutdown hook */ char sc_xname[20]; /* XXX external name */ struct disk sc_dkdev; /* generic disk device info */ struct pool sc_cbufpool; /* component buffer pool */ @@ -283,6 +286,7 @@ static int raidlock __P((struct raid_softc *)); static void raidunlock __P((struct raid_softc *)); int raidlookup __P((char *, struct proc * p, struct vnode **)); +static void rf_markalldirty __P((RF_Raid_t *)); void raidattach(num) @@ -655,8 +659,9 @@ raidioctl(dev, cmd, data, flag, p) RF_ComponentLabel_t *component_label; RF_ComponentLabel_t ci_label; RF_ComponentLabel_t **c_label_ptr; - RF_HotSpare_t *sparePtr; - RF_HotSpare_t hot_spare; + RF_SingleComponent_t *sparePtr,*componentPtr; + RF_SingleComponent_t hot_spare; + RF_SingleComponent_t component; if (unit >= numraid) return (ENXIO); @@ -697,6 +702,7 @@ raidioctl(dev, cmd, data, flag, p) case RAIDFRAME_ADD_HOT_SPARE: case RAIDFRAME_REMOVE_HOT_SPARE: case RAIDFRAME_INIT_LABELS: + case RAIDFRAME_REBUILD_IN_PLACE: if ((rs->sc_flags & RAIDF_INITED) == 0) return (ENXIO); } @@ -771,6 +777,15 @@ raidioctl(dev, cmd, data, flag, p) if (retcode == 0) { retcode = raidinit(dev, raidPtrs[unit], unit); + rf_markalldirty( raidPtrs[unit] ); + /* register our shutdown hook */ + if ((rs->sc_sdhook = + shutdownhook_establish(raid_shutdown, + raidPtrs[unit])) == NULL) { + printf("raid%d: WARNING: unable to establish shutdown hook\n",raidPtrs[unit]->raidid); + } + + } /* free the buffers. No return code here. */ if (k_cfg->layoutSpecificSize) { @@ -808,9 +823,6 @@ raidioctl(dev, cmd, data, flag, p) } raidPtrs[unit]->proc = p; /* XXX necessary evil */ -#if 1 - raidmarkclean( raidPtrs[unit]->Disks[0][0].dev, raidPtrs[unit]->raid_cinfo[0][0].ci_vp); -#endif retcode = rf_Shutdown(raidPtrs[unit]); db1_printf(("Done main shutdown\n")); @@ -820,6 +832,9 @@ raidioctl(dev, cmd, data, flag, p) /* It's no longer initialized... */ rs->sc_flags &= ~RAIDF_INITED; + + shutdownhook_disestablish( rs->sc_sdhook ); + rs->sc_sdhook = NULL; /* Detach the disk. */ disk_detach(&rs->sc_dkdev); @@ -893,21 +908,21 @@ raidioctl(dev, cmd, data, flag, p) printf("Status: %d\n", component_label->status); row = component_label->row; - printf("Row: %d\n",row); - if (row > raidPtrs[unit]->numRow) { - row = 0; /* XXX */ - } column = component_label->column; - printf("Column: %d\n",column); - if (column > raidPtrs[unit]->numCol) { - column = 0; /* XXX */ + + if ((row < 0) || (row > raidPtrs[unit]->numRow) || + (column < 0) || (column > raidPtrs[unit]->numCol)) { + return(EINVAL); } + + /* XXX this isn't allowed to do anything for now :-) */ +#if 0 raidwrite_component_label( raidPtrs[unit]->Disks[row][column].dev, raidPtrs[unit]->raid_cinfo[row][column].ci_vp, component_label ); - - return (retcode); +#endif + return (0); case RAIDFRAME_INIT_LABELS: component_label = (RF_ComponentLabel_t *) data; @@ -917,9 +932,12 @@ raidioctl(dev, cmd, data, flag, p) from the config that was used to create this RAID set. */ - ci_label.version = 1; /* current version number */ + + raidPtrs[unit]->serial_number = component_label->serial_number; + /* current version number */ + ci_label.version = RF_COMPONENT_LABEL_VERSION; ci_label.serial_number = component_label->serial_number; - ci_label.mod_counter = 0; /* XXX this should be non-zero.. */ + ci_label.mod_counter = raidPtrs[unit]->mod_counter; ci_label.num_rows = raidPtrs[unit]->numRow; ci_label.num_columns = raidPtrs[unit]->numCol; ci_label.clean = RF_RAID_DIRTY; /* not clean */ @@ -951,26 +969,40 @@ raidioctl(dev, cmd, data, flag, p) if (retcode) { retcode = EIO; } else { - /* XXX set the clean bit! */ + /* set the clean bit! If we shutdown correctly, + the clean bit on each component label will get + set */ + raidPtrs[unit]->parity_good = RF_RAID_CLEAN; } return (retcode); case RAIDFRAME_ADD_HOT_SPARE: - sparePtr = (RF_HotSpare_t *) data; -#if 0 - retcode = copyin( sparePtr, &hot_spare, sizeof(RF_HotSpare_t)); -#endif - memcpy( &hot_spare, sparePtr, sizeof(RF_HotSpare_t)); - if (!retcode) { - printf("Adding spare\n"); - retcode = rf_add_hot_spare(raidPtrs[unit], &hot_spare); - } + sparePtr = (RF_SingleComponent_t *) data; + memcpy( &hot_spare, sparePtr, sizeof(RF_SingleComponent_t)); + printf("Adding spare\n"); + retcode = rf_add_hot_spare(raidPtrs[unit], &hot_spare); return(retcode); case RAIDFRAME_REMOVE_HOT_SPARE: return(retcode); + case RAIDFRAME_REBUILD_IN_PLACE: + componentPtr = (RF_SingleComponent_t *) data; + memcpy( &component, componentPtr, + sizeof(RF_SingleComponent_t)); + row = component.row; + column = component.column; + printf("Rebuild: %d %d\n",row, column); + if ((row < 0) || (row > raidPtrs[unit]->numRow) || + (column < 0) || (column > raidPtrs[unit]->numCol)) { + return(EINVAL); + } + printf("Attempting a rebuild in place\n"); + raidPtrs[unit]->proc = p; /* Blah... :-p GO */ + retcode = rf_ReconstructInPlace(raidPtrs[unit], row, column); + return(retcode); + /* issue a test-unit-ready through raidframe to the indicated * device */ #if 0 /* XXX not supported yet (ever?) */ @@ -1069,7 +1101,8 @@ raidioctl(dev, cmd, data, flag, p) || rr->col < 0 || rr->col >= raidPtrs[unit]->numCol) return (EINVAL); - printf("Failing the disk: row: %d col: %d\n", rr->row, rr->col); + printf("raid%d: Failing the disk: row: %d col: %d\n", + unit, rr->row, rr->col); /* make a copy of the recon request so that we don't rely on * the user's buffer */ @@ -1277,6 +1310,28 @@ raidinit(dev, raidPtr, unit) return (retcode); } +void +raid_shutdown(arg) + void *arg; +{ + RF_Raid_t *raidPtr = arg; + struct raid_softc *rs; + + /* This is called by out shutdown hook. + The lights are being turned out, so lets shutdown as + gracefully as possible */ + + rs = &raid_softc[raidPtr->raidid]; + + printf("raid%d: shutdown hooks called\n",raidPtr->raidid); + rf_Shutdown(raidPtr); + + /* It's no longer initialized... */ + rs->sc_flags &= ~RAIDF_INITED; + + +} + /********************************************************* * @@ -1968,8 +2023,25 @@ raidunlock(rs) #define RF_COMPONENT_INFO_SIZE 1024 /* bytes */ int -raidmarkclean(dev_t dev, struct vnode *b_vp) +raidmarkclean(dev_t dev, struct vnode *b_vp, int mod_counter) +{ + RF_ComponentLabel_t component_label; + raidread_component_label(dev, b_vp, &component_label); + component_label.mod_counter = mod_counter; + component_label.clean = RF_RAID_CLEAN; + raidwrite_component_label(dev, b_vp, &component_label); + return(0); +} + + +int +raidmarkdirty(dev_t dev, struct vnode *b_vp, int mod_counter) { + RF_ComponentLabel_t component_label; + raidread_component_label(dev, b_vp, &component_label); + component_label.mod_counter = mod_counter; + component_label.clean = RF_RAID_DIRTY; + raidwrite_component_label(dev, b_vp, &component_label); return(0); } @@ -2003,7 +2075,7 @@ raidread_component_label(dev, b_vp, component_label) if (!error) { memcpy(component_label, bp->b_un.b_addr, sizeof(RF_ComponentLabel_t)); -#if 1 +#if 0 printf("raidread_component_label: got component label:\n"); printf("Version: %d\n",component_label->version); printf("Serial Number: %d\n",component_label->serial_number); @@ -2057,3 +2129,98 @@ raidwrite_component_label(dev, b_vp, component_label) return(error); } + +void +rf_markalldirty( raidPtr ) + RF_Raid_t *raidPtr; +{ + RF_ComponentLabel_t c_label; + int r,c; + + raidPtr->mod_counter++; + for (r = 0; r < raidPtr->numRow; r++) { + for (c = 0; c < raidPtr->numCol; c++) { + if (raidPtr->Disks[r][c].status != rf_ds_failed) { + raidread_component_label( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + &c_label); + if (c_label.status == rf_ds_spared) { + /* XXX do something special... + but whatever you do, don't + try to access it!! */ + } else { +#if 0 + c_label.status = + raidPtr->Disks[r][c].status; + raidwrite_component_label( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + &c_label); +#endif + raidmarkdirty( + raidPtr->Disks[r][c].dev, + raidPtr->raid_cinfo[r][c].ci_vp, + raidPtr->mod_counter); + } + } + } + } +#if 0 + for( c = 0; c < raidPtr->numSpare ; c++) { + sparecol = raidPtr->numCol + c; + if (raidPtr->Disks[r][sparecol].status == rf_ds_used_spare) { + /* + + XXX this is where we get fancy and map this spare + into it's correct spot in the array. + + */ + /* + + we claim this disk is "optimal" if it's + rf_ds_used_spare, as that means it should be + directly substitutable for the disk it replaced. + We note that too... + + */ + + for(i=0;i<raidPtr->numRow;i++) { + for(j=0;j<raidPtr->numCol;j++) { + if ((raidPtr->Disks[i][j].spareRow == + r) && + (raidPtr->Disks[i][j].spareCol == + sparecol)) { + srow = r; + scol = sparecol; + break; + } + } + } + + raidread_component_label( + raidPtr->Disks[r][sparecol].dev, + raidPtr->raid_cinfo[r][sparecol].ci_vp, + &c_label); + /* make sure status is noted */ + c_label.version = RF_COMPONENT_LABEL_VERSION; + c_label.mod_counter = raidPtr->mod_counter; + c_label.serial_number = raidPtr->serial_number; + c_label.row = srow; + c_label.column = scol; + c_label.num_rows = raidPtr->numRow; + c_label.num_columns = raidPtr->numCol; + c_label.clean = RF_RAID_DIRTY; /* changed in a bit*/ + c_label.status = rf_ds_optimal; + raidwrite_component_label( + raidPtr->Disks[r][sparecol].dev, + raidPtr->raid_cinfo[r][sparecol].ci_vp, + &c_label); + raidmarkclean( raidPtr->Disks[r][sparecol].dev, + raidPtr->raid_cinfo[r][sparecol].ci_vp); + } + } + +#endif +} + diff --git a/sys/dev/raidframe/rf_raid.h b/sys/dev/raidframe/rf_raid.h index 1af6083ff6c..489d028e5d5 100644 --- a/sys/dev/raidframe/rf_raid.h +++ b/sys/dev/raidframe/rf_raid.h @@ -1,4 +1,4 @@ -/* $NetBSD: rf_raid.h,v 1.4 1999/02/23 23:57:53 oster Exp $ */ +/* $NetBSD: rf_raid.h,v 1.5 1999/03/02 03:18:49 oster Exp $ */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. @@ -59,6 +59,7 @@ #define RF_MAX_DISKS 128 /* max disks per array */ #define RF_DEV2RAIDID(_dev) (DISKUNIT(_dev)) +#define RF_COMPONENT_LABEL_VERSION 1 #define RF_RAID_DIRTY 0 #define RF_RAID_CLEAN 1 @@ -130,6 +131,10 @@ struct RF_Raid_s { RF_LockTableEntry_t *lockTable; /* stripe-lock table */ RF_LockTableEntry_t *quiesceLock; /* quiesnce table */ int numFailures; /* total number of failures in the array */ + + int parity_good; /* !0 if parity is known to be correct */ + int serial_number; /* a "serial number" for this set */ + int mod_counter; /* modification counter for component labels */ int clean; /* the clean bit for this array. */ /* * Cleanup stuff diff --git a/sys/dev/raidframe/rf_raidframe.h b/sys/dev/raidframe/rf_raidframe.h index 826862f8c7e..8cc0b13fbd3 100644 --- a/sys/dev/raidframe/rf_raidframe.h +++ b/sys/dev/raidframe/rf_raidframe.h @@ -1,4 +1,4 @@ -/* $NetBSD: rf_raidframe.h,v 1.4 1999/02/23 23:57:54 oster Exp $ */ +/* $NetBSD: rf_raidframe.h,v 1.5 1999/03/02 03:18:48 oster Exp $ */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. @@ -136,7 +136,8 @@ typedef struct RF_DeviceConfig_s { #define RAIDFRAME_SET_COMPONENT_LABEL _IOW ('r', 20, RF_ComponentLabel_t) #define RAIDFRAME_INIT_LABELS _IOW ('r', 21, RF_ComponentLabel_t) -#define RAIDFRAME_ADD_HOT_SPARE _IOW ('r', 22, RF_HotSpare_t) -#define RAIDFRAME_REMOVE_HOT_SPARE _IOW ('r', 23, RF_HotSpare_t) +#define RAIDFRAME_ADD_HOT_SPARE _IOW ('r', 22, RF_SingleComponent_t) +#define RAIDFRAME_REMOVE_HOT_SPARE _IOW ('r', 23, RF_SingleComponent_t) +#define RAIDFRAME_REBUILD_IN_PLACE _IOW ('r', 24, RF_SingleComponent_t) #endif /* !_RF__RF_RAIDFRAME_H_ */ diff --git a/sys/dev/raidframe/rf_reconstruct.c b/sys/dev/raidframe/rf_reconstruct.c index 3a778deee93..e56f2ffe55a 100644 --- a/sys/dev/raidframe/rf_reconstruct.c +++ b/sys/dev/raidframe/rf_reconstruct.c @@ -1,4 +1,4 @@ -/* $NetBSD: rf_reconstruct.c,v 1.4 1999/02/05 00:06:16 oster Exp $ */ +/* $NetBSD: rf_reconstruct.c,v 1.5 1999/03/02 03:18:49 oster Exp $ */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. @@ -36,6 +36,16 @@ #include <sys/time.h> #include <sys/buf.h> #include <sys/errno.h> + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> +#include <sys/vnode.h> + + #include "rf_raid.h" #include "rf_reconutil.h" #include "rf_revent.h" @@ -120,6 +130,10 @@ static void ForceReconReadDoneProc(void *arg, int status); static void rf_ShutdownReconstruction(void *); +/* XXX these should be in a .h file somewhere */ +int raidlookup __P((char *, struct proc *, struct vnode **)); +int raidwrite_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *); +int raidread_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *); struct RF_ReconDoneProc_s { void (*proc) (RF_Raid_t *, void *); @@ -305,6 +319,7 @@ rf_ReconstructFailedDiskBasic(raidPtr, row, col) RF_RowCol_t row; RF_RowCol_t col; { + RF_ComponentLabel_t c_label; RF_RaidDisk_t *spareDiskPtr = NULL; RF_RaidReconDesc_t *reconDesc; RF_RowCol_t srow, scol; @@ -354,6 +369,256 @@ rf_ReconstructFailedDiskBasic(raidPtr, row, col) reconDesc->reconExecTicks = 0; reconDesc->maxReconExecTicks = 0; rc = rf_ContinueReconstructFailedDisk(reconDesc); + + if (!rc) { + /* fix up the component label */ + /* Don't actually need the read here.. */ + raidread_component_label( + raidPtr->raid_cinfo[srow][scol].ci_dev, + raidPtr->raid_cinfo[srow][scol].ci_vp, + &c_label); + + c_label.version = RF_COMPONENT_LABEL_VERSION; + c_label.mod_counter = raidPtr->mod_counter; + c_label.serial_number = raidPtr->serial_number; + c_label.row = row; + c_label.column = col; + c_label.num_rows = raidPtr->numRow; + c_label.num_columns = raidPtr->numCol; + c_label.clean = RF_RAID_DIRTY; + c_label.status = rf_ds_optimal; + + raidwrite_component_label( + raidPtr->raid_cinfo[srow][scol].ci_dev, + raidPtr->raid_cinfo[srow][scol].ci_vp, + &c_label); + + } + return (rc); +} + +/* + + Allow reconstructing a disk in-place -- i.e. component /dev/sd2e goes AWOL, + and you don't get a spare until the next Monday. With this function + (and hot-swappable drives) you can now put your new disk containing + /dev/sd2e on the bus, scsictl it alive, and then use raidctl(8) to + rebuild the data "on the spot". + +*/ + +int +rf_ReconstructInPlace(raidPtr, row, col) + RF_Raid_t *raidPtr; + RF_RowCol_t row; + RF_RowCol_t col; +{ + RF_RaidDisk_t *spareDiskPtr = NULL; + RF_RaidReconDesc_t *reconDesc; + RF_LayoutSW_t *lp; + RF_RaidDisk_t *badDisk; + RF_ComponentLabel_t c_label; + int numDisksDone = 0, rc; + struct partinfo dpart; + struct vnode *vp; + struct vattr va; + struct proc *proc; + int retcode; + + lp = raidPtr->Layout.map; + if (lp->SubmitReconBuffer) { + /* + * The current infrastructure only supports reconstructing one + * disk at a time for each array. + */ + RF_LOCK_MUTEX(raidPtr->mutex); + if ((raidPtr->Disks[row][col].status == rf_ds_optimal) && + (raidPtr->numFailures > 0)) { + /* XXX 0 above shouldn't be constant!!! */ + /* some component other than this has failed. + Let's not make things worse than they already + are... */ + printf("RAIDFRAME: Unable to reconstruct to disk at:\n"); + printf(" Row: %d Col: %d Too many failures.\n", + row, col); + RF_UNLOCK_MUTEX(raidPtr->mutex); + return (EINVAL); + } + if (raidPtr->Disks[row][col].status == rf_ds_reconstructing) { + printf("RAIDFRAME: Unable to reconstruct to disk at:\n"); + printf(" Row: %d Col: %d Reconstruction already occuring!\n", row, col); + + RF_UNLOCK_MUTEX(raidPtr->mutex); + return (EINVAL); + } + + + if (raidPtr->Disks[row][col].status != rf_ds_failed) { + /* "It's gone..." */ + raidPtr->numFailures++; + raidPtr->Disks[row][col].status = rf_ds_failed; + raidPtr->status[row] = rf_rs_degraded; + } + + while (raidPtr->reconInProgress) { + RF_WAIT_COND(raidPtr->waitForReconCond, raidPtr->mutex); + } + + + /* first look for a spare drive onto which to reconstruct + the data. spare disk descriptors are stored in row 0. + This may have to change eventually */ + + /* Actually, we don't care if it's failed or not... + On a RAID set with correct parity, this function + should be callable on any component without ill affects. */ + /* RF_ASSERT(raidPtr->Disks[row][col].status == rf_ds_failed); + */ + + if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) { + RF_ERRORMSG2("Unable to reconstruct to disk at row %d col %d: operation not supported for RF_DISTRIBUTE_SPARE\n", row, col); + + RF_UNLOCK_MUTEX(raidPtr->mutex); + return (EINVAL); + } + + /* XXX need goop here to see if the disk is alive, + and, if not, make it so... */ + + + + badDisk = &raidPtr->Disks[row][col]; + + proc = raidPtr->proc; /* XXX Yes, this is not nice.. */ + + /* This device may have been opened successfully the + first time. Close it before trying to open it again.. */ + + if (raidPtr->raid_cinfo[row][col].ci_vp != NULL) { + printf("Closed the open device: %s\n", + raidPtr->Disks[row][col].devname); + VOP_UNLOCK(raidPtr->raid_cinfo[row][col].ci_vp, 0); + (void) vn_close(raidPtr->raid_cinfo[row][col].ci_vp, + FREAD | FWRITE, proc->p_ucred, proc); + raidPtr->raid_cinfo[row][col].ci_vp = NULL; + } + printf("About to (re-)open the device for rebuilding: %s\n", + raidPtr->Disks[row][col].devname); + + retcode = raidlookup(raidPtr->Disks[row][col].devname, + proc, &vp); + + if (retcode) { + printf("raid%d: rebuilding: raidlookup on device: %s failed: %d!\n",raidPtr->raidid, + raidPtr->Disks[row][col].devname, retcode); + + /* XXX the component isn't responding properly... + must be + * still dead :-( */ + RF_UNLOCK_MUTEX(raidPtr->mutex); + return(retcode); + + } else { + + /* Ok, so we can at least do a lookup... + How about actually getting a vp for it? */ + + if ((retcode = VOP_GETATTR(vp, &va, proc->p_ucred, + proc)) != 0) { + RF_UNLOCK_MUTEX(raidPtr->mutex); + return(retcode); + } + retcode = VOP_IOCTL(vp, DIOCGPART, (caddr_t) & dpart, + FREAD, proc->p_ucred, proc); + if (retcode) { + RF_UNLOCK_MUTEX(raidPtr->mutex); + return(retcode); + } + raidPtr->Disks[row][col].blockSize = + dpart.disklab->d_secsize; + + raidPtr->Disks[row][col].numBlocks = + dpart.part->p_size - rf_protectedSectors; + + raidPtr->raid_cinfo[row][col].ci_vp = vp; + raidPtr->raid_cinfo[row][col].ci_dev = va.va_rdev; + + raidPtr->Disks[row][col].dev = va.va_rdev; + + /* we allow the user to specify that only a + fraction of the disks should be used this is + just for debug: it speeds up + * the parity scan */ + raidPtr->Disks[row][col].numBlocks = + raidPtr->Disks[row][col].numBlocks * + rf_sizePercentage / 100; + } + + + + spareDiskPtr = &raidPtr->Disks[row][col]; + spareDiskPtr->status = rf_ds_used_spare; + + printf("RECON: initiating in-place reconstruction on\n"); + printf(" row %d col %d -> spare at row %d col %d\n", + row, col, row, col); + + raidPtr->reconInProgress++; + + RF_UNLOCK_MUTEX(raidPtr->mutex); + + reconDesc = AllocRaidReconDesc((void *) raidPtr, row, col, + spareDiskPtr, numDisksDone, + row, col); + raidPtr->reconDesc = (void *) reconDesc; +#if RF_RECON_STATS > 0 + reconDesc->hsStallCount = 0; + reconDesc->numReconExecDelays = 0; + reconDesc->numReconEventWaits = 0; +#endif /* RF_RECON_STATS > 0 */ + reconDesc->reconExecTimerRunning = 0; + reconDesc->reconExecTicks = 0; + reconDesc->maxReconExecTicks = 0; + rc = rf_ContinueReconstructFailedDisk(reconDesc); + } else { + RF_ERRORMSG1("RECON: no way to reconstruct failed disk for arch %c\n", + lp->parityConfig); + rc = EIO; + } + RF_LOCK_MUTEX(raidPtr->mutex); + raidPtr->reconInProgress--; + + if (!rc) { + /* Need to set these here, as at this point it'll be claiming + that the disk is in rf_ds_spared! But we know better :-) */ + + raidPtr->Disks[row][col].status = rf_ds_optimal; + raidPtr->status[row] = rf_rs_optimal; + + /* fix up the component label */ + /* Don't actually need the read here.. */ + raidread_component_label(raidPtr->raid_cinfo[row][col].ci_dev, + raidPtr->raid_cinfo[row][col].ci_vp, + &c_label); + + c_label.version = RF_COMPONENT_LABEL_VERSION; + c_label.mod_counter = raidPtr->mod_counter; + c_label.serial_number = raidPtr->serial_number; + c_label.row = row; + c_label.column = col; + c_label.num_rows = raidPtr->numRow; + c_label.num_columns = raidPtr->numCol; + c_label.clean = RF_RAID_DIRTY; + c_label.status = rf_ds_optimal; + + raidwrite_component_label(raidPtr->raid_cinfo[row][col].ci_dev, + raidPtr->raid_cinfo[row][col].ci_vp, + &c_label); + + } + RF_UNLOCK_MUTEX(raidPtr->mutex); + RF_SIGNAL_COND(raidPtr->waitForReconCond); + wakeup(&raidPtr->waitForReconCond); return (rc); } diff --git a/sys/dev/raidframe/rf_reconstruct.h b/sys/dev/raidframe/rf_reconstruct.h index ae97c39f3a5..b7514326c47 100644 --- a/sys/dev/raidframe/rf_reconstruct.h +++ b/sys/dev/raidframe/rf_reconstruct.h @@ -1,4 +1,4 @@ -/* $NetBSD: rf_reconstruct.h,v 1.3 1999/02/05 00:06:16 oster Exp $ */ +/* $NetBSD: rf_reconstruct.h,v 1.4 1999/03/02 03:18:48 oster Exp $ */ /* * Copyright (c) 1995 Carnegie-Mellon University. * All rights reserved. @@ -182,6 +182,9 @@ int rf_ReconstructFailedDiskBasic(RF_Raid_t * raidPtr, RF_RowCol_t row, RF_RowCol_t col); +int +rf_ReconstructInPlace(RF_Raid_t * raidPtr, RF_RowCol_t row, RF_RowCol_t col); + int rf_ContinueReconstructFailedDisk(RF_RaidReconDesc_t * reconDesc); int |
