1*5c922bdbSkre /* $NetBSD: rf_configure.c,v 1.37 2022/07/21 09:19:53 kre Exp $ */
2340761f6Sthorpej
3f675e35dSoster /*
4f675e35dSoster * Copyright (c) 1995 Carnegie-Mellon University.
5f675e35dSoster * All rights reserved.
6f675e35dSoster *
7f675e35dSoster * Author: Mark Holland
8f675e35dSoster *
9f675e35dSoster * Permission to use, copy, modify and distribute this software and
10f675e35dSoster * its documentation is hereby granted, provided that both the copyright
11f675e35dSoster * notice and this permission notice appear in all copies of the
12f675e35dSoster * software, derivative works or modified versions, and any portions
13f675e35dSoster * thereof, and that both notices appear in supporting documentation.
14f675e35dSoster *
15f675e35dSoster * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16f675e35dSoster * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17f675e35dSoster * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18f675e35dSoster *
19f675e35dSoster * Carnegie Mellon requests users of this software to return to
20f675e35dSoster *
21f675e35dSoster * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22f675e35dSoster * School of Computer Science
23f675e35dSoster * Carnegie Mellon University
24f675e35dSoster * Pittsburgh PA 15213-3890
25f675e35dSoster *
26f675e35dSoster * any improvements or extensions that they make and grant Carnegie the
27f675e35dSoster * rights to redistribute these changes.
28f675e35dSoster */
29f675e35dSoster
30f675e35dSoster /***************************************************************
31f675e35dSoster *
32f675e35dSoster * rf_configure.c -- code related to configuring the raidframe system
33f675e35dSoster *
34f675e35dSoster * configuration is complicated by the fact that we want the same
35f675e35dSoster * driver to work both in the kernel and at user level. In the
36f675e35dSoster * kernel, we can't read the configuration file, so we configure
37f675e35dSoster * by running a user-level program that reads the config file,
38f675e35dSoster * creates a data structure describing the configuration and
39f675e35dSoster * passes it into the kernel via an ioctl. Since we want the config
40f675e35dSoster * code to be common between the two versions of the driver, we
41f675e35dSoster * configure using the same two-step process when running at
42f675e35dSoster * user level. Of course, at user level, the config structure is
43f675e35dSoster * passed directly to the config routine, rather than via ioctl.
44f675e35dSoster *
45f675e35dSoster * This file is not compiled into the kernel, so we have no
46f675e35dSoster * need for KERNEL ifdefs.
47f675e35dSoster *
48f675e35dSoster **************************************************************/
49c2a3b5ecSagc #include <sys/cdefs.h>
50c2a3b5ecSagc
51c2a3b5ecSagc #ifndef lint
52*5c922bdbSkre __RCSID("$NetBSD: rf_configure.c,v 1.37 2022/07/21 09:19:53 kre Exp $");
53c2a3b5ecSagc #endif
54c2a3b5ecSagc
55f675e35dSoster
56f675e35dSoster #include <stdio.h>
57543c143bSoster #include <stdlib.h>
5893bf4aaeSmjacob #include <errno.h>
59543c143bSoster #include <strings.h>
6013a59406Schristos #include <err.h>
61cb7aeb82Skardel #include <util.h>
62b958b2dcSkre #include <assert.h>
63f675e35dSoster #include <sys/types.h>
64f675e35dSoster #include <sys/stat.h>
65541d521aSoster
66541d521aSoster #include <dev/raidframe/raidframevar.h>
67541d521aSoster #include <dev/raidframe/raidframeio.h>
68f675e35dSoster #include "rf_configure.h"
69f675e35dSoster
706937a5d5Schristos static char *rf_find_non_white(char *, int);
716937a5d5Schristos static char *rf_find_white(char *);
726937a5d5Schristos static int rf_search_file_for_start_of(const char *, char *, int, FILE *);
736937a5d5Schristos static int rf_get_next_nonblank_line(char *, int, FILE *, const char *);
74541d521aSoster
756937a5d5Schristos #define RF_MIN(a,b) (((a) < (b)) ? (a) : (b))
766937a5d5Schristos
776937a5d5Schristos static int distSpareYes = 1;
786937a5d5Schristos static int distSpareNo = 0;
79705631a2Soster
8024b75d09Skre /*
8124b75d09Skre * The mapsw[] table below contains all the various RAID types that might
8224b75d09Skre * be supported by the kernel. The actual supported types are found
8324b75d09Skre * in sys/dev/raidframe/rf_layout.c.
8424b75d09Skre */
85705631a2Soster
866937a5d5Schristos static const RF_LayoutSW_t mapsw[] = {
87705631a2Soster /* parity declustering */
88705631a2Soster {'T', "Parity declustering",
89705631a2Soster rf_MakeLayoutSpecificDeclustered, &distSpareNo},
90705631a2Soster /* parity declustering with distributed sparing */
91705631a2Soster {'D', "Distributed sparing parity declustering",
92705631a2Soster rf_MakeLayoutSpecificDeclustered, &distSpareYes},
93705631a2Soster /* declustered P+Q */
94705631a2Soster {'Q', "Declustered P+Q",
95705631a2Soster rf_MakeLayoutSpecificDeclustered, &distSpareNo},
96705631a2Soster /* RAID 5 with rotated sparing */
97705631a2Soster {'R', "RAID Level 5 rotated sparing", rf_MakeLayoutSpecificNULL, NULL},
98705631a2Soster /* Chained Declustering */
99705631a2Soster {'C', "Chained Declustering", rf_MakeLayoutSpecificNULL, NULL},
100705631a2Soster /* Interleaved Declustering */
101705631a2Soster {'I', "Interleaved Declustering", rf_MakeLayoutSpecificNULL, NULL},
102705631a2Soster /* RAID level 0 */
103705631a2Soster {'0', "RAID Level 0", rf_MakeLayoutSpecificNULL, NULL},
104705631a2Soster /* RAID level 1 */
105705631a2Soster {'1', "RAID Level 1", rf_MakeLayoutSpecificNULL, NULL},
106705631a2Soster /* RAID level 4 */
107705631a2Soster {'4', "RAID Level 4", rf_MakeLayoutSpecificNULL, NULL},
108705631a2Soster /* RAID level 5 */
109705631a2Soster {'5', "RAID Level 5", rf_MakeLayoutSpecificNULL, NULL},
110705631a2Soster /* Evenodd */
111705631a2Soster {'E', "EvenOdd", rf_MakeLayoutSpecificNULL, NULL},
112705631a2Soster /* Declustered Evenodd */
113705631a2Soster {'e', "Declustered EvenOdd",
114705631a2Soster rf_MakeLayoutSpecificDeclustered, &distSpareNo},
115705631a2Soster /* parity logging */
116705631a2Soster {'L', "Parity logging", rf_MakeLayoutSpecificNULL, NULL},
117705631a2Soster /* end-of-list marker */
118705631a2Soster {'\0', NULL, NULL, NULL}
119705631a2Soster };
1206937a5d5Schristos
1216937a5d5Schristos static const RF_LayoutSW_t *
rf_GetLayout(RF_ParityConfig_t parityConfig)122705631a2Soster rf_GetLayout(RF_ParityConfig_t parityConfig)
123705631a2Soster {
1246937a5d5Schristos const RF_LayoutSW_t *p;
125705631a2Soster
126705631a2Soster /* look up the specific layout */
127705631a2Soster for (p = &mapsw[0]; p->parityConfig; p++)
128705631a2Soster if (p->parityConfig == parityConfig)
129705631a2Soster break;
130705631a2Soster if (!p->parityConfig)
1316937a5d5Schristos return NULL;
1326937a5d5Schristos return p;
133705631a2Soster }
134705631a2Soster
135340761f6Sthorpej /*
136340761f6Sthorpej * called from user level to read the configuration file and create
137f675e35dSoster * a configuration control structure. This is used in the user-level
138f675e35dSoster * version of the driver, and in the user-level program that configures
139f675e35dSoster * the system via ioctl.
140f675e35dSoster */
141340761f6Sthorpej int
rf_MakeConfig(char * configname,RF_Config_t * cfgPtr)142f0121f1fSxtraeme rf_MakeConfig(char *configname, RF_Config_t *cfgPtr)
143f675e35dSoster {
144f2b04ca0Smrg int numscanned, val, c, retcode, aa, bb, cc;
1456937a5d5Schristos char buf[BUFSIZ], buf1[BUFSIZ], *cp;
1466937a5d5Schristos const RF_LayoutSW_t *lp;
147f675e35dSoster FILE *fp;
148f675e35dSoster
1496937a5d5Schristos memset(cfgPtr, 0, sizeof(*cfgPtr));
150f675e35dSoster
151f675e35dSoster fp = fopen(configname, "r");
152f675e35dSoster if (!fp) {
1536937a5d5Schristos warnx("Can't open config file %s", configname);
1546937a5d5Schristos return -1;
155f675e35dSoster }
156f675e35dSoster rewind(fp);
1576937a5d5Schristos if (rf_search_file_for_start_of("array", buf, sizeof(buf), fp)) {
1586937a5d5Schristos warnx("Unable to find start of \"array\" params in config "
1596937a5d5Schristos "file %s", configname);
160340761f6Sthorpej retcode = -1;
161340761f6Sthorpej goto out;
162f675e35dSoster }
1636937a5d5Schristos rf_get_next_nonblank_line(buf, sizeof(buf), fp,
1646937a5d5Schristos "Config file error (\"array\" section): unable to get numRow "
1656937a5d5Schristos "and numCol");
166340761f6Sthorpej
167f675e35dSoster /*
168340761f6Sthorpej * wackiness with aa, bb, cc to get around size problems on
169340761f6Sthorpej * different platforms
170f675e35dSoster */
171f2b04ca0Smrg
172f2b04ca0Smrg /*
173f2b04ca0Smrg * Allow both "numCol numSpare" as well as old-style
174f2b04ca0Smrg * "numRow numCol numSpare".
175f2b04ca0Smrg * Note that numRow has always been ignored.
176f2b04ca0Smrg */
177f675e35dSoster numscanned = sscanf(buf, "%d %d %d", &aa, &bb, &cc);
178f675e35dSoster if (numscanned != 3) {
179f2b04ca0Smrg numscanned = sscanf(buf, "%d %d", &bb, &cc);
180f2b04ca0Smrg if (numscanned != 2) {
181f2b04ca0Smrg warnx("Config file error (\"array\" section): unable "
182f2b04ca0Smrg "to get numCol, numSpare");
183340761f6Sthorpej retcode = -1;
184340761f6Sthorpej goto out;
185f675e35dSoster }
186f2b04ca0Smrg }
187f675e35dSoster cfgPtr->numCol = (RF_RowCol_t) bb;
188f675e35dSoster cfgPtr->numSpare = (RF_RowCol_t) cc;
189f675e35dSoster
190f675e35dSoster /* debug section is optional */
191f675e35dSoster for (c = 0; c < RF_MAXDBGV; c++)
192f675e35dSoster cfgPtr->debugVars[c][0] = '\0';
193f675e35dSoster rewind(fp);
1946937a5d5Schristos if (!rf_search_file_for_start_of("debug", buf, sizeof(buf), fp)) {
195f675e35dSoster for (c = 0; c < RF_MAXDBGV; c++) {
1966937a5d5Schristos if (rf_get_next_nonblank_line(buf, sizeof(buf), fp,
1976937a5d5Schristos NULL))
198340761f6Sthorpej break;
1996937a5d5Schristos cp = rf_find_non_white(buf, 0);
2006937a5d5Schristos if (!strncmp(cp, "START", sizeof("START") - 1))
201340761f6Sthorpej break;
202dbab1374Schristos (void) strlcpy(cfgPtr->debugVars[c], cp,
2030b04aee3Sitojun sizeof(cfgPtr->debugVars[c]));
204f675e35dSoster }
205f675e35dSoster }
206f675e35dSoster rewind(fp);
2070b04aee3Sitojun strlcpy(cfgPtr->diskQueueType, "fifo", sizeof(cfgPtr->diskQueueType));
208f675e35dSoster cfgPtr->maxOutstandingDiskReqs = 1;
20924b75d09Skre
210f675e35dSoster /* scan the file for the block related to disk queues */
2116937a5d5Schristos if (rf_search_file_for_start_of("queue", buf, sizeof(buf), fp) ||
2126937a5d5Schristos rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) {
2136937a5d5Schristos warnx("[No disk queue discipline specified in config file %s. "
2146937a5d5Schristos "Using %s.]", configname, cfgPtr->diskQueueType);
215f675e35dSoster }
216b958b2dcSkre else {
217f675e35dSoster
21824b75d09Skre /*
21924b75d09Skre * the queue specifier line contains two entries: 1st char of first
220340761f6Sthorpej * word specifies queue to be used 2nd word specifies max num reqs
22124b75d09Skre * that can be outstanding on the disk itself (typically 1)
22224b75d09Skre */
223b958b2dcSkre assert(64 < sizeof buf1);
224b958b2dcSkre if (sscanf(buf, "%64s %d", buf1, &val) != 2 || strlen(buf1) >= 60) {
2256937a5d5Schristos warnx("Can't determine queue type and/or max outstanding "
226b958b2dcSkre "reqs from line: %.*s", (int)(sizeof(buf) - 1), buf);
2276937a5d5Schristos warnx("Using %s-%d", cfgPtr->diskQueueType,
2286937a5d5Schristos cfgPtr->maxOutstandingDiskReqs);
229f675e35dSoster } else {
230b958b2dcSkre #if 0
231a53c712bSthorpej char *ch;
232b958b2dcSkre #endif
2336937a5d5Schristos memcpy(cfgPtr->diskQueueType, buf1,
234340761f6Sthorpej RF_MIN(sizeof(cfgPtr->diskQueueType), strlen(buf1) + 1));
235b958b2dcSkre cfgPtr->diskQueueType[sizeof cfgPtr->diskQueueType - 1] = '\0';
236b958b2dcSkre
237b958b2dcSkre #if 0 /* this indicates a lack of understanding of how scanf() works */
238b958b2dcSkre /* it was also pointless as buf1 data was (b4) never used again */
239a53c712bSthorpej for (ch = buf1; *ch; ch++) {
240a53c712bSthorpej if (*ch == ' ') {
241a53c712bSthorpej *ch = '\0';
242f675e35dSoster break;
243f675e35dSoster }
244f675e35dSoster }
245b958b2dcSkre #endif
246f675e35dSoster cfgPtr->maxOutstandingDiskReqs = val;
247b958b2dcSkre if (cfgPtr->maxOutstandingDiskReqs != val) {
248b958b2dcSkre warnx("Queue length for %s out of range"
249b958b2dcSkre " [%d interp as %d], assuming 1",
250b958b2dcSkre buf1, val, cfgPtr->maxOutstandingDiskReqs);
251b958b2dcSkre cfgPtr->maxOutstandingDiskReqs = 1;
252b958b2dcSkre }
253b958b2dcSkre }
254f675e35dSoster }
255f675e35dSoster
256f675e35dSoster rewind(fp);
257f675e35dSoster
2586937a5d5Schristos if (rf_search_file_for_start_of("disks", buf, sizeof(buf), fp)) {
2596937a5d5Schristos warnx("Can't find \"disks\" section in config file %s",
2606937a5d5Schristos configname);
261340761f6Sthorpej retcode = -1;
262340761f6Sthorpej goto out;
263f675e35dSoster }
264f675e35dSoster for (c = 0; c < cfgPtr->numCol; c++) {
2656937a5d5Schristos char b1[MAXPATHLEN];
266cb7aeb82Skardel const char *b;
267cb7aeb82Skardel
268340761f6Sthorpej if (rf_get_next_nonblank_line(
269cb7aeb82Skardel buf, sizeof(buf), fp, NULL)) {
2705a1ff55aSkre warnx("Config file error: unable to find device "
2715a1ff55aSkre "file name for disk at col %d", c);
272340761f6Sthorpej retcode = -1;
273340761f6Sthorpej goto out;
274f675e35dSoster }
275cb7aeb82Skardel
276cb7aeb82Skardel b = getfsspecname(b1, sizeof(b1), buf);
277cb7aeb82Skardel if (b == NULL) {
2786937a5d5Schristos warnx("Config file error: warning: unable to "
2795a1ff55aSkre "get device file for disk at col %d: %s",
2805a1ff55aSkre c, b1);
281*5c922bdbSkre b = "absent";
282cb7aeb82Skardel }
283cb7aeb82Skardel
284f2b04ca0Smrg strlcpy(cfgPtr->devnames[0][c], b,
285f2b04ca0Smrg sizeof(cfgPtr->devnames[0][c]));
286f675e35dSoster }
287f675e35dSoster
288f675e35dSoster /* "spare" section is optional */
289f675e35dSoster rewind(fp);
2906937a5d5Schristos if (rf_search_file_for_start_of("spare", buf, sizeof(buf), fp))
291340761f6Sthorpej cfgPtr->numSpare = 0;
292f675e35dSoster for (c = 0; c < cfgPtr->numSpare; c++) {
2936937a5d5Schristos char b1[MAXPATHLEN];
294cb7aeb82Skardel const char *b;
295cb7aeb82Skardel
2966937a5d5Schristos if (rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) {
2976937a5d5Schristos warnx("Config file error: unable to get device file "
2986937a5d5Schristos "for spare disk %d", c);
299340761f6Sthorpej retcode = -1;
300340761f6Sthorpej goto out;
301f675e35dSoster }
302cb7aeb82Skardel
303cb7aeb82Skardel b = getfsspecname(b1, sizeof(b1), buf);
304cb7aeb82Skardel if (b == NULL) {
3056937a5d5Schristos warnx("Config file error: warning: unable to get "
30607b516d2Smrg "device file for spare disk %d: %s", c, buf);
307cb7aeb82Skardel b = buf;
308cb7aeb82Skardel }
309cb7aeb82Skardel
310f2b04ca0Smrg strlcpy(cfgPtr->spare_names[c], b,
311f2b04ca0Smrg sizeof(cfgPtr->spare_names[c]));
312f675e35dSoster }
313f675e35dSoster
314f675e35dSoster /* scan the file for the block related to layout */
315f675e35dSoster rewind(fp);
3166937a5d5Schristos if (rf_search_file_for_start_of("layout", buf, sizeof(buf), fp)) {
3176937a5d5Schristos warnx("Can't find \"layout\" section in configuration file %s",
3186937a5d5Schristos configname);
319340761f6Sthorpej retcode = -1;
320340761f6Sthorpej goto out;
321f675e35dSoster }
3226937a5d5Schristos if (rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) {
3236937a5d5Schristos warnx("Config file error (\"layout\" section): unable to find "
3246937a5d5Schristos "common layout param line");
325340761f6Sthorpej retcode = -1;
326340761f6Sthorpej goto out;
327f675e35dSoster }
328f675e35dSoster c = sscanf(buf, "%d %d %d %c", &aa, &bb, &cc, &cfgPtr->parityConfig);
329f675e35dSoster cfgPtr->sectPerSU = (RF_SectorNum_t) aa;
330f675e35dSoster cfgPtr->SUsPerPU = (RF_StripeNum_t) bb;
331f675e35dSoster cfgPtr->SUsPerRU = (RF_StripeNum_t) cc;
332f675e35dSoster if (c != 4) {
3336937a5d5Schristos warnx("Unable to scan common layout line");
334340761f6Sthorpej retcode = -1;
335340761f6Sthorpej goto out;
336f675e35dSoster }
337f675e35dSoster lp = rf_GetLayout(cfgPtr->parityConfig);
338f675e35dSoster if (lp == NULL) {
3396937a5d5Schristos warnx("Unknown parity config '%c'",
340340761f6Sthorpej cfgPtr->parityConfig);
341f675e35dSoster retcode = -1;
342f675e35dSoster goto out;
343f675e35dSoster }
344f675e35dSoster
3456937a5d5Schristos retcode = lp->MakeLayoutSpecific(fp, cfgPtr,
3466937a5d5Schristos lp->makeLayoutSpecificArg);
347f675e35dSoster out:
348f675e35dSoster fclose(fp);
349f675e35dSoster if (retcode < 0)
350f675e35dSoster retcode = errno = EINVAL;
351f675e35dSoster else
352f675e35dSoster errno = retcode;
3536937a5d5Schristos return retcode;
354f675e35dSoster }
355f675e35dSoster
356f675e35dSoster
35724b75d09Skre /*
35824b75d09Skre * used in architectures such as RAID0 where there is no layout-specific
359f675e35dSoster * information to be passed into the configuration code.
360f675e35dSoster */
361340761f6Sthorpej int
rf_MakeLayoutSpecificNULL(FILE * fp,RF_Config_t * cfgPtr,void * ignored)362f0121f1fSxtraeme rf_MakeLayoutSpecificNULL(FILE *fp, RF_Config_t *cfgPtr, void *ignored)
363f675e35dSoster {
364f675e35dSoster cfgPtr->layoutSpecificSize = 0;
365f675e35dSoster cfgPtr->layoutSpecific = NULL;
3666937a5d5Schristos return 0;
367f675e35dSoster }
368f675e35dSoster
369340761f6Sthorpej int
rf_MakeLayoutSpecificDeclustered(FILE * configfp,RF_Config_t * cfgPtr,void * arg)370f0121f1fSxtraeme rf_MakeLayoutSpecificDeclustered(FILE *configfp, RF_Config_t *cfgPtr, void *arg)
371f675e35dSoster {
372f675e35dSoster int b, v, k, r, lambda, norotate, i, val, distSpare;
373f675e35dSoster char *cfgBuf, *bdfile, *p, *smname;
3746937a5d5Schristos char buf[BUFSIZ], smbuf[BUFSIZ];
375f675e35dSoster FILE *fp;
376f675e35dSoster
377f675e35dSoster distSpare = *((int *) arg);
378f675e35dSoster
379f675e35dSoster /* get the block design file name */
3806937a5d5Schristos if (rf_get_next_nonblank_line(buf, sizeof(buf), configfp,
3816937a5d5Schristos "Can't find block design file name in config file"))
3826937a5d5Schristos return EINVAL;
3836937a5d5Schristos bdfile = rf_find_non_white(buf, 1);
384f675e35dSoster /* open bd file, check validity of configuration */
385f675e35dSoster if ((fp = fopen(bdfile, "r")) == NULL) {
3866937a5d5Schristos warn("RAID: config error: Can't open layout table file %s",
3876937a5d5Schristos bdfile);
3886937a5d5Schristos return EINVAL;
389f675e35dSoster }
3906937a5d5Schristos if (fgets(buf, sizeof(buf), fp) == NULL) {
3916937a5d5Schristos warnx("RAID: config error: Can't read layout from layout "
3926937a5d5Schristos "table file %s", bdfile);
3931fcee3dbSdan fclose(fp);
3946937a5d5Schristos return EINVAL;
395944d6ad3Swiz }
3966937a5d5Schristos i = sscanf(buf, "%u %u %u %u %u %u",
3976937a5d5Schristos &b, &v, &k, &r, &lambda, &norotate);
398f675e35dSoster if (i == 5)
399f675e35dSoster norotate = 0; /* no-rotate flag is optional */
400f675e35dSoster else if (i != 6) {
4016937a5d5Schristos warnx("Unable to parse header line in block design file");
4021fcee3dbSdan fclose(fp);
4036937a5d5Schristos return EINVAL;
404f675e35dSoster }
40524b75d09Skre /*
40624b75d09Skre * set the sparemap directory. In the in-kernel version, there's a
40724b75d09Skre * daemon that's responsible for finding the sparemaps
40824b75d09Skre */
409f675e35dSoster if (distSpare) {
41070c1fd98Skre if (rf_get_next_nonblank_line(smbuf, sizeof(smbuf), configfp,
4116937a5d5Schristos "Can't find sparemap file name in config file")) {
4121fcee3dbSdan fclose(fp);
4136937a5d5Schristos return EINVAL;
4141fcee3dbSdan }
4156937a5d5Schristos smname = rf_find_non_white(smbuf, 1);
41670c1fd98Skre if (strlen(smname) >= RF_SPAREMAP_NAME_LEN) {
41770c1fd98Skre warnx("sparemap file name '%s' too long (max %d)",
41870c1fd98Skre smname, RF_SPAREMAP_NAME_LEN - 1);
41970c1fd98Skre fclose(fp);
42070c1fd98Skre return EINVAL;
42170c1fd98Skre }
422340761f6Sthorpej } else {
423f675e35dSoster smbuf[0] = '\0';
424f675e35dSoster smname = smbuf;
425f675e35dSoster }
426f675e35dSoster
427f675e35dSoster /* allocate a buffer to hold the configuration info */
428340761f6Sthorpej cfgPtr->layoutSpecificSize = RF_SPAREMAP_NAME_LEN +
429340761f6Sthorpej 6 * sizeof(int) + b * k;
43042abd8f7Soster
431f675e35dSoster cfgBuf = (char *) malloc(cfgPtr->layoutSpecificSize);
4321fcee3dbSdan if (cfgBuf == NULL) {
4331fcee3dbSdan fclose(fp);
4346937a5d5Schristos return ENOMEM;
4351fcee3dbSdan }
436f675e35dSoster cfgPtr->layoutSpecific = (void *) cfgBuf;
437f675e35dSoster p = cfgBuf;
438f675e35dSoster
439f675e35dSoster /* install name of sparemap file */
440f675e35dSoster for (i = 0; smname[i]; i++)
441f675e35dSoster *p++ = smname[i];
442f675e35dSoster /* pad with zeros */
443f675e35dSoster while (i < RF_SPAREMAP_NAME_LEN) {
444f675e35dSoster *p++ = '\0';
445f675e35dSoster i++;
446f675e35dSoster }
44770c1fd98Skre if ((i & (sizeof(int) - 1)) != 0) {
44870c1fd98Skre /* panic, unaligned data; RF_SPAREMAP_NAME_LEN invalid */
44970c1fd98Skre warnx("Program Bug: (RF_SPAREMAP_NAME_LEN(%d) %% %zd) != 0",
45070c1fd98Skre RF_SPAREMAP_NAME_LEN, sizeof(int));
45170c1fd98Skre fclose(fp);
45270c1fd98Skre return EINVAL;
45370c1fd98Skre }
454f675e35dSoster
455f675e35dSoster /*
456f675e35dSoster * fill in the buffer with the block design parameters
457f675e35dSoster * and then the block design itself
458f675e35dSoster */
459340761f6Sthorpej *((int *) p) = b;
460340761f6Sthorpej p += sizeof(int);
461340761f6Sthorpej *((int *) p) = v;
462340761f6Sthorpej p += sizeof(int);
463340761f6Sthorpej *((int *) p) = k;
464340761f6Sthorpej p += sizeof(int);
465340761f6Sthorpej *((int *) p) = r;
466340761f6Sthorpej p += sizeof(int);
467340761f6Sthorpej *((int *) p) = lambda;
468340761f6Sthorpej p += sizeof(int);
469340761f6Sthorpej *((int *) p) = norotate;
470340761f6Sthorpej p += sizeof(int);
471f675e35dSoster
472f675e35dSoster while (fscanf(fp, "%d", &val) == 1)
473f675e35dSoster *p++ = (char) val;
474f675e35dSoster fclose(fp);
475d4ab6626Slukem if ((unsigned int)(p - cfgBuf) != cfgPtr->layoutSpecificSize) {
4766937a5d5Schristos warnx("Size mismatch creating layout specific data: is %tu sb "
4776937a5d5Schristos "%zu bytes", p - cfgBuf, 6 * sizeof(int) + b * k);
4786937a5d5Schristos return EINVAL;
479f675e35dSoster }
4806937a5d5Schristos return 0;
481f675e35dSoster }
482f675e35dSoster
483f675e35dSoster /****************************************************************************
484f675e35dSoster *
485f675e35dSoster * utilities
486f675e35dSoster *
487f675e35dSoster ***************************************************************************/
488f675e35dSoster
489180bbfd8Soster /* finds a non-white character in the line */
4906937a5d5Schristos static char *
rf_find_non_white(char * p,int eatnl)4916937a5d5Schristos rf_find_non_white(char *p, int eatnl)
492180bbfd8Soster {
49370c1fd98Skre while (*p == ' ' || *p == '\t')
49470c1fd98Skre p++;
4956937a5d5Schristos if (*p == '\n' && eatnl)
4966937a5d5Schristos *p = '\0';
4976937a5d5Schristos return p;
498180bbfd8Soster }
499180bbfd8Soster
500180bbfd8Soster /* finds a white character in the line */
5016937a5d5Schristos static char *
rf_find_white(char * p)502180bbfd8Soster rf_find_white(char *p)
503180bbfd8Soster {
50470c1fd98Skre while (*p != '\0' && *p != ' ' && *p != '\t')
50570c1fd98Skre p++;
5066937a5d5Schristos return p;
507180bbfd8Soster }
508180bbfd8Soster
509340761f6Sthorpej /*
510340761f6Sthorpej * searches a file for a line that says "START string", where string is
511f675e35dSoster * specified as a parameter
512f675e35dSoster */
513340761f6Sthorpej static int
rf_search_file_for_start_of(const char * string,char * buf,int len,FILE * fp)514f0121f1fSxtraeme rf_search_file_for_start_of(const char *string, char *buf, int len, FILE *fp)
515f675e35dSoster {
516f675e35dSoster char *p;
517f675e35dSoster
518f675e35dSoster while (1) {
519340761f6Sthorpej if (fgets(buf, len, fp) == NULL)
5206937a5d5Schristos return -1;
5216937a5d5Schristos p = rf_find_non_white(buf, 0);
522f675e35dSoster if (!strncmp(p, "START", strlen("START"))) {
523f675e35dSoster p = rf_find_white(p);
5246937a5d5Schristos p = rf_find_non_white(p, 0);
525340761f6Sthorpej if (!strncmp(p, string, strlen(string)))
5266937a5d5Schristos return 0;
527f675e35dSoster }
528f675e35dSoster }
529f675e35dSoster }
530f675e35dSoster
531f675e35dSoster /* reads from file fp into buf until it finds an interesting line */
5326937a5d5Schristos static int
rf_get_next_nonblank_line(char * buf,int len,FILE * fp,const char * errmsg)533f0121f1fSxtraeme rf_get_next_nonblank_line(char *buf, int len, FILE *fp, const char *errmsg)
534f675e35dSoster {
535f675e35dSoster char *p;
53670c1fd98Skre size_t l;
537f675e35dSoster
5382b7fd022Soster while (fgets(buf, len, fp) != NULL) {
5396937a5d5Schristos p = rf_find_non_white(buf, 0);
540340761f6Sthorpej if (*p == '\n' || *p == '\0' || *p == '#')
541340761f6Sthorpej continue;
54270c1fd98Skre l = strlen(buf);
54370c1fd98Skre while (l > 0 && (buf[--l] == ' ' || buf[l] == '\n'))
544fa730392Soster buf[l] = '\0';
5456937a5d5Schristos return 0;
546f675e35dSoster }
547340761f6Sthorpej if (errmsg)
5486937a5d5Schristos warnx("%s", errmsg);
5496937a5d5Schristos return 1;
550f675e35dSoster }
551f675e35dSoster
552340761f6Sthorpej /*
553340761f6Sthorpej * Allocates an array for the spare table, and initializes it from a file.
554f675e35dSoster * In the user-level version, this is called when recon is initiated.
555f675e35dSoster * When/if I move recon into the kernel, there'll be a daemon that does
556f675e35dSoster * an ioctl into raidframe which will block until a spare table is needed.
557f675e35dSoster * When it returns, it will read a spare table from the file system,
558f675e35dSoster * pass it into the kernel via a different ioctl, and then block again
559f675e35dSoster * on the original ioctl.
560f675e35dSoster *
561f675e35dSoster * This is specific to the declustered layout, but doesn't belong in
562f675e35dSoster * rf_decluster.c because it uses stuff that can't be compiled into
563f675e35dSoster * the kernel, and it needs to be compiled into the user-level sparemap daemon.
564f675e35dSoster */
565340761f6Sthorpej void *
rf_ReadSpareTable(RF_SparetWait_t * req,char * fname)566f0121f1fSxtraeme rf_ReadSpareTable(RF_SparetWait_t *req, char *fname)
567f675e35dSoster {
568340761f6Sthorpej int i, j, numFound, linecount, tableNum, tupleNum,
569340761f6Sthorpej spareDisk, spareBlkOffset;
5706937a5d5Schristos char buf[BUFSIZ], targString[BUFSIZ], errString[BUFSIZ];
571f675e35dSoster RF_SpareTableEntry_t **table;
572c5f07454Schristos FILE *fp = NULL;
57370c1fd98Skre size_t len;
574f675e35dSoster
575f675e35dSoster /* allocate and initialize the table */
576c5f07454Schristos table = calloc(req->TablesPerSpareRegion, sizeof(*table));
57742abd8f7Soster if (table == NULL) {
578c5f07454Schristos warn("%s: Unable to allocate table", __func__);
579c5f07454Schristos return NULL;
58042abd8f7Soster }
581f675e35dSoster for (i = 0; i < req->TablesPerSpareRegion; i++) {
582c5f07454Schristos table[i] = calloc(req->BlocksPerTable, sizeof(**table));
58342abd8f7Soster if (table[i] == NULL) {
58470c1fd98Skre warn("%s: Unable to allocate table:%d", __func__, i);
585c5f07454Schristos goto out;
58642abd8f7Soster }
587340761f6Sthorpej for (j = 0; j < req->BlocksPerTable; j++)
588340761f6Sthorpej table[i][j].spareDisk =
589340761f6Sthorpej table[i][j].spareBlockOffsetInSUs = -1;
590f675e35dSoster }
591f675e35dSoster
592f675e35dSoster /* 2. open sparemap file, sanity check */
593f675e35dSoster if ((fp = fopen(fname, "r")) == NULL) {
594c5f07454Schristos warn("%s: Can't open sparemap file %s", __func__, fname);
595c5f07454Schristos goto out;
596f675e35dSoster }
597340761f6Sthorpej if (rf_get_next_nonblank_line(buf, 1024, fp,
5986937a5d5Schristos "Invalid sparemap file: can't find header line"))
599c5f07454Schristos goto out;
600c5f07454Schristos
60170c1fd98Skre len = strlen(buf);
602c5f07454Schristos if (len != 0 && buf[len - 1] == '\n')
603c5f07454Schristos buf[len - 1] = '\0';
604f675e35dSoster
6050b04aee3Sitojun snprintf(targString, sizeof(targString), "fdisk %d\n", req->fcol);
6060b04aee3Sitojun snprintf(errString, sizeof(errString),
6076937a5d5Schristos "Invalid sparemap file: Can't find \"fdisk %d\" line", req->fcol);
608c5f07454Schristos for (;;) {
6096937a5d5Schristos rf_get_next_nonblank_line(buf, sizeof(buf), fp, errString);
610340761f6Sthorpej if (!strncmp(buf, targString, strlen(targString)))
611340761f6Sthorpej break;
612f675e35dSoster }
613f675e35dSoster
614f675e35dSoster /* no more blank lines or comments allowed now */
615f675e35dSoster linecount = req->TablesPerSpareRegion * req->TableDepthInPUs;
616f675e35dSoster for (i = 0; i < linecount; i++) {
61770c1fd98Skre char linebuf[BUFSIZ];
61870c1fd98Skre
61970c1fd98Skre if (fgets(linebuf, BUFSIZ, fp) == NULL) {
62013a59406Schristos warnx("Sparemap file prematurely exhausted after %d "
62113a59406Schristos "of %d lines", i, linecount);
622c5f07454Schristos goto out;
623f675e35dSoster }
62470c1fd98Skre numFound = sscanf(linebuf, " %d %d %d %d", &tableNum, &tupleNum,
62570c1fd98Skre &spareDisk, &spareBlkOffset);
62670c1fd98Skre if (numFound != 4) {
62770c1fd98Skre warnx("Sparemap file format error - "
62870c1fd98Skre "line %d of %d lines",
62970c1fd98Skre i + 1, linecount);
63070c1fd98Skre goto out;
63170c1fd98Skre }
632f675e35dSoster
633f675e35dSoster table[tableNum][tupleNum].spareDisk = spareDisk;
634340761f6Sthorpej table[tableNum][tupleNum].spareBlockOffsetInSUs =
635340761f6Sthorpej spareBlkOffset * req->SUsPerPU;
636f675e35dSoster }
637f675e35dSoster
638f675e35dSoster fclose(fp);
6396937a5d5Schristos return (void *) table;
640c5f07454Schristos out:
641c5f07454Schristos if (fp)
642c5f07454Schristos fclose(fp);
643c5f07454Schristos for (i = 0; i < req->TablesPerSpareRegion; i++)
644c5f07454Schristos free(table[i]);
645c5f07454Schristos free(table);
646c5f07454Schristos return NULL;
647f675e35dSoster }
648