rf_reconmap.c revision 1.3 1 /* $NetBSD: rf_reconmap.c,v 1.3 1999/01/26 04:40:03 oster 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 (at) 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_reconmap.c
31 *
32 * code to maintain a map of what sectors have/have not been reconstructed
33 *
34 *************************************************************************/
35
36 #include "rf_raid.h"
37 #include <sys/time.h>
38 #include "rf_general.h"
39 #include "rf_utils.h"
40 #include "rf_sys.h"
41
42 /* special pointer values indicating that a reconstruction unit
43 * has been either totally reconstructed or not at all. Both
44 * are illegal pointer values, so you have to be careful not to
45 * dereference through them. RU_NOTHING must be zero, since
46 * MakeReconMap uses bzero to initialize the structure. These are used
47 * only at the head of the list.
48 */
49 #define RU_ALL ((RF_ReconMapListElem_t *) -1)
50 #define RU_NOTHING ((RF_ReconMapListElem_t *) 0)
51
52 /* used to mark the end of the list */
53 #define RU_NIL ((RF_ReconMapListElem_t *) 0)
54
55
56 static void compact_stat_entry(RF_Raid_t *raidPtr, RF_ReconMap_t *mapPtr,
57 int i);
58 static void crunch_list(RF_ReconMap_t *mapPtr, RF_ReconMapListElem_t *listPtr);
59 static RF_ReconMapListElem_t *MakeReconMapListElem(RF_SectorNum_t startSector,
60 RF_SectorNum_t stopSector, RF_ReconMapListElem_t *next);
61 static void FreeReconMapListElem(RF_ReconMap_t *mapPtr,
62 RF_ReconMapListElem_t *p);
63 static void update_size(RF_ReconMap_t *mapPtr, int size);
64 static void PrintList(RF_ReconMapListElem_t *listPtr);
65
66 /*-----------------------------------------------------------------------------
67 *
68 * Creates and initializes new Reconstruction map
69 *
70 *-----------------------------------------------------------------------------*/
71
72 RF_ReconMap_t *rf_MakeReconMap(raidPtr, ru_sectors, disk_sectors, spareUnitsPerDisk)
73 RF_Raid_t *raidPtr;
74 RF_SectorCount_t ru_sectors; /* size of reconstruction unit in sectors */
75 RF_SectorCount_t disk_sectors; /* size of disk in sectors */
76 RF_ReconUnitCount_t spareUnitsPerDisk; /* zero unless distributed sparing */
77 {
78 RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
79 RF_ReconUnitCount_t num_rus = layoutPtr->stripeUnitsPerDisk / layoutPtr->SUsPerRU;
80 RF_ReconMap_t *p;
81 int rc;
82
83 RF_Malloc(p, sizeof(RF_ReconMap_t), (RF_ReconMap_t *));
84 p->sectorsPerReconUnit = ru_sectors;
85 p->sectorsInDisk = disk_sectors;
86
87 p->totalRUs = num_rus;
88 p->spareRUs = spareUnitsPerDisk;
89 p->unitsLeft = num_rus - spareUnitsPerDisk;
90
91 RF_Malloc(p->status, num_rus * sizeof(RF_ReconMapListElem_t *), (RF_ReconMapListElem_t **));
92 RF_ASSERT(p->status != (RF_ReconMapListElem_t **) NULL);
93
94 (void) bzero((char *) p->status, num_rus * sizeof(RF_ReconMapListElem_t *));
95
96 p->size = sizeof(RF_ReconMap_t) + num_rus * sizeof(RF_ReconMapListElem_t *);
97 p->maxSize = p->size;
98
99 rc = rf_mutex_init(&p->mutex);
100 if (rc) {
101 RF_ERRORMSG3("Unable to init mutex file %s line %d rc=%d\n", __FILE__,
102 __LINE__, rc);
103 RF_Free(p->status, num_rus * sizeof(RF_ReconMapListElem_t *));
104 RF_Free(p, sizeof(RF_ReconMap_t));
105 return(NULL);
106 }
107 return(p);
108 }
109
110
111 /*-----------------------------------------------------------------------------
112 *
113 * marks a new set of sectors as reconstructed. All the possible mergings get
114 * complicated. To simplify matters, the approach I take is to just dump
115 * something into the list, and then clean it up (i.e. merge elements and
116 * eliminate redundant ones) in a second pass over the list (compact_stat_entry()).
117 * Not 100% efficient, since a structure can be allocated and then immediately
118 * freed, but it keeps this code from becoming (more of) a nightmare of
119 * special cases. The only thing that compact_stat_entry() assumes is that the
120 * list is sorted by startSector, and so this is the only condition I maintain
121 * here. (MCH)
122 *
123 *-----------------------------------------------------------------------------*/
124
125 void rf_ReconMapUpdate(raidPtr, mapPtr, startSector, stopSector)
126 RF_Raid_t *raidPtr;
127 RF_ReconMap_t *mapPtr;
128 RF_SectorNum_t startSector;
129 RF_SectorNum_t stopSector;
130 {
131 RF_SectorCount_t sectorsPerReconUnit = mapPtr->sectorsPerReconUnit;
132 RF_SectorNum_t i, first_in_RU, last_in_RU;
133 RF_ReconMapListElem_t *p, *pt;
134
135 RF_LOCK_MUTEX(mapPtr->mutex);
136 RF_ASSERT(startSector >=0 && stopSector < mapPtr->sectorsInDisk && stopSector > startSector);
137
138 while (startSector <= stopSector) {
139 i = startSector/mapPtr->sectorsPerReconUnit;
140 first_in_RU = i*sectorsPerReconUnit;
141 last_in_RU = first_in_RU + sectorsPerReconUnit -1 ;
142 p = mapPtr->status[i];
143 if (p!=RU_ALL) {
144 if (p==RU_NOTHING || p->startSector > startSector ) { /* insert at front of list */
145
146 mapPtr->status[i] = MakeReconMapListElem(startSector, RF_MIN(stopSector,last_in_RU), (p==RU_NOTHING) ? NULL : p);
147 update_size(mapPtr, sizeof(RF_ReconMapListElem_t));
148
149 } else { /* general case */
150 do { /* search for place to insert */
151 pt = p; p = p->next;
152 } while (p && (p->startSector < startSector));
153 pt->next = MakeReconMapListElem(startSector,RF_MIN(stopSector,last_in_RU),p);
154 update_size(mapPtr, sizeof(RF_ReconMapListElem_t));
155 }
156 compact_stat_entry(raidPtr, mapPtr, i);
157 }
158 startSector = RF_MIN(stopSector, last_in_RU) +1;
159 }
160 RF_UNLOCK_MUTEX(mapPtr->mutex);
161 }
162
163
164
165 /*-----------------------------------------------------------------------------
166 *
167 * performs whatever list compactions can be done, and frees any space
168 * that is no longer necessary. Assumes only that the list is sorted
169 * by startSector. crunch_list() compacts a single list as much as possible,
170 * and the second block of code deletes the entire list if possible.
171 * crunch_list() is also called from MakeReconMapAccessList().
172 *
173 * When a recon unit is detected to be fully reconstructed, we set the
174 * corresponding bit in the parity stripe map so that the head follow
175 * code will not select this parity stripe again. This is redundant (but
176 * harmless) when compact_stat_entry is called from the reconstruction code,
177 * but necessary when called from the user-write code.
178 *
179 *-----------------------------------------------------------------------------*/
180
181 static void compact_stat_entry(raidPtr, mapPtr, i)
182 RF_Raid_t *raidPtr;
183 RF_ReconMap_t *mapPtr;
184 int i;
185 {
186 RF_SectorCount_t sectorsPerReconUnit = mapPtr->sectorsPerReconUnit;
187 RF_ReconMapListElem_t *p = mapPtr->status[i];
188
189 crunch_list(mapPtr, p);
190
191 if ((p->startSector == i*sectorsPerReconUnit) &&
192 (p->stopSector == i*sectorsPerReconUnit +sectorsPerReconUnit -1)) {
193 mapPtr->status[i] = RU_ALL;
194 mapPtr->unitsLeft--;
195 FreeReconMapListElem(mapPtr,p);
196 }
197 }
198
199 static void crunch_list(mapPtr, listPtr)
200 RF_ReconMap_t *mapPtr;
201 RF_ReconMapListElem_t *listPtr;
202 {
203 RF_ReconMapListElem_t *pt, *p = listPtr;
204
205 if (!p) return;
206 pt = p; p = p->next;
207 while (p) {
208 if (pt->stopSector >= p->startSector-1) {
209 pt->stopSector = RF_MAX(pt->stopSector, p->stopSector);
210 pt->next = p->next;
211 FreeReconMapListElem(mapPtr, p);
212 p = pt->next;
213 }
214 else {
215 pt = p;
216 p = p->next;
217 }
218 }
219 }
220
221 /*-----------------------------------------------------------------------------
222 *
223 * Allocate and fill a new list element
224 *
225 *-----------------------------------------------------------------------------*/
226
227 static RF_ReconMapListElem_t *MakeReconMapListElem(
228 RF_SectorNum_t startSector,
229 RF_SectorNum_t stopSector,
230 RF_ReconMapListElem_t *next)
231 {
232 RF_ReconMapListElem_t *p;
233
234 RF_Malloc(p, sizeof(RF_ReconMapListElem_t), (RF_ReconMapListElem_t *));
235 if (p == NULL)
236 return(NULL);
237 p->startSector = startSector;
238 p->stopSector = stopSector;
239 p->next = next;
240 return(p);
241 }
242
243 /*-----------------------------------------------------------------------------
244 *
245 * Free a list element
246 *
247 *-----------------------------------------------------------------------------*/
248
249 static void FreeReconMapListElem(mapPtr,p)
250 RF_ReconMap_t *mapPtr;
251 RF_ReconMapListElem_t *p;
252 {
253 int delta;
254
255 if (mapPtr) {
256 delta = 0 - (int)sizeof(RF_ReconMapListElem_t);
257 update_size(mapPtr, delta);
258 }
259 RF_Free(p, sizeof(*p));
260 }
261
262 /*-----------------------------------------------------------------------------
263 *
264 * Free an entire status structure. Inefficient, but can be called at any time.
265 *
266 *-----------------------------------------------------------------------------*/
267 void rf_FreeReconMap(mapPtr)
268 RF_ReconMap_t *mapPtr;
269 {
270 RF_ReconMapListElem_t *p, *q;
271 RF_ReconUnitCount_t numRUs;
272 RF_ReconUnitNum_t i;
273
274 numRUs = mapPtr->sectorsInDisk / mapPtr->sectorsPerReconUnit;
275 if (mapPtr->sectorsInDisk % mapPtr->sectorsPerReconUnit)
276 numRUs++;
277
278 for (i=0; i<numRUs; i++) {
279 p = mapPtr->status[i];
280 while (p != RU_NOTHING && p != RU_ALL) {
281 q = p; p = p->next;
282 RF_Free(q, sizeof(*q));
283 }
284 }
285 rf_mutex_destroy(&mapPtr->mutex);
286 RF_Free(mapPtr->status, mapPtr->totalRUs * sizeof(RF_ReconMapListElem_t *));
287 RF_Free(mapPtr, sizeof(RF_ReconMap_t));
288 }
289
290 /*-----------------------------------------------------------------------------
291 *
292 * returns nonzero if the indicated RU has been reconstructed already
293 *
294 *---------------------------------------------------------------------------*/
295
296 int rf_CheckRUReconstructed(mapPtr, startSector)
297 RF_ReconMap_t *mapPtr;
298 RF_SectorNum_t startSector;
299 {
300 RF_ReconMapListElem_t *l; /* used for searching */
301 RF_ReconUnitNum_t i;
302
303 i = startSector / mapPtr->sectorsPerReconUnit;
304 l = mapPtr->status[i];
305 return( (l == RU_ALL) ? 1 : 0 );
306 }
307
308 RF_ReconUnitCount_t rf_UnitsLeftToReconstruct(mapPtr)
309 RF_ReconMap_t *mapPtr;
310 {
311 RF_ASSERT(mapPtr != NULL);
312 return( mapPtr->unitsLeft );
313 }
314
315 /* updates the size fields of a status descriptor */
316 static void update_size(mapPtr, size)
317 RF_ReconMap_t *mapPtr;
318 int size;
319 {
320 mapPtr->size += size;
321 mapPtr->maxSize = RF_MAX(mapPtr->size, mapPtr->maxSize);
322 }
323
324 static void PrintList(listPtr)
325 RF_ReconMapListElem_t *listPtr;
326 {
327 while (listPtr) {
328 printf("%d,%d -> ",(int)listPtr->startSector,(int)listPtr->stopSector);
329 listPtr = listPtr->next;
330 }
331 printf("\n");
332 }
333
334 void rf_PrintReconMap(raidPtr, mapPtr, frow, fcol)
335 RF_Raid_t *raidPtr;
336 RF_ReconMap_t *mapPtr;
337 RF_RowCol_t frow;
338 RF_RowCol_t fcol;
339 {
340 RF_ReconUnitCount_t numRUs;
341 RF_ReconMapListElem_t *p;
342 RF_ReconUnitNum_t i;
343
344 numRUs = mapPtr->totalRUs;
345 if (mapPtr->sectorsInDisk % mapPtr->sectorsPerReconUnit)
346 numRUs++;
347
348 for (i=0; i<numRUs; i++) {
349 p = mapPtr->status[i];
350 if (p==RU_ALL) /*printf("[%d] ALL\n",i)*/;
351 else if (p == RU_NOTHING) {
352 printf("%d: Unreconstructed\n",i);
353 } else {
354 printf("%d: ", i);
355 PrintList(p);
356 }
357 }
358 }
359
360 void rf_PrintReconSchedule(mapPtr, starttime)
361 RF_ReconMap_t *mapPtr;
362 struct timeval *starttime;
363 {
364 static int old_pctg = -1;
365 struct timeval tv, diff;
366 int new_pctg;
367
368 new_pctg = 100 - (rf_UnitsLeftToReconstruct(mapPtr) * 100 / mapPtr->totalRUs);
369 if (new_pctg != old_pctg) {
370 RF_GETTIME(tv);
371 RF_TIMEVAL_DIFF(starttime, &tv, &diff);
372 printf("%d %d.%06d\n",(int)new_pctg, (int)diff.tv_sec, (int)diff.tv_usec);
373 old_pctg = new_pctg;
374 }
375 }
376