Module Name:    src
Committed By:   snj
Date:           Thu Dec 10 22:59:17 UTC 2009

Modified Files:
        src/sbin/raidctl [netbsd-5]: raidctl.8 raidctl.c
        src/sys/dev/raidframe [netbsd-5]: files.raidframe raidframeio.h
            raidframevar.h rf_copyback.c rf_disks.c rf_driver.c rf_engine.c
            rf_kintf.h rf_netbsdkintf.c rf_parityscan.c rf_parityscan.h
            rf_raid.h rf_reconstruct.c rf_states.c

Log Message:
Pull up following revision(s) (requested by tron in ticket #1187):
        sbin/raidctl/raidctl.8: revisions 1.57-1.59 via patch
        sbin/raidctl/raidctl.c: revision 1.42 via patch
        sys/dev/raidframe/files.raidframe: revision 1.8 via patch
        sys/dev/raidframe/rf_copyback.c: revision 1.42 via patch
        sys/dev/raidframe/rf_disks.c: revision 1.72 via patch
        sys/dev/raidframe/rf_driver.c: revision 1.122 via patch
        sys/dev/raidframe/rf_engine.c: revision 1.40 via patch
        sys/dev/raidframe/rf_kintf.h: revision 1.21 via patch
        sys/dev/raidframe/rf_netbsdkintf.c: revision 1.269 via patch
        sys/dev/raidframe/rf_paritymap.c: revisions 1.1-1.3 via patch
        sys/dev/raidframe/rf_paritymap.h: revision 1.1 via patch
        sys/dev/raidframe/rf_parityscan.c: revision 1.33 via patch
        sys/dev/raidframe/rf_parityscan.h: revision 1.8 via patch
        sys/dev/raidframe/rf_raid.h: revision 1.38 via patch
        sys/dev/raidframe/rf_reconstruct.c: revision 1.108 via patch
        sys/dev/raidframe/rf_states.c: revision 1.44 via patch
        sys/dev/raidframe/raidframeio.h: revision 1.6 via patch
        sys/dev/raidframe/raidframevar.h: revision 1.13 via patch
Pull up the RAIDframe parity map Summer Of Code project.
Drastically reduces the amount of time spent rewriting parity after an
unclean shutdown by keeping better track of which regions might have had
outstanding writes.  Enabled by default; can be disabled on a per-set
basis, or tuned, with the new raidctl(8) commands.


To generate a diff of this commit:
cvs rdiff -u -r1.56 -r1.56.2.1 src/sbin/raidctl/raidctl.8
cvs rdiff -u -r1.39.4.1 -r1.39.4.2 src/sbin/raidctl/raidctl.c
cvs rdiff -u -r1.6 -r1.6.6.1 src/sys/dev/raidframe/files.raidframe
cvs rdiff -u -r1.4 -r1.4.10.1 src/sys/dev/raidframe/raidframeio.h
cvs rdiff -u -r1.12 -r1.12.10.1 src/sys/dev/raidframe/raidframevar.h
cvs rdiff -u -r1.41 -r1.41.20.1 src/sys/dev/raidframe/rf_copyback.c
cvs rdiff -u -r1.70.10.1 -r1.70.10.2 src/sys/dev/raidframe/rf_disks.c
cvs rdiff -u -r1.118.10.1 -r1.118.10.2 src/sys/dev/raidframe/rf_driver.c
cvs rdiff -u -r1.39 -r1.39.64.1 src/sys/dev/raidframe/rf_engine.c
cvs rdiff -u -r1.20 -r1.20.68.1 src/sys/dev/raidframe/rf_kintf.h
cvs rdiff -u -r1.250.4.4 -r1.250.4.5 src/sys/dev/raidframe/rf_netbsdkintf.c
cvs rdiff -u -r1.32 -r1.32.64.1 src/sys/dev/raidframe/rf_parityscan.c
cvs rdiff -u -r1.7 -r1.7.86.1 src/sys/dev/raidframe/rf_parityscan.h
cvs rdiff -u -r1.37 -r1.37.34.1 src/sys/dev/raidframe/rf_raid.h
cvs rdiff -u -r1.105.4.2 -r1.105.4.3 src/sys/dev/raidframe/rf_reconstruct.c
cvs rdiff -u -r1.43 -r1.43.8.1 src/sys/dev/raidframe/rf_states.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/raidctl/raidctl.8
diff -u src/sbin/raidctl/raidctl.8:1.56 src/sbin/raidctl/raidctl.8:1.56.2.1
--- src/sbin/raidctl/raidctl.8:1.56	Thu Aug 28 21:24:30 2008
+++ src/sbin/raidctl/raidctl.8	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-.\"     $NetBSD: raidctl.8,v 1.56 2008/08/28 21:24:30 wiz Exp $
+.\"     $NetBSD: raidctl.8,v 1.56.2.1 2009/12/10 22:59:16 snj Exp $
 .\"
 .\" Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -53,7 +53,7 @@
 .\" any improvements or extensions that they make and grant Carnegie the
 .\" rights to redistribute these changes.
 .\"
-.Dd August 26, 2008
+.Dd November 17, 2009
 .Dt RAIDCTL 8
 .Os
 .Sh NAME
@@ -96,6 +96,16 @@
 .Fl I Ar serial_number Ar dev
 .Nm
 .Op Fl v
+.Fl m Ar dev
+.Nm
+.Op Fl v
+.Fl M
+.Oo yes | no | set
+.Ar params
+.Oc
+.Ar dev
+.Nm
+.Op Fl v
 .Fl p Ar dev
 .Nm
 .Op Fl v
@@ -222,6 +232,44 @@
 This step
 .Em MUST
 be performed when a new RAID set is created.
+.It Fl m Ar dev
+Display status information about the parity map on the RAID set, if any.
+If used with
+.Fl v
+then the current contents of the parity map will be output (in
+hexadecimal format) as well.
+.It Fl M Ic yes Ar dev
+.\"XXX should there be a section with more info on the parity map feature?
+Enable the use of a parity map on the RAID set; this is the default,
+and greatly reduces the time taken to check parity after unclean
+shutdowns at the cost of some very slight overhead during normal
+operation.
+Changes to this setting will take effect the next time the set is
+configured.
+Note that RAID-0 sets, having no parity, will not use a parity map in
+any case.
+.It Fl M Ic no Ar dev
+Disable the use of a parity map on the RAID set; doing this is not
+recommended.
+This will take effect the next time the set is configured.
+.It Fl M Ic set Ar cooldown Ar tickms Ar regions Ar dev
+Alter the parameters of the parity map; parameters to leave unchanged
+can be given as 0, and trailing zeroes may be omitted.
+.\"XXX should this explanation be deferred to another section as well?
+The RAID set is divided into
+.Ar regions
+regions; each region is marked dirty for at most
+.Ar cooldown
+intervals of
+.Ar tickms
+milliseconds each after a write to it, and at least
+.Ar cooldown
+\- 1 such intervals.
+Changes to
+.Ar regions
+take effect the next time is configured, while changes to the other
+parameters are applied immediately.
+The default parameters are expected to be reasonable for most workloads.
 .It Fl p Ar dev
 Check the status of the parity on the RAID set.
 Displays a status message,
@@ -1396,7 +1444,7 @@
 Since there are 4 data sectors per stripe, the maximum
 data per stripe is 64 blocks (32K) or 128 blocks (64K).
 Again, empirical measurement will provide the best indicators of which
-values will yeild better performance.
+values will yield better performance.
 .Pp
 The parameters used for the file system are also critical to good performance.
 For

Index: src/sbin/raidctl/raidctl.c
diff -u src/sbin/raidctl/raidctl.c:1.39.4.1 src/sbin/raidctl/raidctl.c:1.39.4.2
--- src/sbin/raidctl/raidctl.c:1.39.4.1	Sun Feb  1 23:41:37 2009
+++ src/sbin/raidctl/raidctl.c	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-/*      $NetBSD: raidctl.c,v 1.39.4.1 2009/02/01 23:41:37 snj Exp $   */
+/*      $NetBSD: raidctl.c,v 1.39.4.2 2009/12/10 22:59:16 snj Exp $   */
 
 /*-
  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@@ -39,7 +39,7 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: raidctl.c,v 1.39.4.1 2009/02/01 23:41:37 snj Exp $");
+__RCSID("$NetBSD: raidctl.c,v 1.39.4.2 2009/12/10 22:59:16 snj Exp $");
 #endif
 
 
@@ -82,13 +82,15 @@
 static  void do_meter(int, u_long);
 static  void get_bar(char *, double, int);
 static  void get_time_string(char *, int);
+static  void rf_output_pmstat(int, int);
+static  void rf_pm_configure(int, int, char *, int[]);
 
 int verbose;
 
 int
 main(int argc,char *argv[])
 {
-	int ch;
+	int ch, i;
 	int num_options;
 	unsigned long action;
 	char config_filename[PATH_MAX];
@@ -96,6 +98,8 @@
 	char name[PATH_MAX];
 	char component[PATH_MAX];
 	char autoconf[10];
+	char *parityconf = NULL;
+	int parityparams[3];
 	int do_output;
 	int do_recon;
 	int do_rewrite;
@@ -117,7 +121,7 @@
 	force = 0;
 	openmode = O_RDWR;	/* default to read/write */
 
-	while ((ch = getopt(argc, argv, "a:A:Bc:C:f:F:g:GiI:l:r:R:sSpPuv")) 
+	while ((ch = getopt(argc, argv, "a:A:Bc:C:f:F:g:GiI:l:mM:r:R:sSpPuv")) 
 	       != -1)
 		switch(ch) {
 		case 'a':
@@ -181,6 +185,23 @@
 			serial_number = atoi(optarg);
 			num_options++;
 			break;
+		case 'm':
+			action = RAIDFRAME_PARITYMAP_STATUS;
+			openmode = O_RDONLY;
+			num_options++;
+			break;
+		case 'M':
+			action = RAIDFRAME_PARITYMAP_SET_DISABLE;
+			parityconf = strdup(optarg);
+			num_options++;
+			/* XXXjld: should rf_pm_configure do the atoi()s? */
+			i = 0;
+			while (i < 3 && optind < argc &&
+			    isdigit((int)argv[optind][0]))
+				parityparams[i++] = atoi(argv[optind++]);
+			while (i < 3)
+				parityparams[i++] = 0;
+			break;
 		case 'l': 
 			action = RAIDFRAME_SET_COMPONENT_LABEL;
 			strlcpy(component, optarg, sizeof(component));
@@ -308,6 +329,12 @@
 		else
 			rf_get_device_status(fd);
 		break;
+	case RAIDFRAME_PARITYMAP_STATUS:
+		rf_output_pmstat(fd, raidID);
+		break;
+	case RAIDFRAME_PARITYMAP_SET_DISABLE:
+		rf_pm_configure(fd, raidID, parityconf, parityparams);
+		break;
 	case RAIDFRAME_REBUILD_IN_PLACE:
 		rebuild_in_place(fd, component);
 		break;
@@ -455,6 +482,105 @@
 }
 
 static void
+rf_output_pmstat(int fd, int raidID)
+{
+	char srs[7];
+	int i, j, dr;
+	int dis;
+	struct rf_pmstat st;
+
+	do_ioctl(fd, RAIDFRAME_PARITYMAP_STATUS, &st,
+	    "RAIDFRAME_PARITYMAP_STATUS");
+	if (st.enabled) {
+		if (0 > humanize_number(srs, 7, st.region_size * DEV_BSIZE, 
+			"B", HN_AUTOSCALE, HN_NOSPACE))
+			strlcpy(srs, "???", 7);
+
+		printf("raid%d: parity map enabled with %u regions of %s\n",
+		    raidID, st.params.regions, srs);
+		printf("raid%d: parity cleaned after %d intervals of"
+		    " %d.%03ds\n", raidID, st.params.cooldown,
+		    st.params.tickms / 1000, st.params.tickms % 1000);
+		printf("raid%d: write/sync/clean counters "
+		    "%"PRIu64"/%"PRIu64"/%"PRIu64"\n", raidID,
+		    st.ctrs.nwrite, st.ctrs.ncachesync, st.ctrs.nclearing);
+
+		dr = 0;
+		for (i = 0; i < RF_PARITYMAP_NREG; i++)
+			if (isset(st.dirty, i))
+				dr++;
+		printf("raid%d: %d dirty region%s\n", raidID, dr,
+		    dr == 1 ? "" : "s");
+
+		if (verbose > 0) {
+			for (i = 0; i < RF_PARITYMAP_NBYTE; i += 32) {
+				printf("    ");
+				for (j = i; j < RF_PARITYMAP_NBYTE
+					 && j < i + 32; j++)
+					printf("%x%x", st.dirty[j] & 15, 
+					    (st.dirty[j] >> 4) & 15);
+				printf("\n");
+			}
+		}
+	} else {
+		printf("raid%d: parity map disabled\n", raidID);
+	}
+
+	do_ioctl(fd, RAIDFRAME_PARITYMAP_GET_DISABLE, &dis,
+	    "RAIDFRAME_PARITYMAP_GET_DISABLE");
+	printf("raid%d: parity map will %s %sabled on next configure\n", 
+	    raidID, dis == st.enabled ? "be" : "remain", dis ? "dis" : "en");
+}
+
+static void
+rf_pm_configure(int fd, int raidID, char *parityconf, int parityparams[])
+{
+	int dis;
+	struct rf_pmparams params;
+
+	if (strcasecmp(parityconf, "yes") == 0)
+		dis = 0;
+	else if (strcasecmp(parityconf, "no") == 0)
+		dis = 1;
+	else if (strcasecmp(parityconf, "set") == 0) {
+		params.cooldown = parityparams[0];
+		params.tickms = parityparams[1];
+		params.regions = parityparams[2];
+		
+		do_ioctl(fd, RAIDFRAME_PARITYMAP_SET_PARAMS, &params,
+		    "RAIDFRAME_PARITYMAP_SET_PARAMS");
+
+		if (params.cooldown != 0 || params.tickms != 0) {
+			printf("raid%d: parity cleaned after", raidID);
+			if (params.cooldown != 0)
+				printf(" %d", params.cooldown);
+			printf(" intervals");
+			if (params.tickms != 0) {
+				printf(" of %d.%03ds", params.tickms / 1000,
+				    params.tickms % 1000);
+			}
+			printf("\n");
+		}
+		if (params.regions != 0)
+			printf("raid%d: will use %d regions on next"
+			    " configuration\n", raidID, params.regions);
+
+		return;
+		/* XXX the control flow here could be prettier. */
+	} else {
+		fprintf(stderr, "%s: \"%s\" is not a valid parity map command"
+		    "\n", getprogname(), parityconf);
+		exit(1);
+	}
+
+	do_ioctl(fd, RAIDFRAME_PARITYMAP_SET_DISABLE, &dis,
+	    "RAIDFRAME_PARITYMAP_SET_DISABLE");
+	printf("raid%d: parity map will be %sabled on next configure\n", 
+	    raidID, dis ? "dis" : "en");
+}
+
+
+static void
 rf_output_configuration(int fd, const char *name)
 {
 	RF_DeviceConfig_t device_config;
@@ -1022,7 +1148,7 @@
 	const char *progname = getprogname();
 
 	fprintf(stderr, "usage: %s [-v] -a component dev\n", progname);
-	fprintf(stderr, "       %s [-v] -A yes | no | root dev\n", progname);
+	fprintf(stderr, "       %s [-v] -A [yes | no | root] dev\n", progname);
 	fprintf(stderr, "       %s [-v] -B dev\n", progname);
 	fprintf(stderr, "       %s [-v] -c config_file dev\n", progname);
 	fprintf(stderr, "       %s [-v] -C config_file dev\n", progname);
@@ -1032,6 +1158,9 @@
 	fprintf(stderr, "       %s [-v] -G dev\n", progname);
 	fprintf(stderr, "       %s [-v] -i dev\n", progname);
 	fprintf(stderr, "       %s [-v] -I serial_number dev\n", progname);
+	fprintf(stderr, "       %s [-v] -m dev\n", progname);
+	fprintf(stderr, "       %s [-v] -M [yes | no | set params] dev\n",
+	    progname);
 	fprintf(stderr, "       %s [-v] -p dev\n", progname);
 	fprintf(stderr, "       %s [-v] -P dev\n", progname);
 	fprintf(stderr, "       %s [-v] -r component dev\n", progname); 

Index: src/sys/dev/raidframe/files.raidframe
diff -u src/sys/dev/raidframe/files.raidframe:1.6 src/sys/dev/raidframe/files.raidframe:1.6.6.1
--- src/sys/dev/raidframe/files.raidframe:1.6	Tue Jun 10 12:49:16 2008
+++ src/sys/dev/raidframe/files.raidframe	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-#	$NetBSD: files.raidframe,v 1.6 2008/06/10 12:49:16 drochner Exp $
+#	$NetBSD: files.raidframe,v 1.6.6.1 2009/12/10 22:59:16 snj Exp $
 
 defflag			RAID_AUTOCONFIG
 defflag			RAID_DIAGNOSTIC
@@ -42,6 +42,7 @@
 file	dev/raidframe/rf_paritylogDiskMgr.c	raid
 file	dev/raidframe/rf_paritylogging.c	raid
 file	dev/raidframe/rf_parityloggingdags.c	raid
+file	dev/raidframe/rf_paritymap.c		raid
 file	dev/raidframe/rf_parityscan.c		raid
 file	dev/raidframe/rf_pq.c			raid
 file	dev/raidframe/rf_pqdeg.c		raid

Index: src/sys/dev/raidframe/raidframeio.h
diff -u src/sys/dev/raidframe/raidframeio.h:1.4 src/sys/dev/raidframe/raidframeio.h:1.4.10.1
--- src/sys/dev/raidframe/raidframeio.h:1.4	Mon Apr 28 20:23:56 2008
+++ src/sys/dev/raidframe/raidframeio.h	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: raidframeio.h,v 1.4 2008/04/28 20:23:56 martin Exp $ */
+/*	$NetBSD: raidframeio.h,v 1.4.10.1 2009/12/10 22:59:16 snj Exp $ */
 /*-
  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -125,4 +125,9 @@
 #define RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT _IOWR ('r', 33, RF_ProgressInfo_t *)
 #define RAIDFRAME_CHECK_COPYBACK_STATUS_EXT _IOWR ('r', 34, RF_ProgressInfo_t *)
 
+#define RAIDFRAME_PARITYMAP_STATUS  _IOR('r', 37, struct rf_pmstat)
+#define RAIDFRAME_PARITYMAP_GET_DISABLE _IOR('r', 38, int)
+#define RAIDFRAME_PARITYMAP_SET_DISABLE _IOW('r', 39, int)
+#define RAIDFRAME_PARITYMAP_SET_PARAMS _IOW('r', 40, struct rf_pmparams)
+
 #endif				/* !_RF_RAIDFRAMEIO_H_ */

Index: src/sys/dev/raidframe/raidframevar.h
diff -u src/sys/dev/raidframe/raidframevar.h:1.12 src/sys/dev/raidframe/raidframevar.h:1.12.10.1
--- src/sys/dev/raidframe/raidframevar.h:1.12	Mon Apr 28 20:23:56 2008
+++ src/sys/dev/raidframe/raidframevar.h	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: raidframevar.h,v 1.12 2008/04/28 20:23:56 martin Exp $ */
+/*	$NetBSD: raidframevar.h,v 1.12.10.1 2009/12/10 22:59:16 snj Exp $ */
 /*-
  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -265,6 +265,9 @@
 typedef struct RF_ThreadGroup_s RF_ThreadGroup_t;
 typedef struct RF_ThroughputStats_s RF_ThroughputStats_t;
 
+struct rf_paritymap;
+struct rf_paritymap_ondisk;
+
 /*
  * Important assumptions regarding ordering of the states in this list
  * have been made!!!  Before disturbing this ordering, look at code in
@@ -446,7 +449,16 @@
 	u_int partitionSize;  /* number of blocks on this *partition*.
 				 Must exactly match the partition size
 				 from the disklabel. */
-	int future_use[33];   /* Future expansion */
+	/* Parity map stuff. */
+	int parity_map_modcount; /* If equal to mod_counter, then the last
+				    kernel to touch this label was
+				    parity-map-enabled. */
+	u_int parity_map_flags;  /* See top of rf_paritymap.h */
+	int parity_map_tickms; /* Length of parity map cooldown ticks. */
+	int parity_map_ntick;  /* Number of parity map cooldown ticks. */
+	u_int parity_map_regions; /* Number of parity map regions. */
+	int future_use[28];   /* Future expansion */
+
 	int autoconfigure;    /* automatically configure this RAID set.
 				 0 == no, 1 == yes */
 	int root_partition;   /* Use this set as /
@@ -569,4 +581,28 @@
 }       RF_LayoutSW_t;
 #endif
 
+
+/* Parity map declarations. */
+#define RF_PARITYMAP_NREG 4096
+#define RF_PARITYMAP_NBYTE howmany(RF_PARITYMAP_NREG, NBBY)
+
+struct rf_pmctrs {
+	uint64_t nwrite, ncachesync, nclearing;
+};
+
+struct rf_pmparams {
+	int cooldown, tickms;
+	u_int regions;
+};
+
+struct rf_pmstat {
+	int enabled; /* if not set, rest of struct is zeroed */
+	struct rf_pmparams params;
+	daddr_t region_size;
+	char dirty[RF_PARITYMAP_NBYTE];
+	struct rf_pmctrs ctrs;
+};
+
+
+
 #endif				/* !_RF_RAIDFRAMEVAR_H_ */

Index: src/sys/dev/raidframe/rf_copyback.c
diff -u src/sys/dev/raidframe/rf_copyback.c:1.41 src/sys/dev/raidframe/rf_copyback.c:1.41.20.1
--- src/sys/dev/raidframe/rf_copyback.c:1.41	Sat Jan 26 20:44:37 2008
+++ src/sys/dev/raidframe/rf_copyback.c	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_copyback.c,v 1.41 2008/01/26 20:44:37 oster Exp $	*/
+/*	$NetBSD: rf_copyback.c,v 1.41.20.1 2009/12/10 22:59:16 snj Exp $	*/
 /*
  * Copyright (c) 1995 Carnegie-Mellon University.
  * All rights reserved.
@@ -38,7 +38,7 @@
  ****************************************************************************/
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rf_copyback.c,v 1.41 2008/01/26 20:44:37 oster Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rf_copyback.c,v 1.41.20.1 2009/12/10 22:59:16 snj Exp $");
 
 #include <dev/raidframe/raidframevar.h>
 
@@ -86,7 +86,7 @@
 void
 rf_CopybackReconstructedData(RF_Raid_t *raidPtr)
 {
-	RF_ComponentLabel_t c_label;
+	RF_ComponentLabel_t *c_label;
 	int     found, retcode;
 	RF_CopybackDesc_t *desc;
 	RF_RowCol_t fcol;
@@ -206,19 +206,17 @@
 
 	/* Data has been restored.  Fix up the component label. */
 	/* Don't actually need the read here.. */
-	raidread_component_label( raidPtr->raid_cinfo[fcol].ci_dev,
-				  raidPtr->raid_cinfo[fcol].ci_vp,
-				  &c_label);
-
-	raid_init_component_label( raidPtr, &c_label );
-
-	c_label.row = 0;
-	c_label.column = fcol;
-	c_label.partitionSize = raidPtr->Disks[fcol].partitionSize;
-
-	raidwrite_component_label( raidPtr->raid_cinfo[fcol].ci_dev,
-				   raidPtr->raid_cinfo[fcol].ci_vp,
-				   &c_label);
+	
+	c_label = raidget_component_label(raidPtr, fcol);
+	raid_init_component_label(raidPtr, c_label);
+
+	c_label->row = 0;
+	c_label->column = fcol;
+	c_label->partitionSize = raidPtr->Disks[fcol].partitionSize;
+
+	raidflush_component_label(raidPtr, fcol);
+
+	/* XXXjld why is this here? */
 	rf_update_component_labels(raidPtr, RF_NORMAL_COMPONENT_UPDATE);
 }
 

Index: src/sys/dev/raidframe/rf_disks.c
diff -u src/sys/dev/raidframe/rf_disks.c:1.70.10.1 src/sys/dev/raidframe/rf_disks.c:1.70.10.2
--- src/sys/dev/raidframe/rf_disks.c:1.70.10.1	Sat Apr  4 17:15:14 2009
+++ src/sys/dev/raidframe/rf_disks.c	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_disks.c,v 1.70.10.1 2009/04/04 17:15:14 snj Exp $	*/
+/*	$NetBSD: rf_disks.c,v 1.70.10.2 2009/12/10 22:59:16 snj Exp $	*/
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -60,7 +60,7 @@
  ***************************************************************/
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rf_disks.c,v 1.70.10.1 2009/04/04 17:15:14 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rf_disks.c,v 1.70.10.2 2009/12/10 22:59:16 snj Exp $");
 
 #include <dev/raidframe/raidframevar.h>
 
@@ -132,10 +132,7 @@
 			goto fail;
 
 		if (disks[c].status == rf_ds_optimal) {
-			raidread_component_label(
-						 raidPtr->raid_cinfo[c].ci_dev,
-						 raidPtr->raid_cinfo[c].ci_vp,
-						 &raidPtr->raid_cinfo[c].ci_label);
+			raidfetch_component_label(raidPtr, c);
 		}
 
 		if (disks[c].status != rf_ds_optimal) {
@@ -461,7 +458,7 @@
 			raidPtr->raid_cinfo[c].ci_vp = ac->vp;
 			raidPtr->raid_cinfo[c].ci_dev = ac->dev;
 
-			memcpy(&raidPtr->raid_cinfo[c].ci_label,
+			memcpy(raidget_component_label(raidPtr, c),
 			    ac->clabel, sizeof(*ac->clabel));
 			snprintf(diskPtr->devname, sizeof(diskPtr->devname),
 			    "/dev/%s", ac->devname);
@@ -731,7 +728,7 @@
 	num_mod = 0;
 
 	for (c = 0; c < raidPtr->numCol; c++) {
-		ci_label = &raidPtr->raid_cinfo[c].ci_label;
+		ci_label = raidget_component_label(raidPtr, c);
 		found=0;
 		for(i=0;i<num_ser;i++) {
 			if (ser_values[i] == ci_label->serial_number) {
@@ -786,7 +783,7 @@
 			}
 
 			for (c = 0; c < raidPtr->numCol; c++) {
-				ci_label = &raidPtr->raid_cinfo[c].ci_label;
+				ci_label = raidget_component_label(raidPtr, c);
 				if (serial_number != ci_label->serial_number) {
 					hosed_column = c;
 					break;
@@ -841,7 +838,7 @@
 			}
 
 			for (c = 0; c < raidPtr->numCol; c++) {
-				ci_label = &raidPtr->raid_cinfo[c].ci_label;
+				ci_label = raidget_component_label(raidPtr, c);
 				if (mod_number != ci_label->mod_counter) {
 					if (hosed_column == c) {
 						/* same one.  Can
@@ -908,7 +905,7 @@
 
 	for (c = 0; c < raidPtr->numCol; c++) {
 		dev_name = &cfgPtr->devnames[0][c][0];
-		ci_label = &raidPtr->raid_cinfo[c].ci_label;
+		ci_label = raidget_component_label(raidPtr, c);
 
 		if (c == hosed_column) {
 			printf("raid%d: Ignoring %s\n",

Index: src/sys/dev/raidframe/rf_driver.c
diff -u src/sys/dev/raidframe/rf_driver.c:1.118.10.1 src/sys/dev/raidframe/rf_driver.c:1.118.10.2
--- src/sys/dev/raidframe/rf_driver.c:1.118.10.1	Tue Dec 23 04:03:00 2008
+++ src/sys/dev/raidframe/rf_driver.c	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_driver.c,v 1.118.10.1 2008/12/23 04:03:00 snj Exp $	*/
+/*	$NetBSD: rf_driver.c,v 1.118.10.2 2009/12/10 22:59:16 snj Exp $	*/
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -66,7 +66,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rf_driver.c,v 1.118.10.1 2008/12/23 04:03:00 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rf_driver.c,v 1.118.10.2 2009/12/10 22:59:16 snj Exp $");
 
 #include "opt_raid_diagnostic.h"
 
@@ -107,6 +107,7 @@
 #include "rf_options.h"
 #include "rf_shutdown.h"
 #include "rf_kintf.h"
+#include "rf_paritymap.h"
 
 #include <sys/buf.h>
 
@@ -239,6 +240,9 @@
 
 	raidPtr->valid = 0;
 
+	if (raidPtr->parity_map != NULL)
+		rf_paritymap_detach(raidPtr);
+
 	rf_update_component_labels(raidPtr, RF_FINAL_COMPONENT_UPDATE);
 
 	rf_UnconfigureVnodes(raidPtr);
@@ -414,6 +418,11 @@
 		return(rc);
 	}
 
+	/* Set up parity map stuff, if applicable. */
+#ifndef RF_NO_PARITY_MAP
+	rf_paritymap_attach(raidPtr, cfgPtr->force);
+#endif
+
 	raidPtr->valid = 1;
 
 	printf("raid%d: %s\n", raidPtr->raidid,
@@ -674,6 +683,11 @@
 #endif
 	desc->async_flag = async_flag;
 
+	if (raidPtr->parity_map != NULL && 
+	    type == RF_IO_TYPE_WRITE)
+		rf_paritymap_begin(raidPtr->parity_map, raidAddress, 
+		    numBlocks);
+
 	rf_ContinueRaidAccess(desc);
 
 	return (0);

Index: src/sys/dev/raidframe/rf_engine.c
diff -u src/sys/dev/raidframe/rf_engine.c:1.39 src/sys/dev/raidframe/rf_engine.c:1.39.64.1
--- src/sys/dev/raidframe/rf_engine.c:1.39	Thu Nov 16 01:33:23 2006
+++ src/sys/dev/raidframe/rf_engine.c	Thu Dec 10 22:59:16 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_engine.c,v 1.39 2006/11/16 01:33:23 christos Exp $	*/
+/*	$NetBSD: rf_engine.c,v 1.39.64.1 2009/12/10 22:59:16 snj Exp $	*/
 /*
  * Copyright (c) 1995 Carnegie-Mellon University.
  * All rights reserved.
@@ -55,7 +55,7 @@
  ****************************************************************************/
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rf_engine.c,v 1.39 2006/11/16 01:33:23 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rf_engine.c,v 1.39.64.1 2009/12/10 22:59:16 snj Exp $");
 
 #include <sys/errno.h>
 
@@ -68,6 +68,7 @@
 #include "rf_shutdown.h"
 #include "rf_raid.h"
 #include "rf_kintf.h"
+#include "rf_paritymap.h"
 
 static void rf_ShutdownEngine(void *);
 static void DAGExecutionThread(RF_ThreadArg_t arg);
@@ -855,6 +856,13 @@
 				&(raidPtr->iodone_lock));
 		}
 
+		/* Check for deferred parity-map-related work. */
+		if (raidPtr->parity_map != NULL) {
+			simple_unlock(&(raidPtr->iodone_lock));
+			rf_paritymap_checkwork(raidPtr->parity_map);
+			simple_lock(&(raidPtr->iodone_lock));
+		}
+
 		/* See what I/Os, if any, have arrived */
 		while ((req = TAILQ_FIRST(&(raidPtr->iodone))) != NULL) {
 			TAILQ_REMOVE(&(raidPtr->iodone), req, iodone_entries);

Index: src/sys/dev/raidframe/rf_kintf.h
diff -u src/sys/dev/raidframe/rf_kintf.h:1.20 src/sys/dev/raidframe/rf_kintf.h:1.20.68.1
--- src/sys/dev/raidframe/rf_kintf.h:1.20	Sun Aug 27 05:07:12 2006
+++ src/sys/dev/raidframe/rf_kintf.h	Thu Dec 10 22:59:17 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_kintf.h,v 1.20 2006/08/27 05:07:12 christos Exp $	*/
+/*	$NetBSD: rf_kintf.h,v 1.20.68.1 2009/12/10 22:59:17 snj Exp $	*/
 /*
  * rf_kintf.h
  *
@@ -41,18 +41,24 @@
 void    raidstart(RF_Raid_t * raidPtr);
 int     rf_DispatchKernelIO(RF_DiskQueue_t * queue, RF_DiskQueueData_t * req);
 
-int raidwrite_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *);
-int raidread_component_label(dev_t, struct vnode *, RF_ComponentLabel_t *);
+int raidfetch_component_label(RF_Raid_t *, RF_RowCol_t);
+RF_ComponentLabel_t *raidget_component_label(RF_Raid_t *, RF_RowCol_t);
+int raidflush_component_label(RF_Raid_t *, RF_RowCol_t);
+
+void rf_paritymap_kern_write(RF_Raid_t *, struct rf_paritymap_ondisk *);
+void rf_paritymap_kern_read(RF_Raid_t *, struct rf_paritymap_ondisk *);
 
 #define RF_NORMAL_COMPONENT_UPDATE 0
 #define RF_FINAL_COMPONENT_UPDATE 1
 void rf_update_component_labels(RF_Raid_t *, int);
-int raidmarkclean(dev_t dev, struct vnode *b_vp, int);
-int raidmarkdirty(dev_t dev, struct vnode *b_vp, int);
+int raidmarkclean(RF_Raid_t *, RF_RowCol_t);
+int raidmarkdirty(RF_Raid_t *, RF_RowCol_t);
 void raid_init_component_label(RF_Raid_t *, RF_ComponentLabel_t *);
 void rf_print_component_label(RF_ComponentLabel_t *);
 void rf_UnconfigureVnodes( RF_Raid_t * );
 void rf_close_component( RF_Raid_t *, struct vnode *, int);
 void rf_disk_unbusy(RF_RaidAccessDesc_t *);
 int rf_getdisksize(struct vnode *, struct lwp *, RF_RaidDisk_t *);
+int rf_sync_component_caches(RF_Raid_t *raidPtr);
 #endif				/* _RF__RF_KINTF_H_ */
+

Index: src/sys/dev/raidframe/rf_netbsdkintf.c
diff -u src/sys/dev/raidframe/rf_netbsdkintf.c:1.250.4.4 src/sys/dev/raidframe/rf_netbsdkintf.c:1.250.4.5
--- src/sys/dev/raidframe/rf_netbsdkintf.c:1.250.4.4	Sat Apr  4 17:15:14 2009
+++ src/sys/dev/raidframe/rf_netbsdkintf.c	Thu Dec 10 22:59:17 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_netbsdkintf.c,v 1.250.4.4 2009/04/04 17:15:14 snj Exp $	*/
+/*	$NetBSD: rf_netbsdkintf.c,v 1.250.4.5 2009/12/10 22:59:17 snj Exp $	*/
 /*-
  * Copyright (c) 1996, 1997, 1998, 2008 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -139,7 +139,7 @@
  ***********************************************************/
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rf_netbsdkintf.c,v 1.250.4.4 2009/04/04 17:15:14 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rf_netbsdkintf.c,v 1.250.4.5 2009/12/10 22:59:17 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/errno.h>
@@ -165,6 +165,7 @@
 
 #include <dev/raidframe/raidframevar.h>
 #include <dev/raidframe/raidframeio.h>
+#include <dev/raidframe/rf_paritymap.h>
 #include "raid.h"
 #include "opt_raid_autoconfig.h"
 #include "rf_raid.h"
@@ -213,6 +214,17 @@
 static void raid_attach(struct device *, struct device *, void *);
 static int raid_detach(struct device *, int);
 
+static int raidread_component_area(dev_t, struct vnode *, void *, size_t, 
+    daddr_t, daddr_t);
+static int raidwrite_component_area(dev_t, struct vnode *, void *, size_t,
+    daddr_t, daddr_t, int);
+
+static int raidwrite_component_label(dev_t, struct vnode *,
+    RF_ComponentLabel_t *);
+static int raidread_component_label(dev_t, struct vnode *,
+    RF_ComponentLabel_t *);
+
+
 dev_type_open(raidopen);
 dev_type_close(raidclose);
 dev_type_read(raidread);
@@ -317,7 +329,6 @@
 void rf_cleanup_config_set(RF_ConfigSet_t *);
 int rf_have_enough_components(RF_ConfigSet_t *);
 int rf_auto_config_set(RF_ConfigSet_t *, int *);
-static int rf_sync_component_caches(RF_Raid_t *raidPtr);
 
 static int raidautoconfig = 0; /* Debugging, mostly.  Set to 0 to not
 				  allow autoconfig to take place.
@@ -981,7 +992,7 @@
 	u_char *specific_buf;
 	int retcode = 0;
 	int column;
-	int raidid;
+/*	int raidid; */
 	struct rf_recon_req *rrcopy, *rr;
 	RF_ComponentLabel_t *clabel;
 	RF_ComponentLabel_t *ci_label;
@@ -1071,6 +1082,10 @@
 	case RAIDFRAME_SET_ROOT:
 	case RAIDFRAME_DELETE_COMPONENT:
 	case RAIDFRAME_INCORPORATE_HOT_SPARE:
+	case RAIDFRAME_PARITYMAP_STATUS:
+	case RAIDFRAME_PARITYMAP_GET_DISABLE:
+	case RAIDFRAME_PARITYMAP_SET_DISABLE:
+	case RAIDFRAME_PARITYMAP_SET_PARAMS:
 		if ((rs->sc_flags & RAIDF_INITED) == 0)
 			return (ENXIO);
 	}
@@ -1206,18 +1221,16 @@
 		/* need to read the component label for the disk indicated
 		   by row,column in clabel */
 
-		/* For practice, let's get it directly fromdisk, rather
-		   than from the in-core copy */
-		RF_Malloc( clabel, sizeof( RF_ComponentLabel_t ),
-			   (RF_ComponentLabel_t *));
-		if (clabel == NULL)
-			return (ENOMEM);
+		/*
+		 * Perhaps there should be an option to skip the in-core
+		 * copy and hit the disk, as with disklabel(8).
+		 */
+		RF_Malloc(clabel, sizeof(*clabel), (RF_ComponentLabel_t *));
 
 		retcode = copyin( *clabel_ptr, clabel,
 				  sizeof(RF_ComponentLabel_t));
 
 		if (retcode) {
-			RF_Free( clabel, sizeof(RF_ComponentLabel_t));
 			return(retcode);
 		}
 
@@ -1227,21 +1240,20 @@
 
 		if ((column < 0) || (column >= raidPtr->numCol +
 				     raidPtr->numSpare)) {
-			RF_Free( clabel, sizeof(RF_ComponentLabel_t));
 			return(EINVAL);
 		}
 
-		retcode = raidread_component_label(raidPtr->Disks[column].dev,
-				raidPtr->raid_cinfo[column].ci_vp,
-				clabel );
+		RF_Free(clabel, sizeof(*clabel));
+
+		clabel = raidget_component_label(raidPtr, column);
 
 		if (retcode == 0) {
 			retcode = copyout(clabel, *clabel_ptr,
 					  sizeof(RF_ComponentLabel_t));
 		}
-		RF_Free(clabel, sizeof(RF_ComponentLabel_t));
 		return (retcode);
 
+#if 0
 	case RAIDFRAME_SET_COMPONENT_LABEL:
 		clabel = (RF_ComponentLabel_t *) data;
 
@@ -1273,13 +1285,11 @@
 
 		/* XXX and before it is, we need to fill in the rest
 		   of the fields!?!?!?! */
-#if 0
-		raidwrite_component_label(
-		     raidPtr->Disks[column].dev,
-			    raidPtr->raid_cinfo[column].ci_vp,
-			    clabel );
-#endif
+		memcpy(raidget_component_label(raidPtr, column),
+		    clabel, sizeof(*clabel));
+		raidflush_component_label(raidPtr, column);
 		return (0);
+#endif
 
 	case RAIDFRAME_INIT_LABELS:
 		clabel = (RF_ComponentLabel_t *) data;
@@ -1292,27 +1302,24 @@
 
 		raidPtr->serial_number = clabel->serial_number;
 
-		RF_Malloc(ci_label, sizeof(RF_ComponentLabel_t), 
-			  (RF_ComponentLabel_t *));
-		if (ci_label == NULL)
-			return (ENOMEM);
-
-		raid_init_component_label(raidPtr, ci_label);
-		ci_label->serial_number = clabel->serial_number;
-		ci_label->row = 0; /* we dont' pretend to support more */
-
 		for(column=0;column<raidPtr->numCol;column++) {
 			diskPtr = &raidPtr->Disks[column];
 			if (!RF_DEAD_DISK(diskPtr->status)) {
-				ci_label->partitionSize = diskPtr->partitionSize;
+				ci_label = raidget_component_label(raidPtr,
+				    column);
+				/* Zeroing this is important. */
+				memset(ci_label, 0, sizeof(*ci_label));
+				raid_init_component_label(raidPtr, ci_label);
+				ci_label->serial_number = 
+				    raidPtr->serial_number;
+				ci_label->row = 0; /* we dont' pretend to support more */
+				ci_label->partitionSize =
+				    diskPtr->partitionSize;
 				ci_label->column = column;
-				raidwrite_component_label(
-							  raidPtr->Disks[column].dev,
-							  raidPtr->raid_cinfo[column].ci_vp,
-							  ci_label );
+				raidflush_component_label(raidPtr, column);
 			}
+			/* XXXjld what about the spares? */
 		}
-		RF_Free(ci_label, sizeof(RF_ComponentLabel_t));
 		
 		return (retcode);
 	case RAIDFRAME_SET_AUTOCONFIG:
@@ -1473,6 +1480,28 @@
 		*(int *) data = raidPtr->parity_good;
 		return (0);
 
+	case RAIDFRAME_PARITYMAP_STATUS:
+		rf_paritymap_status(raidPtr->parity_map,
+		    (struct rf_pmstat *)data);
+		return 0;
+
+	case RAIDFRAME_PARITYMAP_SET_PARAMS:
+		if (raidPtr->parity_map == NULL)
+			return ENOENT; /* ??? */
+		if (0 != rf_paritymap_set_params(raidPtr->parity_map, 
+			(struct rf_pmparams *)data, 1))
+			return EINVAL;
+		return 0;
+
+	case RAIDFRAME_PARITYMAP_GET_DISABLE:
+		*(int *) data = rf_paritymap_get_disable(raidPtr);
+		return 0;
+
+	case RAIDFRAME_PARITYMAP_SET_DISABLE:
+		rf_paritymap_set_disable(raidPtr, *(int *)data);
+		/* XXX should errors be passed up? */
+		return 0;
+
 	case RAIDFRAME_RESET_ACCTOTALS:
 		memset(&raidPtr->acc_totals, 0, sizeof(raidPtr->acc_totals));
 		return (0);
@@ -2380,34 +2409,75 @@
 
 #define RF_COMPONENT_INFO_OFFSET  16384 /* bytes */
 #define RF_COMPONENT_INFO_SIZE     1024 /* bytes */
+#define RF_PARITY_MAP_OFFSET \
+	(RF_COMPONENT_INFO_OFFSET + RF_COMPONENT_INFO_SIZE)
+#define RF_PARITY_MAP_SIZE   RF_PARITYMAP_NBYTE
 
 int
-raidmarkclean(dev_t dev, struct vnode *b_vp, int mod_counter)
+raidmarkclean(RF_Raid_t *raidPtr, RF_RowCol_t col)
 {
-	RF_ComponentLabel_t clabel;
-	raidread_component_label(dev, b_vp, &clabel);
-	clabel.mod_counter = mod_counter;
-	clabel.clean = RF_RAID_CLEAN;
-	raidwrite_component_label(dev, b_vp, &clabel);
+	RF_ComponentLabel_t *clabel;
+
+	clabel = raidget_component_label(raidPtr, col);
+	clabel->clean = RF_RAID_CLEAN;
+	raidflush_component_label(raidPtr, col);
 	return(0);
 }
 
 
 int
-raidmarkdirty(dev_t dev, struct vnode *b_vp, int mod_counter)
+raidmarkdirty(RF_Raid_t *raidPtr, RF_RowCol_t col)
 {
-	RF_ComponentLabel_t clabel;
-	raidread_component_label(dev, b_vp, &clabel);
-	clabel.mod_counter = mod_counter;
-	clabel.clean = RF_RAID_DIRTY;
-	raidwrite_component_label(dev, b_vp, &clabel);
+	RF_ComponentLabel_t *clabel;
+
+	clabel = raidget_component_label(raidPtr, col);
+	clabel->clean = RF_RAID_DIRTY;
+	raidflush_component_label(raidPtr, col);
 	return(0);
 }
 
-/* ARGSUSED */
 int
+raidfetch_component_label(RF_Raid_t *raidPtr, RF_RowCol_t col)
+{
+	return raidread_component_label(raidPtr->Disks[col].dev,
+	    raidPtr->raid_cinfo[col].ci_vp, 
+	    &raidPtr->raid_cinfo[col].ci_label);
+}
+
+RF_ComponentLabel_t *
+raidget_component_label(RF_Raid_t *raidPtr, RF_RowCol_t col)
+{
+	return &raidPtr->raid_cinfo[col].ci_label;
+}
+
+int
+raidflush_component_label(RF_Raid_t *raidPtr, RF_RowCol_t col)
+{
+	RF_ComponentLabel_t *label;
+
+	label = &raidPtr->raid_cinfo[col].ci_label;
+	label->mod_counter = raidPtr->mod_counter;
+#ifndef RF_NO_PARITY_MAP
+	label->parity_map_modcount = label->mod_counter;
+#endif
+	return raidwrite_component_label(raidPtr->Disks[col].dev,
+	    raidPtr->raid_cinfo[col].ci_vp, label);
+}
+
+
+static int
 raidread_component_label(dev_t dev, struct vnode *b_vp,
-			 RF_ComponentLabel_t *clabel)
+    RF_ComponentLabel_t *clabel)
+{
+	return raidread_component_area(dev, b_vp, clabel, 
+	    sizeof(RF_ComponentLabel_t),
+	    RF_COMPONENT_INFO_OFFSET, RF_COMPONENT_INFO_SIZE);
+}
+
+/* ARGSUSED */
+static int
+raidread_component_area(dev_t dev, struct vnode *b_vp, void *data,
+    size_t msize, daddr_t offset, daddr_t dsize)
 {
 	struct buf *bp;
 	const struct bdevsw *bdev;
@@ -2423,14 +2493,14 @@
 	}
 
 	/* get a block of the appropriate size... */
-	bp = geteblk((int)RF_COMPONENT_INFO_SIZE);
+	bp = geteblk((int)dsize);
 	bp->b_dev = dev;
 
 	/* get our ducks in a row for the read */
-	bp->b_blkno = RF_COMPONENT_INFO_OFFSET / DEV_BSIZE;
-	bp->b_bcount = RF_COMPONENT_INFO_SIZE;
+	bp->b_blkno = offset / DEV_BSIZE;
+	bp->b_bcount = dsize;
 	bp->b_flags |= B_READ;
- 	bp->b_resid = RF_COMPONENT_INFO_SIZE / DEV_BSIZE;
+ 	bp->b_resid = dsize;
 
 	bdev = bdevsw_lookup(bp->b_dev);
 	if (bdev == NULL)
@@ -2440,40 +2510,51 @@
 	error = biowait(bp);
 
 	if (!error) {
-		memcpy(clabel, bp->b_data,
-		       sizeof(RF_ComponentLabel_t));
+		memcpy(data, bp->b_data, msize);
 	}
 
 	brelse(bp, 0);
 	return(error);
 }
-/* ARGSUSED */
-int
+
+
+static int
 raidwrite_component_label(dev_t dev, struct vnode *b_vp,
-			  RF_ComponentLabel_t *clabel)
+	RF_ComponentLabel_t *clabel)
+{
+	return raidwrite_component_area(dev, b_vp, clabel,
+	    sizeof(RF_ComponentLabel_t),
+	    RF_COMPONENT_INFO_OFFSET, RF_COMPONENT_INFO_SIZE, 0);
+}
+
+/* ARGSUSED */
+static int
+raidwrite_component_area(dev_t dev, struct vnode *b_vp, void *data, 
+    size_t msize, daddr_t offset, daddr_t dsize, int asyncp)
 {
 	struct buf *bp;
 	const struct bdevsw *bdev;
 	int error;
 
 	/* get a block of the appropriate size... */
-	bp = geteblk((int)RF_COMPONENT_INFO_SIZE);
+	bp = geteblk((int)dsize);
 	bp->b_dev = dev;
 
 	/* get our ducks in a row for the write */
-	bp->b_blkno = RF_COMPONENT_INFO_OFFSET / DEV_BSIZE;
-	bp->b_bcount = RF_COMPONENT_INFO_SIZE;
-	bp->b_flags |= B_WRITE;
- 	bp->b_resid = RF_COMPONENT_INFO_SIZE / DEV_BSIZE;
+	bp->b_blkno = offset / DEV_BSIZE;
+	bp->b_bcount = dsize;
+	bp->b_flags |= B_WRITE | (asyncp ? B_ASYNC : 0);
+ 	bp->b_resid = dsize;
 
-	memset(bp->b_data, 0, RF_COMPONENT_INFO_SIZE );
-
-	memcpy(bp->b_data, clabel, sizeof(RF_ComponentLabel_t));
+	memset(bp->b_data, 0, dsize);
+	memcpy(bp->b_data, data, msize);
 
 	bdev = bdevsw_lookup(bp->b_dev);
 	if (bdev == NULL)
 		return (ENXIO);
 	(*bdev->d_strategy)(bp);
+	if (asyncp)
+		return 0;
 	error = biowait(bp);
 	brelse(bp, 0);
 	if (error) {
@@ -2486,9 +2567,48 @@
 }
 
 void
+rf_paritymap_kern_write(RF_Raid_t *raidPtr, struct rf_paritymap_ondisk *map)
+{
+	int c;
+
+	for (c = 0; c < raidPtr->numCol; c++) {
+		/* Skip dead disks. */
+		if (RF_DEAD_DISK(raidPtr->Disks[c].status))
+			continue;
+		/* XXXjld: what if an error occurs here? */
+		raidwrite_component_area(raidPtr->Disks[c].dev,
+		    raidPtr->raid_cinfo[c].ci_vp, map,
+		    RF_PARITYMAP_NBYTE,
+		    RF_PARITY_MAP_OFFSET, RF_PARITY_MAP_SIZE, 0);
+	}
+}
+
+void
+rf_paritymap_kern_read(RF_Raid_t *raidPtr, struct rf_paritymap_ondisk *map)
+{
+	struct rf_paritymap_ondisk tmp;
+	int c;
+
+	for (c = 0; c < raidPtr->numCol; c++) {
+		/* Skip dead disks. */
+		if (RF_DEAD_DISK(raidPtr->Disks[c].status))
+			continue;
+		raidread_component_area(raidPtr->Disks[c].dev,
+		    raidPtr->raid_cinfo[c].ci_vp, &tmp,
+		    RF_PARITYMAP_NBYTE,
+		    RF_PARITY_MAP_OFFSET, RF_PARITY_MAP_SIZE);
+		if (c == 0) {
+			memcpy(map, &tmp, sizeof(*map));
+		} else {
+			rf_paritymap_merge(map, &tmp);
+		}
+	}
+}
+
+void
 rf_markalldirty(RF_Raid_t *raidPtr)
 {
-	RF_ComponentLabel_t clabel;
+	RF_ComponentLabel_t *clabel;
 	int sparecol;
 	int c;
 	int j;
@@ -2499,19 +2619,13 @@
 		/* we don't want to touch (at all) a disk that has
 		   failed */
 		if (!RF_DEAD_DISK(raidPtr->Disks[c].status)) {
-			raidread_component_label(
-						 raidPtr->Disks[c].dev,
-						 raidPtr->raid_cinfo[c].ci_vp,
-						 &clabel);
-			if (clabel.status == rf_ds_spared) {
+			clabel = raidget_component_label(raidPtr, c);
+			if (clabel->status == rf_ds_spared) {
 				/* XXX do something special...
 				   but whatever you do, don't
 				   try to access it!! */
 			} else {
-				raidmarkdirty(
-					      raidPtr->Disks[c].dev,
-					      raidPtr->raid_cinfo[c].ci_vp,
-					      raidPtr->mod_counter);
+				raidmarkdirty(raidPtr, c);
 			}
 		}
 	}
@@ -2535,23 +2649,18 @@
 				}
 			}
 
-			raidread_component_label(
-				 raidPtr->Disks[sparecol].dev,
-				 raidPtr->raid_cinfo[sparecol].ci_vp,
-				 &clabel);
+			clabel = raidget_component_label(raidPtr, sparecol);
 			/* make sure status is noted */
 
-			raid_init_component_label(raidPtr, &clabel);
+			raid_init_component_label(raidPtr, clabel);
 
-			clabel.row = 0;
-			clabel.column = scol;
+			clabel->row = 0;
+			clabel->column = scol;
 			/* Note: we *don't* change status from rf_ds_used_spare
 			   to rf_ds_optimal */
 			/* clabel.status = rf_ds_optimal; */
 
-			raidmarkdirty(raidPtr->Disks[sparecol].dev,
-				      raidPtr->raid_cinfo[sparecol].ci_vp,
-				      raidPtr->mod_counter);
+			raidmarkdirty(raidPtr, sparecol);
 		}
 	}
 }
@@ -2560,7 +2669,7 @@
 void
 rf_update_component_labels(RF_Raid_t *raidPtr, int final)
 {
-	RF_ComponentLabel_t clabel;
+	RF_ComponentLabel_t *clabel;
 	int sparecol;
 	int c;
 	int j;
@@ -2575,29 +2684,17 @@
 
 	for (c = 0; c < raidPtr->numCol; c++) {
 		if (raidPtr->Disks[c].status == rf_ds_optimal) {
-			raidread_component_label(
-						 raidPtr->Disks[c].dev,
-						 raidPtr->raid_cinfo[c].ci_vp,
-						 &clabel);
+			clabel = raidget_component_label(raidPtr, c);
 			/* make sure status is noted */
-			clabel.status = rf_ds_optimal;
-			
-			/* bump the counter */
-			clabel.mod_counter = raidPtr->mod_counter;
+			clabel->status = rf_ds_optimal;
 			
 			/* note what unit we are configured as */
-			clabel.last_unit = raidPtr->raidid;
+			clabel->last_unit = raidPtr->raidid;
 
-			raidwrite_component_label(
-						  raidPtr->Disks[c].dev,
-						  raidPtr->raid_cinfo[c].ci_vp,
-						  &clabel);
+			raidflush_component_label(raidPtr, c);
 			if (final == RF_FINAL_COMPONENT_UPDATE) {
 				if (raidPtr->parity_good == RF_RAID_CLEAN) {
-					raidmarkclean(
-						      raidPtr->Disks[c].dev,
-						      raidPtr->raid_cinfo[c].ci_vp,
-						      raidPtr->mod_counter);
+					raidmarkclean(raidPtr, c);
 				}
 			}
 		}
@@ -2625,28 +2722,19 @@
 			}
 
 			/* XXX shouldn't *really* need this... */
-			raidread_component_label(
-				      raidPtr->Disks[sparecol].dev,
-				      raidPtr->raid_cinfo[sparecol].ci_vp,
-				      &clabel);
+			clabel = raidget_component_label(raidPtr, sparecol);
 			/* make sure status is noted */
 
-			raid_init_component_label(raidPtr, &clabel);
+			raid_init_component_label(raidPtr, clabel);
+
+			clabel->column = scol;
+			clabel->status = rf_ds_optimal;
+			clabel->last_unit = raidPtr->raidid;
 
-			clabel.mod_counter = raidPtr->mod_counter;
-			clabel.column = scol;
-			clabel.status = rf_ds_optimal;
-			clabel.last_unit = raidPtr->raidid;
-
-			raidwrite_component_label(
-				      raidPtr->Disks[sparecol].dev,
-				      raidPtr->raid_cinfo[sparecol].ci_vp,
-				      &clabel);
+			raidflush_component_label(raidPtr, sparecol);
 			if (final == RF_FINAL_COMPONENT_UPDATE) {
 				if (raidPtr->parity_good == RF_RAID_CLEAN) {
-					raidmarkclean( raidPtr->Disks[sparecol].dev,
-						       raidPtr->raid_cinfo[sparecol].ci_vp,
-						       raidPtr->mod_counter);
+					raidmarkclean(raidPtr, sparecol);
 				}
 			}
 		}
@@ -3301,9 +3389,7 @@
 int
 rf_set_autoconfig(RF_Raid_t *raidPtr, int new_value)
 {
-	RF_ComponentLabel_t clabel;
-	struct vnode *vp;
-	dev_t dev;
+	RF_ComponentLabel_t *clabel;
 	int column;
 	int sparecol;
 
@@ -3311,21 +3397,17 @@
 
 	for(column=0; column<raidPtr->numCol; column++) {
 		if (raidPtr->Disks[column].status == rf_ds_optimal) {
-			dev = raidPtr->Disks[column].dev;
-			vp = raidPtr->raid_cinfo[column].ci_vp;
-			raidread_component_label(dev, vp, &clabel);
-			clabel.autoconfigure = new_value;
-			raidwrite_component_label(dev, vp, &clabel);
+			clabel = raidget_component_label(raidPtr, column);
+			clabel->autoconfigure = new_value;
+			raidflush_component_label(raidPtr, column);
 		}
 	}
 	for(column = 0; column < raidPtr->numSpare ; column++) {
 		sparecol = raidPtr->numCol + column;
 		if (raidPtr->Disks[sparecol].status == rf_ds_used_spare) {
-			dev = raidPtr->Disks[sparecol].dev;
-			vp = raidPtr->raid_cinfo[sparecol].ci_vp;
-			raidread_component_label(dev, vp, &clabel);
-			clabel.autoconfigure = new_value;
-			raidwrite_component_label(dev, vp, &clabel);
+			clabel = raidget_component_label(raidPtr, sparecol);
+			clabel->autoconfigure = new_value;
+			raidflush_component_label(raidPtr, sparecol);
 		}
 	}
 	return(new_value);
@@ -3334,30 +3416,24 @@
 int
 rf_set_rootpartition(RF_Raid_t *raidPtr, int new_value)
 {
-	RF_ComponentLabel_t clabel;
-	struct vnode *vp;
-	dev_t dev;
+	RF_ComponentLabel_t *clabel;
 	int column;
 	int sparecol;
 
 	raidPtr->root_partition = new_value;
 	for(column=0; column<raidPtr->numCol; column++) {
 		if (raidPtr->Disks[column].status == rf_ds_optimal) {
-			dev = raidPtr->Disks[column].dev;
-			vp = raidPtr->raid_cinfo[column].ci_vp;
-			raidread_component_label(dev, vp, &clabel);
-			clabel.root_partition = new_value;
-			raidwrite_component_label(dev, vp, &clabel);
+			clabel = raidget_component_label(raidPtr, column);
+			clabel->root_partition = new_value;
+			raidflush_component_label(raidPtr, column);
 		}
 	}
 	for(column = 0; column < raidPtr->numSpare ; column++) {
 		sparecol = raidPtr->numCol + column;
 		if (raidPtr->Disks[sparecol].status == rf_ds_used_spare) {
-			dev = raidPtr->Disks[sparecol].dev;
-			vp = raidPtr->raid_cinfo[sparecol].ci_vp;
-			raidread_component_label(dev, vp, &clabel);
-			clabel.root_partition = new_value;
-			raidwrite_component_label(dev, vp, &clabel);
+			clabel = raidget_component_label(raidPtr, sparecol);
+			clabel->root_partition = new_value;
+			raidflush_component_label(raidPtr, sparecol);
 		}
 	}
 	return(new_value);
@@ -3410,6 +3486,7 @@
 	clabel->version = RF_COMPONENT_LABEL_VERSION;
 	clabel->serial_number = raidPtr->serial_number;
 	clabel->mod_counter = raidPtr->mod_counter;
+
 	clabel->num_rows = 1;
 	clabel->num_columns = raidPtr->numCol;
 	clabel->clean = RF_RAID_DIRTY; /* not clean */
@@ -3429,6 +3506,10 @@
 	clabel->root_partition = raidPtr->root_partition;
 	clabel->last_unit = raidPtr->raidid;
 	clabel->config_order = raidPtr->config_order;
+
+#ifndef RF_NO_PARITY_MAP
+	rf_paritymap_init_label(raidPtr->parity_map, clabel);
+#endif
 }
 
 int
@@ -3659,7 +3740,7 @@
  * that fails.
  */
 
-static int
+int
 rf_sync_component_caches(RF_Raid_t *raidPtr)
 {
 	int c, sparecol;

Index: src/sys/dev/raidframe/rf_parityscan.c
diff -u src/sys/dev/raidframe/rf_parityscan.c:1.32 src/sys/dev/raidframe/rf_parityscan.c:1.32.64.1
--- src/sys/dev/raidframe/rf_parityscan.c:1.32	Thu Nov 16 01:33:23 2006
+++ src/sys/dev/raidframe/rf_parityscan.c	Thu Dec 10 22:59:17 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_parityscan.c,v 1.32 2006/11/16 01:33:23 christos Exp $	*/
+/*	$NetBSD: rf_parityscan.c,v 1.32.64.1 2009/12/10 22:59:17 snj Exp $	*/
 /*
  * Copyright (c) 1995 Carnegie-Mellon University.
  * All rights reserved.
@@ -33,7 +33,7 @@
  ****************************************************************************/
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rf_parityscan.c,v 1.32 2006/11/16 01:33:23 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rf_parityscan.c,v 1.32.64.1 2009/12/10 22:59:17 snj Exp $");
 
 #include <dev/raidframe/raidframevar.h>
 
@@ -46,6 +46,7 @@
 #include "rf_engine.h"
 #include "rf_parityscan.h"
 #include "rf_map.h"
+#include "rf_paritymap.h"
 
 /*****************************************************************************
  *
@@ -63,6 +64,20 @@
 int
 rf_RewriteParity(RF_Raid_t *raidPtr)
 {
+	if (raidPtr->parity_map != NULL)
+		return rf_paritymap_rewrite(raidPtr->parity_map);
+	else
+		return rf_RewriteParityRange(raidPtr, 0, raidPtr->totalSectors);
+}
+
+int
+rf_RewriteParityRange(RF_Raid_t *raidPtr, RF_SectorNum_t sec_begin,
+    RF_SectorNum_t sec_len)
+{
+	/* 
+	 * Note: It is the caller's responsibility to ensure that
+	 * sec_begin and sec_len are stripe-aligned.
+	 */
 	RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
 	RF_AccessStripeMapHeader_t *asm_h;
 	int ret_val;
@@ -86,7 +101,7 @@
 
 	rc = RF_PARITY_OKAY;
 
-	for (i = 0; i < raidPtr->totalSectors &&
+	for (i = sec_begin; i < sec_begin + sec_len &&
 		     rc <= RF_PARITY_CORRECTED;
 	     i += layoutPtr->dataSectorsPerStripe) {
 		if (raidPtr->waitShutdown) {

Index: src/sys/dev/raidframe/rf_parityscan.h
diff -u src/sys/dev/raidframe/rf_parityscan.h:1.7 src/sys/dev/raidframe/rf_parityscan.h:1.7.86.1
--- src/sys/dev/raidframe/rf_parityscan.h:1.7	Sun Dec 11 12:23:37 2005
+++ src/sys/dev/raidframe/rf_parityscan.h	Thu Dec 10 22:59:17 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_parityscan.h,v 1.7 2005/12/11 12:23:37 christos Exp $	*/
+/*	$NetBSD: rf_parityscan.h,v 1.7.86.1 2009/12/10 22:59:17 snj Exp $	*/
 /*
  * Copyright (c) 1995 Carnegie-Mellon University.
  * All rights reserved.
@@ -34,6 +34,7 @@
 #include "rf_alloclist.h"
 
 int     rf_RewriteParity(RF_Raid_t *);
+int	rf_RewriteParityRange(RF_Raid_t *, RF_SectorNum_t, RF_SectorNum_t);
 int 	rf_VerifyParityBasic(RF_Raid_t *, RF_RaidAddr_t, RF_PhysDiskAddr_t *,
     int, RF_RaidAccessFlags_t);
 int	rf_VerifyParity(RF_Raid_t *, RF_AccessStripeMap_t *, int,

Index: src/sys/dev/raidframe/rf_raid.h
diff -u src/sys/dev/raidframe/rf_raid.h:1.37 src/sys/dev/raidframe/rf_raid.h:1.37.34.1
--- src/sys/dev/raidframe/rf_raid.h:1.37	Sun Sep 16 02:13:35 2007
+++ src/sys/dev/raidframe/rf_raid.h	Thu Dec 10 22:59:17 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_raid.h,v 1.37 2007/09/16 02:13:35 oster Exp $	*/
+/*	$NetBSD: rf_raid.h,v 1.37.34.1 2009/12/10 22:59:17 snj Exp $	*/
 /*
  * Copyright (c) 1995 Carnegie-Mellon University.
  * All rights reserved.
@@ -137,7 +137,7 @@
 	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. */
+	int     clean;          /* completely unused and should be removed */
 
 	int     openings;       /* Number of IO's which can be scheduled
 				   simultaneously (high-level - not a
@@ -295,5 +295,6 @@
 	RF_Thread_t pLogDiskThreadHandle;
 
 #endif				/* RF_INCLUDE_PARITYLOGGING > 0 */
+	struct rf_paritymap *parity_map;
 };
 #endif				/* !_RF__RF_RAID_H_ */

Index: src/sys/dev/raidframe/rf_reconstruct.c
diff -u src/sys/dev/raidframe/rf_reconstruct.c:1.105.4.2 src/sys/dev/raidframe/rf_reconstruct.c:1.105.4.3
--- src/sys/dev/raidframe/rf_reconstruct.c:1.105.4.2	Thu Feb 19 20:27:08 2009
+++ src/sys/dev/raidframe/rf_reconstruct.c	Thu Dec 10 22:59:17 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_reconstruct.c,v 1.105.4.2 2009/02/19 20:27:08 snj Exp $	*/
+/*	$NetBSD: rf_reconstruct.c,v 1.105.4.3 2009/12/10 22:59:17 snj Exp $	*/
 /*
  * Copyright (c) 1995 Carnegie-Mellon University.
  * All rights reserved.
@@ -33,7 +33,7 @@
  ************************************************************/
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rf_reconstruct.c,v 1.105.4.2 2009/02/19 20:27:08 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rf_reconstruct.c,v 1.105.4.3 2009/12/10 22:59:17 snj Exp $");
 
 #include <sys/param.h>
 #include <sys/time.h>
@@ -234,7 +234,7 @@
 int
 rf_ReconstructFailedDiskBasic(RF_Raid_t *raidPtr, RF_RowCol_t col)
 {
-	RF_ComponentLabel_t c_label;
+	RF_ComponentLabel_t *c_label;
 	RF_RaidDisk_t *spareDiskPtr = NULL;
 	RF_RaidReconDesc_t *reconDesc;
 	RF_RowCol_t scol;
@@ -289,17 +289,14 @@
 	if (!rc) {
 		/* fix up the component label */
 		/* Don't actually need the read here.. */
-		raidread_component_label(
-                        raidPtr->raid_cinfo[scol].ci_dev,
-			raidPtr->raid_cinfo[scol].ci_vp,
-			&c_label);
-
-		raid_init_component_label( raidPtr, &c_label);
-		c_label.row = 0;
-		c_label.column = col;
-		c_label.clean = RF_RAID_DIRTY;
-		c_label.status = rf_ds_optimal;
-		c_label.partitionSize = raidPtr->Disks[scol].partitionSize;
+		c_label = raidget_component_label(raidPtr, scol);
+
+		raid_init_component_label(raidPtr, c_label);
+		c_label->row = 0;
+		c_label->column = col;
+		c_label->clean = RF_RAID_DIRTY;
+		c_label->status = rf_ds_optimal;
+		c_label->partitionSize = raidPtr->Disks[scol].partitionSize;
 
 		/* We've just done a rebuild based on all the other
 		   disks, so at this point the parity is known to be
@@ -313,11 +310,7 @@
 
 		/* XXXX MORE NEEDED HERE */
 
-		raidwrite_component_label(
-                        raidPtr->raid_cinfo[scol].ci_dev,
-			raidPtr->raid_cinfo[scol].ci_vp,
-			&c_label);
-
+		raidflush_component_label(raidPtr, scol);
 	} else {
 		/* Reconstruct failed. */
 
@@ -350,7 +343,7 @@
 	RF_RaidDisk_t *spareDiskPtr = NULL;
 	RF_RaidReconDesc_t *reconDesc;
 	const RF_LayoutSW_t *lp;
-	RF_ComponentLabel_t c_label;
+	RF_ComponentLabel_t *c_label;
 	int     numDisksDone = 0, rc;
 	struct partinfo dpart;
 	struct vnode *vp;
@@ -515,15 +508,13 @@
 
 		/* fix up the component label */
 		/* Don't actually need the read here.. */
-		raidread_component_label(raidPtr->raid_cinfo[col].ci_dev,
-					 raidPtr->raid_cinfo[col].ci_vp,
-					 &c_label);
+		c_label = raidget_component_label(raidPtr, col);
 
 		RF_LOCK_MUTEX(raidPtr->mutex);
-		raid_init_component_label(raidPtr, &c_label);
+		raid_init_component_label(raidPtr, c_label);
 
-		c_label.row = 0;
-		c_label.column = col;
+		c_label->row = 0;
+		c_label->column = col;
 
 		/* We've just done a rebuild based on all the other
 		   disks, so at this point the parity is known to be
@@ -534,10 +525,7 @@
 		raidPtr->parity_good = RF_RAID_CLEAN;
 		RF_UNLOCK_MUTEX(raidPtr->mutex);
 
-		raidwrite_component_label(raidPtr->raid_cinfo[col].ci_dev,
-					  raidPtr->raid_cinfo[col].ci_vp,
-					  &c_label);
-
+		raidflush_component_label(raidPtr, col);
 	} else {
 		/* Reconstruct-in-place failed.  Disk goes back to
 		   "failed" status, regardless of what it was before.  */

Index: src/sys/dev/raidframe/rf_states.c
diff -u src/sys/dev/raidframe/rf_states.c:1.43 src/sys/dev/raidframe/rf_states.c:1.43.8.1
--- src/sys/dev/raidframe/rf_states.c:1.43	Tue May 20 00:29:54 2008
+++ src/sys/dev/raidframe/rf_states.c	Thu Dec 10 22:59:17 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: rf_states.c,v 1.43 2008/05/20 00:29:54 oster Exp $	*/
+/*	$NetBSD: rf_states.c,v 1.43.8.1 2009/12/10 22:59:17 snj Exp $	*/
 /*
  * Copyright (c) 1995 Carnegie-Mellon University.
  * All rights reserved.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rf_states.c,v 1.43 2008/05/20 00:29:54 oster Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rf_states.c,v 1.43.8.1 2009/12/10 22:59:17 snj Exp $");
 
 #include <sys/errno.h>
 
@@ -45,6 +45,7 @@
 #include "rf_map.h"
 #include "rf_etimer.h"
 #include "rf_kintf.h"
+#include "rf_paritymap.h"
 
 #ifndef RF_DEBUG_STATES
 #define RF_DEBUG_STATES 0
@@ -237,6 +238,15 @@
 
 	wakeup(&(desc->raidPtr->iodone));
 
+	/*
+	 * The parity_map hook has to go here, because the iodone
+	 * callback goes straight into the kintf layer.
+	 */
+	if (desc->raidPtr->parity_map != NULL &&
+	    desc->type == RF_IO_TYPE_WRITE)
+		rf_paritymap_end(desc->raidPtr->parity_map, 
+		    desc->raidAddress, desc->numBlocks);
+
 	/* printf("Calling biodone on 0x%x\n",desc->bp); */
 	biodone(desc->bp);	/* access came through ioctl */
 

Reply via email to