Update for recent changes including component label support, clean
bits, rebuilding components in-place, adding hot spares, shutdownhooks, etc.
This commit is contained in:
parent
d17a319fc8
commit
98d8c12355
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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".
|
||||
|
||||
*/
|
||||
|
||||
num_ser = 0;
|
||||
num_mod = 0;
|
||||
for (r = 0; r < raidPtr->numRow && !fatal_error ; r++) {
|
||||
for (c = 0; c < raidPtr->numCol; c++) {
|
||||
ci_label = &raidPtr->raid_cinfo[r][c].ci_label;
|
||||
found=0;
|
||||
for(i=0;i<num_ser;i++) {
|
||||
if (ser_values[i] == ci_label->serial_number) {
|
||||
ser_count[i]++;
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
found=0;
|
||||
for(i=0;i<num_mod;i++) {
|
||||
if (mod_values[i] == ci_label->mod_counter) {
|
||||
mod_count[i]++;
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
|
||||
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!");
|
||||
|
||||
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 (version != ci_label->version) {
|
||||
printf("%s has a different %s\n",
|
||||
dev_name, "version!");
|
||||
fatal_error = 1;
|
||||
if (ci_label->clean != RF_RAID_CLEAN) {
|
||||
parity_good = RF_RAID_DIRTY;
|
||||
}
|
||||
if (mod_counter != ci_label->mod_counter) {
|
||||
printf("%s has a different modfication count!\n",dev_name);
|
||||
}
|
||||
} 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 (c != 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 it's not fatal */
|
||||
printf("%s is not clean!\n", dev_name);
|
||||
}
|
||||
disk_num++;
|
||||
}
|
||||
}
|
||||
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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user