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