1 | /* $NetBSD: rf_reconutil.c,v 1.35 2013/09/15 12:48:58 martin 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 | * rf_reconutil.c -- reconstruction utilities |
31 | ********************************************/ |
32 | |
33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: rf_reconutil.c,v 1.35 2013/09/15 12:48:58 martin Exp $" ); |
35 | |
36 | #include <dev/raidframe/raidframevar.h> |
37 | |
38 | #include "rf_raid.h" |
39 | #include "rf_desc.h" |
40 | #include "rf_reconutil.h" |
41 | #include "rf_reconbuffer.h" |
42 | #include "rf_general.h" |
43 | #include "rf_decluster.h" |
44 | #include "rf_raid5_rotatedspare.h" |
45 | #include "rf_interdecluster.h" |
46 | #include "rf_chaindecluster.h" |
47 | |
48 | /******************************************************************* |
49 | * allocates/frees the reconstruction control information structures |
50 | *******************************************************************/ |
51 | |
52 | /* fcol - failed column |
53 | * scol - identifies which spare we are using |
54 | */ |
55 | |
56 | RF_ReconCtrl_t * |
57 | rf_MakeReconControl(RF_RaidReconDesc_t *reconDesc, |
58 | RF_RowCol_t fcol, RF_RowCol_t scol) |
59 | { |
60 | RF_Raid_t *raidPtr = reconDesc->raidPtr; |
61 | RF_RaidLayout_t *layoutPtr = &raidPtr->Layout; |
62 | RF_ReconUnitCount_t RUsPerPU = layoutPtr->SUsPerPU / layoutPtr->SUsPerRU; |
63 | RF_ReconUnitCount_t numSpareRUs; |
64 | RF_ReconCtrl_t *reconCtrlPtr; |
65 | RF_ReconBuffer_t *rbuf; |
66 | const RF_LayoutSW_t *lp; |
67 | #if (RF_INCLUDE_PARITY_DECLUSTERING_DS > 0) |
68 | int retcode; |
69 | #endif |
70 | RF_RowCol_t i; |
71 | |
72 | lp = raidPtr->Layout.map; |
73 | |
74 | /* make and zero the global reconstruction structure and the per-disk |
75 | * structure */ |
76 | RF_Malloc(reconCtrlPtr, sizeof(RF_ReconCtrl_t), (RF_ReconCtrl_t *)); |
77 | |
78 | /* note: this zeros the perDiskInfo */ |
79 | RF_Malloc(reconCtrlPtr->perDiskInfo, raidPtr->numCol * |
80 | sizeof(RF_PerDiskReconCtrl_t), (RF_PerDiskReconCtrl_t *)); |
81 | reconCtrlPtr->reconDesc = reconDesc; |
82 | reconCtrlPtr->fcol = fcol; |
83 | reconCtrlPtr->spareCol = scol; |
84 | reconCtrlPtr->lastPSID = layoutPtr->numStripe / layoutPtr->SUsPerPU; |
85 | reconCtrlPtr->percentComplete = 0; |
86 | reconCtrlPtr->error = 0; |
87 | reconCtrlPtr->pending_writes = 0; |
88 | |
89 | /* initialize each per-disk recon information structure */ |
90 | for (i = 0; i < raidPtr->numCol; i++) { |
91 | reconCtrlPtr->perDiskInfo[i].reconCtrl = reconCtrlPtr; |
92 | reconCtrlPtr->perDiskInfo[i].col = i; |
93 | /* make it appear as if we just finished an RU */ |
94 | reconCtrlPtr->perDiskInfo[i].curPSID = -1; |
95 | reconCtrlPtr->perDiskInfo[i].ru_count = RUsPerPU - 1; |
96 | } |
97 | |
98 | /* Get the number of spare units per disk and the sparemap in case |
99 | * spare is distributed */ |
100 | |
101 | if (lp->GetNumSpareRUs) { |
102 | numSpareRUs = lp->GetNumSpareRUs(raidPtr); |
103 | } else { |
104 | numSpareRUs = 0; |
105 | } |
106 | |
107 | #if (RF_INCLUDE_PARITY_DECLUSTERING_DS > 0) |
108 | /* |
109 | * Not all distributed sparing archs need dynamic mappings |
110 | */ |
111 | if (lp->InstallSpareTable) { |
112 | retcode = rf_InstallSpareTable(raidPtr, 0, fcol); |
113 | if (retcode) { |
114 | RF_PANIC(); /* XXX fix this */ |
115 | } |
116 | } |
117 | #endif |
118 | /* make the reconstruction map */ |
119 | reconCtrlPtr->reconMap = rf_MakeReconMap(raidPtr, (int) (layoutPtr->SUsPerRU * layoutPtr->sectorsPerStripeUnit), |
120 | raidPtr->sectorsPerDisk, numSpareRUs); |
121 | |
122 | /* make the per-disk reconstruction buffers */ |
123 | for (i = 0; i < raidPtr->numCol; i++) { |
124 | reconCtrlPtr->perDiskInfo[i].rbuf = (i == fcol) ? NULL : rf_MakeReconBuffer(raidPtr, i, RF_RBUF_TYPE_EXCLUSIVE); |
125 | } |
126 | |
127 | /* initialize the event queue */ |
128 | rf_init_mutex2(reconCtrlPtr->eq_mutex, IPL_VM); |
129 | rf_init_cond2(reconCtrlPtr->eq_cv, "rfevq" ); |
130 | |
131 | reconCtrlPtr->eventQueue = NULL; |
132 | reconCtrlPtr->eq_count = 0; |
133 | |
134 | /* make the floating recon buffers and append them to the free list */ |
135 | rf_init_mutex2(reconCtrlPtr->rb_mutex, IPL_VM); |
136 | rf_init_cond2(reconCtrlPtr->rb_cv, "rfrcw" ); |
137 | |
138 | reconCtrlPtr->fullBufferList = NULL; |
139 | reconCtrlPtr->floatingRbufs = NULL; |
140 | reconCtrlPtr->committedRbufs = NULL; |
141 | for (i = 0; i < raidPtr->numFloatingReconBufs; i++) { |
142 | rbuf = rf_MakeReconBuffer(raidPtr, fcol, |
143 | RF_RBUF_TYPE_FLOATING); |
144 | rbuf->next = reconCtrlPtr->floatingRbufs; |
145 | reconCtrlPtr->floatingRbufs = rbuf; |
146 | } |
147 | |
148 | /* create the parity stripe status table */ |
149 | reconCtrlPtr->pssTable = rf_MakeParityStripeStatusTable(raidPtr); |
150 | |
151 | /* set the initial min head sep counter val */ |
152 | reconCtrlPtr->minHeadSepCounter = 0; |
153 | |
154 | return (reconCtrlPtr); |
155 | } |
156 | |
157 | void |
158 | rf_FreeReconControl(RF_Raid_t *raidPtr) |
159 | { |
160 | RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl; |
161 | RF_ReconBuffer_t *t; |
162 | RF_ReconUnitNum_t i; |
163 | |
164 | RF_ASSERT(reconCtrlPtr); |
165 | for (i = 0; i < raidPtr->numCol; i++) |
166 | if (reconCtrlPtr->perDiskInfo[i].rbuf) |
167 | rf_FreeReconBuffer(reconCtrlPtr->perDiskInfo[i].rbuf); |
168 | |
169 | t = reconCtrlPtr->floatingRbufs; |
170 | while (t) { |
171 | reconCtrlPtr->floatingRbufs = t->next; |
172 | rf_FreeReconBuffer(t); |
173 | t = reconCtrlPtr->floatingRbufs; |
174 | } |
175 | |
176 | rf_destroy_mutex2(reconCtrlPtr->eq_mutex); |
177 | rf_destroy_cond2(reconCtrlPtr->eq_cv); |
178 | |
179 | rf_destroy_mutex2(reconCtrlPtr->rb_mutex); |
180 | rf_destroy_cond2(reconCtrlPtr->rb_cv); |
181 | |
182 | rf_FreeReconMap(reconCtrlPtr->reconMap); |
183 | rf_FreeParityStripeStatusTable(raidPtr, reconCtrlPtr->pssTable); |
184 | RF_Free(reconCtrlPtr->perDiskInfo, |
185 | raidPtr->numCol * sizeof(RF_PerDiskReconCtrl_t)); |
186 | RF_Free(reconCtrlPtr, sizeof(*reconCtrlPtr)); |
187 | } |
188 | |
189 | |
190 | /****************************************************************************** |
191 | * computes the default head separation limit |
192 | *****************************************************************************/ |
193 | RF_HeadSepLimit_t |
194 | rf_GetDefaultHeadSepLimit(RF_Raid_t *raidPtr) |
195 | { |
196 | RF_HeadSepLimit_t hsl; |
197 | const RF_LayoutSW_t *lp; |
198 | |
199 | lp = raidPtr->Layout.map; |
200 | if (lp->GetDefaultHeadSepLimit == NULL) |
201 | return (-1); |
202 | hsl = lp->GetDefaultHeadSepLimit(raidPtr); |
203 | return (hsl); |
204 | } |
205 | |
206 | |
207 | /****************************************************************************** |
208 | * computes the default number of floating recon buffers |
209 | *****************************************************************************/ |
210 | int |
211 | rf_GetDefaultNumFloatingReconBuffers(RF_Raid_t *raidPtr) |
212 | { |
213 | const RF_LayoutSW_t *lp; |
214 | int nrb; |
215 | |
216 | lp = raidPtr->Layout.map; |
217 | if (lp->GetDefaultNumFloatingReconBuffers == NULL) |
218 | return (3 * raidPtr->numCol); |
219 | nrb = lp->GetDefaultNumFloatingReconBuffers(raidPtr); |
220 | return (nrb); |
221 | } |
222 | |
223 | |
224 | /****************************************************************************** |
225 | * creates and initializes a reconstruction buffer |
226 | *****************************************************************************/ |
227 | RF_ReconBuffer_t * |
228 | rf_MakeReconBuffer(RF_Raid_t *raidPtr, RF_RowCol_t col, RF_RbufType_t type) |
229 | { |
230 | RF_RaidLayout_t *layoutPtr = &raidPtr->Layout; |
231 | RF_ReconBuffer_t *t; |
232 | u_int recon_buffer_size = rf_RaidAddressToByte(raidPtr, layoutPtr->SUsPerRU * layoutPtr->sectorsPerStripeUnit); |
233 | |
234 | t = pool_get(&rf_pools.reconbuffer, PR_WAITOK); |
235 | RF_Malloc(t->buffer, recon_buffer_size, (void *)); |
236 | t->raidPtr = raidPtr; |
237 | t->col = col; |
238 | t->priority = RF_IO_RECON_PRIORITY; |
239 | t->type = type; |
240 | t->pssPtr = NULL; |
241 | t->next = NULL; |
242 | return (t); |
243 | } |
244 | /****************************************************************************** |
245 | * frees a reconstruction buffer |
246 | *****************************************************************************/ |
247 | void |
248 | rf_FreeReconBuffer(RF_ReconBuffer_t *rbuf) |
249 | { |
250 | RF_Raid_t *raidPtr = rbuf->raidPtr; |
251 | u_int recon_buffer_size __unused; |
252 | |
253 | recon_buffer_size = rf_RaidAddressToByte(raidPtr, raidPtr->Layout.SUsPerRU * raidPtr->Layout.sectorsPerStripeUnit); |
254 | |
255 | RF_Free(rbuf->buffer, recon_buffer_size); |
256 | pool_put(&rf_pools.reconbuffer, rbuf); |
257 | } |
258 | |
259 | #if RF_DEBUG_RECON |
260 | XXXX IF you use this, you really want to fix the locking in here. |
261 | /****************************************************************************** |
262 | * debug only: sanity check the number of floating recon bufs in use |
263 | *****************************************************************************/ |
264 | void |
265 | rf_CheckFloatingRbufCount(RF_Raid_t *raidPtr, int dolock) |
266 | { |
267 | RF_ReconParityStripeStatus_t *p; |
268 | RF_PSStatusHeader_t *pssTable; |
269 | RF_ReconBuffer_t *rbuf; |
270 | int i, j, sum = 0; |
271 | |
272 | if (dolock) |
273 | rf_lock_mutex2(raidPtr->reconControl->rb_mutex); |
274 | pssTable = raidPtr->reconControl->pssTable; |
275 | |
276 | for (i = 0; i < raidPtr->pssTableSize; i++) { |
277 | rf_lock_mutex2(pssTable[i].mutex); |
278 | for (p = pssTable[i].chain; p; p = p->next) { |
279 | rbuf = (RF_ReconBuffer_t *) p->rbuf; |
280 | if (rbuf && rbuf->type == RF_RBUF_TYPE_FLOATING) |
281 | sum++; |
282 | |
283 | rbuf = (RF_ReconBuffer_t *) p->writeRbuf; |
284 | if (rbuf && rbuf->type == RF_RBUF_TYPE_FLOATING) |
285 | sum++; |
286 | |
287 | for (j = 0; j < p->xorBufCount; j++) { |
288 | rbuf = (RF_ReconBuffer_t *) p->rbufsForXor[j]; |
289 | RF_ASSERT(rbuf); |
290 | if (rbuf->type == RF_RBUF_TYPE_FLOATING) |
291 | sum++; |
292 | } |
293 | } |
294 | rf_unlock_mutex2(pssTable[i].mutex); |
295 | } |
296 | |
297 | for (rbuf = raidPtr->reconControl->floatingRbufs; rbuf; |
298 | rbuf = rbuf->next) { |
299 | if (rbuf->type == RF_RBUF_TYPE_FLOATING) |
300 | sum++; |
301 | } |
302 | for (rbuf = raidPtr->reconControl->committedRbufs; rbuf; |
303 | rbuf = rbuf->next) { |
304 | if (rbuf->type == RF_RBUF_TYPE_FLOATING) |
305 | sum++; |
306 | } |
307 | for (rbuf = raidPtr->reconControl->fullBufferList; rbuf; |
308 | rbuf = rbuf->next) { |
309 | if (rbuf->type == RF_RBUF_TYPE_FLOATING) |
310 | sum++; |
311 | } |
312 | RF_ASSERT(sum == raidPtr->numFloatingReconBufs); |
313 | |
314 | if (dolock) |
315 | rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); |
316 | } |
317 | #endif |
318 | |
319 | |