1 | /* $NetBSD: rf_psstatus.c,v 1.34 2011/05/03 08:18:43 mrg Exp $ */ |
2 | /* |
3 | * Copyright (c) 1995 Carnegie-Mellon University. |
4 | * All rights reserved. |
5 | * |
6 | * Author: Mark Holland |
7 | * |
8 | * Permission to use, copy, modify and distribute this software and |
9 | * its documentation is hereby granted, provided that both the copyright |
10 | * notice and this permission notice appear in all copies of the |
11 | * software, derivative works or modified versions, and any portions |
12 | * thereof, and that both notices appear in supporting documentation. |
13 | * |
14 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
15 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND |
16 | * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. |
17 | * |
18 | * Carnegie Mellon requests users of this software to return to |
19 | * |
20 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
21 | * School of Computer Science |
22 | * Carnegie Mellon University |
23 | * Pittsburgh PA 15213-3890 |
24 | * |
25 | * any improvements or extensions that they make and grant Carnegie the |
26 | * rights to redistribute these changes. |
27 | */ |
28 | |
29 | /***************************************************************************** |
30 | * |
31 | * psstatus.c |
32 | * |
33 | * The reconstruction code maintains a bunch of status related to the parity |
34 | * stripes that are currently under reconstruction. This header file defines |
35 | * the status structures. |
36 | * |
37 | *****************************************************************************/ |
38 | |
39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: rf_psstatus.c,v 1.34 2011/05/03 08:18:43 mrg Exp $" ); |
41 | |
42 | #include <dev/raidframe/raidframevar.h> |
43 | |
44 | #include "rf_raid.h" |
45 | #include "rf_general.h" |
46 | #include "rf_debugprint.h" |
47 | #include "rf_psstatus.h" |
48 | #include "rf_shutdown.h" |
49 | |
50 | #if RF_DEBUG_PSS |
51 | #define Dprintf1(s,a) if (rf_pssDebug) rf_debug_printf(s,(void *)((unsigned long)a),NULL,NULL,NULL,NULL,NULL,NULL,NULL) |
52 | #define Dprintf2(s,a,b) if (rf_pssDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),NULL,NULL,NULL,NULL,NULL,NULL) |
53 | #define Dprintf3(s,a,b,c) if (rf_pssDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),NULL,NULL,NULL,NULL,NULL) |
54 | #else |
55 | #define Dprintf1(s,a) |
56 | #define Dprintf2(s,a,b) |
57 | #define Dprintf3(s,a,b,c) |
58 | #endif |
59 | |
60 | static void |
61 | RealPrintPSStatusTable(RF_Raid_t * raidPtr, |
62 | RF_PSStatusHeader_t * pssTable); |
63 | |
64 | #define RF_MAX_FREE_PSS 32 |
65 | #define RF_MIN_FREE_PSS 8 |
66 | |
67 | static void rf_ShutdownPSStatus(void *); |
68 | |
69 | static void |
70 | rf_ShutdownPSStatus(void *arg) |
71 | { |
72 | |
73 | pool_destroy(&rf_pools.pss); |
74 | } |
75 | |
76 | int |
77 | rf_ConfigurePSStatus(RF_ShutdownList_t **listp) |
78 | { |
79 | |
80 | rf_pool_init(&rf_pools.pss, sizeof(RF_ReconParityStripeStatus_t), |
81 | "raidpsspl" , RF_MIN_FREE_PSS, RF_MAX_FREE_PSS); |
82 | rf_ShutdownCreate(listp, rf_ShutdownPSStatus, NULL); |
83 | |
84 | return (0); |
85 | } |
86 | |
87 | void |
88 | rf_InitPSStatus(RF_Raid_t *raidPtr) |
89 | { |
90 | raidPtr->pssTableSize = RF_PSS_DEFAULT_TABLESIZE; |
91 | } |
92 | |
93 | |
94 | /***************************************************************************************** |
95 | * sets up the pss table |
96 | * We pre-allocate a bunch of entries to avoid as much as possible having to |
97 | * malloc up hash chain entries. |
98 | ****************************************************************************************/ |
99 | RF_PSStatusHeader_t * |
100 | rf_MakeParityStripeStatusTable(RF_Raid_t *raidPtr) |
101 | { |
102 | RF_PSStatusHeader_t *pssTable; |
103 | int i; |
104 | |
105 | RF_Malloc(pssTable, |
106 | raidPtr->pssTableSize * sizeof(RF_PSStatusHeader_t), |
107 | (RF_PSStatusHeader_t *)); |
108 | for (i = 0; i < raidPtr->pssTableSize; i++) { |
109 | rf_init_mutex2(pssTable[i].mutex, IPL_VM); |
110 | rf_init_cond2(pssTable[i].cond, "rfpsslk" ); |
111 | } |
112 | return (pssTable); |
113 | } |
114 | |
115 | void |
116 | rf_FreeParityStripeStatusTable(RF_Raid_t *raidPtr, |
117 | RF_PSStatusHeader_t *pssTable) |
118 | { |
119 | int i; |
120 | |
121 | #if RF_DEBUG_PSS |
122 | if (rf_pssDebug) |
123 | RealPrintPSStatusTable(raidPtr, pssTable); |
124 | |
125 | for (i = 0; i < raidPtr->pssTableSize; i++) { |
126 | if (pssTable[i].chain) { |
127 | printf("ERROR: pss hash chain not null at recon shutdown\n" ); |
128 | } |
129 | } |
130 | #endif |
131 | for (i = 0; i < raidPtr->pssTableSize; i++) { |
132 | rf_destroy_mutex2(pssTable[i].mutex); |
133 | rf_destroy_cond2(pssTable[i].cond); |
134 | } |
135 | RF_Free(pssTable, raidPtr->pssTableSize * sizeof(RF_PSStatusHeader_t)); |
136 | } |
137 | |
138 | |
139 | /* looks up the status structure for a parity stripe. |
140 | * if the create_flag is on, uses (and returns) newpssPtr if |
141 | * a parity status structure doesn't exist |
142 | * otherwise returns NULL if the status structure does not exist |
143 | * |
144 | * ASSUMES THE PSS DESCRIPTOR IS LOCKED UPON ENTRY |
145 | * |
146 | * flags - whether or not to use newpssPtr if the needed PSS |
147 | * doesn't exist and what flags to set it to initially |
148 | */ |
149 | RF_ReconParityStripeStatus_t * |
150 | rf_LookupRUStatus(RF_Raid_t *raidPtr, RF_PSStatusHeader_t *pssTable, |
151 | RF_StripeNum_t psID, RF_ReconUnitNum_t which_ru, |
152 | RF_PSSFlags_t flags, RF_ReconParityStripeStatus_t *newpssPtr) |
153 | { |
154 | RF_PSStatusHeader_t *hdr = &pssTable[RF_HASH_PSID(raidPtr, psID)]; |
155 | RF_ReconParityStripeStatus_t *p, *pssPtr = hdr->chain; |
156 | |
157 | for (p = pssPtr; p; p = p->next) { |
158 | if (p->parityStripeID == psID && p->which_ru == which_ru) |
159 | break; |
160 | } |
161 | |
162 | if (!p && (flags & RF_PSS_CREATE)) { |
163 | p = newpssPtr; |
164 | p->next = hdr->chain; |
165 | hdr->chain = p; |
166 | |
167 | p->parityStripeID = psID; |
168 | p->which_ru = which_ru; |
169 | p->flags = flags; |
170 | p->rbuf = NULL; |
171 | p->writeRbuf = NULL; |
172 | p->xorBufCount = 0; |
173 | p->blockCount = 0; |
174 | p->procWaitList = NULL; |
175 | p->blockWaitList = NULL; |
176 | p->bufWaitList = NULL; |
177 | } else |
178 | if (p) { /* we didn't create, but we want to specify |
179 | * some new status */ |
180 | p->flags |= flags; /* add in whatever flags we're |
181 | * specifying */ |
182 | } |
183 | if (p && (flags & RF_PSS_RECON_BLOCKED)) { |
184 | p->blockCount++;/* if we're asking to block recon, bump the |
185 | * count */ |
186 | Dprintf3("raid%d: Blocked recon on psid %ld. count now %d\n" , |
187 | raidPtr->raidid, psID, p->blockCount); |
188 | } |
189 | return (p); |
190 | } |
191 | /* deletes an entry from the parity stripe status table. typically used |
192 | * when an entry has been allocated solely to block reconstruction, and |
193 | * no recon was requested while recon was blocked. Assumes the hash |
194 | * chain is ALREADY LOCKED. |
195 | */ |
196 | void |
197 | rf_PSStatusDelete(RF_Raid_t *raidPtr, RF_PSStatusHeader_t *pssTable, |
198 | RF_ReconParityStripeStatus_t *pssPtr) |
199 | { |
200 | RF_PSStatusHeader_t *hdr = &(pssTable[RF_HASH_PSID(raidPtr, pssPtr->parityStripeID)]); |
201 | RF_ReconParityStripeStatus_t *p = hdr->chain, *pt = NULL; |
202 | |
203 | while (p) { |
204 | if (p == pssPtr) { |
205 | if (pt) |
206 | pt->next = p->next; |
207 | else |
208 | hdr->chain = p->next; |
209 | p->next = NULL; |
210 | rf_FreePSStatus(raidPtr, p); |
211 | return; |
212 | } |
213 | pt = p; |
214 | p = p->next; |
215 | } |
216 | RF_ASSERT(0); /* we must find it here */ |
217 | } |
218 | /* deletes an entry from the ps status table after reconstruction has completed */ |
219 | void |
220 | rf_RemoveFromActiveReconTable(RF_Raid_t *raidPtr, RF_StripeNum_t psid, |
221 | RF_ReconUnitNum_t which_ru) |
222 | { |
223 | RF_PSStatusHeader_t *hdr = &(raidPtr->reconControl->pssTable[RF_HASH_PSID(raidPtr, psid)]); |
224 | RF_ReconParityStripeStatus_t *p, *pt; |
225 | RF_CallbackDesc_t *cb, *cb1; |
226 | |
227 | rf_lock_mutex2(hdr->mutex); |
228 | while(hdr->lock) { |
229 | rf_wait_cond2(hdr->cond, hdr->mutex); |
230 | } |
231 | hdr->lock = 1; |
232 | rf_unlock_mutex2(hdr->mutex); |
233 | for (pt = NULL, p = hdr->chain; p; pt = p, p = p->next) { |
234 | if ((p->parityStripeID == psid) && (p->which_ru == which_ru)) |
235 | break; |
236 | } |
237 | if (p == NULL) { |
238 | rf_PrintPSStatusTable(raidPtr); |
239 | } |
240 | RF_ASSERT(p); /* it must be there */ |
241 | |
242 | Dprintf2("PSS: deleting pss for psid %ld ru %d\n" , psid, which_ru); |
243 | |
244 | /* delete this entry from the hash chain */ |
245 | if (pt) |
246 | pt->next = p->next; |
247 | else |
248 | hdr->chain = p->next; |
249 | p->next = NULL; |
250 | |
251 | rf_lock_mutex2(hdr->mutex); |
252 | hdr->lock = 0; |
253 | rf_unlock_mutex2(hdr->mutex); |
254 | |
255 | /* wakup anyone waiting on the parity stripe ID */ |
256 | cb = p->procWaitList; |
257 | p->procWaitList = NULL; |
258 | while (cb) { |
259 | Dprintf1("Waking up access waiting on parity stripe ID %ld\n" , p->parityStripeID); |
260 | cb1 = cb->next; |
261 | (cb->callbackFunc) (cb->callbackArg); |
262 | rf_FreeCallbackDesc(cb); |
263 | cb = cb1; |
264 | } |
265 | |
266 | rf_FreePSStatus(raidPtr, p); |
267 | } |
268 | |
269 | RF_ReconParityStripeStatus_t * |
270 | rf_AllocPSStatus(RF_Raid_t *raidPtr) |
271 | { |
272 | RF_ReconParityStripeStatus_t *p; |
273 | |
274 | p = pool_get(&rf_pools.pss, PR_WAITOK); |
275 | memset(p, 0, sizeof(RF_ReconParityStripeStatus_t)); |
276 | return (p); |
277 | } |
278 | |
279 | void |
280 | rf_FreePSStatus(RF_Raid_t *raidPtr, RF_ReconParityStripeStatus_t *p) |
281 | { |
282 | RF_ASSERT(p->procWaitList == NULL); |
283 | RF_ASSERT(p->blockWaitList == NULL); |
284 | RF_ASSERT(p->bufWaitList == NULL); |
285 | |
286 | pool_put(&rf_pools.pss, p); |
287 | } |
288 | |
289 | static void |
290 | RealPrintPSStatusTable(RF_Raid_t *raidPtr, RF_PSStatusHeader_t *pssTable) |
291 | { |
292 | int i, j, procsWaiting, blocksWaiting, bufsWaiting; |
293 | RF_ReconParityStripeStatus_t *p; |
294 | RF_CallbackDesc_t *cb; |
295 | |
296 | printf("\nParity Stripe Status Table\n" ); |
297 | for (i = 0; i < raidPtr->pssTableSize; i++) { |
298 | for (p = pssTable[i].chain; p; p = p->next) { |
299 | procsWaiting = blocksWaiting = bufsWaiting = 0; |
300 | for (cb = p->procWaitList; cb; cb = cb->next) |
301 | procsWaiting++; |
302 | for (cb = p->blockWaitList; cb; cb = cb->next) |
303 | blocksWaiting++; |
304 | for (cb = p->bufWaitList; cb; cb = cb->next) |
305 | bufsWaiting++; |
306 | printf("PSID %ld RU %d : blockCount %d %d/%d/%d proc/block/buf waiting, issued " , |
307 | (long) p->parityStripeID, p->which_ru, p->blockCount, procsWaiting, blocksWaiting, bufsWaiting); |
308 | for (j = 0; j < raidPtr->numCol; j++) |
309 | printf("%c" , (p->issued[j]) ? '1' : '0'); |
310 | if (!p->flags) |
311 | printf(" flags: (none)" ); |
312 | else { |
313 | if (p->flags & RF_PSS_UNDER_RECON) |
314 | printf(" under-recon" ); |
315 | if (p->flags & RF_PSS_FORCED_ON_WRITE) |
316 | printf(" forced-w" ); |
317 | if (p->flags & RF_PSS_FORCED_ON_READ) |
318 | printf(" forced-r" ); |
319 | if (p->flags & RF_PSS_RECON_BLOCKED) |
320 | printf(" blocked" ); |
321 | if (p->flags & RF_PSS_BUFFERWAIT) |
322 | printf(" bufwait" ); |
323 | } |
324 | printf("\n" ); |
325 | } |
326 | } |
327 | } |
328 | |
329 | void |
330 | rf_PrintPSStatusTable(RF_Raid_t *raidPtr) |
331 | { |
332 | RF_PSStatusHeader_t *pssTable = raidPtr->reconControl->pssTable; |
333 | RealPrintPSStatusTable(raidPtr, pssTable); |
334 | } |
335 | |