Changeset 561 in MondoRescue for trunk/mondo/mondo/common/libmondo-raid.c


Ignore:
Timestamp:
May 20, 2006, 5:51:21 PM (18 years ago)
Author:
bcornec
Message:

merge -r 542:560 $SVN_M/branches/stable

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/mondo/mondo/common/libmondo-raid.c

    r507 r561  
    344344
    345345    fprintf(fout, "raiddev %s\n", raidrec->raid_device);
    346     if (raidrec->raid_level == -1) {
     346    if (raidrec->raid_level == -2) {
     347        fprintf(fout, "    raid-level            multipath\n");
     348    } else if (raidrec->raid_level == -1) {
    347349        fprintf(fout, "    raid-level            linear\n");
    348350    } else {
     
    350352                raidrec->raid_level);
    351353    }
    352     fprintf(fout, "    chunk-size            %d\n", raidrec->chunk_size);
    353354    fprintf(fout, "    nr-raid-disks         %d\n",
    354355            raidrec->data_disks.entries);
    355     fprintf(fout, "    nr-spare-disks        %d\n",
    356             raidrec->spare_disks.entries);
     356    if (raidrec->spare_disks.entries > 0) {
     357        fprintf(fout, "    nr-spare-disks        %d\n",
     358                raidrec->spare_disks.entries);
     359    }
    357360    if (raidrec->parity_disks.entries > 0) {
    358361        fprintf(fout, "    nr-parity-disks       %d\n",
    359362                raidrec->parity_disks.entries);
    360363    }
    361 
    362364    fprintf(fout, "    persistent-superblock %d\n",
    363365            raidrec->persistent_superblock);
     366    if (raidrec->chunk_size > -1) {
     367      fprintf(fout, "    chunk-size            %d\n", raidrec->chunk_size);
     368    }
     369    if (raidrec->parity > -1) {
     370      switch(raidrec->parity) {
     371      case 0:
     372        fprintf(fout, "    parity-algorithm      left-asymmetric\n");
     373        break;
     374      case 1:
     375        fprintf(fout, "    parity-algorithm      right-asymmetric\n");
     376        break;
     377      case 2:
     378        fprintf(fout, "    parity-algorithm      left-symmetric\n");
     379        break;
     380      case 3:
     381        fprintf(fout, "    parity-algorithm      right-symmetric\n");
     382        break;
     383      default:
     384        fatal_error("Unknown RAID parity algorithm.");
     385        break;
     386      }
     387    }
    364388    save_additional_vars_to_file(&raidrec->additional_vars, fout);
    365389    fprintf(fout, "\n");
     
    642666
    643667    if (!strcmp(label, "raid-level")) {
    644         if (!strcmp(value, "linear")) {
     668        if (!strcmp(value, "multipath")) {
     669            raidrec->raid_level = -2;
     670        } else if (!strcmp(value, "linear")) {
    645671            raidrec->raid_level = -1;
    646672        } else {
     
    655681    } else if (!strcmp(label, "chunk-size")) {
    656682        raidrec->chunk_size = atoi(value);
     683    } else if (!strcmp(label, "parity-algorithm")) {
     684        if (!strcmp(value, "left-asymmetric")) {
     685            raidrec->parity = 0;
     686        } else if (!strcmp(value, "right-asymmetric")) {
     687            raidrec->parity = 1;
     688        } else if (!strcmp(value, "left-symmetric")) {
     689            raidrec->parity = 2;
     690        } else if (!strcmp(value, "right-symmetric")) {
     691            raidrec->parity = 3;
     692        } else {
     693            log_msg(1, "Unknown RAID parity algorithm '%s'\n.", value);
     694        }
    657695    } else if (!strcmp(label, "device")) {
    658696        get_next_raidtab_line(fin, labelB, valueB);
     
    898936
    899937
    900 int read_mdstat(struct s_mdstat *mdstat, char *mdstat_file)
    901 {
    902     FILE *fin;
    903     char *tmp;
    904     char *stub;
    905     char *incoming = NULL;
    906     char *p, *q, *r;
    907     int diskno;
    908     size_t n = 0;
    909 
    910     malloc_string(incoming);
    911     if (!(fin = fopen(mdstat_file, "r"))) {
    912         log_msg(1, "%s not found", mdstat_file);
     938int parse_mdstat(struct raidlist_itself *raidlist, char *device_prefix) {
     939
     940  const char delims[] = " ";
     941
     942  FILE   *fin;
     943  int    res = 0, row, i, index_min;
     944  int lastpos = 0;
     945  size_t len = 0;
     946  char   *token;
     947  char *string = NULL;
     948  char *pos;
     949  char type;
     950  char *strtmp;
     951
     952  // open file
     953  if (!(fin = fopen(MDSTAT_FILE, "r"))) {
     954    log_msg(1, "Could not open %s.\n", MDSTAT_FILE);
     955    return 1;
     956  }
     957  // initialise record, build progress and row counters
     958  raidlist->entries = 0;
     959  raidlist->el[raidlist->entries].progress = 999;
     960  row = 1;
     961  // skip first output row - contains registered RAID levels
     962  res = getline(&string, &len, fin);
     963  // parse the rest
     964  while ( !feof_unlocked(fin) ) {
     965    res = getline(&string, &len, fin);
     966    if (res <= 0) break;
     967    // trim leading spaces
     968    pos = string;
     969    while (*pos == ' ') *pos++;
     970    asprintf(&string, pos);
     971    //
     972    // if we have newline after only spaces, this is a blank line, update
     973    // counters, otherwise do normal parsing
     974    if (*string == '\n') {
     975      row = 1;
     976      raidlist->entries++;
     977      raidlist->el[raidlist->entries].progress = 999;
     978    } else {
     979      switch (row) {
     980      case 1:  // device information
     981    // check whether last line of record and if so skip
     982    pos = strcasestr(string, "unused devices: ");
     983    if (pos == string) {
     984      //raidlist->entries--;
     985      break;
     986    }
     987    // tokenise string
     988    token = mr_strtok (string, delims, &lastpos);
     989    // get RAID device name
     990    asprintf(&strtmp,"%s%s", device_prefix, token);
     991    strcpy(raidlist->el[raidlist->entries].raid_device, strtmp);
     992    paranoid_free(strtmp);
     993    paranoid_free(token);
     994    // skip ':' and status
     995    token = strtok (string, delims, &lastpos);
     996    paranoid_free(token);
     997    token = strtok (string, delims, &lastpos);
     998    if (!strcmp(token, "inactive")) {
     999      log_msg(1, "RAID device '%s' inactive.\n",
     1000         raidlist->el[raidlist->entries].raid_device);
     1001      paranoid_free(string);
     1002      paranoid_free(token);
     1003      return 1;
     1004    }
     1005    paranoid_free(token);
     1006
     1007    // get RAID level
     1008    token = strtok (string, delims, &lastpos);
     1009    if (!strcmp(token, "multipath")) {
     1010      raidlist->el[raidlist->entries].raid_level = -2;
     1011    } else if (!strcmp(token, "linear")) {
     1012      raidlist->el[raidlist->entries].raid_level = -1;
     1013    } else if (!strcmp(token, "raid0")) {
     1014      raidlist->el[raidlist->entries].raid_level = 0;
     1015    } else if (!strcmp(token, "raid1")) {
     1016      raidlist->el[raidlist->entries].raid_level = 1;
     1017    } else if (!strcmp(token, "raid4")) {
     1018      raidlist->el[raidlist->entries].raid_level = 4;
     1019    } else if (!strcmp(token, "raid5")) {
     1020      raidlist->el[raidlist->entries].raid_level = 5;
     1021    } else if (!strcmp(token, "raid6")) {
     1022      raidlist->el[raidlist->entries].raid_level = 6;
     1023    } else if (!strcmp(token, "raid10")) {
     1024      raidlist->el[raidlist->entries].raid_level = 10;
     1025    } else {
     1026      log_msg(1, "Unknown RAID level '%s'.\n", token);
     1027      paranoid_free(string);
     1028      paranoid_free(token);
     1029      return 1;
     1030    }
     1031    paranoid_free(token);
     1032
     1033    // get RAID devices (type, index, device)
     1034    // Note: parity disk for RAID4 is last normal disk, there is no '(P)'
     1035    raidlist->el[raidlist->entries].data_disks.entries = 0;
     1036    raidlist->el[raidlist->entries].spare_disks.entries = 0;
     1037    raidlist->el[raidlist->entries].failed_disks.entries = 0;
     1038    while((token = strtok (string, delims, &lastpos))) {
     1039      if ((pos = strstr(token, "("))) {
     1040        type = *(pos+1);
     1041      } else {
     1042        type = ' ';
     1043      }
     1044      pos = strstr(token, "[");
     1045      *pos = '\0';
     1046      switch(type) {
     1047      case ' ': // normal data disks
     1048        raidlist->el[raidlist->entries].data_disks.el[raidlist->el[raidlist->entries].data_disks.entries].index = atoi(pos + 1);
     1049        asprintf(&strtmp,"%s%s", device_prefix, token);
     1050        strcpy(raidlist->el[raidlist->entries].data_disks.el[raidlist->el[raidlist->entries].data_disks.entries].device, strtmp);
     1051        paranoid_free(strtmp);
     1052        raidlist->el[raidlist->entries].data_disks.entries++;
     1053        break;
     1054      case 'S': // spare disks
     1055        raidlist->el[raidlist->entries].spare_disks.el[raidlist->el[raidlist->entries].spare_disks.entries].index = atoi(pos + 1);
     1056        asprintf(&strtmp,"%s%s", device_prefix, token);
     1057        strcpy(raidlist->el[raidlist->entries].spare_disks.el[raidlist->el[raidlist->entries].spare_disks.entries].device, strtmp);
     1058        paranoid_free(strtmp);
     1059        raidlist->el[raidlist->entries].spare_disks.entries++;
     1060        break;
     1061      case 'F': // failed disks
     1062        raidlist->el[raidlist->entries].failed_disks.el[raidlist->el[raidlist->entries].failed_disks.entries].index = atoi(pos + 1);
     1063        asprintf(&strtmp,"%s%s", device_prefix, token);
     1064        strcpy(raidlist->el[raidlist->entries].failed_disks.el[raidlist->el[raidlist->entries].failed_disks.entries].device, strtmp);
     1065        paranoid_free(strtmp);
     1066        raidlist->el[raidlist->entries].failed_disks.entries++;
     1067        log_it("At least one failed disk found in RAID array.\n");
     1068        break;
     1069      default: // error
     1070        log_msg(1, "Unknown device type '%c'\n", type);
     1071        paranoid_free(string);
     1072        paranoid_free(token);
     1073        return 1;
     1074        break;
     1075      }
     1076      paranoid_free(token);
     1077    }
     1078
     1079    // adjust index for each device so that it starts with 0 for every type
     1080    index_min = 99;
     1081    for (i=0; i<raidlist->el[raidlist->entries].data_disks.entries;i++) {
     1082      if (raidlist->el[raidlist->entries].data_disks.el[i].index < index_min) {
     1083        index_min = raidlist->el[raidlist->entries].data_disks.el[i].index;
     1084      }
     1085    }
     1086    if (index_min > 0) {
     1087      for (i=0; i<raidlist->el[raidlist->entries].data_disks.entries;i++) {
     1088        raidlist->el[raidlist->entries].data_disks.el[i].index = raidlist->el[raidlist->entries].data_disks.el[i].index - index_min;   
     1089      }
     1090    }
     1091    index_min = 99;
     1092    for (i=0; i<raidlist->el[raidlist->entries].spare_disks.entries;i++) {
     1093      if (raidlist->el[raidlist->entries].spare_disks.el[i].index < index_min) {
     1094        index_min = raidlist->el[raidlist->entries].spare_disks.el[i].index;
     1095      }
     1096    }
     1097    if (index_min > 0) {
     1098      for (i=0; i<raidlist->el[raidlist->entries].spare_disks.entries;i++) {
     1099        raidlist->el[raidlist->entries].spare_disks.el[i].index = raidlist->el[raidlist->entries].spare_disks.el[i].index - index_min; 
     1100      }
     1101    }
     1102    index_min = 99;
     1103    for (i=0; i<raidlist->el[raidlist->entries].failed_disks.entries;i++) {
     1104      if (raidlist->el[raidlist->entries].failed_disks.el[i].index < index_min) {
     1105        index_min = raidlist->el[raidlist->entries].failed_disks.el[i].index;
     1106      }
     1107    }
     1108    if (index_min > 0) {
     1109      for (i=0; i<raidlist->el[raidlist->entries].failed_disks.entries;i++) {
     1110        raidlist->el[raidlist->entries].failed_disks.el[i].index = raidlist->el[raidlist->entries].failed_disks.el[i].index - index_min;   
     1111      }
     1112    }
     1113    break;
     1114      case 2:  // config information
     1115    // check for persistent super block
     1116    if (strcasestr(string, "super non-persistent")) {
     1117      raidlist->el[raidlist->entries].persistent_superblock = 0;
     1118    } else {
     1119      raidlist->el[raidlist->entries].persistent_superblock = 1;
     1120    }
     1121    // extract chunk size
     1122    if (!(pos = strcasestr(string, "k chunk"))) {
     1123      raidlist->el[raidlist->entries].chunk_size = -1;
     1124    } else {
     1125      while (*pos != ' ') {
     1126        *pos--;
     1127        if (pos < string) {
     1128          log_it("String underflow!\n");
     1129          paranoid_free(string);
     1130          return 1;
     1131        }
     1132      }
     1133      raidlist->el[raidlist->entries].chunk_size = atoi(pos + 1);
     1134    }
     1135    // extract parity if present
     1136    if ((pos = strcasestr(string, "algorithm"))) {
     1137      raidlist->el[raidlist->entries].parity = atoi(pos + 9);
     1138    } else {
     1139      raidlist->el[raidlist->entries].parity = -1;
     1140    }
     1141    break;
     1142      case 3:  // optional build status information
     1143    if (!(pos = strchr(string, '\%'))) {
     1144      if (strcasestr(string, "delayed")) {
     1145        raidlist->el[raidlist->entries].progress = -1;  // delayed (therefore, stuck at 0%)
     1146      } else {
     1147        raidlist->el[raidlist->entries].progress = 999; // not found
     1148      }
     1149    } else {
     1150      while (*pos != ' ') {
     1151        *pos--;
     1152        if (pos < string) {
     1153          printf("ERROR: String underflow!\n");
     1154          paranoid_free(string);
     1155          return 1;
     1156        }
     1157      }
     1158      raidlist->el[raidlist->entries].progress = atoi(pos);
     1159    }
     1160    break;
     1161      default: // error
     1162    log_msg(1, "Row %d should not occur in record!\n", row);
     1163    break;
     1164      }
     1165      row++;
     1166    }
     1167  }
     1168  // close file
     1169  fclose(fin);
     1170  // free string
     1171  paranoid_free(string);
     1172  // return success
     1173  return 0;
     1174
     1175}
     1176
     1177
     1178
     1179
     1180int create_raidtab_from_mdstat(char *raidtab_fname)
     1181{
     1182    struct raidlist_itself *raidlist;
     1183    int retval = 0;
     1184
     1185    raidlist = malloc(sizeof(struct raidlist_itself));
     1186
     1187    // FIXME: Prefix '/dev/' should really be dynamic!
     1188    if (parse_mdstat(raidlist, "/dev/")) {
     1189        log_to_screen("Sorry, cannot read %s", MDSTAT_FILE);
    9131190        return (1);
    9141191    }
    915     mdstat->entries = 0;
    916     for (getline(&incoming, &n, fin); !feof(fin);
    917          getline(&incoming, &n, fin)) {
    918         p = incoming;
    919         if (*p != 'm' && *(p + 1) == 'm') {
    920             p++;
    921         }
    922         if (strncmp(p, "md", 2)) {
    923             continue;
    924         }
    925 // read first line --- mdN : active raidX ............
    926         mdstat->el[mdstat->entries].md = atoi(p + 2);
    927         log_msg(8, "Storing /dev/md%d's info", atoi(p + 2));
    928         while (*p != ':' && *p) {
    929             p++;
    930         }
    931         while ((*p != 'r' || *(p + 1) != 'a') && *p) {
    932             p++;
    933         }
    934         if (!strncmp(p, "raid", 4)) {
    935             mdstat->el[mdstat->entries].raidlevel = *(p + 4) - '0';
    936         }
    937         p += 4;
    938         while (*p != ' ' && *p) {
    939             p++;
    940         }
    941         while (*p == ' ' && *p) {
    942             p++;
    943         }
    944         for (diskno = 0; *p; diskno++) {
    945             asprintf(&stub, "%s", p);
    946             q = strchr(stub, '[');
    947             if (q) {
    948                 *q = '\0';
    949                 q++;
    950                 r = strchr(q, ']');
    951                 if (r) {
    952                     *r = '\0';
    953                 }
    954                 mdstat->el[mdstat->entries].disks.el[diskno].index =
    955                     atoi(q);
    956             } else {
    957                 mdstat->el[mdstat->entries].disks.el[diskno].index = -1;
    958                 q = strchr(stub, ' ');
    959                 if (q) {
    960                     *q = '\0';
    961                 }
    962             }
    963             asprintf(&tmp, "/dev/%s", stub);
    964             paranoid_free(stub);
    965 
    966             log_msg(8, "/dev/md%d : disk#%d : %s (%d)",
    967                     mdstat->el[mdstat->entries].md, diskno, tmp,
    968                     mdstat->el[mdstat->entries].disks.el[diskno].index);
    969             strcpy(mdstat->el[mdstat->entries].disks.el[diskno].device,
    970                    tmp);
    971             paranoid_free(tmp);
    972 
    973             while (*p != ' ' && *p) {
    974                 p++;
    975             }
    976             while (*p == ' ' && *p) {
    977                 p++;
    978             }
    979         }
    980         mdstat->el[mdstat->entries].disks.entries = diskno;
    981 // next line --- skip it
    982         if (!feof(fin)) {
    983             getline(&incoming, &n, fin);
    984         } else {
    985             continue;
    986         }
    987 // next line --- the 'progress' line
    988         if (!feof(fin)) {
    989             getline(&incoming, &n, fin);
    990         } else {
    991             continue;
    992         }
    993 //  log_msg(1, "Percentage line = '%s'", incoming);
    994         if (!(p = strchr(incoming, '\%'))) {
    995             mdstat->el[mdstat->entries].progress = 999; // not found
    996         } else if (strstr(incoming, "DELAYED")) {
    997             mdstat->el[mdstat->entries].progress = -1;  // delayed (therefore, stuck at 0%)
    998         } else {
    999             for (*p = '\0'; *p != ' '; p--);
    1000             mdstat->el[mdstat->entries].progress = atoi(p);
    1001         }
    1002         log_msg(8, "progress =%d", mdstat->el[mdstat->entries].progress);
    1003         mdstat->entries++;
    1004     }
    1005     fclose(fin);
    1006     paranoid_free(incoming);
    1007     return (0);
    1008 }
    1009 
    1010 
    1011 
    1012 int create_raidtab_from_mdstat(char *raidtab_fname, char *mdstat_fname)
    1013 {
    1014     struct raidlist_itself *raidlist;
    1015     struct s_mdstat *mdstat;
    1016     int retval = 0;
    1017     int i;
    1018 
    1019     raidlist = malloc(sizeof(struct raidlist_itself));
    1020     mdstat = malloc(sizeof(struct s_mdstat));
    1021 
    1022     if (read_mdstat(mdstat, mdstat_fname)) {
    1023         log_to_screen("Sorry, cannot read %s", mdstat_fname);
    1024         return (1);
    1025     }
    1026 
    1027     for (i = 0; i < mdstat->entries; i++) {
    1028         sprintf(raidlist->el[i].raid_device, "/dev/md%d",
    1029                 mdstat->el[i].md);
    1030         raidlist->el[i].raid_level = mdstat->el[i].raidlevel;
    1031         raidlist->el[i].persistent_superblock = 1;
    1032         raidlist->el[i].chunk_size = 4;
    1033         memcpy((void *) &raidlist->el[i].data_disks,
    1034                (void *) &mdstat->el[i].disks,
    1035                sizeof(struct list_of_disks));
    1036         // FIXME --- the above line does not allow for spare disks
    1037         log_to_screen
    1038             (_("FIXME - create_raidtab_from_mdstat does not allow for spare disks"));
    1039     }
    1040     raidlist->entries = i;
     1192
    10411193    retval += save_raidlist_to_raidtab(raidlist, raidtab_fname);
    10421194    return (retval);
Note: See TracChangeset for help on using the changeset viewer.