rf_reconbuffer.c revision 1.1 1 1.1 oster /* $NetBSD: rf_reconbuffer.c,v 1.1 1998/11/13 04:20:33 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_reconbuffer.c -- reconstruction buffer manager
32 1.1 oster *
33 1.1 oster ***************************************************/
34 1.1 oster
35 1.1 oster /* :
36 1.1 oster * Log: rf_reconbuffer.c,v
37 1.1 oster * Revision 1.33 1996/07/27 23:36:08 jimz
38 1.1 oster * Solaris port of simulator
39 1.1 oster *
40 1.1 oster * Revision 1.32 1996/07/17 21:00:58 jimz
41 1.1 oster * clean up timer interface, tracing
42 1.1 oster *
43 1.1 oster * Revision 1.31 1996/07/13 00:00:59 jimz
44 1.1 oster * sanitized generalized reconstruction architecture
45 1.1 oster * cleaned up head sep, rbuf problems
46 1.1 oster *
47 1.1 oster * Revision 1.30 1996/06/07 21:33:04 jimz
48 1.1 oster * begin using consistent types for sector numbers,
49 1.1 oster * stripe numbers, row+col numbers, recon unit numbers
50 1.1 oster *
51 1.1 oster * Revision 1.29 1996/06/06 01:23:58 jimz
52 1.1 oster * don't free reconCtrlPtr until after all fields have been used out of it
53 1.1 oster *
54 1.1 oster * Revision 1.28 1996/06/05 18:06:02 jimz
55 1.1 oster * Major code cleanup. The Great Renaming is now done.
56 1.1 oster * Better modularity. Better typing. Fixed a bunch of
57 1.1 oster * synchronization bugs. Made a lot of global stuff
58 1.1 oster * per-desc or per-array. Removed dead code.
59 1.1 oster *
60 1.1 oster * Revision 1.27 1996/06/03 23:28:26 jimz
61 1.1 oster * more bugfixes
62 1.1 oster * check in tree to sync for IPDS runs with current bugfixes
63 1.1 oster * there still may be a problem with threads in the script test
64 1.1 oster * getting I/Os stuck- not trivially reproducible (runs ~50 times
65 1.1 oster * in a row without getting stuck)
66 1.1 oster *
67 1.1 oster * Revision 1.26 1996/06/02 17:31:48 jimz
68 1.1 oster * Moved a lot of global stuff into array structure, where it belongs.
69 1.1 oster * Fixed up paritylogging, pss modules in this manner. Some general
70 1.1 oster * code cleanup. Removed lots of dead code, some dead files.
71 1.1 oster *
72 1.1 oster * Revision 1.25 1996/05/31 22:26:54 jimz
73 1.1 oster * fix a lot of mapping problems, memory allocation problems
74 1.1 oster * found some weird lock issues, fixed 'em
75 1.1 oster * more code cleanup
76 1.1 oster *
77 1.1 oster * Revision 1.24 1996/05/30 12:59:18 jimz
78 1.1 oster * make etimer happier, more portable
79 1.1 oster *
80 1.1 oster * Revision 1.23 1996/05/27 18:56:37 jimz
81 1.1 oster * more code cleanup
82 1.1 oster * better typing
83 1.1 oster * compiles in all 3 environments
84 1.1 oster *
85 1.1 oster * Revision 1.22 1996/05/24 22:17:04 jimz
86 1.1 oster * continue code + namespace cleanup
87 1.1 oster * typed a bunch of flags
88 1.1 oster *
89 1.1 oster * Revision 1.21 1996/05/23 21:46:35 jimz
90 1.1 oster * checkpoint in code cleanup (release prep)
91 1.1 oster * lots of types, function names have been fixed
92 1.1 oster *
93 1.1 oster * Revision 1.20 1996/05/23 00:33:23 jimz
94 1.1 oster * code cleanup: move all debug decls to rf_options.c, all extern
95 1.1 oster * debug decls to rf_options.h, all debug vars preceded by rf_
96 1.1 oster *
97 1.1 oster * Revision 1.19 1996/05/18 19:51:34 jimz
98 1.1 oster * major code cleanup- fix syntax, make some types consistent,
99 1.1 oster * add prototypes, clean out dead code, et cetera
100 1.1 oster *
101 1.1 oster * Revision 1.18 1995/12/12 18:10:06 jimz
102 1.1 oster * MIN -> RF_MIN, MAX -> RF_MAX, ASSERT -> RF_ASSERT
103 1.1 oster * fix 80-column brain damage in comments
104 1.1 oster *
105 1.1 oster * Revision 1.17 1995/12/06 15:03:24 root
106 1.1 oster * added copyright info
107 1.1 oster *
108 1.1 oster */
109 1.1 oster
110 1.1 oster #ifdef _KERNEL
111 1.1 oster #define KERNEL
112 1.1 oster #endif
113 1.1 oster
114 1.1 oster #include "rf_raid.h"
115 1.1 oster #include "rf_reconbuffer.h"
116 1.1 oster #include "rf_acctrace.h"
117 1.1 oster #include "rf_etimer.h"
118 1.1 oster #include "rf_general.h"
119 1.1 oster #include "rf_debugprint.h"
120 1.1 oster #include "rf_revent.h"
121 1.1 oster #include "rf_reconutil.h"
122 1.1 oster #include "rf_nwayxor.h"
123 1.1 oster
124 1.1 oster #ifdef KERNEL
125 1.1 oster #define Dprintf1(s,a) if (rf_reconbufferDebug) printf(s,a)
126 1.1 oster #define Dprintf2(s,a,b) if (rf_reconbufferDebug) printf(s,a,b)
127 1.1 oster #define Dprintf3(s,a,b,c) if (rf_reconbufferDebug) printf(s,a,b,c)
128 1.1 oster #define Dprintf4(s,a,b,c,d) if (rf_reconbufferDebug) printf(s,a,b,c,d)
129 1.1 oster #define Dprintf5(s,a,b,c,d,e) if (rf_reconbufferDebug) printf(s,a,b,c,d,e)
130 1.1 oster #else /* KERNEL */
131 1.1 oster #define Dprintf1(s,a) if (rf_reconbufferDebug) rf_debug_printf(s,(void *)((unsigned long)a),NULL,NULL,NULL,NULL,NULL,NULL,NULL)
132 1.1 oster #define Dprintf2(s,a,b) if (rf_reconbufferDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),NULL,NULL,NULL,NULL,NULL,NULL)
133 1.1 oster #define Dprintf3(s,a,b,c) if (rf_reconbufferDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),NULL,NULL,NULL,NULL,NULL)
134 1.1 oster #define Dprintf4(s,a,b,c,d) if (rf_reconbufferDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),NULL,NULL,NULL,NULL)
135 1.1 oster #define Dprintf5(s,a,b,c,d,e) if (rf_reconbufferDebug) 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)
136 1.1 oster #endif /* KERNEL */
137 1.1 oster
138 1.1 oster #if defined(__NetBSD__) && defined(_KERNEL)
139 1.1 oster
140 1.1 oster /* XXX XXX XXX This is wrong, for a number of reasons:
141 1.1 oster a) thread_block doesn't exist with UVM
142 1.1 oster b) The prototype begin used here is wrong for the regular VM
143 1.1 oster (regular VM expects a (char *) as an argument. I don't put
144 1.1 oster that in here as this code uses thread_block with no arguments.. :-/
145 1.1 oster
146 1.1 oster */
147 1.1 oster #if 0
148 1.1 oster void thread_block(void);
149 1.1 oster #endif
150 1.1 oster #endif
151 1.1 oster
152 1.1 oster /*****************************************************************************************
153 1.1 oster *
154 1.1 oster * Submit a reconstruction buffer to the manager for XOR.
155 1.1 oster * We can only submit a buffer if (1) we can xor into an existing buffer, which means
156 1.1 oster * we don't have to acquire a new one, (2) we can acquire a floating
157 1.1 oster * recon buffer, or (3) the caller has indicated that we are allowed to keep the
158 1.1 oster * submitted buffer.
159 1.1 oster *
160 1.1 oster * Returns non-zero if and only if we were not able to submit.
161 1.1 oster * In this case, we append the current disk ID to the wait list on the indicated
162 1.1 oster * RU, so that it will be re-enabled when we acquire a buffer for this RU.
163 1.1 oster *
164 1.1 oster ****************************************************************************************/
165 1.1 oster
166 1.1 oster /* just to make the code below more readable */
167 1.1 oster #define BUFWAIT_APPEND(_cb_, _pssPtr_, _row_, _col_) \
168 1.1 oster _cb_ = rf_AllocCallbackDesc(); \
169 1.1 oster (_cb_)->row = (_row_); (_cb_)->col = (_col_); (_cb_)->next = (_pssPtr_)->bufWaitList; (_pssPtr_)->bufWaitList = (_cb_);
170 1.1 oster
171 1.1 oster /*
172 1.1 oster * nWayXorFuncs[i] is a pointer to a function that will xor "i"
173 1.1 oster * bufs into the accumulating sum.
174 1.1 oster */
175 1.1 oster static RF_VoidFuncPtr nWayXorFuncs[] = {
176 1.1 oster NULL,
177 1.1 oster (RF_VoidFuncPtr)rf_nWayXor1,
178 1.1 oster (RF_VoidFuncPtr)rf_nWayXor2,
179 1.1 oster (RF_VoidFuncPtr)rf_nWayXor3,
180 1.1 oster (RF_VoidFuncPtr)rf_nWayXor4,
181 1.1 oster (RF_VoidFuncPtr)rf_nWayXor5,
182 1.1 oster (RF_VoidFuncPtr)rf_nWayXor6,
183 1.1 oster (RF_VoidFuncPtr)rf_nWayXor7,
184 1.1 oster (RF_VoidFuncPtr)rf_nWayXor8,
185 1.1 oster (RF_VoidFuncPtr)rf_nWayXor9
186 1.1 oster };
187 1.1 oster
188 1.1 oster int rf_SubmitReconBuffer(rbuf, keep_it, use_committed)
189 1.1 oster RF_ReconBuffer_t *rbuf; /* the recon buffer to submit */
190 1.1 oster int keep_it; /* whether we can keep this buffer or we have to return it */
191 1.1 oster int use_committed; /* whether to use a committed or an available recon buffer */
192 1.1 oster {
193 1.1 oster RF_LayoutSW_t *lp;
194 1.1 oster int rc;
195 1.1 oster
196 1.1 oster lp = rbuf->raidPtr->Layout.map;
197 1.1 oster rc = lp->SubmitReconBuffer(rbuf, keep_it, use_committed);
198 1.1 oster return(rc);
199 1.1 oster }
200 1.1 oster
201 1.1 oster int rf_SubmitReconBufferBasic(rbuf, keep_it, use_committed)
202 1.1 oster RF_ReconBuffer_t *rbuf; /* the recon buffer to submit */
203 1.1 oster int keep_it; /* whether we can keep this buffer or we have to return it */
204 1.1 oster int use_committed; /* whether to use a committed or an available recon buffer */
205 1.1 oster {
206 1.1 oster RF_Raid_t *raidPtr = rbuf->raidPtr;
207 1.1 oster RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
208 1.1 oster RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl[rbuf->row];
209 1.1 oster RF_ReconParityStripeStatus_t *pssPtr;
210 1.1 oster RF_ReconBuffer_t *targetRbuf, *t = NULL; /* temporary rbuf pointers */
211 1.1 oster caddr_t ta; /* temporary data buffer pointer */
212 1.1 oster RF_CallbackDesc_t *cb, *p;
213 1.1 oster int retcode = 0, created = 0;
214 1.1 oster
215 1.1 oster RF_Etimer_t timer;
216 1.1 oster
217 1.1 oster /* makes no sense to have a submission from the failed disk */
218 1.1 oster RF_ASSERT(rbuf);
219 1.1 oster RF_ASSERT(rbuf->col != reconCtrlPtr->fcol);
220 1.1 oster
221 1.1 oster Dprintf5("RECON: submission by row %d col %d for psid %ld ru %d (failed offset %ld)\n",
222 1.1 oster rbuf->row, rbuf->col, (long)rbuf->parityStripeID, rbuf->which_ru, (long)rbuf->failedDiskSectorOffset);
223 1.1 oster
224 1.1 oster RF_LOCK_PSS_MUTEX(raidPtr,rbuf->row,rbuf->parityStripeID);
225 1.1 oster
226 1.1 oster RF_LOCK_MUTEX(reconCtrlPtr->rb_mutex);
227 1.1 oster
228 1.1 oster pssPtr = rf_LookupRUStatus(raidPtr, reconCtrlPtr->pssTable, rbuf->parityStripeID, rbuf->which_ru, RF_PSS_NONE, &created);
229 1.1 oster RF_ASSERT(pssPtr); /* if it didn't exist, we wouldn't have gotten an rbuf for it */
230 1.1 oster
231 1.1 oster /* check to see if enough buffers have accumulated to do an XOR. If so, there's no need to
232 1.1 oster * acquire a floating rbuf. Before we can do any XORing, we must have acquired a destination
233 1.1 oster * buffer. If we have, then we can go ahead and do the XOR if (1) including this buffer, enough
234 1.1 oster * bufs have accumulated, or (2) this is the last submission for this stripe.
235 1.1 oster * Otherwise, we have to go acquire a floating rbuf.
236 1.1 oster */
237 1.1 oster
238 1.1 oster targetRbuf = (RF_ReconBuffer_t *) pssPtr->rbuf;
239 1.1 oster if ( (targetRbuf != NULL) &&
240 1.1 oster ((pssPtr->xorBufCount == rf_numBufsToAccumulate-1) || (targetRbuf->count + pssPtr->xorBufCount + 1 == layoutPtr->numDataCol)) ) {
241 1.1 oster pssPtr->rbufsForXor[ pssPtr->xorBufCount++ ] = rbuf; /* install this buffer */
242 1.1 oster Dprintf3("RECON: row %d col %d invoking a %d-way XOR\n",rbuf->row, rbuf->col,pssPtr->xorBufCount);
243 1.1 oster RF_ETIMER_START(timer);
244 1.1 oster rf_MultiWayReconXor(raidPtr, pssPtr);
245 1.1 oster RF_ETIMER_STOP(timer); RF_ETIMER_EVAL(timer);
246 1.1 oster raidPtr->accumXorTimeUs += RF_ETIMER_VAL_US(timer);
247 1.1 oster if (!keep_it) {
248 1.1 oster raidPtr->recon_tracerecs[rbuf->col].xor_us = RF_ETIMER_VAL_US(timer);
249 1.1 oster RF_ETIMER_STOP(raidPtr->recon_tracerecs[rbuf->col].recon_timer);
250 1.1 oster RF_ETIMER_EVAL(raidPtr->recon_tracerecs[rbuf->col].recon_timer);
251 1.1 oster raidPtr->recon_tracerecs[rbuf->col].specific.recon.recon_return_to_submit_us +=
252 1.1 oster RF_ETIMER_VAL_US(raidPtr->recon_tracerecs[rbuf->col].recon_timer);
253 1.1 oster RF_ETIMER_START(raidPtr->recon_tracerecs[rbuf->col].recon_timer);
254 1.1 oster
255 1.1 oster rf_LogTraceRec(raidPtr, &raidPtr->recon_tracerecs[rbuf->col]);
256 1.1 oster }
257 1.1 oster rf_CheckForFullRbuf(raidPtr, reconCtrlPtr, pssPtr, layoutPtr->numDataCol);
258 1.1 oster
259 1.1 oster /* if use_committed is on, we _must_ consume a buffer off the committed list. */
260 1.1 oster if (use_committed) {
261 1.1 oster t = reconCtrlPtr->committedRbufs;
262 1.1 oster RF_ASSERT(t);
263 1.1 oster reconCtrlPtr->committedRbufs = t->next;
264 1.1 oster rf_ReleaseFloatingReconBuffer(raidPtr, rbuf->row, t);
265 1.1 oster }
266 1.1 oster if (keep_it) {
267 1.1 oster RF_UNLOCK_PSS_MUTEX( raidPtr,rbuf->row,rbuf->parityStripeID);
268 1.1 oster RF_UNLOCK_MUTEX( reconCtrlPtr->rb_mutex );
269 1.1 oster rf_FreeReconBuffer(rbuf);
270 1.1 oster return(retcode);
271 1.1 oster }
272 1.1 oster goto out;
273 1.1 oster }
274 1.1 oster
275 1.1 oster /* set the value of "t", which we'll use as the rbuf from here on */
276 1.1 oster if (keep_it) {
277 1.1 oster t = rbuf;
278 1.1 oster }
279 1.1 oster else {
280 1.1 oster if (use_committed) { /* if a buffer has been committed to us, use it */
281 1.1 oster t = reconCtrlPtr->committedRbufs;
282 1.1 oster RF_ASSERT(t);
283 1.1 oster reconCtrlPtr->committedRbufs = t->next;
284 1.1 oster t->next = NULL;
285 1.1 oster } else if (reconCtrlPtr->floatingRbufs) {
286 1.1 oster t = reconCtrlPtr->floatingRbufs;
287 1.1 oster reconCtrlPtr->floatingRbufs = t->next;
288 1.1 oster t->next = NULL;
289 1.1 oster }
290 1.1 oster }
291 1.1 oster
292 1.1 oster /* If we weren't able to acquire a buffer,
293 1.1 oster * append to the end of the buf list in the recon ctrl struct.
294 1.1 oster */
295 1.1 oster if (!t) {
296 1.1 oster RF_ASSERT(!keep_it && !use_committed);
297 1.1 oster Dprintf2("RECON: row %d col %d failed to acquire floating rbuf\n",rbuf->row, rbuf->col);
298 1.1 oster
299 1.1 oster raidPtr->procsInBufWait++;
300 1.1 oster if ( (raidPtr->procsInBufWait == raidPtr->numCol -1) && (raidPtr->numFullReconBuffers == 0)) {
301 1.1 oster printf("Buffer wait deadlock detected. Exiting.\n");
302 1.1 oster rf_PrintPSStatusTable(raidPtr, rbuf->row);
303 1.1 oster RF_PANIC();
304 1.1 oster }
305 1.1 oster pssPtr->flags |= RF_PSS_BUFFERWAIT;
306 1.1 oster cb = rf_AllocCallbackDesc(); /* append to buf wait list in recon ctrl structure */
307 1.1 oster cb->row = rbuf->row; cb->col = rbuf->col;
308 1.1 oster cb->callbackArg.v = rbuf->parityStripeID;
309 1.1 oster cb->callbackArg2.v = rbuf->which_ru;
310 1.1 oster cb->next = NULL;
311 1.1 oster if (!reconCtrlPtr->bufferWaitList) reconCtrlPtr->bufferWaitList = cb;
312 1.1 oster else { /* might want to maintain head/tail pointers here rather than search for end of list */
313 1.1 oster for (p = reconCtrlPtr->bufferWaitList; p->next; p=p->next);
314 1.1 oster p->next = cb;
315 1.1 oster }
316 1.1 oster retcode = 1;
317 1.1 oster goto out;
318 1.1 oster }
319 1.1 oster Dprintf2("RECON: row %d col %d acquired rbuf\n",rbuf->row, rbuf->col);
320 1.1 oster RF_ETIMER_STOP(raidPtr->recon_tracerecs[rbuf->col].recon_timer);
321 1.1 oster RF_ETIMER_EVAL(raidPtr->recon_tracerecs[rbuf->col].recon_timer);
322 1.1 oster raidPtr->recon_tracerecs[rbuf->col].specific.recon.recon_return_to_submit_us +=
323 1.1 oster RF_ETIMER_VAL_US(raidPtr->recon_tracerecs[rbuf->col].recon_timer);
324 1.1 oster RF_ETIMER_START(raidPtr->recon_tracerecs[rbuf->col].recon_timer);
325 1.1 oster
326 1.1 oster rf_LogTraceRec(raidPtr, &raidPtr->recon_tracerecs[rbuf->col]);
327 1.1 oster
328 1.1 oster /* initialize the buffer */
329 1.1 oster if (t!=rbuf) {
330 1.1 oster t->row = rbuf->row; t->col = reconCtrlPtr->fcol;
331 1.1 oster t->parityStripeID = rbuf->parityStripeID;
332 1.1 oster t->which_ru = rbuf->which_ru;
333 1.1 oster t->failedDiskSectorOffset = rbuf->failedDiskSectorOffset;
334 1.1 oster t->spRow=rbuf->spRow;
335 1.1 oster t->spCol=rbuf->spCol;
336 1.1 oster t->spOffset=rbuf->spOffset;
337 1.1 oster
338 1.1 oster ta = t->buffer; t->buffer = rbuf->buffer; rbuf->buffer = ta; /* swap buffers */
339 1.1 oster }
340 1.1 oster
341 1.1 oster /* the first installation always gets installed as the destination buffer.
342 1.1 oster * subsequent installations get stacked up to allow for multi-way XOR
343 1.1 oster */
344 1.1 oster if (!pssPtr->rbuf) {pssPtr->rbuf = t; t->count = 1;}
345 1.1 oster else pssPtr->rbufsForXor[ pssPtr->xorBufCount++ ] = t; /* install this buffer */
346 1.1 oster
347 1.1 oster rf_CheckForFullRbuf(raidPtr, reconCtrlPtr, pssPtr, layoutPtr->numDataCol); /* the buffer is full if G=2 */
348 1.1 oster
349 1.1 oster out:
350 1.1 oster RF_UNLOCK_PSS_MUTEX( raidPtr,rbuf->row,rbuf->parityStripeID);
351 1.1 oster RF_UNLOCK_MUTEX( reconCtrlPtr->rb_mutex );
352 1.1 oster return(retcode);
353 1.1 oster }
354 1.1 oster
355 1.1 oster int rf_MultiWayReconXor(raidPtr, pssPtr)
356 1.1 oster RF_Raid_t *raidPtr;
357 1.1 oster RF_ReconParityStripeStatus_t *pssPtr; /* the pss descriptor for this parity stripe */
358 1.1 oster {
359 1.1 oster int i, numBufs = pssPtr->xorBufCount;
360 1.1 oster int numBytes = rf_RaidAddressToByte(raidPtr, raidPtr->Layout.sectorsPerStripeUnit * raidPtr->Layout.SUsPerRU);
361 1.1 oster RF_ReconBuffer_t **rbufs = (RF_ReconBuffer_t **) pssPtr->rbufsForXor;
362 1.1 oster RF_ReconBuffer_t *targetRbuf = (RF_ReconBuffer_t *) pssPtr->rbuf;
363 1.1 oster
364 1.1 oster RF_ASSERT(pssPtr->rbuf != NULL);
365 1.1 oster RF_ASSERT(numBufs > 0 && numBufs < RF_PS_MAX_BUFS);
366 1.1 oster #ifdef KERNEL
367 1.1 oster #ifndef __NetBSD__
368 1.1 oster thread_block(); /* yield the processor before doing a big XOR */
369 1.1 oster #endif
370 1.1 oster #endif /* KERNEL */
371 1.1 oster /*
372 1.1 oster * XXX
373 1.1 oster *
374 1.1 oster * What if more than 9 bufs?
375 1.1 oster */
376 1.1 oster nWayXorFuncs[numBufs](pssPtr->rbufsForXor, targetRbuf, numBytes/sizeof(long));
377 1.1 oster
378 1.1 oster /* release all the reconstruction buffers except the last one, which belongs to the
379 1.1 oster * the disk who's submission caused this XOR to take place
380 1.1 oster */
381 1.1 oster for (i=0; i < numBufs-1; i++) {
382 1.1 oster if (rbufs[i]->type == RF_RBUF_TYPE_FLOATING) rf_ReleaseFloatingReconBuffer(raidPtr, rbufs[i]->row, rbufs[i]);
383 1.1 oster else if (rbufs[i]->type == RF_RBUF_TYPE_FORCED) rf_FreeReconBuffer(rbufs[i]);
384 1.1 oster else RF_ASSERT(0);
385 1.1 oster }
386 1.1 oster targetRbuf->count += pssPtr->xorBufCount;
387 1.1 oster pssPtr->xorBufCount = 0;
388 1.1 oster return(0);
389 1.1 oster }
390 1.1 oster
391 1.1 oster /* removes one full buffer from one of the full-buffer lists and returns it.
392 1.1 oster *
393 1.1 oster * ASSUMES THE RB_MUTEX IS UNLOCKED AT ENTRY.
394 1.1 oster */
395 1.1 oster RF_ReconBuffer_t *rf_GetFullReconBuffer(reconCtrlPtr)
396 1.1 oster RF_ReconCtrl_t *reconCtrlPtr;
397 1.1 oster {
398 1.1 oster RF_ReconBuffer_t *p;
399 1.1 oster
400 1.1 oster RF_LOCK_MUTEX(reconCtrlPtr->rb_mutex);
401 1.1 oster
402 1.1 oster if ( (p=reconCtrlPtr->priorityList) != NULL) {
403 1.1 oster reconCtrlPtr->priorityList = p->next;
404 1.1 oster p->next = NULL;
405 1.1 oster goto out;
406 1.1 oster }
407 1.1 oster if ( (p=reconCtrlPtr->fullBufferList) != NULL) {
408 1.1 oster reconCtrlPtr->fullBufferList = p->next;
409 1.1 oster p->next = NULL;
410 1.1 oster goto out;
411 1.1 oster }
412 1.1 oster
413 1.1 oster out:
414 1.1 oster RF_UNLOCK_MUTEX(reconCtrlPtr->rb_mutex);
415 1.1 oster return(p);
416 1.1 oster }
417 1.1 oster
418 1.1 oster
419 1.1 oster /* if the reconstruction buffer is full, move it to the full list, which is maintained
420 1.1 oster * sorted by failed disk sector offset
421 1.1 oster *
422 1.1 oster * ASSUMES THE RB_MUTEX IS LOCKED AT ENTRY.
423 1.1 oster */
424 1.1 oster int rf_CheckForFullRbuf(raidPtr, reconCtrl, pssPtr, numDataCol)
425 1.1 oster RF_Raid_t *raidPtr;
426 1.1 oster RF_ReconCtrl_t *reconCtrl;
427 1.1 oster RF_ReconParityStripeStatus_t *pssPtr;
428 1.1 oster int numDataCol;
429 1.1 oster {
430 1.1 oster RF_ReconBuffer_t *p, *pt, *rbuf = (RF_ReconBuffer_t *) pssPtr->rbuf;
431 1.1 oster
432 1.1 oster if (rbuf->count == numDataCol) {
433 1.1 oster raidPtr->numFullReconBuffers++;
434 1.1 oster Dprintf2("RECON: rbuf for psid %ld ru %d has filled\n",
435 1.1 oster (long)rbuf->parityStripeID, rbuf->which_ru);
436 1.1 oster if (!reconCtrl->fullBufferList || (rbuf->failedDiskSectorOffset < reconCtrl->fullBufferList->failedDiskSectorOffset)) {
437 1.1 oster Dprintf2("RECON: rbuf for psid %ld ru %d is head of list\n",
438 1.1 oster (long)rbuf->parityStripeID, rbuf->which_ru);
439 1.1 oster rbuf->next = reconCtrl->fullBufferList;
440 1.1 oster reconCtrl->fullBufferList = rbuf;
441 1.1 oster }
442 1.1 oster else {
443 1.1 oster for (pt = reconCtrl->fullBufferList, p = pt->next; p && p->failedDiskSectorOffset < rbuf->failedDiskSectorOffset; pt=p, p=p->next);
444 1.1 oster rbuf->next = p;
445 1.1 oster pt->next = rbuf;
446 1.1 oster Dprintf2("RECON: rbuf for psid %ld ru %d is in list\n",
447 1.1 oster (long)rbuf->parityStripeID, rbuf->which_ru);
448 1.1 oster }
449 1.1 oster #if 0
450 1.1 oster pssPtr->writeRbuf = pssPtr->rbuf; /* DEBUG ONLY: we like to be able to find this rbuf while it's awaiting write */
451 1.1 oster #else
452 1.1 oster rbuf->pssPtr = pssPtr;
453 1.1 oster #endif
454 1.1 oster pssPtr->rbuf = NULL;
455 1.1 oster rf_CauseReconEvent(raidPtr, rbuf->row, rbuf->col, NULL, RF_REVENT_BUFREADY);
456 1.1 oster }
457 1.1 oster return(0);
458 1.1 oster }
459 1.1 oster
460 1.1 oster
461 1.1 oster /* release a floating recon buffer for someone else to use.
462 1.1 oster * assumes the rb_mutex is LOCKED at entry
463 1.1 oster */
464 1.1 oster void rf_ReleaseFloatingReconBuffer(raidPtr, row, rbuf)
465 1.1 oster RF_Raid_t *raidPtr;
466 1.1 oster RF_RowCol_t row;
467 1.1 oster RF_ReconBuffer_t *rbuf;
468 1.1 oster {
469 1.1 oster RF_ReconCtrl_t *rcPtr = raidPtr->reconControl[row];
470 1.1 oster RF_CallbackDesc_t *cb;
471 1.1 oster
472 1.1 oster Dprintf2("RECON: releasing rbuf for psid %ld ru %d\n",
473 1.1 oster (long)rbuf->parityStripeID, rbuf->which_ru);
474 1.1 oster
475 1.1 oster /* if anyone is waiting on buffers, wake one of them up. They will subsequently wake up anyone
476 1.1 oster * else waiting on their RU
477 1.1 oster */
478 1.1 oster if (rcPtr->bufferWaitList) {
479 1.1 oster rbuf->next = rcPtr->committedRbufs;
480 1.1 oster rcPtr->committedRbufs = rbuf;
481 1.1 oster cb = rcPtr->bufferWaitList;
482 1.1 oster rcPtr->bufferWaitList = cb->next;
483 1.1 oster rf_CauseReconEvent(raidPtr, cb->row, cb->col, (void *) 1, RF_REVENT_BUFCLEAR); /* arg==1 => we've committed a buffer */
484 1.1 oster rf_FreeCallbackDesc(cb);
485 1.1 oster raidPtr->procsInBufWait--;
486 1.1 oster } else {
487 1.1 oster rbuf->next = rcPtr->floatingRbufs;
488 1.1 oster rcPtr->floatingRbufs = rbuf;
489 1.1 oster }
490 1.1 oster }
491 1.1 oster
492 1.1 oster /* release any disk that is waiting on a buffer for the indicated RU.
493 1.1 oster * assumes the rb_mutex is LOCKED at entry
494 1.1 oster */
495 1.1 oster void rf_ReleaseBufferWaiters(raidPtr, pssPtr)
496 1.1 oster RF_Raid_t *raidPtr;
497 1.1 oster RF_ReconParityStripeStatus_t *pssPtr;
498 1.1 oster {
499 1.1 oster RF_CallbackDesc_t *cb1, *cb = pssPtr->bufWaitList;
500 1.1 oster
501 1.1 oster Dprintf2("RECON: releasing buf waiters for psid %ld ru %d\n",
502 1.1 oster (long)pssPtr->parityStripeID, pssPtr->which_ru);
503 1.1 oster pssPtr->flags &= ~RF_PSS_BUFFERWAIT;
504 1.1 oster while (cb) {
505 1.1 oster cb1 = cb->next;
506 1.1 oster cb->next = NULL;
507 1.1 oster rf_CauseReconEvent(raidPtr, cb->row, cb->col, (void *) 0, RF_REVENT_BUFCLEAR); /* arg==0 => we haven't committed a buffer */
508 1.1 oster rf_FreeCallbackDesc(cb);
509 1.1 oster cb = cb1;
510 1.1 oster }
511 1.1 oster pssPtr->bufWaitList = NULL;
512 1.1 oster }
513 1.1 oster
514 1.1 oster /* when reconstruction is forced on an RU, there may be some disks waiting to
515 1.1 oster * acquire a buffer for that RU. Since we allocate a new buffer as part of
516 1.1 oster * the forced-reconstruction process, we no longer have to wait for any
517 1.1 oster * buffers, so we wakeup any waiter that we find in the bufferWaitList
518 1.1 oster *
519 1.1 oster * assumes the rb_mutex is LOCKED at entry
520 1.1 oster */
521 1.1 oster void rf_ReleaseBufferWaiter(rcPtr, rbuf)
522 1.1 oster RF_ReconCtrl_t *rcPtr;
523 1.1 oster RF_ReconBuffer_t *rbuf;
524 1.1 oster {
525 1.1 oster RF_CallbackDesc_t *cb, *cbt;
526 1.1 oster
527 1.1 oster for (cbt = NULL, cb = rcPtr->bufferWaitList; cb; cbt = cb, cb=cb->next) {
528 1.1 oster if ( (cb->callbackArg.v == rbuf->parityStripeID) && ( cb->callbackArg2.v == rbuf->which_ru)) {
529 1.1 oster Dprintf2("RECON: Dropping row %d col %d from buffer wait list\n", cb->row, cb->col);
530 1.1 oster if (cbt) cbt->next = cb->next;
531 1.1 oster else rcPtr->bufferWaitList = cb->next;
532 1.1 oster rf_CauseReconEvent((RF_Raid_t *) rbuf->raidPtr, cb->row, cb->col, (void *) 0, RF_REVENT_BUFREADY); /* arg==0 => no committed buffer */
533 1.1 oster rf_FreeCallbackDesc(cb);
534 1.1 oster return;
535 1.1 oster }
536 1.1 oster }
537 1.1 oster }
538