1 1.37 kre /* $NetBSD: rf_configure.c,v 1.37 2022/07/21 09:19:53 kre Exp $ */ 2 1.10 thorpej 3 1.1 oster /* 4 1.1 oster * Copyright (c) 1995 Carnegie-Mellon University. 5 1.1 oster * All rights reserved. 6 1.1 oster * 7 1.1 oster * Author: Mark Holland 8 1.1 oster * 9 1.1 oster * Permission to use, copy, modify and distribute this software and 10 1.1 oster * its documentation is hereby granted, provided that both the copyright 11 1.1 oster * notice and this permission notice appear in all copies of the 12 1.1 oster * software, derivative works or modified versions, and any portions 13 1.1 oster * thereof, and that both notices appear in supporting documentation. 14 1.1 oster * 15 1.1 oster * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 1.1 oster * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 1.1 oster * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 1.1 oster * 19 1.1 oster * Carnegie Mellon requests users of this software to return to 20 1.1 oster * 21 1.1 oster * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 22 1.1 oster * School of Computer Science 23 1.1 oster * Carnegie Mellon University 24 1.1 oster * Pittsburgh PA 15213-3890 25 1.1 oster * 26 1.1 oster * any improvements or extensions that they make and grant Carnegie the 27 1.1 oster * rights to redistribute these changes. 28 1.1 oster */ 29 1.1 oster 30 1.1 oster /*************************************************************** 31 1.1 oster * 32 1.1 oster * rf_configure.c -- code related to configuring the raidframe system 33 1.1 oster * 34 1.1 oster * configuration is complicated by the fact that we want the same 35 1.1 oster * driver to work both in the kernel and at user level. In the 36 1.1 oster * kernel, we can't read the configuration file, so we configure 37 1.1 oster * by running a user-level program that reads the config file, 38 1.1 oster * creates a data structure describing the configuration and 39 1.1 oster * passes it into the kernel via an ioctl. Since we want the config 40 1.1 oster * code to be common between the two versions of the driver, we 41 1.1 oster * configure using the same two-step process when running at 42 1.1 oster * user level. Of course, at user level, the config structure is 43 1.1 oster * passed directly to the config routine, rather than via ioctl. 44 1.1 oster * 45 1.1 oster * This file is not compiled into the kernel, so we have no 46 1.1 oster * need for KERNEL ifdefs. 47 1.1 oster * 48 1.1 oster **************************************************************/ 49 1.17 agc #include <sys/cdefs.h> 50 1.17 agc 51 1.17 agc #ifndef lint 52 1.37 kre __RCSID("$NetBSD: rf_configure.c,v 1.37 2022/07/21 09:19:53 kre Exp $"); 53 1.17 agc #endif 54 1.17 agc 55 1.1 oster 56 1.1 oster #include <stdio.h> 57 1.4 oster #include <stdlib.h> 58 1.3 mjacob #include <errno.h> 59 1.4 oster #include <strings.h> 60 1.25 christos #include <err.h> 61 1.27 kardel #include <util.h> 62 1.36 kre #include <assert.h> 63 1.1 oster #include <sys/types.h> 64 1.1 oster #include <sys/stat.h> 65 1.15 oster 66 1.15 oster #include <dev/raidframe/raidframevar.h> 67 1.15 oster #include <dev/raidframe/raidframeio.h> 68 1.1 oster #include "rf_configure.h" 69 1.1 oster 70 1.28 christos static char *rf_find_non_white(char *, int); 71 1.28 christos static char *rf_find_white(char *); 72 1.28 christos static int rf_search_file_for_start_of(const char *, char *, int, FILE *); 73 1.28 christos static int rf_get_next_nonblank_line(char *, int, FILE *, const char *); 74 1.28 christos 75 1.15 oster #define RF_MIN(a,b) (((a) < (b)) ? (a) : (b)) 76 1.15 oster 77 1.28 christos static int distSpareYes = 1; 78 1.28 christos static int distSpareNo = 0; 79 1.13 oster 80 1.29 kre /* 81 1.29 kre * The mapsw[] table below contains all the various RAID types that might 82 1.29 kre * be supported by the kernel. The actual supported types are found 83 1.29 kre * in sys/dev/raidframe/rf_layout.c. 84 1.29 kre */ 85 1.13 oster 86 1.28 christos static const RF_LayoutSW_t mapsw[] = { 87 1.13 oster /* parity declustering */ 88 1.13 oster {'T', "Parity declustering", 89 1.13 oster rf_MakeLayoutSpecificDeclustered, &distSpareNo}, 90 1.13 oster /* parity declustering with distributed sparing */ 91 1.13 oster {'D', "Distributed sparing parity declustering", 92 1.13 oster rf_MakeLayoutSpecificDeclustered, &distSpareYes}, 93 1.13 oster /* declustered P+Q */ 94 1.13 oster {'Q', "Declustered P+Q", 95 1.13 oster rf_MakeLayoutSpecificDeclustered, &distSpareNo}, 96 1.13 oster /* RAID 5 with rotated sparing */ 97 1.13 oster {'R', "RAID Level 5 rotated sparing", rf_MakeLayoutSpecificNULL, NULL}, 98 1.13 oster /* Chained Declustering */ 99 1.13 oster {'C', "Chained Declustering", rf_MakeLayoutSpecificNULL, NULL}, 100 1.13 oster /* Interleaved Declustering */ 101 1.13 oster {'I', "Interleaved Declustering", rf_MakeLayoutSpecificNULL, NULL}, 102 1.13 oster /* RAID level 0 */ 103 1.13 oster {'0', "RAID Level 0", rf_MakeLayoutSpecificNULL, NULL}, 104 1.13 oster /* RAID level 1 */ 105 1.13 oster {'1', "RAID Level 1", rf_MakeLayoutSpecificNULL, NULL}, 106 1.13 oster /* RAID level 4 */ 107 1.13 oster {'4', "RAID Level 4", rf_MakeLayoutSpecificNULL, NULL}, 108 1.13 oster /* RAID level 5 */ 109 1.13 oster {'5', "RAID Level 5", rf_MakeLayoutSpecificNULL, NULL}, 110 1.13 oster /* Evenodd */ 111 1.13 oster {'E', "EvenOdd", rf_MakeLayoutSpecificNULL, NULL}, 112 1.13 oster /* Declustered Evenodd */ 113 1.13 oster {'e', "Declustered EvenOdd", 114 1.13 oster rf_MakeLayoutSpecificDeclustered, &distSpareNo}, 115 1.13 oster /* parity logging */ 116 1.13 oster {'L', "Parity logging", rf_MakeLayoutSpecificNULL, NULL}, 117 1.13 oster /* end-of-list marker */ 118 1.13 oster {'\0', NULL, NULL, NULL} 119 1.13 oster }; 120 1.28 christos 121 1.28 christos static const RF_LayoutSW_t * 122 1.13 oster rf_GetLayout(RF_ParityConfig_t parityConfig) 123 1.13 oster { 124 1.28 christos const RF_LayoutSW_t *p; 125 1.13 oster 126 1.13 oster /* look up the specific layout */ 127 1.13 oster for (p = &mapsw[0]; p->parityConfig; p++) 128 1.13 oster if (p->parityConfig == parityConfig) 129 1.13 oster break; 130 1.13 oster if (!p->parityConfig) 131 1.28 christos return NULL; 132 1.28 christos return p; 133 1.13 oster } 134 1.7 oster 135 1.10 thorpej /* 136 1.10 thorpej * called from user level to read the configuration file and create 137 1.1 oster * a configuration control structure. This is used in the user-level 138 1.1 oster * version of the driver, and in the user-level program that configures 139 1.1 oster * the system via ioctl. 140 1.1 oster */ 141 1.29 kre int 142 1.22 xtraeme rf_MakeConfig(char *configname, RF_Config_t *cfgPtr) 143 1.1 oster { 144 1.33 mrg int numscanned, val, c, retcode, aa, bb, cc; 145 1.28 christos char buf[BUFSIZ], buf1[BUFSIZ], *cp; 146 1.28 christos const RF_LayoutSW_t *lp; 147 1.10 thorpej FILE *fp; 148 1.10 thorpej 149 1.28 christos memset(cfgPtr, 0, sizeof(*cfgPtr)); 150 1.10 thorpej 151 1.10 thorpej fp = fopen(configname, "r"); 152 1.10 thorpej if (!fp) { 153 1.28 christos warnx("Can't open config file %s", configname); 154 1.28 christos return -1; 155 1.10 thorpej } 156 1.10 thorpej rewind(fp); 157 1.28 christos if (rf_search_file_for_start_of("array", buf, sizeof(buf), fp)) { 158 1.28 christos warnx("Unable to find start of \"array\" params in config " 159 1.28 christos "file %s", configname); 160 1.10 thorpej retcode = -1; 161 1.10 thorpej goto out; 162 1.10 thorpej } 163 1.28 christos rf_get_next_nonblank_line(buf, sizeof(buf), fp, 164 1.28 christos "Config file error (\"array\" section): unable to get numRow " 165 1.28 christos "and numCol"); 166 1.10 thorpej 167 1.10 thorpej /* 168 1.29 kre * wackiness with aa, bb, cc to get around size problems on 169 1.29 kre * different platforms 170 1.29 kre */ 171 1.33 mrg 172 1.33 mrg /* 173 1.33 mrg * Allow both "numCol numSpare" as well as old-style 174 1.33 mrg * "numRow numCol numSpare". 175 1.33 mrg * Note that numRow has always been ignored. 176 1.33 mrg */ 177 1.10 thorpej numscanned = sscanf(buf, "%d %d %d", &aa, &bb, &cc); 178 1.10 thorpej if (numscanned != 3) { 179 1.33 mrg numscanned = sscanf(buf, "%d %d", &bb, &cc); 180 1.33 mrg if (numscanned != 2) { 181 1.33 mrg warnx("Config file error (\"array\" section): unable " 182 1.33 mrg "to get numCol, numSpare"); 183 1.33 mrg retcode = -1; 184 1.33 mrg goto out; 185 1.33 mrg } 186 1.10 thorpej } 187 1.10 thorpej cfgPtr->numCol = (RF_RowCol_t) bb; 188 1.10 thorpej cfgPtr->numSpare = (RF_RowCol_t) cc; 189 1.10 thorpej 190 1.10 thorpej /* debug section is optional */ 191 1.10 thorpej for (c = 0; c < RF_MAXDBGV; c++) 192 1.10 thorpej cfgPtr->debugVars[c][0] = '\0'; 193 1.10 thorpej rewind(fp); 194 1.28 christos if (!rf_search_file_for_start_of("debug", buf, sizeof(buf), fp)) { 195 1.10 thorpej for (c = 0; c < RF_MAXDBGV; c++) { 196 1.28 christos if (rf_get_next_nonblank_line(buf, sizeof(buf), fp, 197 1.28 christos NULL)) 198 1.10 thorpej break; 199 1.28 christos cp = rf_find_non_white(buf, 0); 200 1.28 christos if (!strncmp(cp, "START", sizeof("START") - 1)) 201 1.10 thorpej break; 202 1.31 christos (void) strlcpy(cfgPtr->debugVars[c], cp, 203 1.18 itojun sizeof(cfgPtr->debugVars[c])); 204 1.10 thorpej } 205 1.10 thorpej } 206 1.10 thorpej rewind(fp); 207 1.18 itojun strlcpy(cfgPtr->diskQueueType, "fifo", sizeof(cfgPtr->diskQueueType)); 208 1.10 thorpej cfgPtr->maxOutstandingDiskReqs = 1; 209 1.29 kre 210 1.10 thorpej /* scan the file for the block related to disk queues */ 211 1.28 christos if (rf_search_file_for_start_of("queue", buf, sizeof(buf), fp) || 212 1.28 christos rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) { 213 1.28 christos warnx("[No disk queue discipline specified in config file %s. " 214 1.28 christos "Using %s.]", configname, cfgPtr->diskQueueType); 215 1.10 thorpej } 216 1.36 kre else { 217 1.10 thorpej 218 1.29 kre /* 219 1.29 kre * the queue specifier line contains two entries: 1st char of first 220 1.10 thorpej * word specifies queue to be used 2nd word specifies max num reqs 221 1.29 kre * that can be outstanding on the disk itself (typically 1) 222 1.29 kre */ 223 1.36 kre assert(64 < sizeof buf1); 224 1.36 kre if (sscanf(buf, "%64s %d", buf1, &val) != 2 || strlen(buf1) >= 60) { 225 1.28 christos warnx("Can't determine queue type and/or max outstanding " 226 1.36 kre "reqs from line: %.*s", (int)(sizeof(buf) - 1), buf); 227 1.28 christos warnx("Using %s-%d", cfgPtr->diskQueueType, 228 1.28 christos cfgPtr->maxOutstandingDiskReqs); 229 1.10 thorpej } else { 230 1.36 kre #if 0 231 1.10 thorpej char *ch; 232 1.36 kre #endif 233 1.28 christos memcpy(cfgPtr->diskQueueType, buf1, 234 1.10 thorpej RF_MIN(sizeof(cfgPtr->diskQueueType), strlen(buf1) + 1)); 235 1.36 kre cfgPtr->diskQueueType[sizeof cfgPtr->diskQueueType - 1] = '\0'; 236 1.36 kre 237 1.36 kre #if 0 /* this indicates a lack of understanding of how scanf() works */ 238 1.36 kre /* it was also pointless as buf1 data was (b4) never used again */ 239 1.10 thorpej for (ch = buf1; *ch; ch++) { 240 1.10 thorpej if (*ch == ' ') { 241 1.10 thorpej *ch = '\0'; 242 1.10 thorpej break; 243 1.10 thorpej } 244 1.10 thorpej } 245 1.36 kre #endif 246 1.10 thorpej cfgPtr->maxOutstandingDiskReqs = val; 247 1.36 kre if (cfgPtr->maxOutstandingDiskReqs != val) { 248 1.36 kre warnx("Queue length for %s out of range" 249 1.36 kre " [%d interp as %d], assuming 1", 250 1.36 kre buf1, val, cfgPtr->maxOutstandingDiskReqs); 251 1.36 kre cfgPtr->maxOutstandingDiskReqs = 1; 252 1.36 kre } 253 1.10 thorpej } 254 1.36 kre } 255 1.10 thorpej 256 1.10 thorpej rewind(fp); 257 1.10 thorpej 258 1.28 christos if (rf_search_file_for_start_of("disks", buf, sizeof(buf), fp)) { 259 1.28 christos warnx("Can't find \"disks\" section in config file %s", 260 1.28 christos configname); 261 1.10 thorpej retcode = -1; 262 1.10 thorpej goto out; 263 1.10 thorpej } 264 1.33 mrg for (c = 0; c < cfgPtr->numCol; c++) { 265 1.33 mrg char b1[MAXPATHLEN]; 266 1.33 mrg const char *b; 267 1.27 kardel 268 1.33 mrg if (rf_get_next_nonblank_line( 269 1.33 mrg buf, sizeof(buf), fp, NULL)) { 270 1.35 kre warnx("Config file error: unable to find device " 271 1.35 kre "file name for disk at col %d", c); 272 1.33 mrg retcode = -1; 273 1.33 mrg goto out; 274 1.33 mrg } 275 1.27 kardel 276 1.33 mrg b = getfsspecname(b1, sizeof(b1), buf); 277 1.33 mrg if (b == NULL) { 278 1.33 mrg warnx("Config file error: warning: unable to " 279 1.35 kre "get device file for disk at col %d: %s", 280 1.35 kre c, b1); 281 1.37 kre b = "absent"; 282 1.10 thorpej } 283 1.33 mrg 284 1.33 mrg strlcpy(cfgPtr->devnames[0][c], b, 285 1.33 mrg sizeof(cfgPtr->devnames[0][c])); 286 1.10 thorpej } 287 1.10 thorpej 288 1.10 thorpej /* "spare" section is optional */ 289 1.10 thorpej rewind(fp); 290 1.28 christos if (rf_search_file_for_start_of("spare", buf, sizeof(buf), fp)) 291 1.10 thorpej cfgPtr->numSpare = 0; 292 1.10 thorpej for (c = 0; c < cfgPtr->numSpare; c++) { 293 1.28 christos char b1[MAXPATHLEN]; 294 1.27 kardel const char *b; 295 1.27 kardel 296 1.28 christos if (rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) { 297 1.28 christos warnx("Config file error: unable to get device file " 298 1.28 christos "for spare disk %d", c); 299 1.10 thorpej retcode = -1; 300 1.10 thorpej goto out; 301 1.10 thorpej } 302 1.27 kardel 303 1.27 kardel b = getfsspecname(b1, sizeof(b1), buf); 304 1.27 kardel if (b == NULL) { 305 1.28 christos warnx("Config file error: warning: unable to get " 306 1.34 mrg "device file for spare disk %d: %s", c, buf); 307 1.27 kardel b = buf; 308 1.27 kardel } 309 1.27 kardel 310 1.33 mrg strlcpy(cfgPtr->spare_names[c], b, 311 1.33 mrg sizeof(cfgPtr->spare_names[c])); 312 1.10 thorpej } 313 1.10 thorpej 314 1.10 thorpej /* scan the file for the block related to layout */ 315 1.10 thorpej rewind(fp); 316 1.28 christos if (rf_search_file_for_start_of("layout", buf, sizeof(buf), fp)) { 317 1.28 christos warnx("Can't find \"layout\" section in configuration file %s", 318 1.28 christos configname); 319 1.10 thorpej retcode = -1; 320 1.10 thorpej goto out; 321 1.10 thorpej } 322 1.28 christos if (rf_get_next_nonblank_line(buf, sizeof(buf), fp, NULL)) { 323 1.28 christos warnx("Config file error (\"layout\" section): unable to find " 324 1.28 christos "common layout param line"); 325 1.10 thorpej retcode = -1; 326 1.10 thorpej goto out; 327 1.10 thorpej } 328 1.10 thorpej c = sscanf(buf, "%d %d %d %c", &aa, &bb, &cc, &cfgPtr->parityConfig); 329 1.10 thorpej cfgPtr->sectPerSU = (RF_SectorNum_t) aa; 330 1.10 thorpej cfgPtr->SUsPerPU = (RF_StripeNum_t) bb; 331 1.10 thorpej cfgPtr->SUsPerRU = (RF_StripeNum_t) cc; 332 1.10 thorpej if (c != 4) { 333 1.28 christos warnx("Unable to scan common layout line"); 334 1.10 thorpej retcode = -1; 335 1.10 thorpej goto out; 336 1.10 thorpej } 337 1.10 thorpej lp = rf_GetLayout(cfgPtr->parityConfig); 338 1.10 thorpej if (lp == NULL) { 339 1.28 christos warnx("Unknown parity config '%c'", 340 1.10 thorpej cfgPtr->parityConfig); 341 1.10 thorpej retcode = -1; 342 1.10 thorpej goto out; 343 1.10 thorpej } 344 1.10 thorpej 345 1.28 christos retcode = lp->MakeLayoutSpecific(fp, cfgPtr, 346 1.28 christos lp->makeLayoutSpecificArg); 347 1.1 oster out: 348 1.10 thorpej fclose(fp); 349 1.10 thorpej if (retcode < 0) 350 1.10 thorpej retcode = errno = EINVAL; 351 1.10 thorpej else 352 1.10 thorpej errno = retcode; 353 1.28 christos return retcode; 354 1.1 oster } 355 1.1 oster 356 1.1 oster 357 1.29 kre /* 358 1.29 kre * used in architectures such as RAID0 where there is no layout-specific 359 1.1 oster * information to be passed into the configuration code. 360 1.1 oster */ 361 1.29 kre int 362 1.22 xtraeme rf_MakeLayoutSpecificNULL(FILE *fp, RF_Config_t *cfgPtr, void *ignored) 363 1.1 oster { 364 1.10 thorpej cfgPtr->layoutSpecificSize = 0; 365 1.10 thorpej cfgPtr->layoutSpecific = NULL; 366 1.28 christos return 0; 367 1.1 oster } 368 1.1 oster 369 1.29 kre int 370 1.22 xtraeme rf_MakeLayoutSpecificDeclustered(FILE *configfp, RF_Config_t *cfgPtr, void *arg) 371 1.1 oster { 372 1.10 thorpej int b, v, k, r, lambda, norotate, i, val, distSpare; 373 1.10 thorpej char *cfgBuf, *bdfile, *p, *smname; 374 1.28 christos char buf[BUFSIZ], smbuf[BUFSIZ]; 375 1.10 thorpej FILE *fp; 376 1.10 thorpej 377 1.10 thorpej distSpare = *((int *) arg); 378 1.10 thorpej 379 1.10 thorpej /* get the block design file name */ 380 1.28 christos if (rf_get_next_nonblank_line(buf, sizeof(buf), configfp, 381 1.28 christos "Can't find block design file name in config file")) 382 1.28 christos return EINVAL; 383 1.28 christos bdfile = rf_find_non_white(buf, 1); 384 1.10 thorpej /* open bd file, check validity of configuration */ 385 1.10 thorpej if ((fp = fopen(bdfile, "r")) == NULL) { 386 1.28 christos warn("RAID: config error: Can't open layout table file %s", 387 1.28 christos bdfile); 388 1.28 christos return EINVAL; 389 1.28 christos } 390 1.28 christos if (fgets(buf, sizeof(buf), fp) == NULL) { 391 1.28 christos warnx("RAID: config error: Can't read layout from layout " 392 1.28 christos "table file %s", bdfile); 393 1.23 dan fclose(fp); 394 1.28 christos return EINVAL; 395 1.12 wiz } 396 1.28 christos i = sscanf(buf, "%u %u %u %u %u %u", 397 1.28 christos &b, &v, &k, &r, &lambda, &norotate); 398 1.10 thorpej if (i == 5) 399 1.10 thorpej norotate = 0; /* no-rotate flag is optional */ 400 1.10 thorpej else if (i != 6) { 401 1.28 christos warnx("Unable to parse header line in block design file"); 402 1.23 dan fclose(fp); 403 1.28 christos return EINVAL; 404 1.10 thorpej } 405 1.29 kre /* 406 1.29 kre * set the sparemap directory. In the in-kernel version, there's a 407 1.29 kre * daemon that's responsible for finding the sparemaps 408 1.29 kre */ 409 1.10 thorpej if (distSpare) { 410 1.32 kre if (rf_get_next_nonblank_line(smbuf, sizeof(smbuf), configfp, 411 1.28 christos "Can't find sparemap file name in config file")) { 412 1.23 dan fclose(fp); 413 1.28 christos return EINVAL; 414 1.10 thorpej } 415 1.28 christos smname = rf_find_non_white(smbuf, 1); 416 1.32 kre if (strlen(smname) >= RF_SPAREMAP_NAME_LEN) { 417 1.32 kre warnx("sparemap file name '%s' too long (max %d)", 418 1.32 kre smname, RF_SPAREMAP_NAME_LEN - 1); 419 1.32 kre fclose(fp); 420 1.32 kre return EINVAL; 421 1.32 kre } 422 1.10 thorpej } else { 423 1.10 thorpej smbuf[0] = '\0'; 424 1.10 thorpej smname = smbuf; 425 1.10 thorpej } 426 1.10 thorpej 427 1.10 thorpej /* allocate a buffer to hold the configuration info */ 428 1.10 thorpej cfgPtr->layoutSpecificSize = RF_SPAREMAP_NAME_LEN + 429 1.10 thorpej 6 * sizeof(int) + b * k; 430 1.21 oster 431 1.10 thorpej cfgBuf = (char *) malloc(cfgPtr->layoutSpecificSize); 432 1.23 dan if (cfgBuf == NULL) { 433 1.23 dan fclose(fp); 434 1.28 christos return ENOMEM; 435 1.23 dan } 436 1.10 thorpej cfgPtr->layoutSpecific = (void *) cfgBuf; 437 1.10 thorpej p = cfgBuf; 438 1.10 thorpej 439 1.10 thorpej /* install name of sparemap file */ 440 1.10 thorpej for (i = 0; smname[i]; i++) 441 1.10 thorpej *p++ = smname[i]; 442 1.10 thorpej /* pad with zeros */ 443 1.10 thorpej while (i < RF_SPAREMAP_NAME_LEN) { 444 1.10 thorpej *p++ = '\0'; 445 1.10 thorpej i++; 446 1.10 thorpej } 447 1.32 kre if ((i & (sizeof(int) - 1)) != 0) { 448 1.32 kre /* panic, unaligned data; RF_SPAREMAP_NAME_LEN invalid */ 449 1.32 kre warnx("Program Bug: (RF_SPAREMAP_NAME_LEN(%d) %% %zd) != 0", 450 1.32 kre RF_SPAREMAP_NAME_LEN, sizeof(int)); 451 1.32 kre fclose(fp); 452 1.32 kre return EINVAL; 453 1.32 kre } 454 1.10 thorpej 455 1.10 thorpej /* 456 1.29 kre * fill in the buffer with the block design parameters 457 1.29 kre * and then the block design itself 458 1.29 kre */ 459 1.10 thorpej *((int *) p) = b; 460 1.10 thorpej p += sizeof(int); 461 1.10 thorpej *((int *) p) = v; 462 1.10 thorpej p += sizeof(int); 463 1.10 thorpej *((int *) p) = k; 464 1.10 thorpej p += sizeof(int); 465 1.10 thorpej *((int *) p) = r; 466 1.10 thorpej p += sizeof(int); 467 1.10 thorpej *((int *) p) = lambda; 468 1.10 thorpej p += sizeof(int); 469 1.10 thorpej *((int *) p) = norotate; 470 1.10 thorpej p += sizeof(int); 471 1.10 thorpej 472 1.10 thorpej while (fscanf(fp, "%d", &val) == 1) 473 1.10 thorpej *p++ = (char) val; 474 1.10 thorpej fclose(fp); 475 1.24 lukem if ((unsigned int)(p - cfgBuf) != cfgPtr->layoutSpecificSize) { 476 1.28 christos warnx("Size mismatch creating layout specific data: is %tu sb " 477 1.28 christos "%zu bytes", p - cfgBuf, 6 * sizeof(int) + b * k); 478 1.28 christos return EINVAL; 479 1.10 thorpej } 480 1.28 christos return 0; 481 1.1 oster } 482 1.1 oster 483 1.1 oster /**************************************************************************** 484 1.1 oster * 485 1.1 oster * utilities 486 1.1 oster * 487 1.1 oster ***************************************************************************/ 488 1.7 oster 489 1.7 oster /* finds a non-white character in the line */ 490 1.28 christos static char * 491 1.28 christos rf_find_non_white(char *p, int eatnl) 492 1.7 oster { 493 1.32 kre while (*p == ' ' || *p == '\t') 494 1.32 kre p++; 495 1.28 christos if (*p == '\n' && eatnl) 496 1.28 christos *p = '\0'; 497 1.28 christos return p; 498 1.7 oster } 499 1.7 oster 500 1.7 oster /* finds a white character in the line */ 501 1.28 christos static char * 502 1.7 oster rf_find_white(char *p) 503 1.7 oster { 504 1.32 kre while (*p != '\0' && *p != ' ' && *p != '\t') 505 1.32 kre p++; 506 1.28 christos return p; 507 1.7 oster } 508 1.1 oster 509 1.10 thorpej /* 510 1.10 thorpej * searches a file for a line that says "START string", where string is 511 1.1 oster * specified as a parameter 512 1.1 oster */ 513 1.29 kre static int 514 1.22 xtraeme rf_search_file_for_start_of(const char *string, char *buf, int len, FILE *fp) 515 1.1 oster { 516 1.10 thorpej char *p; 517 1.1 oster 518 1.10 thorpej while (1) { 519 1.10 thorpej if (fgets(buf, len, fp) == NULL) 520 1.28 christos return -1; 521 1.28 christos p = rf_find_non_white(buf, 0); 522 1.10 thorpej if (!strncmp(p, "START", strlen("START"))) { 523 1.10 thorpej p = rf_find_white(p); 524 1.28 christos p = rf_find_non_white(p, 0); 525 1.10 thorpej if (!strncmp(p, string, strlen(string))) 526 1.28 christos return 0; 527 1.10 thorpej } 528 1.10 thorpej } 529 1.1 oster } 530 1.1 oster 531 1.1 oster /* reads from file fp into buf until it finds an interesting line */ 532 1.29 kre static int 533 1.22 xtraeme rf_get_next_nonblank_line(char *buf, int len, FILE *fp, const char *errmsg) 534 1.1 oster { 535 1.10 thorpej char *p; 536 1.32 kre size_t l; 537 1.1 oster 538 1.19 oster while (fgets(buf, len, fp) != NULL) { 539 1.28 christos p = rf_find_non_white(buf, 0); 540 1.10 thorpej if (*p == '\n' || *p == '\0' || *p == '#') 541 1.10 thorpej continue; 542 1.32 kre l = strlen(buf); 543 1.32 kre while (l > 0 && (buf[--l] == ' ' || buf[l] == '\n')) 544 1.28 christos buf[l] = '\0'; 545 1.28 christos return 0; 546 1.10 thorpej } 547 1.10 thorpej if (errmsg) 548 1.28 christos warnx("%s", errmsg); 549 1.28 christos return 1; 550 1.1 oster } 551 1.1 oster 552 1.10 thorpej /* 553 1.10 thorpej * Allocates an array for the spare table, and initializes it from a file. 554 1.1 oster * In the user-level version, this is called when recon is initiated. 555 1.1 oster * When/if I move recon into the kernel, there'll be a daemon that does 556 1.1 oster * an ioctl into raidframe which will block until a spare table is needed. 557 1.1 oster * When it returns, it will read a spare table from the file system, 558 1.1 oster * pass it into the kernel via a different ioctl, and then block again 559 1.1 oster * on the original ioctl. 560 1.1 oster * 561 1.1 oster * This is specific to the declustered layout, but doesn't belong in 562 1.1 oster * rf_decluster.c because it uses stuff that can't be compiled into 563 1.1 oster * the kernel, and it needs to be compiled into the user-level sparemap daemon. 564 1.1 oster */ 565 1.10 thorpej void * 566 1.22 xtraeme rf_ReadSpareTable(RF_SparetWait_t *req, char *fname) 567 1.1 oster { 568 1.10 thorpej int i, j, numFound, linecount, tableNum, tupleNum, 569 1.10 thorpej spareDisk, spareBlkOffset; 570 1.28 christos char buf[BUFSIZ], targString[BUFSIZ], errString[BUFSIZ]; 571 1.10 thorpej RF_SpareTableEntry_t **table; 572 1.26 christos FILE *fp = NULL; 573 1.32 kre size_t len; 574 1.10 thorpej 575 1.10 thorpej /* allocate and initialize the table */ 576 1.26 christos table = calloc(req->TablesPerSpareRegion, sizeof(*table)); 577 1.21 oster if (table == NULL) { 578 1.26 christos warn("%s: Unable to allocate table", __func__); 579 1.26 christos return NULL; 580 1.21 oster } 581 1.10 thorpej for (i = 0; i < req->TablesPerSpareRegion; i++) { 582 1.26 christos table[i] = calloc(req->BlocksPerTable, sizeof(**table)); 583 1.21 oster if (table[i] == NULL) { 584 1.32 kre warn("%s: Unable to allocate table:%d", __func__, i); 585 1.26 christos goto out; 586 1.21 oster } 587 1.10 thorpej for (j = 0; j < req->BlocksPerTable; j++) 588 1.10 thorpej table[i][j].spareDisk = 589 1.10 thorpej table[i][j].spareBlockOffsetInSUs = -1; 590 1.10 thorpej } 591 1.10 thorpej 592 1.10 thorpej /* 2. open sparemap file, sanity check */ 593 1.10 thorpej if ((fp = fopen(fname, "r")) == NULL) { 594 1.26 christos warn("%s: Can't open sparemap file %s", __func__, fname); 595 1.26 christos goto out; 596 1.10 thorpej } 597 1.10 thorpej if (rf_get_next_nonblank_line(buf, 1024, fp, 598 1.28 christos "Invalid sparemap file: can't find header line")) 599 1.26 christos goto out; 600 1.26 christos 601 1.32 kre len = strlen(buf); 602 1.26 christos if (len != 0 && buf[len - 1] == '\n') 603 1.26 christos buf[len - 1] = '\0'; 604 1.10 thorpej 605 1.18 itojun snprintf(targString, sizeof(targString), "fdisk %d\n", req->fcol); 606 1.18 itojun snprintf(errString, sizeof(errString), 607 1.28 christos "Invalid sparemap file: Can't find \"fdisk %d\" line", req->fcol); 608 1.26 christos for (;;) { 609 1.28 christos rf_get_next_nonblank_line(buf, sizeof(buf), fp, errString); 610 1.10 thorpej if (!strncmp(buf, targString, strlen(targString))) 611 1.10 thorpej break; 612 1.10 thorpej } 613 1.10 thorpej 614 1.10 thorpej /* no more blank lines or comments allowed now */ 615 1.10 thorpej linecount = req->TablesPerSpareRegion * req->TableDepthInPUs; 616 1.10 thorpej for (i = 0; i < linecount; i++) { 617 1.32 kre char linebuf[BUFSIZ]; 618 1.32 kre 619 1.32 kre if (fgets(linebuf, BUFSIZ, fp) == NULL) { 620 1.32 kre warnx("Sparemap file prematurely exhausted after %d " 621 1.32 kre "of %d lines", i, linecount); 622 1.32 kre goto out; 623 1.32 kre } 624 1.32 kre numFound = sscanf(linebuf, " %d %d %d %d", &tableNum, &tupleNum, 625 1.10 thorpej &spareDisk, &spareBlkOffset); 626 1.10 thorpej if (numFound != 4) { 627 1.32 kre warnx("Sparemap file format error - " 628 1.32 kre "line %d of %d lines", 629 1.32 kre i + 1, linecount); 630 1.26 christos goto out; 631 1.10 thorpej } 632 1.10 thorpej 633 1.10 thorpej table[tableNum][tupleNum].spareDisk = spareDisk; 634 1.10 thorpej table[tableNum][tupleNum].spareBlockOffsetInSUs = 635 1.10 thorpej spareBlkOffset * req->SUsPerPU; 636 1.10 thorpej } 637 1.1 oster 638 1.10 thorpej fclose(fp); 639 1.28 christos return (void *) table; 640 1.26 christos out: 641 1.26 christos if (fp) 642 1.26 christos fclose(fp); 643 1.26 christos for (i = 0; i < req->TablesPerSpareRegion; i++) 644 1.26 christos free(table[i]); 645 1.26 christos free(table); 646 1.26 christos return NULL; 647 1.1 oster } 648