rf_configure.c revision 1.10 1 /* $NetBSD: rf_configure.c,v 1.10 2000/05/23 01:03:05 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1995 Carnegie-Mellon University.
5 * All rights reserved.
6 *
7 * Author: Mark Holland
8 *
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
28 */
29
30 /***************************************************************
31 *
32 * rf_configure.c -- code related to configuring the raidframe system
33 *
34 * configuration is complicated by the fact that we want the same
35 * driver to work both in the kernel and at user level. In the
36 * kernel, we can't read the configuration file, so we configure
37 * by running a user-level program that reads the config file,
38 * creates a data structure describing the configuration and
39 * passes it into the kernel via an ioctl. Since we want the config
40 * code to be common between the two versions of the driver, we
41 * configure using the same two-step process when running at
42 * user level. Of course, at user level, the config structure is
43 * passed directly to the config routine, rather than via ioctl.
44 *
45 * This file is not compiled into the kernel, so we have no
46 * need for KERNEL ifdefs.
47 *
48 **************************************************************/
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <errno.h>
53 #include <strings.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include "rf_raid.h"
57 #include "rf_raidframe.h"
58 #include "rf_general.h"
59 #include "rf_decluster.h"
60 #include "rf_configure.h"
61
62 /*
63 * XXX we include this here so we don't need to drag rf_debugMem.c into
64 * the picture... This is userland, afterall...
65 */
66
67 /*
68 * XXX sucky hack to override the defn. of RF_Malloc as given in
69 * rf_debugMem.c... but I *really* don't want (nor need) to link with
70 * that file here in userland.. GO
71 */
72
73 #undef RF_Malloc
74 #define RF_Malloc(_p_, _size_, _cast_) \
75 { \
76 _p_ = _cast_ malloc((u_long)_size_); \
77 bzero((char *)_p_, _size_); \
78 }
79
80 char *rf_find_non_white(char *p);
81 char *rf_find_white(char *p);
82
83 static int rf_search_file_for_start_of(const char *string, char *buf,
84 int len, FILE * fp);
85 static int rf_get_next_nonblank_line(char *buf, int len, FILE * fp,
86 const char *errmsg);
87
88 /*
89 * called from user level to read the configuration file and create
90 * a configuration control structure. This is used in the user-level
91 * version of the driver, and in the user-level program that configures
92 * the system via ioctl.
93 */
94 int
95 rf_MakeConfig(configname, cfgPtr)
96 char *configname;
97 RF_Config_t *cfgPtr;
98 {
99 int numscanned, val, r, c, retcode, aa, bb, cc;
100 char buf[256], buf1[256], *cp;
101 RF_LayoutSW_t *lp;
102 FILE *fp;
103
104 bzero((char *) cfgPtr, sizeof(RF_Config_t));
105
106 fp = fopen(configname, "r");
107 if (!fp) {
108 RF_ERRORMSG1("Can't open config file %s\n", configname);
109 return (-1);
110 }
111 rewind(fp);
112 if (rf_search_file_for_start_of("array", buf, 256, fp)) {
113 RF_ERRORMSG1("Unable to find start of \"array\" params in config file %s\n", configname);
114 retcode = -1;
115 goto out;
116 }
117 rf_get_next_nonblank_line(buf, 256, fp, "Config file error (\"array\" section): unable to get numRow and numCol\n");
118
119 /*
120 * wackiness with aa, bb, cc to get around size problems on
121 * different platforms
122 */
123 numscanned = sscanf(buf, "%d %d %d", &aa, &bb, &cc);
124 if (numscanned != 3) {
125 RF_ERRORMSG("Config file error (\"array\" section): unable to get numRow, numCol, numSpare\n");
126 retcode = -1;
127 goto out;
128 }
129 cfgPtr->numRow = (RF_RowCol_t) aa;
130 cfgPtr->numCol = (RF_RowCol_t) bb;
131 cfgPtr->numSpare = (RF_RowCol_t) cc;
132
133 /* debug section is optional */
134 for (c = 0; c < RF_MAXDBGV; c++)
135 cfgPtr->debugVars[c][0] = '\0';
136 rewind(fp);
137 if (!rf_search_file_for_start_of("debug", buf, 256, fp)) {
138 for (c = 0; c < RF_MAXDBGV; c++) {
139 if (rf_get_next_nonblank_line(buf, 256, fp, NULL))
140 break;
141 cp = rf_find_non_white(buf);
142 if (!strncmp(cp, "START", strlen("START")))
143 break;
144 (void) strcpy(&cfgPtr->debugVars[c][0], cp);
145 }
146 }
147 rewind(fp);
148 strcpy(cfgPtr->diskQueueType, "fifo");
149 cfgPtr->maxOutstandingDiskReqs = 1;
150 /* scan the file for the block related to disk queues */
151 if (rf_search_file_for_start_of("queue", buf, 256, fp)) {
152 RF_ERRORMSG2("[No disk queue discipline specified in config file %s. Using %s.]\n", configname, cfgPtr->diskQueueType);
153 } else {
154 if (rf_get_next_nonblank_line(buf, 256, fp, NULL)) {
155 RF_ERRORMSG2("[No disk queue discipline specified in config file %s. Using %s.]\n", configname, cfgPtr->diskQueueType);
156 }
157 }
158
159 /* the queue specifier line contains two entries: 1st char of first
160 * word specifies queue to be used 2nd word specifies max num reqs
161 * that can be outstanding on the disk itself (typically 1) */
162 if (sscanf(buf, "%s %d", buf1, &val) != 2) {
163 RF_ERRORMSG1("Can't determine queue type and/or max outstanding reqs from line: %s", buf);
164 RF_ERRORMSG2("Using %s-%d\n", cfgPtr->diskQueueType, cfgPtr->maxOutstandingDiskReqs);
165 } else {
166 char *ch;
167 bcopy(buf1, cfgPtr->diskQueueType,
168 RF_MIN(sizeof(cfgPtr->diskQueueType), strlen(buf1) + 1));
169 for (ch = buf1; *ch; ch++) {
170 if (*ch == ' ') {
171 *ch = '\0';
172 break;
173 }
174 }
175 cfgPtr->maxOutstandingDiskReqs = val;
176 }
177
178 rewind(fp);
179
180 if (rf_search_file_for_start_of("disks", buf, 256, fp)) {
181 RF_ERRORMSG1("Can't find \"disks\" section in config file %s\n", configname);
182 retcode = -1;
183 goto out;
184 }
185 for (r = 0; r < cfgPtr->numRow; r++) {
186 for (c = 0; c < cfgPtr->numCol; c++) {
187 if (rf_get_next_nonblank_line(
188 &cfgPtr->devnames[r][c][0], 50, fp, NULL)) {
189 RF_ERRORMSG2("Config file error: unable to get device file for disk at row %d col %d\n", r, c);
190 retcode = -1;
191 goto out;
192 }
193 }
194 }
195
196 /* "spare" section is optional */
197 rewind(fp);
198 if (rf_search_file_for_start_of("spare", buf, 256, fp))
199 cfgPtr->numSpare = 0;
200 for (c = 0; c < cfgPtr->numSpare; c++) {
201 if (rf_get_next_nonblank_line(&cfgPtr->spare_names[c][0],
202 256, fp, NULL)) {
203 RF_ERRORMSG1("Config file error: unable to get device file for spare disk %d\n", c);
204 retcode = -1;
205 goto out;
206 }
207 }
208
209 /* scan the file for the block related to layout */
210 rewind(fp);
211 if (rf_search_file_for_start_of("layout", buf, 256, fp)) {
212 RF_ERRORMSG1("Can't find \"layout\" section in configuration file %s\n", configname);
213 retcode = -1;
214 goto out;
215 }
216 if (rf_get_next_nonblank_line(buf, 256, fp, NULL)) {
217 RF_ERRORMSG("Config file error (\"layout\" section): unable to find common layout param line\n");
218 retcode = -1;
219 goto out;
220 }
221 c = sscanf(buf, "%d %d %d %c", &aa, &bb, &cc, &cfgPtr->parityConfig);
222 cfgPtr->sectPerSU = (RF_SectorNum_t) aa;
223 cfgPtr->SUsPerPU = (RF_StripeNum_t) bb;
224 cfgPtr->SUsPerRU = (RF_StripeNum_t) cc;
225 if (c != 4) {
226 RF_ERRORMSG("Unable to scan common layout line\n");
227 retcode = -1;
228 goto out;
229 }
230 lp = rf_GetLayout(cfgPtr->parityConfig);
231 if (lp == NULL) {
232 RF_ERRORMSG1("Unknown parity config '%c'\n",
233 cfgPtr->parityConfig);
234 retcode = -1;
235 goto out;
236 }
237
238 /*
239 * XXX who cares.. it's not going into the kernel, so we should ignore
240 * this...
241 */
242 #ifndef _KERNEL
243 retcode = lp->MakeLayoutSpecific(fp, cfgPtr, lp->makeLayoutSpecificArg);
244 #endif
245 out:
246 fclose(fp);
247 if (retcode < 0)
248 retcode = errno = EINVAL;
249 else
250 errno = retcode;
251 return (retcode);
252 }
253
254
255 /* used in architectures such as RAID0 where there is no layout-specific
256 * information to be passed into the configuration code.
257 */
258 int
259 rf_MakeLayoutSpecificNULL(fp, cfgPtr, ignored)
260 FILE *fp;
261 RF_Config_t *cfgPtr;
262 void *ignored;
263 {
264 cfgPtr->layoutSpecificSize = 0;
265 cfgPtr->layoutSpecific = NULL;
266 return (0);
267 }
268
269 int
270 rf_MakeLayoutSpecificDeclustered(configfp, cfgPtr, arg)
271 FILE *configfp;
272 RF_Config_t *cfgPtr;
273 void *arg;
274 {
275 int b, v, k, r, lambda, norotate, i, val, distSpare;
276 char *cfgBuf, *bdfile, *p, *smname;
277 char buf[256], smbuf[256];
278 FILE *fp;
279
280 distSpare = *((int *) arg);
281
282 /* get the block design file name */
283 if (rf_get_next_nonblank_line(buf, 256, configfp,
284 "Can't find block design file name in config file\n"))
285 return (EINVAL);
286 bdfile = rf_find_non_white(buf);
287 if (bdfile[strlen(bdfile) - 1] == '\n') {
288 /* strip newline char */
289 bdfile[strlen(bdfile) - 1] = '\0';
290 }
291 /* open bd file, check validity of configuration */
292 if ((fp = fopen(bdfile, "r")) == NULL) {
293 RF_ERRORMSG1("RAID: config error: Can't open layout table file %s\n", bdfile);
294 return (EINVAL);
295 }
296 fgets(buf, 256, fp);
297 i = sscanf(buf, "%u %u %u %u %u %u", &b, &v, &k, &r, &lambda, &norotate);
298 if (i == 5)
299 norotate = 0; /* no-rotate flag is optional */
300 else if (i != 6) {
301 RF_ERRORMSG("Unable to parse header line in block design file\n");
302 return (EINVAL);
303 }
304 /* set the sparemap directory. In the in-kernel version, there's a
305 * daemon that's responsible for finding the sparemaps */
306 if (distSpare) {
307 if (rf_get_next_nonblank_line(smbuf, 256, configfp,
308 "Can't find sparemap file name in config file\n"))
309 return (EINVAL);
310 smname = rf_find_non_white(smbuf);
311 if (smname[strlen(smname) - 1] == '\n') {
312 /* strip newline char */
313 smname[strlen(smname) - 1] = '\0';
314 }
315 } else {
316 smbuf[0] = '\0';
317 smname = smbuf;
318 }
319
320 /* allocate a buffer to hold the configuration info */
321 cfgPtr->layoutSpecificSize = RF_SPAREMAP_NAME_LEN +
322 6 * sizeof(int) + b * k;
323 /* can't use RF_Malloc here b/c debugMem module not yet init'd */
324 cfgBuf = (char *) malloc(cfgPtr->layoutSpecificSize);
325 cfgPtr->layoutSpecific = (void *) cfgBuf;
326 p = cfgBuf;
327
328 /* install name of sparemap file */
329 for (i = 0; smname[i]; i++)
330 *p++ = smname[i];
331 /* pad with zeros */
332 while (i < RF_SPAREMAP_NAME_LEN) {
333 *p++ = '\0';
334 i++;
335 }
336
337 /*
338 * fill in the buffer with the block design parameters
339 * and then the block design itself
340 */
341 *((int *) p) = b;
342 p += sizeof(int);
343 *((int *) p) = v;
344 p += sizeof(int);
345 *((int *) p) = k;
346 p += sizeof(int);
347 *((int *) p) = r;
348 p += sizeof(int);
349 *((int *) p) = lambda;
350 p += sizeof(int);
351 *((int *) p) = norotate;
352 p += sizeof(int);
353
354 while (fscanf(fp, "%d", &val) == 1)
355 *p++ = (char) val;
356 fclose(fp);
357 if (p - cfgBuf != cfgPtr->layoutSpecificSize) {
358 RF_ERRORMSG2("Size mismatch creating layout specific data: is %d sb %d bytes\n", (int) (p - cfgBuf), (int) (6 * sizeof(int) + b * k));
359 return (EINVAL);
360 }
361 return (0);
362 }
363
364 /****************************************************************************
365 *
366 * utilities
367 *
368 ***************************************************************************/
369
370 /* finds a non-white character in the line */
371 char *
372 rf_find_non_white(char *p)
373 {
374 for (; *p != '\0' && (*p == ' ' || *p == '\t'); p++);
375 return (p);
376 }
377
378 /* finds a white character in the line */
379 char *
380 rf_find_white(char *p)
381 {
382 for (; *p != '\0' && (*p != ' ' && *p != '\t'); p++);
383 return (p);
384 }
385
386 /*
387 * searches a file for a line that says "START string", where string is
388 * specified as a parameter
389 */
390 static int
391 rf_search_file_for_start_of(string, buf, len, fp)
392 const char *string;
393 char *buf;
394 int len;
395 FILE *fp;
396 {
397 char *p;
398
399 while (1) {
400 if (fgets(buf, len, fp) == NULL)
401 return (-1);
402 p = rf_find_non_white(buf);
403 if (!strncmp(p, "START", strlen("START"))) {
404 p = rf_find_white(p);
405 p = rf_find_non_white(p);
406 if (!strncmp(p, string, strlen(string)))
407 return (0);
408 }
409 }
410 }
411
412 /* reads from file fp into buf until it finds an interesting line */
413 int
414 rf_get_next_nonblank_line(buf, len, fp, errmsg)
415 char *buf;
416 int len;
417 FILE *fp;
418 const char *errmsg;
419 {
420 char *p;
421
422 while (fgets(buf, 256, fp) != NULL) {
423 p = rf_find_non_white(buf);
424 if (*p == '\n' || *p == '\0' || *p == '#')
425 continue;
426 return (0);
427 }
428 if (errmsg)
429 RF_ERRORMSG(errmsg);
430 return (1);
431 }
432
433 /*
434 * Allocates an array for the spare table, and initializes it from a file.
435 * In the user-level version, this is called when recon is initiated.
436 * When/if I move recon into the kernel, there'll be a daemon that does
437 * an ioctl into raidframe which will block until a spare table is needed.
438 * When it returns, it will read a spare table from the file system,
439 * pass it into the kernel via a different ioctl, and then block again
440 * on the original ioctl.
441 *
442 * This is specific to the declustered layout, but doesn't belong in
443 * rf_decluster.c because it uses stuff that can't be compiled into
444 * the kernel, and it needs to be compiled into the user-level sparemap daemon.
445 *
446 */
447 void *
448 rf_ReadSpareTable(req, fname)
449 RF_SparetWait_t *req;
450 char *fname;
451 {
452 int i, j, numFound, linecount, tableNum, tupleNum,
453 spareDisk, spareBlkOffset;
454 char buf[1024], targString[100], errString[100];
455 RF_SpareTableEntry_t **table;
456 FILE *fp;
457
458 /* allocate and initialize the table */
459 RF_Malloc(table,
460 req->TablesPerSpareRegion * sizeof(RF_SpareTableEntry_t *),
461 (RF_SpareTableEntry_t **));
462 for (i = 0; i < req->TablesPerSpareRegion; i++) {
463 RF_Malloc(table[i],
464 req->BlocksPerTable * sizeof(RF_SpareTableEntry_t),
465 (RF_SpareTableEntry_t *));
466 for (j = 0; j < req->BlocksPerTable; j++)
467 table[i][j].spareDisk =
468 table[i][j].spareBlockOffsetInSUs = -1;
469 }
470
471 /* 2. open sparemap file, sanity check */
472 if ((fp = fopen(fname, "r")) == NULL) {
473 fprintf(stderr,
474 "rf_ReadSpareTable: Can't open sparemap file %s\n", fname);
475 return (NULL);
476 }
477 if (rf_get_next_nonblank_line(buf, 1024, fp,
478 "Invalid sparemap file: can't find header line\n"))
479 return (NULL);
480 if (buf[strlen(buf) - 1] == '\n')
481 buf[strlen(buf) - 1] = '\0';
482
483 sprintf(targString, "fdisk %d\n", req->fcol);
484 sprintf(errString,
485 "Invalid sparemap file: can't find \"fdisk %d\" line\n",
486 req->fcol);
487 while (1) {
488 rf_get_next_nonblank_line(buf, 1024, fp, errString);
489 if (!strncmp(buf, targString, strlen(targString)))
490 break;
491 }
492
493 /* no more blank lines or comments allowed now */
494 linecount = req->TablesPerSpareRegion * req->TableDepthInPUs;
495 for (i = 0; i < linecount; i++) {
496 numFound = fscanf(fp, " %d %d %d %d", &tableNum, &tupleNum,
497 &spareDisk, &spareBlkOffset);
498 if (numFound != 4) {
499 fprintf(stderr, "Sparemap file prematurely exhausted after %d of %d lines\n", i, linecount);
500 return (NULL);
501 }
502 RF_ASSERT(tableNum >= 0 &&
503 tableNum < req->TablesPerSpareRegion);
504 RF_ASSERT(tupleNum >= 0 && tupleNum < req->BlocksPerTable);
505 RF_ASSERT(spareDisk >= 0 && spareDisk < req->C);
506 RF_ASSERT(spareBlkOffset >= 0 && spareBlkOffset <
507 req->SpareSpaceDepthPerRegionInSUs / req->SUsPerPU);
508
509 table[tableNum][tupleNum].spareDisk = spareDisk;
510 table[tableNum][tupleNum].spareBlockOffsetInSUs =
511 spareBlkOffset * req->SUsPerPU;
512 }
513
514 fclose(fp);
515 return ((void *) table);
516 }
517