rf_reconstruct.c revision 1.82 1 1.82 oster /* $NetBSD: rf_reconstruct.c,v 1.82 2005/02/05 23:32:43 oster Exp $ */
2 1.1 oster /*
3 1.1 oster * Copyright (c) 1995 Carnegie-Mellon University.
4 1.1 oster * All rights reserved.
5 1.1 oster *
6 1.1 oster * Author: Mark Holland
7 1.1 oster *
8 1.1 oster * Permission to use, copy, modify and distribute this software and
9 1.1 oster * its documentation is hereby granted, provided that both the copyright
10 1.1 oster * notice and this permission notice appear in all copies of the
11 1.1 oster * software, derivative works or modified versions, and any portions
12 1.1 oster * thereof, and that both notices appear in supporting documentation.
13 1.1 oster *
14 1.1 oster * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 1.1 oster * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
16 1.1 oster * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 1.1 oster *
18 1.1 oster * Carnegie Mellon requests users of this software to return to
19 1.1 oster *
20 1.1 oster * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
21 1.1 oster * School of Computer Science
22 1.1 oster * Carnegie Mellon University
23 1.1 oster * Pittsburgh PA 15213-3890
24 1.1 oster *
25 1.1 oster * any improvements or extensions that they make and grant Carnegie the
26 1.1 oster * rights to redistribute these changes.
27 1.1 oster */
28 1.1 oster
29 1.1 oster /************************************************************
30 1.1 oster *
31 1.1 oster * rf_reconstruct.c -- code to perform on-line reconstruction
32 1.1 oster *
33 1.1 oster ************************************************************/
34 1.31 lukem
35 1.31 lukem #include <sys/cdefs.h>
36 1.82 oster __KERNEL_RCSID(0, "$NetBSD: rf_reconstruct.c,v 1.82 2005/02/05 23:32:43 oster Exp $");
37 1.1 oster
38 1.1 oster #include <sys/time.h>
39 1.1 oster #include <sys/buf.h>
40 1.1 oster #include <sys/errno.h>
41 1.5 oster
42 1.5 oster #include <sys/param.h>
43 1.5 oster #include <sys/systm.h>
44 1.5 oster #include <sys/proc.h>
45 1.5 oster #include <sys/ioctl.h>
46 1.5 oster #include <sys/fcntl.h>
47 1.5 oster #include <sys/vnode.h>
48 1.30 oster #include <dev/raidframe/raidframevar.h>
49 1.5 oster
50 1.1 oster #include "rf_raid.h"
51 1.1 oster #include "rf_reconutil.h"
52 1.1 oster #include "rf_revent.h"
53 1.1 oster #include "rf_reconbuffer.h"
54 1.1 oster #include "rf_acctrace.h"
55 1.1 oster #include "rf_etimer.h"
56 1.1 oster #include "rf_dag.h"
57 1.1 oster #include "rf_desc.h"
58 1.36 oster #include "rf_debugprint.h"
59 1.1 oster #include "rf_general.h"
60 1.1 oster #include "rf_driver.h"
61 1.1 oster #include "rf_utils.h"
62 1.1 oster #include "rf_shutdown.h"
63 1.1 oster
64 1.1 oster #include "rf_kintf.h"
65 1.1 oster
66 1.1 oster /* setting these to -1 causes them to be set to their default values if not set by debug options */
67 1.1 oster
68 1.41 oster #if RF_DEBUG_RECON
69 1.1 oster #define Dprintf(s) if (rf_reconDebug) rf_debug_printf(s,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)
70 1.1 oster #define Dprintf1(s,a) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),NULL,NULL,NULL,NULL,NULL,NULL,NULL)
71 1.1 oster #define Dprintf2(s,a,b) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),NULL,NULL,NULL,NULL,NULL,NULL)
72 1.1 oster #define Dprintf3(s,a,b,c) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),NULL,NULL,NULL,NULL,NULL)
73 1.1 oster #define Dprintf4(s,a,b,c,d) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),NULL,NULL,NULL,NULL)
74 1.1 oster #define Dprintf5(s,a,b,c,d,e) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),NULL,NULL,NULL)
75 1.1 oster #define Dprintf6(s,a,b,c,d,e,f) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),(void *)((unsigned long)f),NULL,NULL)
76 1.1 oster #define Dprintf7(s,a,b,c,d,e,f,g) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),(void *)((unsigned long)f),(void *)((unsigned long)g),NULL)
77 1.1 oster
78 1.1 oster #define DDprintf1(s,a) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),NULL,NULL,NULL,NULL,NULL,NULL,NULL)
79 1.1 oster #define DDprintf2(s,a,b) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),NULL,NULL,NULL,NULL,NULL,NULL)
80 1.33 oster
81 1.41 oster #else /* RF_DEBUG_RECON */
82 1.33 oster
83 1.33 oster #define Dprintf(s) {}
84 1.33 oster #define Dprintf1(s,a) {}
85 1.33 oster #define Dprintf2(s,a,b) {}
86 1.33 oster #define Dprintf3(s,a,b,c) {}
87 1.33 oster #define Dprintf4(s,a,b,c,d) {}
88 1.33 oster #define Dprintf5(s,a,b,c,d,e) {}
89 1.33 oster #define Dprintf6(s,a,b,c,d,e,f) {}
90 1.33 oster #define Dprintf7(s,a,b,c,d,e,f,g) {}
91 1.33 oster
92 1.33 oster #define DDprintf1(s,a) {}
93 1.33 oster #define DDprintf2(s,a,b) {}
94 1.33 oster
95 1.41 oster #endif /* RF_DEBUG_RECON */
96 1.33 oster
97 1.82 oster #define RF_RECON_DONE_READS 1
98 1.82 oster #define RF_RECON_READ_ERROR 2
99 1.82 oster #define RF_RECON_WRITE_ERROR 3
100 1.82 oster #define RF_RECON_READ_STOPPED 4
101 1.82 oster
102 1.73 oster #define RF_MAX_FREE_RECONBUFFER 32
103 1.73 oster #define RF_MIN_FREE_RECONBUFFER 16
104 1.1 oster
105 1.69 oster static RF_RaidReconDesc_t *AllocRaidReconDesc(RF_Raid_t *, RF_RowCol_t,
106 1.69 oster RF_RaidDisk_t *, int, RF_RowCol_t);
107 1.69 oster static void FreeReconDesc(RF_RaidReconDesc_t *);
108 1.69 oster static int ProcessReconEvent(RF_Raid_t *, RF_ReconEvent_t *);
109 1.69 oster static int IssueNextReadRequest(RF_Raid_t *, RF_RowCol_t);
110 1.69 oster static int TryToRead(RF_Raid_t *, RF_RowCol_t);
111 1.69 oster static int ComputePSDiskOffsets(RF_Raid_t *, RF_StripeNum_t, RF_RowCol_t,
112 1.69 oster RF_SectorNum_t *, RF_SectorNum_t *, RF_RowCol_t *,
113 1.69 oster RF_SectorNum_t *);
114 1.69 oster static int IssueNextWriteRequest(RF_Raid_t *);
115 1.69 oster static int ReconReadDoneProc(void *, int);
116 1.69 oster static int ReconWriteDoneProc(void *, int);
117 1.69 oster static void CheckForNewMinHeadSep(RF_Raid_t *, RF_HeadSepLimit_t);
118 1.69 oster static int CheckHeadSeparation(RF_Raid_t *, RF_PerDiskReconCtrl_t *,
119 1.69 oster RF_RowCol_t, RF_HeadSepLimit_t,
120 1.69 oster RF_ReconUnitNum_t);
121 1.69 oster static int CheckForcedOrBlockedReconstruction(RF_Raid_t *,
122 1.69 oster RF_ReconParityStripeStatus_t *,
123 1.69 oster RF_PerDiskReconCtrl_t *,
124 1.69 oster RF_RowCol_t, RF_StripeNum_t,
125 1.69 oster RF_ReconUnitNum_t);
126 1.69 oster static void ForceReconReadDoneProc(void *, int);
127 1.1 oster static void rf_ShutdownReconstruction(void *);
128 1.1 oster
129 1.1 oster struct RF_ReconDoneProc_s {
130 1.4 oster void (*proc) (RF_Raid_t *, void *);
131 1.4 oster void *arg;
132 1.4 oster RF_ReconDoneProc_t *next;
133 1.1 oster };
134 1.1 oster
135 1.13 oster /**************************************************************************
136 1.1 oster *
137 1.1 oster * sets up the parameters that will be used by the reconstruction process
138 1.1 oster * currently there are none, except for those that the layout-specific
139 1.1 oster * configuration (e.g. rf_ConfigureDeclustered) routine sets up.
140 1.1 oster *
141 1.1 oster * in the kernel, we fire off the recon thread.
142 1.1 oster *
143 1.13 oster **************************************************************************/
144 1.4 oster static void
145 1.60 oster rf_ShutdownReconstruction(void *ignored)
146 1.4 oster {
147 1.74 oster pool_destroy(&rf_pools.reconbuffer);
148 1.4 oster }
149 1.4 oster
150 1.4 oster int
151 1.60 oster rf_ConfigureReconstruction(RF_ShutdownList_t **listp)
152 1.4 oster {
153 1.4 oster
154 1.74 oster rf_pool_init(&rf_pools.reconbuffer, sizeof(RF_ReconBuffer_t),
155 1.74 oster "rf_reconbuffer_pl", RF_MIN_FREE_RECONBUFFER, RF_MAX_FREE_RECONBUFFER);
156 1.66 oster rf_ShutdownCreate(listp, rf_ShutdownReconstruction, NULL);
157 1.66 oster
158 1.4 oster return (0);
159 1.4 oster }
160 1.4 oster
161 1.4 oster static RF_RaidReconDesc_t *
162 1.60 oster AllocRaidReconDesc(RF_Raid_t *raidPtr, RF_RowCol_t col,
163 1.60 oster RF_RaidDisk_t *spareDiskPtr, int numDisksDone,
164 1.60 oster RF_RowCol_t scol)
165 1.1 oster {
166 1.1 oster
167 1.4 oster RF_RaidReconDesc_t *reconDesc;
168 1.4 oster
169 1.80 oster RF_Malloc(reconDesc, sizeof(RF_RaidReconDesc_t),
170 1.80 oster (RF_RaidReconDesc_t *));
171 1.4 oster reconDesc->raidPtr = raidPtr;
172 1.4 oster reconDesc->col = col;
173 1.4 oster reconDesc->spareDiskPtr = spareDiskPtr;
174 1.4 oster reconDesc->numDisksDone = numDisksDone;
175 1.4 oster reconDesc->scol = scol;
176 1.4 oster reconDesc->next = NULL;
177 1.1 oster
178 1.4 oster return (reconDesc);
179 1.1 oster }
180 1.1 oster
181 1.4 oster static void
182 1.60 oster FreeReconDesc(RF_RaidReconDesc_t *reconDesc)
183 1.1 oster {
184 1.1 oster #if RF_RECON_STATS > 0
185 1.50 oster printf("raid%d: %lu recon event waits, %lu recon delays\n",
186 1.50 oster reconDesc->raidPtr->raidid,
187 1.50 oster (long) reconDesc->numReconEventWaits,
188 1.50 oster (long) reconDesc->numReconExecDelays);
189 1.4 oster #endif /* RF_RECON_STATS > 0 */
190 1.50 oster printf("raid%d: %lu max exec ticks\n",
191 1.50 oster reconDesc->raidPtr->raidid,
192 1.50 oster (long) reconDesc->maxReconExecTicks);
193 1.1 oster #if (RF_RECON_STATS > 0) || defined(KERNEL)
194 1.4 oster printf("\n");
195 1.4 oster #endif /* (RF_RECON_STATS > 0) || KERNEL */
196 1.80 oster RF_Free(reconDesc, sizeof(RF_RaidReconDesc_t));
197 1.1 oster }
198 1.1 oster
199 1.1 oster
200 1.13 oster /*****************************************************************************
201 1.1 oster *
202 1.1 oster * primary routine to reconstruct a failed disk. This should be called from
203 1.1 oster * within its own thread. It won't return until reconstruction completes,
204 1.1 oster * fails, or is aborted.
205 1.13 oster *****************************************************************************/
206 1.4 oster int
207 1.60 oster rf_ReconstructFailedDisk(RF_Raid_t *raidPtr, RF_RowCol_t col)
208 1.4 oster {
209 1.52 jdolecek const RF_LayoutSW_t *lp;
210 1.4 oster int rc;
211 1.4 oster
212 1.4 oster lp = raidPtr->Layout.map;
213 1.4 oster if (lp->SubmitReconBuffer) {
214 1.4 oster /*
215 1.4 oster * The current infrastructure only supports reconstructing one
216 1.4 oster * disk at a time for each array.
217 1.4 oster */
218 1.4 oster RF_LOCK_MUTEX(raidPtr->mutex);
219 1.4 oster while (raidPtr->reconInProgress) {
220 1.4 oster RF_WAIT_COND(raidPtr->waitForReconCond, raidPtr->mutex);
221 1.4 oster }
222 1.4 oster raidPtr->reconInProgress++;
223 1.4 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
224 1.57 oster rc = rf_ReconstructFailedDiskBasic(raidPtr, col);
225 1.6 oster RF_LOCK_MUTEX(raidPtr->mutex);
226 1.6 oster raidPtr->reconInProgress--;
227 1.6 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
228 1.4 oster } else {
229 1.4 oster RF_ERRORMSG1("RECON: no way to reconstruct failed disk for arch %c\n",
230 1.4 oster lp->parityConfig);
231 1.4 oster rc = EIO;
232 1.4 oster }
233 1.4 oster RF_SIGNAL_COND(raidPtr->waitForReconCond);
234 1.4 oster return (rc);
235 1.4 oster }
236 1.4 oster
237 1.4 oster int
238 1.60 oster rf_ReconstructFailedDiskBasic(RF_Raid_t *raidPtr, RF_RowCol_t col)
239 1.4 oster {
240 1.5 oster RF_ComponentLabel_t c_label;
241 1.4 oster RF_RaidDisk_t *spareDiskPtr = NULL;
242 1.4 oster RF_RaidReconDesc_t *reconDesc;
243 1.57 oster RF_RowCol_t scol;
244 1.4 oster int numDisksDone = 0, rc;
245 1.4 oster
246 1.4 oster /* first look for a spare drive onto which to reconstruct the data */
247 1.4 oster /* spare disk descriptors are stored in row 0. This may have to
248 1.4 oster * change eventually */
249 1.4 oster
250 1.4 oster RF_LOCK_MUTEX(raidPtr->mutex);
251 1.57 oster RF_ASSERT(raidPtr->Disks[col].status == rf_ds_failed);
252 1.72 oster #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0
253 1.4 oster if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
254 1.57 oster if (raidPtr->status != rf_rs_degraded) {
255 1.57 oster RF_ERRORMSG1("Unable to reconstruct disk at col %d because status not degraded\n", col);
256 1.4 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
257 1.4 oster return (EINVAL);
258 1.4 oster }
259 1.4 oster scol = (-1);
260 1.4 oster } else {
261 1.72 oster #endif
262 1.4 oster for (scol = raidPtr->numCol; scol < raidPtr->numCol + raidPtr->numSpare; scol++) {
263 1.57 oster if (raidPtr->Disks[scol].status == rf_ds_spare) {
264 1.57 oster spareDiskPtr = &raidPtr->Disks[scol];
265 1.4 oster spareDiskPtr->status = rf_ds_used_spare;
266 1.4 oster break;
267 1.4 oster }
268 1.4 oster }
269 1.4 oster if (!spareDiskPtr) {
270 1.57 oster RF_ERRORMSG1("Unable to reconstruct disk at col %d because no spares are available\n", col);
271 1.4 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
272 1.4 oster return (ENOSPC);
273 1.4 oster }
274 1.57 oster printf("RECON: initiating reconstruction on col %d -> spare at col %d\n", col, scol);
275 1.72 oster #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0
276 1.4 oster }
277 1.72 oster #endif
278 1.4 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
279 1.1 oster
280 1.57 oster reconDesc = AllocRaidReconDesc((void *) raidPtr, col, spareDiskPtr, numDisksDone, scol);
281 1.4 oster raidPtr->reconDesc = (void *) reconDesc;
282 1.1 oster #if RF_RECON_STATS > 0
283 1.4 oster reconDesc->hsStallCount = 0;
284 1.4 oster reconDesc->numReconExecDelays = 0;
285 1.4 oster reconDesc->numReconEventWaits = 0;
286 1.4 oster #endif /* RF_RECON_STATS > 0 */
287 1.4 oster reconDesc->reconExecTimerRunning = 0;
288 1.4 oster reconDesc->reconExecTicks = 0;
289 1.4 oster reconDesc->maxReconExecTicks = 0;
290 1.4 oster rc = rf_ContinueReconstructFailedDisk(reconDesc);
291 1.5 oster
292 1.5 oster if (!rc) {
293 1.5 oster /* fix up the component label */
294 1.5 oster /* Don't actually need the read here.. */
295 1.5 oster raidread_component_label(
296 1.57 oster raidPtr->raid_cinfo[scol].ci_dev,
297 1.57 oster raidPtr->raid_cinfo[scol].ci_vp,
298 1.5 oster &c_label);
299 1.5 oster
300 1.15 oster raid_init_component_label( raidPtr, &c_label);
301 1.57 oster c_label.row = 0;
302 1.5 oster c_label.column = col;
303 1.5 oster c_label.clean = RF_RAID_DIRTY;
304 1.5 oster c_label.status = rf_ds_optimal;
305 1.57 oster c_label.partitionSize = raidPtr->Disks[scol].partitionSize;
306 1.15 oster
307 1.28 oster /* We've just done a rebuild based on all the other
308 1.28 oster disks, so at this point the parity is known to be
309 1.28 oster clean, even if it wasn't before. */
310 1.28 oster
311 1.28 oster /* XXX doesn't hold for RAID 6!!*/
312 1.28 oster
313 1.48 oster RF_LOCK_MUTEX(raidPtr->mutex);
314 1.28 oster raidPtr->parity_good = RF_RAID_CLEAN;
315 1.48 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
316 1.28 oster
317 1.15 oster /* XXXX MORE NEEDED HERE */
318 1.5 oster
319 1.5 oster raidwrite_component_label(
320 1.57 oster raidPtr->raid_cinfo[scol].ci_dev,
321 1.57 oster raidPtr->raid_cinfo[scol].ci_vp,
322 1.5 oster &c_label);
323 1.5 oster
324 1.49 oster
325 1.49 oster rf_update_component_labels(raidPtr,
326 1.49 oster RF_NORMAL_COMPONENT_UPDATE);
327 1.49 oster
328 1.82 oster } else {
329 1.82 oster /* Reconstruct failed. */
330 1.82 oster
331 1.82 oster RF_LOCK_MUTEX(raidPtr->mutex);
332 1.82 oster /* Failed disk goes back to "failed" status */
333 1.82 oster raidPtr->Disks[col].status = rf_ds_failed;
334 1.82 oster
335 1.82 oster /* Spare disk goes back to "spare" status. */
336 1.82 oster spareDiskPtr->status = rf_ds_spare;
337 1.82 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
338 1.5 oster }
339 1.5 oster return (rc);
340 1.5 oster }
341 1.5 oster
342 1.5 oster /*
343 1.5 oster
344 1.5 oster Allow reconstructing a disk in-place -- i.e. component /dev/sd2e goes AWOL,
345 1.5 oster and you don't get a spare until the next Monday. With this function
346 1.5 oster (and hot-swappable drives) you can now put your new disk containing
347 1.5 oster /dev/sd2e on the bus, scsictl it alive, and then use raidctl(8) to
348 1.5 oster rebuild the data "on the spot".
349 1.5 oster
350 1.5 oster */
351 1.5 oster
352 1.5 oster int
353 1.60 oster rf_ReconstructInPlace(RF_Raid_t *raidPtr, RF_RowCol_t col)
354 1.5 oster {
355 1.5 oster RF_RaidDisk_t *spareDiskPtr = NULL;
356 1.5 oster RF_RaidReconDesc_t *reconDesc;
357 1.52 jdolecek const RF_LayoutSW_t *lp;
358 1.5 oster RF_ComponentLabel_t c_label;
359 1.5 oster int numDisksDone = 0, rc;
360 1.5 oster struct partinfo dpart;
361 1.5 oster struct vnode *vp;
362 1.5 oster struct vattr va;
363 1.56 fvdl struct proc *proc;
364 1.5 oster int retcode;
365 1.21 oster int ac;
366 1.5 oster
367 1.5 oster lp = raidPtr->Layout.map;
368 1.61 oster if (!lp->SubmitReconBuffer) {
369 1.61 oster RF_ERRORMSG1("RECON: no way to reconstruct failed disk for arch %c\n",
370 1.61 oster lp->parityConfig);
371 1.61 oster /* wakeup anyone who might be waiting to do a reconstruct */
372 1.61 oster RF_SIGNAL_COND(raidPtr->waitForReconCond);
373 1.61 oster return(EIO);
374 1.62 oster }
375 1.5 oster
376 1.62 oster /*
377 1.62 oster * The current infrastructure only supports reconstructing one
378 1.62 oster * disk at a time for each array.
379 1.62 oster */
380 1.62 oster RF_LOCK_MUTEX(raidPtr->mutex);
381 1.5 oster
382 1.62 oster if (raidPtr->Disks[col].status != rf_ds_failed) {
383 1.62 oster /* "It's gone..." */
384 1.62 oster raidPtr->numFailures++;
385 1.62 oster raidPtr->Disks[col].status = rf_ds_failed;
386 1.62 oster raidPtr->status = rf_rs_degraded;
387 1.62 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
388 1.62 oster rf_update_component_labels(raidPtr,
389 1.62 oster RF_NORMAL_COMPONENT_UPDATE);
390 1.62 oster RF_LOCK_MUTEX(raidPtr->mutex);
391 1.62 oster }
392 1.62 oster
393 1.62 oster while (raidPtr->reconInProgress) {
394 1.62 oster RF_WAIT_COND(raidPtr->waitForReconCond, raidPtr->mutex);
395 1.62 oster }
396 1.62 oster
397 1.62 oster raidPtr->reconInProgress++;
398 1.64 oster
399 1.62 oster /* first look for a spare drive onto which to reconstruct the
400 1.62 oster data. spare disk descriptors are stored in row 0. This
401 1.62 oster may have to change eventually */
402 1.62 oster
403 1.62 oster /* Actually, we don't care if it's failed or not... On a RAID
404 1.62 oster set with correct parity, this function should be callable
405 1.62 oster on any component without ill affects. */
406 1.62 oster /* RF_ASSERT(raidPtr->Disks[col].status == rf_ds_failed); */
407 1.62 oster
408 1.72 oster #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0
409 1.62 oster if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
410 1.62 oster RF_ERRORMSG1("Unable to reconstruct to disk at col %d: operation not supported for RF_DISTRIBUTE_SPARE\n", col);
411 1.62 oster
412 1.62 oster raidPtr->reconInProgress--;
413 1.62 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
414 1.64 oster RF_SIGNAL_COND(raidPtr->waitForReconCond);
415 1.62 oster return (EINVAL);
416 1.62 oster }
417 1.72 oster #endif
418 1.62 oster proc = raidPtr->engine_thread;
419 1.62 oster
420 1.62 oster /* This device may have been opened successfully the
421 1.62 oster first time. Close it before trying to open it again.. */
422 1.62 oster
423 1.62 oster if (raidPtr->raid_cinfo[col].ci_vp != NULL) {
424 1.37 oster #if 0
425 1.62 oster printf("Closed the open device: %s\n",
426 1.62 oster raidPtr->Disks[col].devname);
427 1.37 oster #endif
428 1.62 oster vp = raidPtr->raid_cinfo[col].ci_vp;
429 1.62 oster ac = raidPtr->Disks[col].auto_configured;
430 1.62 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
431 1.62 oster rf_close_component(raidPtr, vp, ac);
432 1.62 oster RF_LOCK_MUTEX(raidPtr->mutex);
433 1.62 oster raidPtr->raid_cinfo[col].ci_vp = NULL;
434 1.62 oster }
435 1.62 oster /* note that this disk was *not* auto_configured (any longer)*/
436 1.62 oster raidPtr->Disks[col].auto_configured = 0;
437 1.62 oster
438 1.37 oster #if 0
439 1.62 oster printf("About to (re-)open the device for rebuilding: %s\n",
440 1.62 oster raidPtr->Disks[col].devname);
441 1.37 oster #endif
442 1.62 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
443 1.62 oster retcode = raidlookup(raidPtr->Disks[col].devname, proc, &vp);
444 1.62 oster
445 1.62 oster if (retcode) {
446 1.62 oster printf("raid%d: rebuilding: raidlookup on device: %s failed: %d!\n",raidPtr->raidid,
447 1.62 oster raidPtr->Disks[col].devname, retcode);
448 1.62 oster
449 1.62 oster /* the component isn't responding properly...
450 1.62 oster must be still dead :-( */
451 1.62 oster RF_LOCK_MUTEX(raidPtr->mutex);
452 1.62 oster raidPtr->reconInProgress--;
453 1.48 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
454 1.64 oster RF_SIGNAL_COND(raidPtr->waitForReconCond);
455 1.62 oster return(retcode);
456 1.63 oster }
457 1.63 oster
458 1.63 oster /* Ok, so we can at least do a lookup...
459 1.63 oster How about actually getting a vp for it? */
460 1.63 oster
461 1.63 oster if ((retcode = VOP_GETATTR(vp, &va, proc->p_ucred, proc)) != 0) {
462 1.63 oster RF_LOCK_MUTEX(raidPtr->mutex);
463 1.63 oster raidPtr->reconInProgress--;
464 1.63 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
465 1.64 oster RF_SIGNAL_COND(raidPtr->waitForReconCond);
466 1.63 oster return(retcode);
467 1.63 oster }
468 1.63 oster
469 1.64 oster retcode = VOP_IOCTL(vp, DIOCGPART, &dpart, FREAD, proc->p_ucred, proc);
470 1.63 oster if (retcode) {
471 1.62 oster RF_LOCK_MUTEX(raidPtr->mutex);
472 1.63 oster raidPtr->reconInProgress--;
473 1.62 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
474 1.64 oster RF_SIGNAL_COND(raidPtr->waitForReconCond);
475 1.63 oster return(retcode);
476 1.62 oster }
477 1.63 oster RF_LOCK_MUTEX(raidPtr->mutex);
478 1.63 oster raidPtr->Disks[col].blockSize = dpart.disklab->d_secsize;
479 1.62 oster
480 1.64 oster raidPtr->Disks[col].numBlocks = dpart.part->p_size -
481 1.63 oster rf_protectedSectors;
482 1.62 oster
483 1.63 oster raidPtr->raid_cinfo[col].ci_vp = vp;
484 1.63 oster raidPtr->raid_cinfo[col].ci_dev = va.va_rdev;
485 1.63 oster
486 1.63 oster raidPtr->Disks[col].dev = va.va_rdev;
487 1.63 oster
488 1.63 oster /* we allow the user to specify that only a fraction
489 1.63 oster of the disks should be used this is just for debug:
490 1.63 oster it speeds up * the parity scan */
491 1.63 oster raidPtr->Disks[col].numBlocks = raidPtr->Disks[col].numBlocks *
492 1.63 oster rf_sizePercentage / 100;
493 1.63 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
494 1.62 oster
495 1.62 oster spareDiskPtr = &raidPtr->Disks[col];
496 1.62 oster spareDiskPtr->status = rf_ds_used_spare;
497 1.62 oster
498 1.62 oster printf("raid%d: initiating in-place reconstruction on column %d\n",
499 1.62 oster raidPtr->raidid, col);
500 1.5 oster
501 1.62 oster reconDesc = AllocRaidReconDesc((void *) raidPtr, col, spareDiskPtr,
502 1.62 oster numDisksDone, col);
503 1.62 oster raidPtr->reconDesc = (void *) reconDesc;
504 1.5 oster #if RF_RECON_STATS > 0
505 1.62 oster reconDesc->hsStallCount = 0;
506 1.62 oster reconDesc->numReconExecDelays = 0;
507 1.62 oster reconDesc->numReconEventWaits = 0;
508 1.5 oster #endif /* RF_RECON_STATS > 0 */
509 1.62 oster reconDesc->reconExecTimerRunning = 0;
510 1.62 oster reconDesc->reconExecTicks = 0;
511 1.62 oster reconDesc->maxReconExecTicks = 0;
512 1.62 oster rc = rf_ContinueReconstructFailedDisk(reconDesc);
513 1.62 oster
514 1.5 oster if (!rc) {
515 1.48 oster RF_LOCK_MUTEX(raidPtr->mutex);
516 1.5 oster /* Need to set these here, as at this point it'll be claiming
517 1.5 oster that the disk is in rf_ds_spared! But we know better :-) */
518 1.5 oster
519 1.57 oster raidPtr->Disks[col].status = rf_ds_optimal;
520 1.57 oster raidPtr->status = rf_rs_optimal;
521 1.48 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
522 1.5 oster
523 1.5 oster /* fix up the component label */
524 1.5 oster /* Don't actually need the read here.. */
525 1.57 oster raidread_component_label(raidPtr->raid_cinfo[col].ci_dev,
526 1.57 oster raidPtr->raid_cinfo[col].ci_vp,
527 1.5 oster &c_label);
528 1.16 oster
529 1.48 oster RF_LOCK_MUTEX(raidPtr->mutex);
530 1.16 oster raid_init_component_label(raidPtr, &c_label);
531 1.16 oster
532 1.57 oster c_label.row = 0;
533 1.5 oster c_label.column = col;
534 1.28 oster
535 1.28 oster /* We've just done a rebuild based on all the other
536 1.28 oster disks, so at this point the parity is known to be
537 1.28 oster clean, even if it wasn't before. */
538 1.28 oster
539 1.28 oster /* XXX doesn't hold for RAID 6!!*/
540 1.28 oster
541 1.28 oster raidPtr->parity_good = RF_RAID_CLEAN;
542 1.48 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
543 1.28 oster
544 1.57 oster raidwrite_component_label(raidPtr->raid_cinfo[col].ci_dev,
545 1.57 oster raidPtr->raid_cinfo[col].ci_vp,
546 1.5 oster &c_label);
547 1.49 oster
548 1.49 oster rf_update_component_labels(raidPtr,
549 1.49 oster RF_NORMAL_COMPONENT_UPDATE);
550 1.82 oster } else {
551 1.82 oster /* Reconstruct-in-place failed. Disk goes back to
552 1.82 oster "failed" status, regardless of what it was before. */
553 1.82 oster RF_LOCK_MUTEX(raidPtr->mutex);
554 1.82 oster raidPtr->Disks[col].status = rf_ds_failed;
555 1.82 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
556 1.82 oster }
557 1.5 oster
558 1.82 oster RF_LOCK_MUTEX(raidPtr->mutex);
559 1.82 oster raidPtr->reconInProgress--;
560 1.82 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
561 1.82 oster
562 1.5 oster RF_SIGNAL_COND(raidPtr->waitForReconCond);
563 1.4 oster return (rc);
564 1.4 oster }
565 1.4 oster
566 1.4 oster
567 1.4 oster int
568 1.60 oster rf_ContinueReconstructFailedDisk(RF_RaidReconDesc_t *reconDesc)
569 1.4 oster {
570 1.4 oster RF_Raid_t *raidPtr = reconDesc->raidPtr;
571 1.4 oster RF_RowCol_t col = reconDesc->col;
572 1.4 oster RF_RowCol_t scol = reconDesc->scol;
573 1.4 oster RF_ReconMap_t *mapPtr;
574 1.46 oster RF_ReconCtrl_t *tmp_reconctrl;
575 1.4 oster RF_ReconEvent_t *event;
576 1.82 oster RF_CallbackDesc_t *p;
577 1.4 oster struct timeval etime, elpsd;
578 1.4 oster unsigned long xor_s, xor_resid_us;
579 1.54 simonb int i, ds;
580 1.82 oster int status;
581 1.82 oster int recon_error, write_error;
582 1.4 oster
583 1.78 oster raidPtr->accumXorTimeUs = 0;
584 1.67 oster #if RF_ACC_TRACE > 0
585 1.78 oster /* create one trace record per physical disk */
586 1.78 oster RF_Malloc(raidPtr->recon_tracerecs, raidPtr->numCol * sizeof(RF_AccTraceEntry_t), (RF_AccTraceEntry_t *));
587 1.67 oster #endif
588 1.78 oster
589 1.78 oster /* quiesce the array prior to starting recon. this is needed
590 1.78 oster * to assure no nasty interactions with pending user writes.
591 1.78 oster * We need to do this before we change the disk or row status. */
592 1.78 oster
593 1.78 oster Dprintf("RECON: begin request suspend\n");
594 1.78 oster rf_SuspendNewRequestsAndWait(raidPtr);
595 1.78 oster Dprintf("RECON: end request suspend\n");
596 1.78 oster
597 1.78 oster /* allocate our RF_ReconCTRL_t before we protect raidPtr->reconControl[row] */
598 1.78 oster tmp_reconctrl = rf_MakeReconControl(reconDesc, col, scol);
599 1.78 oster
600 1.78 oster RF_LOCK_MUTEX(raidPtr->mutex);
601 1.78 oster
602 1.78 oster /* create the reconstruction control pointer and install it in
603 1.78 oster * the right slot */
604 1.78 oster raidPtr->reconControl = tmp_reconctrl;
605 1.78 oster mapPtr = raidPtr->reconControl->reconMap;
606 1.78 oster raidPtr->status = rf_rs_reconstructing;
607 1.78 oster raidPtr->Disks[col].status = rf_ds_reconstructing;
608 1.78 oster raidPtr->Disks[col].spareCol = scol;
609 1.78 oster
610 1.78 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
611 1.78 oster
612 1.78 oster RF_GETTIME(raidPtr->reconControl->starttime);
613 1.78 oster
614 1.78 oster /* now start up the actual reconstruction: issue a read for
615 1.78 oster * each surviving disk */
616 1.78 oster
617 1.78 oster reconDesc->numDisksDone = 0;
618 1.78 oster for (i = 0; i < raidPtr->numCol; i++) {
619 1.78 oster if (i != col) {
620 1.78 oster /* find and issue the next I/O on the
621 1.78 oster * indicated disk */
622 1.78 oster if (IssueNextReadRequest(raidPtr, i)) {
623 1.78 oster Dprintf1("RECON: done issuing for c%d\n", i);
624 1.78 oster reconDesc->numDisksDone++;
625 1.4 oster }
626 1.4 oster }
627 1.78 oster }
628 1.4 oster
629 1.78 oster Dprintf("RECON: resume requests\n");
630 1.78 oster rf_ResumeNewRequests(raidPtr);
631 1.78 oster
632 1.78 oster /* process reconstruction events until all disks report that
633 1.78 oster * they've completed all work */
634 1.4 oster
635 1.78 oster mapPtr = raidPtr->reconControl->reconMap;
636 1.82 oster recon_error = 0;
637 1.82 oster write_error = 0;
638 1.82 oster
639 1.78 oster while (reconDesc->numDisksDone < raidPtr->numCol - 1) {
640 1.78 oster
641 1.78 oster event = rf_GetNextReconEvent(reconDesc);
642 1.78 oster RF_ASSERT(event);
643 1.82 oster
644 1.82 oster status = ProcessReconEvent(raidPtr, event);
645 1.82 oster
646 1.82 oster /* the normal case is that a read completes, and all is well. */
647 1.82 oster if (status == RF_RECON_DONE_READS) {
648 1.82 oster reconDesc->numDisksDone++;
649 1.82 oster } else if ((status == RF_RECON_READ_ERROR) ||
650 1.82 oster (status == RF_RECON_WRITE_ERROR)) {
651 1.82 oster /* an error was encountered while reconstructing...
652 1.82 oster Pretend we've finished this disk.
653 1.82 oster */
654 1.82 oster recon_error = 1;
655 1.82 oster raidPtr->reconControl->error = 1;
656 1.82 oster
657 1.82 oster /* bump the numDisksDone count for reads,
658 1.82 oster but not for writes */
659 1.82 oster if (status == RF_RECON_READ_ERROR)
660 1.82 oster reconDesc->numDisksDone++;
661 1.82 oster
662 1.82 oster /* write errors are special -- when we are
663 1.82 oster done dealing with the reads that are
664 1.82 oster finished, we don't want to wait for any
665 1.82 oster writes */
666 1.82 oster if (status == RF_RECON_WRITE_ERROR)
667 1.82 oster write_error = 1;
668 1.82 oster
669 1.82 oster } else if (status == RF_RECON_READ_STOPPED) {
670 1.82 oster /* count this component as being "done" */
671 1.78 oster reconDesc->numDisksDone++;
672 1.82 oster }
673 1.82 oster
674 1.82 oster if (recon_error) {
675 1.82 oster
676 1.82 oster /* make sure any stragglers are woken up so that
677 1.82 oster their theads will complete, and we can get out
678 1.82 oster of here with all IO processed */
679 1.82 oster
680 1.82 oster while (raidPtr->reconControl->headSepCBList) {
681 1.82 oster p = raidPtr->reconControl->headSepCBList;
682 1.82 oster raidPtr->reconControl->headSepCBList = p->next;
683 1.82 oster p->next = NULL;
684 1.82 oster rf_CauseReconEvent(raidPtr, p->col, NULL, RF_REVENT_HEADSEPCLEAR);
685 1.82 oster rf_FreeCallbackDesc(p);
686 1.82 oster }
687 1.82 oster }
688 1.82 oster
689 1.78 oster raidPtr->reconControl->numRUsTotal =
690 1.78 oster mapPtr->totalRUs;
691 1.78 oster raidPtr->reconControl->numRUsComplete =
692 1.78 oster mapPtr->totalRUs -
693 1.78 oster rf_UnitsLeftToReconstruct(mapPtr);
694 1.82 oster
695 1.65 oster #if RF_DEBUG_RECON
696 1.78 oster raidPtr->reconControl->percentComplete =
697 1.78 oster (raidPtr->reconControl->numRUsComplete * 100 / raidPtr->reconControl->numRUsTotal);
698 1.78 oster if (rf_prReconSched) {
699 1.78 oster rf_PrintReconSchedule(raidPtr->reconControl->reconMap, &(raidPtr->reconControl->starttime));
700 1.78 oster }
701 1.41 oster #endif
702 1.78 oster }
703 1.78 oster
704 1.78 oster mapPtr = raidPtr->reconControl->reconMap;
705 1.78 oster if (rf_reconDebug) {
706 1.78 oster printf("RECON: all reads completed\n");
707 1.78 oster }
708 1.78 oster /* at this point all the reads have completed. We now wait
709 1.78 oster * for any pending writes to complete, and then we're done */
710 1.82 oster
711 1.82 oster while (!recon_error && rf_UnitsLeftToReconstruct(raidPtr->reconControl->reconMap) > 0) {
712 1.78 oster
713 1.78 oster event = rf_GetNextReconEvent(reconDesc);
714 1.78 oster RF_ASSERT(event);
715 1.82 oster
716 1.82 oster status = ProcessReconEvent(raidPtr, event);
717 1.82 oster if (status == RF_RECON_WRITE_ERROR) {
718 1.82 oster recon_error = 1;
719 1.82 oster raidPtr->reconControl->error = 1;
720 1.82 oster /* an error was encountered at the very end... bail */
721 1.82 oster } else {
722 1.82 oster #if RF_DEBUG_RECON
723 1.82 oster raidPtr->reconControl->percentComplete = 100 - (rf_UnitsLeftToReconstruct(mapPtr) * 100 / mapPtr->totalRUs);
724 1.82 oster if (rf_prReconSched) {
725 1.82 oster rf_PrintReconSchedule(raidPtr->reconControl->reconMap, &(raidPtr->reconControl->starttime));
726 1.82 oster }
727 1.82 oster #endif
728 1.82 oster }
729 1.82 oster }
730 1.82 oster
731 1.82 oster if (recon_error) {
732 1.82 oster /* we've encountered an error in reconstructing. */
733 1.82 oster printf("raid%d: reconstruction failed.\n", raidPtr->raidid);
734 1.78 oster
735 1.82 oster /* we start by blocking IO to the RAID set. */
736 1.82 oster rf_SuspendNewRequestsAndWait(raidPtr);
737 1.82 oster
738 1.82 oster RF_LOCK_MUTEX(raidPtr->mutex);
739 1.82 oster /* mark set as being degraded, rather than
740 1.82 oster rf_rs_reconstructing as we were before the problem.
741 1.82 oster After this is done we can update status of the
742 1.82 oster component disks without worrying about someone
743 1.82 oster trying to read from a failed component.
744 1.82 oster */
745 1.82 oster raidPtr->status = rf_rs_degraded;
746 1.82 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
747 1.82 oster
748 1.82 oster /* resume IO */
749 1.82 oster rf_ResumeNewRequests(raidPtr);
750 1.82 oster
751 1.82 oster /* At this point there are two cases:
752 1.82 oster 1) If we've experienced a read error, then we've
753 1.82 oster already waited for all the reads we're going to get,
754 1.82 oster and we just need to wait for the writes.
755 1.82 oster
756 1.82 oster 2) If we've experienced a write error, we've also
757 1.82 oster already waited for all the reads to complete,
758 1.82 oster but there is little point in waiting for the writes --
759 1.82 oster when they do complete, they will just be ignored.
760 1.82 oster
761 1.82 oster So we just wait for writes to complete if we didn't have a
762 1.82 oster write error.
763 1.82 oster */
764 1.82 oster
765 1.82 oster if (!write_error) {
766 1.82 oster /* wait for writes to complete */
767 1.82 oster while (raidPtr->reconControl->pending_writes > 0) {
768 1.82 oster event = rf_GetNextReconEvent(reconDesc);
769 1.82 oster status = ProcessReconEvent(raidPtr, event);
770 1.82 oster
771 1.82 oster if (status == RF_RECON_WRITE_ERROR) {
772 1.82 oster raidPtr->reconControl->error = 1;
773 1.82 oster /* an error was encountered at the very end... bail.
774 1.82 oster This will be very bad news for the user, since
775 1.82 oster at this point there will have been a read error
776 1.82 oster on one component, and a write error on another!
777 1.82 oster */
778 1.82 oster break;
779 1.82 oster }
780 1.82 oster }
781 1.4 oster }
782 1.82 oster
783 1.82 oster
784 1.82 oster /* cleanup */
785 1.82 oster
786 1.82 oster /* drain the event queue - after waiting for the writes above,
787 1.82 oster there shouldn't be much (if anything!) left in the queue. */
788 1.82 oster
789 1.82 oster rf_DrainReconEventQueue(reconDesc);
790 1.82 oster
791 1.82 oster /* XXX As much as we'd like to free the recon control structure
792 1.82 oster and the reconDesc, we have no way of knowing if/when those will
793 1.82 oster be touched by IO that has yet to occur. It is rather poor to be
794 1.82 oster basically causing a 'memory leak' here, but there doesn't seem to be
795 1.82 oster a cleaner alternative at this time. Perhaps when the reconstruct code
796 1.82 oster gets a makeover this problem will go away.
797 1.82 oster */
798 1.82 oster #if 0
799 1.82 oster rf_FreeReconControl(raidPtr);
800 1.82 oster #endif
801 1.82 oster
802 1.82 oster #if RF_ACC_TRACE > 0
803 1.82 oster RF_Free(raidPtr->recon_tracerecs, raidPtr->numCol * sizeof(RF_AccTraceEntry_t));
804 1.41 oster #endif
805 1.82 oster /* XXX see comment above */
806 1.82 oster #if 0
807 1.82 oster FreeReconDesc(reconDesc);
808 1.82 oster #endif
809 1.82 oster
810 1.82 oster return (1);
811 1.78 oster }
812 1.14 oster
813 1.78 oster /* Success: mark the dead disk as reconstructed. We quiesce
814 1.78 oster * the array here to assure no nasty interactions with pending
815 1.78 oster * user accesses when we free up the psstatus structure as
816 1.78 oster * part of FreeReconControl() */
817 1.78 oster
818 1.78 oster rf_SuspendNewRequestsAndWait(raidPtr);
819 1.78 oster
820 1.78 oster RF_LOCK_MUTEX(raidPtr->mutex);
821 1.78 oster raidPtr->numFailures--;
822 1.78 oster ds = (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE);
823 1.78 oster raidPtr->Disks[col].status = (ds) ? rf_ds_dist_spared : rf_ds_spared;
824 1.78 oster raidPtr->status = (ds) ? rf_rs_reconfigured : rf_rs_optimal;
825 1.78 oster RF_UNLOCK_MUTEX(raidPtr->mutex);
826 1.78 oster RF_GETTIME(etime);
827 1.78 oster RF_TIMEVAL_DIFF(&(raidPtr->reconControl->starttime), &etime, &elpsd);
828 1.78 oster
829 1.78 oster rf_ResumeNewRequests(raidPtr);
830 1.78 oster
831 1.78 oster printf("raid%d: Reconstruction of disk at col %d completed\n",
832 1.78 oster raidPtr->raidid, col);
833 1.78 oster xor_s = raidPtr->accumXorTimeUs / 1000000;
834 1.78 oster xor_resid_us = raidPtr->accumXorTimeUs % 1000000;
835 1.78 oster printf("raid%d: Recon time was %d.%06d seconds, accumulated XOR time was %ld us (%ld.%06ld)\n",
836 1.78 oster raidPtr->raidid,
837 1.78 oster (int) elpsd.tv_sec, (int) elpsd.tv_usec,
838 1.78 oster raidPtr->accumXorTimeUs, xor_s, xor_resid_us);
839 1.78 oster printf("raid%d: (start time %d sec %d usec, end time %d sec %d usec)\n",
840 1.78 oster raidPtr->raidid,
841 1.78 oster (int) raidPtr->reconControl->starttime.tv_sec,
842 1.78 oster (int) raidPtr->reconControl->starttime.tv_usec,
843 1.78 oster (int) etime.tv_sec, (int) etime.tv_usec);
844 1.1 oster #if RF_RECON_STATS > 0
845 1.78 oster printf("raid%d: Total head-sep stall count was %d\n",
846 1.78 oster raidPtr->raidid, (int) reconDesc->hsStallCount);
847 1.4 oster #endif /* RF_RECON_STATS > 0 */
848 1.78 oster rf_FreeReconControl(raidPtr);
849 1.67 oster #if RF_ACC_TRACE > 0
850 1.78 oster RF_Free(raidPtr->recon_tracerecs, raidPtr->numCol * sizeof(RF_AccTraceEntry_t));
851 1.67 oster #endif
852 1.78 oster FreeReconDesc(reconDesc);
853 1.78 oster
854 1.4 oster return (0);
855 1.82 oster
856 1.1 oster }
857 1.13 oster /*****************************************************************************
858 1.1 oster * do the right thing upon each reconstruction event.
859 1.13 oster *****************************************************************************/
860 1.4 oster static int
861 1.60 oster ProcessReconEvent(RF_Raid_t *raidPtr, RF_ReconEvent_t *event)
862 1.4 oster {
863 1.4 oster int retcode = 0, submitblocked;
864 1.4 oster RF_ReconBuffer_t *rbuf;
865 1.4 oster RF_SectorCount_t sectorsPerRU;
866 1.4 oster
867 1.82 oster retcode = RF_RECON_READ_STOPPED;
868 1.82 oster
869 1.4 oster Dprintf1("RECON: ProcessReconEvent type %d\n", event->type);
870 1.4 oster switch (event->type) {
871 1.4 oster
872 1.4 oster /* a read I/O has completed */
873 1.4 oster case RF_REVENT_READDONE:
874 1.57 oster rbuf = raidPtr->reconControl->perDiskInfo[event->col].rbuf;
875 1.57 oster Dprintf2("RECON: READDONE EVENT: col %d psid %ld\n",
876 1.57 oster event->col, rbuf->parityStripeID);
877 1.4 oster Dprintf7("RECON: done read psid %ld buf %lx %02x %02x %02x %02x %02x\n",
878 1.4 oster rbuf->parityStripeID, rbuf->buffer, rbuf->buffer[0] & 0xff, rbuf->buffer[1] & 0xff,
879 1.4 oster rbuf->buffer[2] & 0xff, rbuf->buffer[3] & 0xff, rbuf->buffer[4] & 0xff);
880 1.4 oster rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg);
881 1.82 oster if (!raidPtr->reconControl->error) {
882 1.82 oster submitblocked = rf_SubmitReconBuffer(rbuf, 0, 0);
883 1.82 oster Dprintf1("RECON: submitblocked=%d\n", submitblocked);
884 1.82 oster if (!submitblocked)
885 1.82 oster retcode = IssueNextReadRequest(raidPtr, event->col);
886 1.82 oster }
887 1.4 oster break;
888 1.4 oster
889 1.4 oster /* a write I/O has completed */
890 1.4 oster case RF_REVENT_WRITEDONE:
891 1.40 oster #if RF_DEBUG_RECON
892 1.4 oster if (rf_floatingRbufDebug) {
893 1.4 oster rf_CheckFloatingRbufCount(raidPtr, 1);
894 1.4 oster }
895 1.38 oster #endif
896 1.4 oster sectorsPerRU = raidPtr->Layout.sectorsPerStripeUnit * raidPtr->Layout.SUsPerRU;
897 1.4 oster rbuf = (RF_ReconBuffer_t *) event->arg;
898 1.4 oster rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg);
899 1.4 oster Dprintf3("RECON: WRITEDONE EVENT: psid %d ru %d (%d %% complete)\n",
900 1.57 oster rbuf->parityStripeID, rbuf->which_ru, raidPtr->reconControl->percentComplete);
901 1.57 oster rf_ReconMapUpdate(raidPtr, raidPtr->reconControl->reconMap,
902 1.4 oster rbuf->failedDiskSectorOffset, rbuf->failedDiskSectorOffset + sectorsPerRU - 1);
903 1.57 oster rf_RemoveFromActiveReconTable(raidPtr, rbuf->parityStripeID, rbuf->which_ru);
904 1.4 oster
905 1.82 oster RF_LOCK_MUTEX(raidPtr->reconControl->rb_mutex);
906 1.82 oster raidPtr->reconControl->pending_writes--;
907 1.82 oster RF_UNLOCK_MUTEX(raidPtr->reconControl->rb_mutex);
908 1.82 oster
909 1.4 oster if (rbuf->type == RF_RBUF_TYPE_FLOATING) {
910 1.57 oster RF_LOCK_MUTEX(raidPtr->reconControl->rb_mutex);
911 1.76 oster while(raidPtr->reconControl->rb_lock) {
912 1.76 oster ltsleep(&raidPtr->reconControl->rb_lock, PRIBIO, "reconctrlpre1", 0,
913 1.76 oster &raidPtr->reconControl->rb_mutex);
914 1.76 oster }
915 1.76 oster raidPtr->reconControl->rb_lock = 1;
916 1.76 oster RF_UNLOCK_MUTEX(raidPtr->reconControl->rb_mutex);
917 1.76 oster
918 1.4 oster raidPtr->numFullReconBuffers--;
919 1.57 oster rf_ReleaseFloatingReconBuffer(raidPtr, rbuf);
920 1.76 oster
921 1.76 oster RF_LOCK_MUTEX(raidPtr->reconControl->rb_mutex);
922 1.76 oster raidPtr->reconControl->rb_lock = 0;
923 1.76 oster wakeup(&raidPtr->reconControl->rb_lock);
924 1.57 oster RF_UNLOCK_MUTEX(raidPtr->reconControl->rb_mutex);
925 1.4 oster } else
926 1.4 oster if (rbuf->type == RF_RBUF_TYPE_FORCED)
927 1.4 oster rf_FreeReconBuffer(rbuf);
928 1.4 oster else
929 1.4 oster RF_ASSERT(0);
930 1.82 oster retcode = 0;
931 1.4 oster break;
932 1.4 oster
933 1.4 oster case RF_REVENT_BUFCLEAR: /* A buffer-stall condition has been
934 1.4 oster * cleared */
935 1.57 oster Dprintf1("RECON: BUFCLEAR EVENT: col %d\n", event->col);
936 1.82 oster if (!raidPtr->reconControl->error) {
937 1.82 oster submitblocked = rf_SubmitReconBuffer(raidPtr->reconControl->perDiskInfo[event->col].rbuf,
938 1.82 oster 0, (int) (long) event->arg);
939 1.82 oster RF_ASSERT(!submitblocked); /* we wouldn't have gotten the
940 1.82 oster * BUFCLEAR event if we
941 1.82 oster * couldn't submit */
942 1.82 oster retcode = IssueNextReadRequest(raidPtr, event->col);
943 1.82 oster }
944 1.4 oster break;
945 1.4 oster
946 1.4 oster case RF_REVENT_BLOCKCLEAR: /* A user-write reconstruction
947 1.4 oster * blockage has been cleared */
948 1.57 oster DDprintf1("RECON: BLOCKCLEAR EVENT: col %d\n", event->col);
949 1.82 oster if (!raidPtr->reconControl->error) {
950 1.82 oster retcode = TryToRead(raidPtr, event->col);
951 1.82 oster }
952 1.4 oster break;
953 1.4 oster
954 1.4 oster case RF_REVENT_HEADSEPCLEAR: /* A max-head-separation
955 1.4 oster * reconstruction blockage has been
956 1.4 oster * cleared */
957 1.57 oster Dprintf1("RECON: HEADSEPCLEAR EVENT: col %d\n", event->col);
958 1.82 oster if (!raidPtr->reconControl->error) {
959 1.82 oster retcode = TryToRead(raidPtr, event->col);
960 1.82 oster }
961 1.4 oster break;
962 1.4 oster
963 1.4 oster /* a buffer has become ready to write */
964 1.4 oster case RF_REVENT_BUFREADY:
965 1.57 oster Dprintf1("RECON: BUFREADY EVENT: col %d\n", event->col);
966 1.82 oster if (!raidPtr->reconControl->error) {
967 1.82 oster retcode = IssueNextWriteRequest(raidPtr);
968 1.40 oster #if RF_DEBUG_RECON
969 1.82 oster if (rf_floatingRbufDebug) {
970 1.82 oster rf_CheckFloatingRbufCount(raidPtr, 1);
971 1.82 oster }
972 1.82 oster #endif
973 1.4 oster }
974 1.4 oster break;
975 1.4 oster
976 1.4 oster /* we need to skip the current RU entirely because it got
977 1.4 oster * recon'd while we were waiting for something else to happen */
978 1.4 oster case RF_REVENT_SKIP:
979 1.57 oster DDprintf1("RECON: SKIP EVENT: col %d\n", event->col);
980 1.82 oster if (!raidPtr->reconControl->error) {
981 1.82 oster retcode = IssueNextReadRequest(raidPtr, event->col);
982 1.82 oster }
983 1.4 oster break;
984 1.4 oster
985 1.4 oster /* a forced-reconstruction read access has completed. Just
986 1.4 oster * submit the buffer */
987 1.4 oster case RF_REVENT_FORCEDREADDONE:
988 1.4 oster rbuf = (RF_ReconBuffer_t *) event->arg;
989 1.4 oster rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg);
990 1.57 oster DDprintf1("RECON: FORCEDREADDONE EVENT: col %d\n", event->col);
991 1.82 oster if (!raidPtr->reconControl->error) {
992 1.82 oster submitblocked = rf_SubmitReconBuffer(rbuf, 1, 0);
993 1.82 oster RF_ASSERT(!submitblocked);
994 1.82 oster }
995 1.4 oster break;
996 1.4 oster
997 1.70 oster /* A read I/O failed to complete */
998 1.70 oster case RF_REVENT_READ_FAILED:
999 1.82 oster retcode = RF_RECON_READ_ERROR;
1000 1.82 oster break;
1001 1.70 oster
1002 1.70 oster /* A write I/O failed to complete */
1003 1.70 oster case RF_REVENT_WRITE_FAILED:
1004 1.82 oster retcode = RF_RECON_WRITE_ERROR;
1005 1.82 oster
1006 1.82 oster rbuf = (RF_ReconBuffer_t *) event->arg;
1007 1.82 oster
1008 1.82 oster /* cleanup the disk queue data */
1009 1.82 oster rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg);
1010 1.82 oster
1011 1.82 oster /* At this point we're erroring out, badly, and floatingRbufs
1012 1.82 oster may not even be valid. Rather than putting this back onto
1013 1.82 oster the floatingRbufs list, just arrange for its immediate
1014 1.82 oster destruction.
1015 1.82 oster */
1016 1.82 oster rf_FreeReconBuffer(rbuf);
1017 1.82 oster break;
1018 1.70 oster
1019 1.70 oster /* a forced read I/O failed to complete */
1020 1.70 oster case RF_REVENT_FORCEDREAD_FAILED:
1021 1.82 oster retcode = RF_RECON_READ_ERROR;
1022 1.82 oster break;
1023 1.70 oster
1024 1.4 oster default:
1025 1.4 oster RF_PANIC();
1026 1.4 oster }
1027 1.4 oster rf_FreeReconEventDesc(event);
1028 1.4 oster return (retcode);
1029 1.1 oster }
1030 1.13 oster /*****************************************************************************
1031 1.1 oster *
1032 1.13 oster * find the next thing that's needed on the indicated disk, and issue
1033 1.13 oster * a read request for it. We assume that the reconstruction buffer
1034 1.13 oster * associated with this process is free to receive the data. If
1035 1.13 oster * reconstruction is blocked on the indicated RU, we issue a
1036 1.13 oster * blockage-release request instead of a physical disk read request.
1037 1.13 oster * If the current disk gets too far ahead of the others, we issue a
1038 1.13 oster * head-separation wait request and return.
1039 1.13 oster *
1040 1.13 oster * ctrl->{ru_count, curPSID, diskOffset} and
1041 1.22 soren * rbuf->failedDiskSectorOffset are maintained to point to the unit
1042 1.13 oster * we're currently accessing. Note that this deviates from the
1043 1.13 oster * standard C idiom of having counters point to the next thing to be
1044 1.13 oster * accessed. This allows us to easily retry when we're blocked by
1045 1.13 oster * head separation or reconstruction-blockage events.
1046 1.1 oster *
1047 1.13 oster *****************************************************************************/
1048 1.4 oster static int
1049 1.60 oster IssueNextReadRequest(RF_Raid_t *raidPtr, RF_RowCol_t col)
1050 1.4 oster {
1051 1.57 oster RF_PerDiskReconCtrl_t *ctrl = &raidPtr->reconControl->perDiskInfo[col];
1052 1.4 oster RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
1053 1.4 oster RF_ReconBuffer_t *rbuf = ctrl->rbuf;
1054 1.4 oster RF_ReconUnitCount_t RUsPerPU = layoutPtr->SUsPerPU / layoutPtr->SUsPerRU;
1055 1.4 oster RF_SectorCount_t sectorsPerRU = layoutPtr->sectorsPerStripeUnit * layoutPtr->SUsPerRU;
1056 1.4 oster int do_new_check = 0, retcode = 0, status;
1057 1.4 oster
1058 1.4 oster /* if we are currently the slowest disk, mark that we have to do a new
1059 1.4 oster * check */
1060 1.57 oster if (ctrl->headSepCounter <= raidPtr->reconControl->minHeadSepCounter)
1061 1.4 oster do_new_check = 1;
1062 1.4 oster
1063 1.4 oster while (1) {
1064 1.4 oster
1065 1.4 oster ctrl->ru_count++;
1066 1.4 oster if (ctrl->ru_count < RUsPerPU) {
1067 1.4 oster ctrl->diskOffset += sectorsPerRU;
1068 1.4 oster rbuf->failedDiskSectorOffset += sectorsPerRU;
1069 1.4 oster } else {
1070 1.4 oster ctrl->curPSID++;
1071 1.4 oster ctrl->ru_count = 0;
1072 1.4 oster /* code left over from when head-sep was based on
1073 1.4 oster * parity stripe id */
1074 1.57 oster if (ctrl->curPSID >= raidPtr->reconControl->lastPSID) {
1075 1.57 oster CheckForNewMinHeadSep(raidPtr, ++(ctrl->headSepCounter));
1076 1.82 oster return (RF_RECON_DONE_READS); /* finito! */
1077 1.4 oster }
1078 1.4 oster /* find the disk offsets of the start of the parity
1079 1.4 oster * stripe on both the current disk and the failed
1080 1.4 oster * disk. skip this entire parity stripe if either disk
1081 1.4 oster * does not appear in the indicated PS */
1082 1.57 oster status = ComputePSDiskOffsets(raidPtr, ctrl->curPSID, col, &ctrl->diskOffset, &rbuf->failedDiskSectorOffset,
1083 1.57 oster &rbuf->spCol, &rbuf->spOffset);
1084 1.4 oster if (status) {
1085 1.4 oster ctrl->ru_count = RUsPerPU - 1;
1086 1.4 oster continue;
1087 1.4 oster }
1088 1.4 oster }
1089 1.4 oster rbuf->which_ru = ctrl->ru_count;
1090 1.4 oster
1091 1.4 oster /* skip this RU if it's already been reconstructed */
1092 1.57 oster if (rf_CheckRUReconstructed(raidPtr->reconControl->reconMap, rbuf->failedDiskSectorOffset)) {
1093 1.4 oster Dprintf2("Skipping psid %ld ru %d: already reconstructed\n", ctrl->curPSID, ctrl->ru_count);
1094 1.4 oster continue;
1095 1.4 oster }
1096 1.4 oster break;
1097 1.4 oster }
1098 1.4 oster ctrl->headSepCounter++;
1099 1.4 oster if (do_new_check)
1100 1.57 oster CheckForNewMinHeadSep(raidPtr, ctrl->headSepCounter); /* update min if needed */
1101 1.4 oster
1102 1.4 oster
1103 1.4 oster /* at this point, we have definitely decided what to do, and we have
1104 1.4 oster * only to see if we can actually do it now */
1105 1.4 oster rbuf->parityStripeID = ctrl->curPSID;
1106 1.4 oster rbuf->which_ru = ctrl->ru_count;
1107 1.67 oster #if RF_ACC_TRACE > 0
1108 1.29 thorpej memset((char *) &raidPtr->recon_tracerecs[col], 0,
1109 1.29 thorpej sizeof(raidPtr->recon_tracerecs[col]));
1110 1.4 oster raidPtr->recon_tracerecs[col].reconacc = 1;
1111 1.4 oster RF_ETIMER_START(raidPtr->recon_tracerecs[col].recon_timer);
1112 1.67 oster #endif
1113 1.57 oster retcode = TryToRead(raidPtr, col);
1114 1.4 oster return (retcode);
1115 1.1 oster }
1116 1.13 oster
1117 1.13 oster /*
1118 1.13 oster * tries to issue the next read on the indicated disk. We may be
1119 1.13 oster * blocked by (a) the heads being too far apart, or (b) recon on the
1120 1.13 oster * indicated RU being blocked due to a write by a user thread. In
1121 1.13 oster * this case, we issue a head-sep or blockage wait request, which will
1122 1.13 oster * cause this same routine to be invoked again later when the blockage
1123 1.13 oster * has cleared.
1124 1.1 oster */
1125 1.13 oster
1126 1.4 oster static int
1127 1.60 oster TryToRead(RF_Raid_t *raidPtr, RF_RowCol_t col)
1128 1.4 oster {
1129 1.57 oster RF_PerDiskReconCtrl_t *ctrl = &raidPtr->reconControl->perDiskInfo[col];
1130 1.4 oster RF_SectorCount_t sectorsPerRU = raidPtr->Layout.sectorsPerStripeUnit * raidPtr->Layout.SUsPerRU;
1131 1.4 oster RF_StripeNum_t psid = ctrl->curPSID;
1132 1.4 oster RF_ReconUnitNum_t which_ru = ctrl->ru_count;
1133 1.4 oster RF_DiskQueueData_t *req;
1134 1.68 oster int status;
1135 1.68 oster RF_ReconParityStripeStatus_t *pssPtr, *newpssPtr;
1136 1.4 oster
1137 1.4 oster /* if the current disk is too far ahead of the others, issue a
1138 1.4 oster * head-separation wait and return */
1139 1.57 oster if (CheckHeadSeparation(raidPtr, ctrl, col, ctrl->headSepCounter, which_ru))
1140 1.4 oster return (0);
1141 1.68 oster
1142 1.68 oster /* allocate a new PSS in case we need it */
1143 1.68 oster newpssPtr = rf_AllocPSStatus(raidPtr);
1144 1.68 oster
1145 1.57 oster RF_LOCK_PSS_MUTEX(raidPtr, psid);
1146 1.68 oster pssPtr = rf_LookupRUStatus(raidPtr, raidPtr->reconControl->pssTable, psid, which_ru, RF_PSS_CREATE, newpssPtr);
1147 1.68 oster
1148 1.68 oster if (pssPtr != newpssPtr) {
1149 1.68 oster rf_FreePSStatus(raidPtr, newpssPtr);
1150 1.68 oster }
1151 1.4 oster
1152 1.4 oster /* if recon is blocked on the indicated parity stripe, issue a
1153 1.4 oster * block-wait request and return. this also must mark the indicated RU
1154 1.4 oster * in the stripe as under reconstruction if not blocked. */
1155 1.57 oster status = CheckForcedOrBlockedReconstruction(raidPtr, pssPtr, ctrl, col, psid, which_ru);
1156 1.4 oster if (status == RF_PSS_RECON_BLOCKED) {
1157 1.4 oster Dprintf2("RECON: Stalling psid %ld ru %d: recon blocked\n", psid, which_ru);
1158 1.4 oster goto out;
1159 1.4 oster } else
1160 1.4 oster if (status == RF_PSS_FORCED_ON_WRITE) {
1161 1.57 oster rf_CauseReconEvent(raidPtr, col, NULL, RF_REVENT_SKIP);
1162 1.4 oster goto out;
1163 1.4 oster }
1164 1.4 oster /* make one last check to be sure that the indicated RU didn't get
1165 1.4 oster * reconstructed while we were waiting for something else to happen.
1166 1.4 oster * This is unfortunate in that it causes us to make this check twice
1167 1.4 oster * in the normal case. Might want to make some attempt to re-work
1168 1.4 oster * this so that we only do this check if we've definitely blocked on
1169 1.4 oster * one of the above checks. When this condition is detected, we may
1170 1.4 oster * have just created a bogus status entry, which we need to delete. */
1171 1.57 oster if (rf_CheckRUReconstructed(raidPtr->reconControl->reconMap, ctrl->rbuf->failedDiskSectorOffset)) {
1172 1.4 oster Dprintf2("RECON: Skipping psid %ld ru %d: prior recon after stall\n", psid, which_ru);
1173 1.68 oster if (pssPtr == newpssPtr)
1174 1.57 oster rf_PSStatusDelete(raidPtr, raidPtr->reconControl->pssTable, pssPtr);
1175 1.57 oster rf_CauseReconEvent(raidPtr, col, NULL, RF_REVENT_SKIP);
1176 1.4 oster goto out;
1177 1.4 oster }
1178 1.4 oster /* found something to read. issue the I/O */
1179 1.57 oster Dprintf4("RECON: Read for psid %ld on col %d offset %ld buf %lx\n",
1180 1.57 oster psid, col, ctrl->diskOffset, ctrl->rbuf->buffer);
1181 1.67 oster #if RF_ACC_TRACE > 0
1182 1.4 oster RF_ETIMER_STOP(raidPtr->recon_tracerecs[col].recon_timer);
1183 1.4 oster RF_ETIMER_EVAL(raidPtr->recon_tracerecs[col].recon_timer);
1184 1.4 oster raidPtr->recon_tracerecs[col].specific.recon.recon_start_to_fetch_us =
1185 1.4 oster RF_ETIMER_VAL_US(raidPtr->recon_tracerecs[col].recon_timer);
1186 1.4 oster RF_ETIMER_START(raidPtr->recon_tracerecs[col].recon_timer);
1187 1.67 oster #endif
1188 1.4 oster /* should be ok to use a NULL proc pointer here, all the bufs we use
1189 1.4 oster * should be in kernel space */
1190 1.4 oster req = rf_CreateDiskQueueData(RF_IO_TYPE_READ, ctrl->diskOffset, sectorsPerRU, ctrl->rbuf->buffer, psid, which_ru,
1191 1.67 oster ReconReadDoneProc, (void *) ctrl, NULL,
1192 1.67 oster #if RF_ACC_TRACE > 0
1193 1.67 oster &raidPtr->recon_tracerecs[col],
1194 1.67 oster #else
1195 1.67 oster NULL,
1196 1.67 oster #endif
1197 1.67 oster (void *) raidPtr, 0, NULL);
1198 1.4 oster
1199 1.4 oster RF_ASSERT(req); /* XXX -- fix this -- XXX */
1200 1.4 oster
1201 1.4 oster ctrl->rbuf->arg = (void *) req;
1202 1.57 oster rf_DiskIOEnqueue(&raidPtr->Queues[col], req, RF_IO_RECON_PRIORITY);
1203 1.4 oster pssPtr->issued[col] = 1;
1204 1.1 oster
1205 1.1 oster out:
1206 1.57 oster RF_UNLOCK_PSS_MUTEX(raidPtr, psid);
1207 1.4 oster return (0);
1208 1.1 oster }
1209 1.1 oster
1210 1.1 oster
1211 1.13 oster /*
1212 1.13 oster * given a parity stripe ID, we want to find out whether both the
1213 1.13 oster * current disk and the failed disk exist in that parity stripe. If
1214 1.13 oster * not, we want to skip this whole PS. If so, we want to find the
1215 1.13 oster * disk offset of the start of the PS on both the current disk and the
1216 1.13 oster * failed disk.
1217 1.13 oster *
1218 1.13 oster * this works by getting a list of disks comprising the indicated
1219 1.13 oster * parity stripe, and searching the list for the current and failed
1220 1.13 oster * disks. Once we've decided they both exist in the parity stripe, we
1221 1.13 oster * need to decide whether each is data or parity, so that we'll know
1222 1.13 oster * which mapping function to call to get the corresponding disk
1223 1.1 oster * offsets.
1224 1.1 oster *
1225 1.13 oster * this is kind of unpleasant, but doing it this way allows the
1226 1.13 oster * reconstruction code to use parity stripe IDs rather than physical
1227 1.13 oster * disks address to march through the failed disk, which greatly
1228 1.13 oster * simplifies a lot of code, as well as eliminating the need for a
1229 1.13 oster * reverse-mapping function. I also think it will execute faster,
1230 1.13 oster * since the calls to the mapping module are kept to a minimum.
1231 1.1 oster *
1232 1.13 oster * ASSUMES THAT THE STRIPE IDENTIFIER IDENTIFIES THE DISKS COMPRISING
1233 1.60 oster * THE STRIPE IN THE CORRECT ORDER
1234 1.60 oster *
1235 1.60 oster * raidPtr - raid descriptor
1236 1.60 oster * psid - parity stripe identifier
1237 1.60 oster * col - column of disk to find the offsets for
1238 1.60 oster * spCol - out: col of spare unit for failed unit
1239 1.60 oster * spOffset - out: offset into disk containing spare unit
1240 1.60 oster *
1241 1.60 oster */
1242 1.13 oster
1243 1.13 oster
1244 1.4 oster static int
1245 1.60 oster ComputePSDiskOffsets(RF_Raid_t *raidPtr, RF_StripeNum_t psid,
1246 1.60 oster RF_RowCol_t col, RF_SectorNum_t *outDiskOffset,
1247 1.60 oster RF_SectorNum_t *outFailedDiskSectorOffset,
1248 1.60 oster RF_RowCol_t *spCol, RF_SectorNum_t *spOffset)
1249 1.60 oster {
1250 1.4 oster RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
1251 1.57 oster RF_RowCol_t fcol = raidPtr->reconControl->fcol;
1252 1.4 oster RF_RaidAddr_t sosRaidAddress; /* start-of-stripe */
1253 1.4 oster RF_RowCol_t *diskids;
1254 1.4 oster u_int i, j, k, i_offset, j_offset;
1255 1.57 oster RF_RowCol_t pcol;
1256 1.57 oster int testcol;
1257 1.4 oster RF_SectorNum_t poffset;
1258 1.4 oster char i_is_parity = 0, j_is_parity = 0;
1259 1.4 oster RF_RowCol_t stripeWidth = layoutPtr->numDataCol + layoutPtr->numParityCol;
1260 1.4 oster
1261 1.4 oster /* get a listing of the disks comprising that stripe */
1262 1.4 oster sosRaidAddress = rf_ParityStripeIDToRaidAddress(layoutPtr, psid);
1263 1.57 oster (layoutPtr->map->IdentifyStripe) (raidPtr, sosRaidAddress, &diskids);
1264 1.4 oster RF_ASSERT(diskids);
1265 1.4 oster
1266 1.4 oster /* reject this entire parity stripe if it does not contain the
1267 1.4 oster * indicated disk or it does not contain the failed disk */
1268 1.57 oster
1269 1.4 oster for (i = 0; i < stripeWidth; i++) {
1270 1.4 oster if (col == diskids[i])
1271 1.4 oster break;
1272 1.4 oster }
1273 1.4 oster if (i == stripeWidth)
1274 1.4 oster goto skipit;
1275 1.4 oster for (j = 0; j < stripeWidth; j++) {
1276 1.4 oster if (fcol == diskids[j])
1277 1.4 oster break;
1278 1.4 oster }
1279 1.4 oster if (j == stripeWidth) {
1280 1.4 oster goto skipit;
1281 1.4 oster }
1282 1.4 oster /* find out which disk the parity is on */
1283 1.57 oster (layoutPtr->map->MapParity) (raidPtr, sosRaidAddress, &pcol, &poffset, RF_DONT_REMAP);
1284 1.4 oster
1285 1.4 oster /* find out if either the current RU or the failed RU is parity */
1286 1.4 oster /* also, if the parity occurs in this stripe prior to the data and/or
1287 1.4 oster * failed col, we need to decrement i and/or j */
1288 1.4 oster for (k = 0; k < stripeWidth; k++)
1289 1.4 oster if (diskids[k] == pcol)
1290 1.4 oster break;
1291 1.4 oster RF_ASSERT(k < stripeWidth);
1292 1.4 oster i_offset = i;
1293 1.4 oster j_offset = j;
1294 1.4 oster if (k < i)
1295 1.4 oster i_offset--;
1296 1.4 oster else
1297 1.4 oster if (k == i) {
1298 1.4 oster i_is_parity = 1;
1299 1.4 oster i_offset = 0;
1300 1.4 oster } /* set offsets to zero to disable multiply
1301 1.4 oster * below */
1302 1.4 oster if (k < j)
1303 1.4 oster j_offset--;
1304 1.4 oster else
1305 1.4 oster if (k == j) {
1306 1.4 oster j_is_parity = 1;
1307 1.4 oster j_offset = 0;
1308 1.4 oster }
1309 1.4 oster /* at this point, [ij]_is_parity tells us whether the [current,failed]
1310 1.4 oster * disk is parity at the start of this RU, and, if data, "[ij]_offset"
1311 1.4 oster * tells us how far into the stripe the [current,failed] disk is. */
1312 1.4 oster
1313 1.4 oster /* call the mapping routine to get the offset into the current disk,
1314 1.4 oster * repeat for failed disk. */
1315 1.4 oster if (i_is_parity)
1316 1.57 oster layoutPtr->map->MapParity(raidPtr, sosRaidAddress + i_offset * layoutPtr->sectorsPerStripeUnit, &testcol, outDiskOffset, RF_DONT_REMAP);
1317 1.4 oster else
1318 1.57 oster layoutPtr->map->MapSector(raidPtr, sosRaidAddress + i_offset * layoutPtr->sectorsPerStripeUnit, &testcol, outDiskOffset, RF_DONT_REMAP);
1319 1.4 oster
1320 1.57 oster RF_ASSERT(col == testcol);
1321 1.4 oster
1322 1.4 oster if (j_is_parity)
1323 1.57 oster layoutPtr->map->MapParity(raidPtr, sosRaidAddress + j_offset * layoutPtr->sectorsPerStripeUnit, &testcol, outFailedDiskSectorOffset, RF_DONT_REMAP);
1324 1.4 oster else
1325 1.57 oster layoutPtr->map->MapSector(raidPtr, sosRaidAddress + j_offset * layoutPtr->sectorsPerStripeUnit, &testcol, outFailedDiskSectorOffset, RF_DONT_REMAP);
1326 1.57 oster RF_ASSERT(fcol == testcol);
1327 1.4 oster
1328 1.4 oster /* now locate the spare unit for the failed unit */
1329 1.72 oster #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0
1330 1.4 oster if (layoutPtr->map->flags & RF_DISTRIBUTE_SPARE) {
1331 1.4 oster if (j_is_parity)
1332 1.57 oster layoutPtr->map->MapParity(raidPtr, sosRaidAddress + j_offset * layoutPtr->sectorsPerStripeUnit, spCol, spOffset, RF_REMAP);
1333 1.4 oster else
1334 1.57 oster layoutPtr->map->MapSector(raidPtr, sosRaidAddress + j_offset * layoutPtr->sectorsPerStripeUnit, spCol, spOffset, RF_REMAP);
1335 1.4 oster } else {
1336 1.72 oster #endif
1337 1.57 oster *spCol = raidPtr->reconControl->spareCol;
1338 1.4 oster *spOffset = *outFailedDiskSectorOffset;
1339 1.72 oster #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0
1340 1.4 oster }
1341 1.72 oster #endif
1342 1.4 oster return (0);
1343 1.1 oster
1344 1.1 oster skipit:
1345 1.57 oster Dprintf2("RECON: Skipping psid %ld: nothing needed from r%d c%d\n",
1346 1.57 oster psid, col);
1347 1.4 oster return (1);
1348 1.1 oster }
1349 1.4 oster /* this is called when a buffer has become ready to write to the replacement disk */
1350 1.4 oster static int
1351 1.60 oster IssueNextWriteRequest(RF_Raid_t *raidPtr)
1352 1.4 oster {
1353 1.4 oster RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
1354 1.4 oster RF_SectorCount_t sectorsPerRU = layoutPtr->sectorsPerStripeUnit * layoutPtr->SUsPerRU;
1355 1.67 oster #if RF_ACC_TRACE > 0
1356 1.57 oster RF_RowCol_t fcol = raidPtr->reconControl->fcol;
1357 1.67 oster #endif
1358 1.4 oster RF_ReconBuffer_t *rbuf;
1359 1.4 oster RF_DiskQueueData_t *req;
1360 1.4 oster
1361 1.57 oster rbuf = rf_GetFullReconBuffer(raidPtr->reconControl);
1362 1.4 oster RF_ASSERT(rbuf); /* there must be one available, or we wouldn't
1363 1.4 oster * have gotten the event that sent us here */
1364 1.4 oster RF_ASSERT(rbuf->pssPtr);
1365 1.4 oster
1366 1.4 oster rbuf->pssPtr->writeRbuf = rbuf;
1367 1.4 oster rbuf->pssPtr = NULL;
1368 1.4 oster
1369 1.57 oster Dprintf6("RECON: New write (c %d offs %d) for psid %ld ru %d (failed disk offset %ld) buf %lx\n",
1370 1.57 oster rbuf->spCol, rbuf->spOffset, rbuf->parityStripeID,
1371 1.4 oster rbuf->which_ru, rbuf->failedDiskSectorOffset, rbuf->buffer);
1372 1.4 oster Dprintf6("RECON: new write psid %ld %02x %02x %02x %02x %02x\n",
1373 1.4 oster rbuf->parityStripeID, rbuf->buffer[0] & 0xff, rbuf->buffer[1] & 0xff,
1374 1.4 oster rbuf->buffer[2] & 0xff, rbuf->buffer[3] & 0xff, rbuf->buffer[4] & 0xff);
1375 1.4 oster
1376 1.4 oster /* should be ok to use a NULL b_proc here b/c all addrs should be in
1377 1.4 oster * kernel space */
1378 1.4 oster req = rf_CreateDiskQueueData(RF_IO_TYPE_WRITE, rbuf->spOffset,
1379 1.4 oster sectorsPerRU, rbuf->buffer,
1380 1.4 oster rbuf->parityStripeID, rbuf->which_ru,
1381 1.4 oster ReconWriteDoneProc, (void *) rbuf, NULL,
1382 1.67 oster #if RF_ACC_TRACE > 0
1383 1.4 oster &raidPtr->recon_tracerecs[fcol],
1384 1.67 oster #else
1385 1.67 oster NULL,
1386 1.67 oster #endif
1387 1.4 oster (void *) raidPtr, 0, NULL);
1388 1.4 oster
1389 1.4 oster RF_ASSERT(req); /* XXX -- fix this -- XXX */
1390 1.1 oster
1391 1.4 oster rbuf->arg = (void *) req;
1392 1.82 oster RF_LOCK_MUTEX(raidPtr->reconControl->rb_mutex);
1393 1.82 oster raidPtr->reconControl->pending_writes++;
1394 1.82 oster RF_UNLOCK_MUTEX(raidPtr->reconControl->rb_mutex);
1395 1.57 oster rf_DiskIOEnqueue(&raidPtr->Queues[rbuf->spCol], req, RF_IO_RECON_PRIORITY);
1396 1.1 oster
1397 1.4 oster return (0);
1398 1.1 oster }
1399 1.13 oster
1400 1.13 oster /*
1401 1.13 oster * this gets called upon the completion of a reconstruction read
1402 1.13 oster * operation the arg is a pointer to the per-disk reconstruction
1403 1.13 oster * control structure for the process that just finished a read.
1404 1.1 oster *
1405 1.13 oster * called at interrupt context in the kernel, so don't do anything
1406 1.13 oster * illegal here.
1407 1.1 oster */
1408 1.4 oster static int
1409 1.60 oster ReconReadDoneProc(void *arg, int status)
1410 1.4 oster {
1411 1.4 oster RF_PerDiskReconCtrl_t *ctrl = (RF_PerDiskReconCtrl_t *) arg;
1412 1.82 oster RF_Raid_t *raidPtr;
1413 1.82 oster
1414 1.82 oster /* Detect that reconCtrl is no longer valid, and if that
1415 1.82 oster is the case, bail without calling rf_CauseReconEvent().
1416 1.82 oster There won't be anyone listening for this event anyway */
1417 1.82 oster
1418 1.82 oster if (ctrl->reconCtrl == NULL)
1419 1.82 oster return(0);
1420 1.82 oster
1421 1.82 oster raidPtr = ctrl->reconCtrl->reconDesc->raidPtr;
1422 1.4 oster
1423 1.4 oster if (status) {
1424 1.70 oster printf("raid%d: Recon read failed!\n", raidPtr->raidid);
1425 1.70 oster rf_CauseReconEvent(raidPtr, ctrl->col, NULL, RF_REVENT_READ_FAILED);
1426 1.70 oster return(0);
1427 1.4 oster }
1428 1.67 oster #if RF_ACC_TRACE > 0
1429 1.4 oster RF_ETIMER_STOP(raidPtr->recon_tracerecs[ctrl->col].recon_timer);
1430 1.4 oster RF_ETIMER_EVAL(raidPtr->recon_tracerecs[ctrl->col].recon_timer);
1431 1.4 oster raidPtr->recon_tracerecs[ctrl->col].specific.recon.recon_fetch_to_return_us =
1432 1.4 oster RF_ETIMER_VAL_US(raidPtr->recon_tracerecs[ctrl->col].recon_timer);
1433 1.4 oster RF_ETIMER_START(raidPtr->recon_tracerecs[ctrl->col].recon_timer);
1434 1.67 oster #endif
1435 1.57 oster rf_CauseReconEvent(raidPtr, ctrl->col, NULL, RF_REVENT_READDONE);
1436 1.4 oster return (0);
1437 1.1 oster }
1438 1.1 oster /* this gets called upon the completion of a reconstruction write operation.
1439 1.1 oster * the arg is a pointer to the rbuf that was just written
1440 1.1 oster *
1441 1.1 oster * called at interrupt context in the kernel, so don't do anything illegal here.
1442 1.1 oster */
1443 1.4 oster static int
1444 1.60 oster ReconWriteDoneProc(void *arg, int status)
1445 1.4 oster {
1446 1.4 oster RF_ReconBuffer_t *rbuf = (RF_ReconBuffer_t *) arg;
1447 1.4 oster
1448 1.82 oster /* Detect that reconControl is no longer valid, and if that
1449 1.82 oster is the case, bail without calling rf_CauseReconEvent().
1450 1.82 oster There won't be anyone listening for this event anyway */
1451 1.82 oster
1452 1.82 oster if (rbuf->raidPtr->reconControl == NULL)
1453 1.82 oster return(0);
1454 1.82 oster
1455 1.4 oster Dprintf2("Reconstruction completed on psid %ld ru %d\n", rbuf->parityStripeID, rbuf->which_ru);
1456 1.4 oster if (status) {
1457 1.70 oster printf("raid%d: Recon write failed!\n", rbuf->raidPtr->raidid);
1458 1.71 oster rf_CauseReconEvent(rbuf->raidPtr, rbuf->col, arg, RF_REVENT_WRITE_FAILED);
1459 1.70 oster return(0);
1460 1.4 oster }
1461 1.71 oster rf_CauseReconEvent(rbuf->raidPtr, rbuf->col, arg, RF_REVENT_WRITEDONE);
1462 1.4 oster return (0);
1463 1.1 oster }
1464 1.1 oster
1465 1.1 oster
1466 1.13 oster /*
1467 1.13 oster * computes a new minimum head sep, and wakes up anyone who needs to
1468 1.13 oster * be woken as a result
1469 1.13 oster */
1470 1.4 oster static void
1471 1.60 oster CheckForNewMinHeadSep(RF_Raid_t *raidPtr, RF_HeadSepLimit_t hsCtr)
1472 1.4 oster {
1473 1.57 oster RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl;
1474 1.4 oster RF_HeadSepLimit_t new_min;
1475 1.4 oster RF_RowCol_t i;
1476 1.4 oster RF_CallbackDesc_t *p;
1477 1.4 oster RF_ASSERT(hsCtr >= reconCtrlPtr->minHeadSepCounter); /* from the definition
1478 1.4 oster * of a minimum */
1479 1.4 oster
1480 1.4 oster
1481 1.4 oster RF_LOCK_MUTEX(reconCtrlPtr->rb_mutex);
1482 1.76 oster while(reconCtrlPtr->rb_lock) {
1483 1.76 oster ltsleep(&reconCtrlPtr->rb_lock, PRIBIO, "reconctlcnmhs", 0, &reconCtrlPtr->rb_mutex);
1484 1.76 oster }
1485 1.76 oster reconCtrlPtr->rb_lock = 1;
1486 1.76 oster RF_UNLOCK_MUTEX(reconCtrlPtr->rb_mutex);
1487 1.4 oster
1488 1.4 oster new_min = ~(1L << (8 * sizeof(long) - 1)); /* 0x7FFF....FFF */
1489 1.4 oster for (i = 0; i < raidPtr->numCol; i++)
1490 1.4 oster if (i != reconCtrlPtr->fcol) {
1491 1.4 oster if (reconCtrlPtr->perDiskInfo[i].headSepCounter < new_min)
1492 1.4 oster new_min = reconCtrlPtr->perDiskInfo[i].headSepCounter;
1493 1.4 oster }
1494 1.4 oster /* set the new minimum and wake up anyone who can now run again */
1495 1.4 oster if (new_min != reconCtrlPtr->minHeadSepCounter) {
1496 1.4 oster reconCtrlPtr->minHeadSepCounter = new_min;
1497 1.4 oster Dprintf1("RECON: new min head pos counter val is %ld\n", new_min);
1498 1.4 oster while (reconCtrlPtr->headSepCBList) {
1499 1.4 oster if (reconCtrlPtr->headSepCBList->callbackArg.v > new_min)
1500 1.4 oster break;
1501 1.4 oster p = reconCtrlPtr->headSepCBList;
1502 1.4 oster reconCtrlPtr->headSepCBList = p->next;
1503 1.4 oster p->next = NULL;
1504 1.57 oster rf_CauseReconEvent(raidPtr, p->col, NULL, RF_REVENT_HEADSEPCLEAR);
1505 1.4 oster rf_FreeCallbackDesc(p);
1506 1.4 oster }
1507 1.1 oster
1508 1.4 oster }
1509 1.76 oster RF_LOCK_MUTEX(reconCtrlPtr->rb_mutex);
1510 1.76 oster reconCtrlPtr->rb_lock = 0;
1511 1.76 oster wakeup(&reconCtrlPtr->rb_lock);
1512 1.4 oster RF_UNLOCK_MUTEX(reconCtrlPtr->rb_mutex);
1513 1.1 oster }
1514 1.13 oster
1515 1.13 oster /*
1516 1.13 oster * checks to see that the maximum head separation will not be violated
1517 1.13 oster * if we initiate a reconstruction I/O on the indicated disk.
1518 1.13 oster * Limiting the maximum head separation between two disks eliminates
1519 1.13 oster * the nasty buffer-stall conditions that occur when one disk races
1520 1.13 oster * ahead of the others and consumes all of the floating recon buffers.
1521 1.13 oster * This code is complex and unpleasant but it's necessary to avoid
1522 1.13 oster * some very nasty, albeit fairly rare, reconstruction behavior.
1523 1.1 oster *
1524 1.13 oster * returns non-zero if and only if we have to stop working on the
1525 1.13 oster * indicated disk due to a head-separation delay.
1526 1.1 oster */
1527 1.4 oster static int
1528 1.60 oster CheckHeadSeparation(RF_Raid_t *raidPtr, RF_PerDiskReconCtrl_t *ctrl,
1529 1.60 oster RF_RowCol_t col, RF_HeadSepLimit_t hsCtr,
1530 1.60 oster RF_ReconUnitNum_t which_ru)
1531 1.4 oster {
1532 1.57 oster RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl;
1533 1.4 oster RF_CallbackDesc_t *cb, *p, *pt;
1534 1.10 oster int retval = 0;
1535 1.4 oster
1536 1.4 oster /* if we're too far ahead of the slowest disk, stop working on this
1537 1.4 oster * disk until the slower ones catch up. We do this by scheduling a
1538 1.4 oster * wakeup callback for the time when the slowest disk has caught up.
1539 1.4 oster * We define "caught up" with 20% hysteresis, i.e. the head separation
1540 1.4 oster * must have fallen to at most 80% of the max allowable head
1541 1.4 oster * separation before we'll wake up.
1542 1.4 oster *
1543 1.4 oster */
1544 1.4 oster RF_LOCK_MUTEX(reconCtrlPtr->rb_mutex);
1545 1.76 oster while(reconCtrlPtr->rb_lock) {
1546 1.76 oster ltsleep(&reconCtrlPtr->rb_lock, PRIBIO, "reconctlchs", 0, &reconCtrlPtr->rb_mutex);
1547 1.76 oster }
1548 1.76 oster reconCtrlPtr->rb_lock = 1;
1549 1.76 oster RF_UNLOCK_MUTEX(reconCtrlPtr->rb_mutex);
1550 1.4 oster if ((raidPtr->headSepLimit >= 0) &&
1551 1.4 oster ((ctrl->headSepCounter - reconCtrlPtr->minHeadSepCounter) > raidPtr->headSepLimit)) {
1552 1.57 oster Dprintf5("raid%d: RECON: head sep stall: col %d hsCtr %ld minHSCtr %ld limit %ld\n",
1553 1.57 oster raidPtr->raidid, col, ctrl->headSepCounter,
1554 1.10 oster reconCtrlPtr->minHeadSepCounter,
1555 1.10 oster raidPtr->headSepLimit);
1556 1.4 oster cb = rf_AllocCallbackDesc();
1557 1.4 oster /* the minHeadSepCounter value we have to get to before we'll
1558 1.4 oster * wake up. build in 20% hysteresis. */
1559 1.4 oster cb->callbackArg.v = (ctrl->headSepCounter - raidPtr->headSepLimit + raidPtr->headSepLimit / 5);
1560 1.4 oster cb->col = col;
1561 1.4 oster cb->next = NULL;
1562 1.4 oster
1563 1.4 oster /* insert this callback descriptor into the sorted list of
1564 1.4 oster * pending head-sep callbacks */
1565 1.4 oster p = reconCtrlPtr->headSepCBList;
1566 1.4 oster if (!p)
1567 1.4 oster reconCtrlPtr->headSepCBList = cb;
1568 1.4 oster else
1569 1.4 oster if (cb->callbackArg.v < p->callbackArg.v) {
1570 1.4 oster cb->next = reconCtrlPtr->headSepCBList;
1571 1.4 oster reconCtrlPtr->headSepCBList = cb;
1572 1.4 oster } else {
1573 1.4 oster for (pt = p, p = p->next; p && (p->callbackArg.v < cb->callbackArg.v); pt = p, p = p->next);
1574 1.4 oster cb->next = p;
1575 1.4 oster pt->next = cb;
1576 1.4 oster }
1577 1.4 oster retval = 1;
1578 1.1 oster #if RF_RECON_STATS > 0
1579 1.4 oster ctrl->reconCtrl->reconDesc->hsStallCount++;
1580 1.4 oster #endif /* RF_RECON_STATS > 0 */
1581 1.4 oster }
1582 1.76 oster RF_LOCK_MUTEX(reconCtrlPtr->rb_mutex);
1583 1.76 oster reconCtrlPtr->rb_lock = 0;
1584 1.76 oster wakeup(&reconCtrlPtr->rb_lock);
1585 1.4 oster RF_UNLOCK_MUTEX(reconCtrlPtr->rb_mutex);
1586 1.1 oster
1587 1.4 oster return (retval);
1588 1.1 oster }
1589 1.13 oster /*
1590 1.13 oster * checks to see if reconstruction has been either forced or blocked
1591 1.13 oster * by a user operation. if forced, we skip this RU entirely. else if
1592 1.13 oster * blocked, put ourselves on the wait list. else return 0.
1593 1.1 oster *
1594 1.13 oster * ASSUMES THE PSS MUTEX IS LOCKED UPON ENTRY
1595 1.1 oster */
1596 1.4 oster static int
1597 1.60 oster CheckForcedOrBlockedReconstruction(RF_Raid_t *raidPtr,
1598 1.60 oster RF_ReconParityStripeStatus_t *pssPtr,
1599 1.60 oster RF_PerDiskReconCtrl_t *ctrl,
1600 1.60 oster RF_RowCol_t col, RF_StripeNum_t psid,
1601 1.60 oster RF_ReconUnitNum_t which_ru)
1602 1.4 oster {
1603 1.4 oster RF_CallbackDesc_t *cb;
1604 1.4 oster int retcode = 0;
1605 1.4 oster
1606 1.4 oster if ((pssPtr->flags & RF_PSS_FORCED_ON_READ) || (pssPtr->flags & RF_PSS_FORCED_ON_WRITE))
1607 1.4 oster retcode = RF_PSS_FORCED_ON_WRITE;
1608 1.4 oster else
1609 1.4 oster if (pssPtr->flags & RF_PSS_RECON_BLOCKED) {
1610 1.57 oster Dprintf3("RECON: col %d blocked at psid %ld ru %d\n", col, psid, which_ru);
1611 1.4 oster cb = rf_AllocCallbackDesc(); /* append ourselves to
1612 1.4 oster * the blockage-wait
1613 1.4 oster * list */
1614 1.4 oster cb->col = col;
1615 1.4 oster cb->next = pssPtr->blockWaitList;
1616 1.4 oster pssPtr->blockWaitList = cb;
1617 1.4 oster retcode = RF_PSS_RECON_BLOCKED;
1618 1.4 oster }
1619 1.4 oster if (!retcode)
1620 1.4 oster pssPtr->flags |= RF_PSS_UNDER_RECON; /* mark this RU as under
1621 1.4 oster * reconstruction */
1622 1.4 oster
1623 1.4 oster return (retcode);
1624 1.1 oster }
1625 1.13 oster /*
1626 1.13 oster * if reconstruction is currently ongoing for the indicated stripeID,
1627 1.13 oster * reconstruction is forced to completion and we return non-zero to
1628 1.13 oster * indicate that the caller must wait. If not, then reconstruction is
1629 1.13 oster * blocked on the indicated stripe and the routine returns zero. If
1630 1.13 oster * and only if we return non-zero, we'll cause the cbFunc to get
1631 1.13 oster * invoked with the cbArg when the reconstruction has completed.
1632 1.1 oster */
1633 1.4 oster int
1634 1.60 oster rf_ForceOrBlockRecon(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
1635 1.60 oster void (*cbFunc)(RF_Raid_t *, void *), void *cbArg)
1636 1.4 oster {
1637 1.4 oster RF_StripeNum_t stripeID = asmap->stripeID; /* the stripe ID we're
1638 1.4 oster * forcing recon on */
1639 1.4 oster RF_SectorCount_t sectorsPerRU = raidPtr->Layout.sectorsPerStripeUnit * raidPtr->Layout.SUsPerRU; /* num sects in one RU */
1640 1.68 oster RF_ReconParityStripeStatus_t *pssPtr, *newpssPtr; /* a pointer to the parity
1641 1.4 oster * stripe status structure */
1642 1.4 oster RF_StripeNum_t psid; /* parity stripe id */
1643 1.4 oster RF_SectorNum_t offset, fd_offset; /* disk offset, failed-disk
1644 1.4 oster * offset */
1645 1.4 oster RF_RowCol_t *diskids;
1646 1.4 oster RF_ReconUnitNum_t which_ru; /* RU within parity stripe */
1647 1.4 oster RF_RowCol_t fcol, diskno, i;
1648 1.4 oster RF_ReconBuffer_t *new_rbuf; /* ptr to newly allocated rbufs */
1649 1.4 oster RF_DiskQueueData_t *req;/* disk I/O req to be enqueued */
1650 1.4 oster RF_CallbackDesc_t *cb;
1651 1.68 oster int nPromoted;
1652 1.4 oster
1653 1.4 oster psid = rf_MapStripeIDToParityStripeID(&raidPtr->Layout, stripeID, &which_ru);
1654 1.4 oster
1655 1.68 oster /* allocate a new PSS in case we need it */
1656 1.68 oster newpssPtr = rf_AllocPSStatus(raidPtr);
1657 1.68 oster
1658 1.57 oster RF_LOCK_PSS_MUTEX(raidPtr, psid);
1659 1.4 oster
1660 1.68 oster pssPtr = rf_LookupRUStatus(raidPtr, raidPtr->reconControl->pssTable, psid, which_ru, RF_PSS_CREATE | RF_PSS_RECON_BLOCKED, newpssPtr);
1661 1.68 oster
1662 1.68 oster if (pssPtr != newpssPtr) {
1663 1.68 oster rf_FreePSStatus(raidPtr, newpssPtr);
1664 1.68 oster }
1665 1.4 oster
1666 1.4 oster /* if recon is not ongoing on this PS, just return */
1667 1.4 oster if (!(pssPtr->flags & RF_PSS_UNDER_RECON)) {
1668 1.57 oster RF_UNLOCK_PSS_MUTEX(raidPtr, psid);
1669 1.4 oster return (0);
1670 1.4 oster }
1671 1.4 oster /* otherwise, we have to wait for reconstruction to complete on this
1672 1.4 oster * RU. */
1673 1.4 oster /* In order to avoid waiting for a potentially large number of
1674 1.4 oster * low-priority accesses to complete, we force a normal-priority (i.e.
1675 1.4 oster * not low-priority) reconstruction on this RU. */
1676 1.4 oster if (!(pssPtr->flags & RF_PSS_FORCED_ON_WRITE) && !(pssPtr->flags & RF_PSS_FORCED_ON_READ)) {
1677 1.4 oster DDprintf1("Forcing recon on psid %ld\n", psid);
1678 1.4 oster pssPtr->flags |= RF_PSS_FORCED_ON_WRITE; /* mark this RU as under
1679 1.4 oster * forced recon */
1680 1.4 oster pssPtr->flags &= ~RF_PSS_RECON_BLOCKED; /* clear the blockage
1681 1.4 oster * that we just set */
1682 1.57 oster fcol = raidPtr->reconControl->fcol;
1683 1.4 oster
1684 1.4 oster /* get a listing of the disks comprising the indicated stripe */
1685 1.57 oster (raidPtr->Layout.map->IdentifyStripe) (raidPtr, asmap->raidAddress, &diskids);
1686 1.4 oster
1687 1.4 oster /* For previously issued reads, elevate them to normal
1688 1.4 oster * priority. If the I/O has already completed, it won't be
1689 1.4 oster * found in the queue, and hence this will be a no-op. For
1690 1.4 oster * unissued reads, allocate buffers and issue new reads. The
1691 1.4 oster * fact that we've set the FORCED bit means that the regular
1692 1.4 oster * recon procs will not re-issue these reqs */
1693 1.4 oster for (i = 0; i < raidPtr->Layout.numDataCol + raidPtr->Layout.numParityCol; i++)
1694 1.4 oster if ((diskno = diskids[i]) != fcol) {
1695 1.4 oster if (pssPtr->issued[diskno]) {
1696 1.57 oster nPromoted = rf_DiskIOPromote(&raidPtr->Queues[diskno], psid, which_ru);
1697 1.4 oster if (rf_reconDebug && nPromoted)
1698 1.57 oster printf("raid%d: promoted read from col %d\n", raidPtr->raidid, diskno);
1699 1.4 oster } else {
1700 1.57 oster new_rbuf = rf_MakeReconBuffer(raidPtr, diskno, RF_RBUF_TYPE_FORCED); /* create new buf */
1701 1.57 oster ComputePSDiskOffsets(raidPtr, psid, diskno, &offset, &fd_offset,
1702 1.57 oster &new_rbuf->spCol, &new_rbuf->spOffset); /* find offsets & spare
1703 1.4 oster * location */
1704 1.4 oster new_rbuf->parityStripeID = psid; /* fill in the buffer */
1705 1.4 oster new_rbuf->which_ru = which_ru;
1706 1.4 oster new_rbuf->failedDiskSectorOffset = fd_offset;
1707 1.4 oster new_rbuf->priority = RF_IO_NORMAL_PRIORITY;
1708 1.4 oster
1709 1.4 oster /* use NULL b_proc b/c all addrs
1710 1.4 oster * should be in kernel space */
1711 1.4 oster req = rf_CreateDiskQueueData(RF_IO_TYPE_READ, offset + which_ru * sectorsPerRU, sectorsPerRU, new_rbuf->buffer,
1712 1.4 oster psid, which_ru, (int (*) (void *, int)) ForceReconReadDoneProc, (void *) new_rbuf, NULL,
1713 1.4 oster NULL, (void *) raidPtr, 0, NULL);
1714 1.4 oster
1715 1.4 oster RF_ASSERT(req); /* XXX -- fix this --
1716 1.4 oster * XXX */
1717 1.4 oster
1718 1.4 oster new_rbuf->arg = req;
1719 1.57 oster rf_DiskIOEnqueue(&raidPtr->Queues[diskno], req, RF_IO_NORMAL_PRIORITY); /* enqueue the I/O */
1720 1.57 oster Dprintf2("raid%d: Issued new read req on col %d\n", raidPtr->raidid, diskno);
1721 1.4 oster }
1722 1.4 oster }
1723 1.4 oster /* if the write is sitting in the disk queue, elevate its
1724 1.4 oster * priority */
1725 1.57 oster if (rf_DiskIOPromote(&raidPtr->Queues[fcol], psid, which_ru))
1726 1.57 oster printf("raid%d: promoted write to col %d\n",
1727 1.57 oster raidPtr->raidid, fcol);
1728 1.4 oster }
1729 1.4 oster /* install a callback descriptor to be invoked when recon completes on
1730 1.4 oster * this parity stripe. */
1731 1.4 oster cb = rf_AllocCallbackDesc();
1732 1.4 oster /* XXX the following is bogus.. These functions don't really match!!
1733 1.4 oster * GO */
1734 1.4 oster cb->callbackFunc = (void (*) (RF_CBParam_t)) cbFunc;
1735 1.4 oster cb->callbackArg.p = (void *) cbArg;
1736 1.4 oster cb->next = pssPtr->procWaitList;
1737 1.4 oster pssPtr->procWaitList = cb;
1738 1.10 oster DDprintf2("raid%d: Waiting for forced recon on psid %ld\n",
1739 1.10 oster raidPtr->raidid, psid);
1740 1.4 oster
1741 1.57 oster RF_UNLOCK_PSS_MUTEX(raidPtr, psid);
1742 1.4 oster return (1);
1743 1.1 oster }
1744 1.1 oster /* called upon the completion of a forced reconstruction read.
1745 1.1 oster * all we do is schedule the FORCEDREADONE event.
1746 1.1 oster * called at interrupt context in the kernel, so don't do anything illegal here.
1747 1.1 oster */
1748 1.4 oster static void
1749 1.60 oster ForceReconReadDoneProc(void *arg, int status)
1750 1.4 oster {
1751 1.4 oster RF_ReconBuffer_t *rbuf = arg;
1752 1.4 oster
1753 1.82 oster /* Detect that reconControl is no longer valid, and if that
1754 1.82 oster is the case, bail without calling rf_CauseReconEvent().
1755 1.82 oster There won't be anyone listening for this event anyway */
1756 1.82 oster
1757 1.82 oster if (rbuf->raidPtr->reconControl == NULL)
1758 1.82 oster return;
1759 1.82 oster
1760 1.4 oster if (status) {
1761 1.70 oster printf("raid%d: Forced recon read failed!\n", rbuf->raidPtr->raidid);
1762 1.71 oster rf_CauseReconEvent(rbuf->raidPtr, rbuf->col, (void *) rbuf, RF_REVENT_FORCEDREAD_FAILED);
1763 1.79 oster return;
1764 1.4 oster }
1765 1.71 oster rf_CauseReconEvent(rbuf->raidPtr, rbuf->col, (void *) rbuf, RF_REVENT_FORCEDREADDONE);
1766 1.1 oster }
1767 1.1 oster /* releases a block on the reconstruction of the indicated stripe */
1768 1.4 oster int
1769 1.60 oster rf_UnblockRecon(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap)
1770 1.4 oster {
1771 1.4 oster RF_StripeNum_t stripeID = asmap->stripeID;
1772 1.4 oster RF_ReconParityStripeStatus_t *pssPtr;
1773 1.4 oster RF_ReconUnitNum_t which_ru;
1774 1.4 oster RF_StripeNum_t psid;
1775 1.4 oster RF_CallbackDesc_t *cb;
1776 1.4 oster
1777 1.4 oster psid = rf_MapStripeIDToParityStripeID(&raidPtr->Layout, stripeID, &which_ru);
1778 1.57 oster RF_LOCK_PSS_MUTEX(raidPtr, psid);
1779 1.68 oster pssPtr = rf_LookupRUStatus(raidPtr, raidPtr->reconControl->pssTable, psid, which_ru, RF_PSS_NONE, NULL);
1780 1.4 oster
1781 1.4 oster /* When recon is forced, the pss desc can get deleted before we get
1782 1.4 oster * back to unblock recon. But, this can _only_ happen when recon is
1783 1.4 oster * forced. It would be good to put some kind of sanity check here, but
1784 1.4 oster * how to decide if recon was just forced or not? */
1785 1.4 oster if (!pssPtr) {
1786 1.4 oster /* printf("Warning: no pss descriptor upon unblock on psid %ld
1787 1.4 oster * RU %d\n",psid,which_ru); */
1788 1.43 oster #if (RF_DEBUG_RECON > 0) || (RF_DEBUG_PSS > 0)
1789 1.4 oster if (rf_reconDebug || rf_pssDebug)
1790 1.4 oster printf("Warning: no pss descriptor upon unblock on psid %ld RU %d\n", (long) psid, which_ru);
1791 1.43 oster #endif
1792 1.4 oster goto out;
1793 1.4 oster }
1794 1.4 oster pssPtr->blockCount--;
1795 1.10 oster Dprintf3("raid%d: unblocking recon on psid %ld: blockcount is %d\n",
1796 1.10 oster raidPtr->raidid, psid, pssPtr->blockCount);
1797 1.4 oster if (pssPtr->blockCount == 0) { /* if recon blockage has been released */
1798 1.4 oster
1799 1.4 oster /* unblock recon before calling CauseReconEvent in case
1800 1.4 oster * CauseReconEvent causes us to try to issue a new read before
1801 1.4 oster * returning here. */
1802 1.4 oster pssPtr->flags &= ~RF_PSS_RECON_BLOCKED;
1803 1.4 oster
1804 1.4 oster
1805 1.13 oster while (pssPtr->blockWaitList) {
1806 1.13 oster /* spin through the block-wait list and
1807 1.13 oster release all the waiters */
1808 1.4 oster cb = pssPtr->blockWaitList;
1809 1.4 oster pssPtr->blockWaitList = cb->next;
1810 1.4 oster cb->next = NULL;
1811 1.57 oster rf_CauseReconEvent(raidPtr, cb->col, NULL, RF_REVENT_BLOCKCLEAR);
1812 1.4 oster rf_FreeCallbackDesc(cb);
1813 1.4 oster }
1814 1.13 oster if (!(pssPtr->flags & RF_PSS_UNDER_RECON)) {
1815 1.13 oster /* if no recon was requested while recon was blocked */
1816 1.57 oster rf_PSStatusDelete(raidPtr, raidPtr->reconControl->pssTable, pssPtr);
1817 1.4 oster }
1818 1.4 oster }
1819 1.1 oster out:
1820 1.57 oster RF_UNLOCK_PSS_MUTEX(raidPtr, psid);
1821 1.4 oster return (0);
1822 1.1 oster }
1823