diff options
author | Thierry Deval <tdeval@cvs.openbsd.org> | 2002-02-17 20:23:38 +0000 |
---|---|---|
committer | Thierry Deval <tdeval@cvs.openbsd.org> | 2002-02-17 20:23:38 +0000 |
commit | e493ca639b9386fb7189b278268b60cb6669612f (patch) | |
tree | 84941fc11625a2f0f420ec7d8bc6299f0bc11da8 /sbin/raidctl | |
parent | 66af7f635bac24fb1060e7694a6d1049f56675b1 (diff) |
raidctl can do some actions on 'all' configured raids now :
-B : CopyBack
-G : Generate config
-i : Initialize
-p : Check parity
-P : Check and re-write parity
-s : Status
-S : Progress status
-u : Unconfigure
Diffstat (limited to 'sbin/raidctl')
-rw-r--r-- | sbin/raidctl/raidctl.8 | 51 | ||||
-rw-r--r-- | sbin/raidctl/raidctl.c | 820 |
2 files changed, 540 insertions, 331 deletions
diff --git a/sbin/raidctl/raidctl.8 b/sbin/raidctl/raidctl.8 index a466ca9e6c2..75306db11c5 100644 --- a/sbin/raidctl/raidctl.8 +++ b/sbin/raidctl/raidctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: raidctl.8,v 1.21 2002/02/11 18:43:51 mpech Exp $ +.\" $OpenBSD: raidctl.8,v 1.22 2002/02/17 20:23:36 tdeval Exp $ .\" $NetBSD: raidctl.8,v 1.24 2001/07/10 01:30:52 lukem Exp $ .\" .\" Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -75,9 +75,9 @@ .Op Fl v .Fl A Op yes | no | root .Ar dev -.Nm raifctl +.Nm raidctl .Op Fl v -.Fl B Ar dev +.Fl B Ar dev | Ic all .Nm raidctl .Op Fl v .Fl c Ar config_file Ar dev @@ -95,19 +95,19 @@ .Fl g Ar component Ar dev .Nm raidctl .Op Fl v -.Fl G Ar dev +.Fl G Ar dev | Ic all .Nm raidctl .Op Fl v -.Fl i Ar dev +.Fl i Ar dev | Ic all .Nm raidctl .Op Fl v .Fl I Ar serial_number Ar dev .Nm raidctl .Op Fl v -.Fl p Ar dev +.Fl p Ar dev | Ic all .Nm raidctl .Op Fl v -.Fl P Ar dev +.Fl P Ar dev | Ic all .Nm raidctl .Op Fl v .Fl r Ar component Ar dev @@ -116,13 +116,13 @@ .Fl R Ar component Ar dev .Nm raidctl .Op Fl v -.Fl s Ar dev +.Fl s Ar dev | Ic all .Nm raidctl .Op Fl v -.Fl S Ar dev +.Fl S Ar dev | Ic all .Nm raidctl .Op Fl v -.Fl u Ar dev +.Fl u Ar dev | Ic all .Sh DESCRIPTION .Nm is the user-land control program for @@ -162,7 +162,7 @@ will the use of the boot disk as the root device. All components of the set must be of type RAID in the disklabel. Note that the kernel being booted must currently reside on a non-RAID set. -.It Fl B Ar dev +.It Fl B Ar dev | Ic all Initiate a copyback of reconstructed data from a spare disk to its original disk. This is performed after a component has failed, and the failed drive has been reconstructed onto a spare drive. @@ -192,14 +192,14 @@ disk onto an available hot spare. This is one of the mechanisms used to start the reconstruction process if a component does have a hardware failure. .It Fl g Ar component Ar dev Get the component label for the specified component. -.It Fl G Ar dev +.It Fl G Ar dev | Ic all Generate the configuration of the RAIDframe device in a format suitable for use with .Nm .Fl c or .Fl C . -.It Fl i Ar dev +.It Fl i Ar dev | Ic all Initialize the RAID device. In particular, (re-write) the parity on the selected device. This .Ar MUST @@ -216,10 +216,10 @@ strictly enforced, different serial numbers should be used for different RAID sets. This step .Ar MUST be performed when a new RAID set is created. -.It Fl p Ar dev +.It Fl p Ar dev | Ic all Check the status of the parity on the RAID set. Displays a status message, and returns successfully if the parity is up-to-date. -.It Fl P Ar dev +.It Fl P Ar dev | Ic all Check the status of the parity on the RAID set, and initialize (re-write) the parity if the parity is not known to be up-to-date. This is normally used after a system crash (and before a @@ -236,14 +236,14 @@ if necessary, and immediately begins a reconstruction back to .Ar component . This is useful for reconstructing back onto a component after it has been replaced following a failure. -.It Fl s Ar dev +.It Fl s Ar dev | Ic all Display the status of the RAIDframe device for each of the components and spares. -.It Fl S Ar dev +.It Fl S Ar dev | Ic all Check the status of parity re-writing, component reconstruction, and component copyback. The output indicates the amount of progress achieved in each of these areas. -.It Fl u Ar dev +.It Fl u Ar dev | Ic all Unconfigure the RAIDframe device. .It Fl v Be more verbose. For operations such as reconstructions, parity @@ -258,6 +258,21 @@ is specified by may be either the full name of the device, e.g. /dev/rraid0c, or just simply raid0 (for /dev/rraid0c). .Pp +For several commands, +.Nm +can accept the word +.Ic all +as the +.Ar dev +argument. +If +.Ic all +is used, +.Nm +will execute the requested action for all the configured +.Xr raid 4 +devices. +.Pp .Ss Configuration file The format of the configuration file is complex, and only an abbreviated treatment is given here. In the configuration diff --git a/sbin/raidctl/raidctl.c b/sbin/raidctl/raidctl.c index 5a769713b12..bbbd6153881 100644 --- a/sbin/raidctl/raidctl.c +++ b/sbin/raidctl/raidctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: raidctl.c,v 1.9 2002/02/16 21:27:37 millert Exp $ */ +/* $OpenBSD: raidctl.c,v 1.10 2002/02/17 20:23:37 tdeval Exp $ */ /* $NetBSD: raidctl.c,v 1.27 2001/07/10 01:30:52 lukem Exp $ */ /*- @@ -48,6 +48,7 @@ #include <sys/param.h> #include <sys/ioctl.h> #include <sys/stat.h> +#include <sys/sysctl.h> #ifdef NETBSD #include <sys/disklabel.h> #endif @@ -67,29 +68,37 @@ extern char *__progname; +typedef struct { + int fd; + int id; +} fdidpair; + int main(int, char *[]); void do_ioctl(int, u_long, void *, const char *); -static void rf_configure(int, char*, int); +static void rf_configure(fdidpair *, char*, int); static const char *device_status(RF_DiskStatus_t); -static void rf_get_device_status(int); -static void rf_output_configuration(int, const char *); -static void get_component_number(int, char *, int *, int *); -static void rf_fail_disk(int, char *, int); +static void rf_get_device_status(fdidpair *, int); +static void rf_output_configuration(fdidpair *, int); +static void get_component_number(fdidpair *, char *, int *, int *); +static void rf_fail_disk(fdidpair *, char *, int); static void usage(void); -static void get_component_label(int, char *); -static void set_component_label(int, char *); -static void init_component_labels(int, int); -static void set_autoconfig(int, int, char *); -static void add_hot_spare(int, char *); -static void remove_hot_spare(int, char *); -static void rebuild_in_place(int, char *); -static void check_status(int,int); -static void check_parity(int,int,char *); -static void do_meter(int, u_long); +static void get_component_label(fdidpair *, char *); +static void set_component_label(fdidpair *, char *); +static void init_component_labels(fdidpair *, int); +static void set_autoconfig(fdidpair *, char *); +static void add_hot_spare(fdidpair *, char *); +static void remove_hot_spare(fdidpair *, char *); +static void rebuild_in_place(fdidpair *, char *); +static void check_status(fdidpair *,int,int); +static void check_parity(fdidpair *,int,int); +static void do_meter(fdidpair *, int, u_long); static void get_bar(char *, double, int); static void get_time_string(char *, int); +static int open_device(fdidpair **, char *); +static int get_all_devices(char ***, const char *); int verbose; +int do_all; int main(argc, argv) @@ -100,25 +109,28 @@ main(argc, argv) int num_options; unsigned long action; char config_filename[PATH_MAX]; - char dev_name[PATH_MAX]; char name[PATH_MAX]; char component[PATH_MAX]; char autoconf[10]; int do_output; int do_recon; int do_rewrite; - int raidID; int serial_number; struct stat st; - int fd; + int i, nfd; + fdidpair *fds; int force; int rawpart; + u_long meter; + const char *actionstr; num_options = 0; action = 0; + meter = 0; do_output = 0; do_recon = 0; do_rewrite = 0; + do_all = 0; force = 0; while ((ch = getopt(argc, argv, "a:A:Bc:C:f:F:g:GiI:l:r:R:sSpPuv")) @@ -231,97 +243,106 @@ main(argc, argv) strlcpy(name, argv[0], PATH_MAX); - if ((name[0] == '/') || (name[0] == '.')) { - /* they've (apparently) given a full path... */ - strlcpy(dev_name, name, PATH_MAX); - } else { - if (isdigit(name[strlen(name) - 1])) { - rawpart = getrawpartition(); - snprintf(dev_name, PATH_MAX, "%s%s%c", _PATH_DEV, - name, 'a' + rawpart); - } else { - snprintf(dev_name, PATH_MAX, "%s%s", _PATH_DEV, name); + nfd = open_device(&fds, name); + if (do_all) { + switch(action) { + case RAIDFRAME_ADD_HOT_SPARE: + case RAIDFRAME_REMOVE_HOT_SPARE: + case RAIDFRAME_CONFIGURE: + case RAIDFRAME_SET_AUTOCONFIG: + case RAIDFRAME_FAIL_DISK: + case RAIDFRAME_SET_COMPONENT_LABEL: + case RAIDFRAME_GET_COMPONENT_LABEL: + case RAIDFRAME_INIT_LABELS: + case RAIDFRAME_REBUILD_IN_PLACE: + errx(1, + "This action doesn't work with the 'all' device"); + break; + default: + break; } - } - - if (stat(dev_name, &st) != 0) - errx(errno, "stat failure on: %s", dev_name); - if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) - errx(EINVAL, "invalid device: %s", dev_name); - - raidID = RF_DEV2RAIDID(st.st_rdev); - - if ((fd = open(dev_name, O_RDWR, 0640)) < 0) - errx(1, "unable to open device file: %s", dev_name); - + } switch(action) { case RAIDFRAME_ADD_HOT_SPARE: - add_hot_spare(fd, component); + add_hot_spare(fds, component); break; case RAIDFRAME_REMOVE_HOT_SPARE: - remove_hot_spare(fd, component); + remove_hot_spare(fds, component); break; case RAIDFRAME_CONFIGURE: - rf_configure(fd, config_filename, force); + rf_configure(fds, config_filename, force); break; case RAIDFRAME_SET_AUTOCONFIG: - set_autoconfig(fd, raidID, autoconf); + set_autoconfig(fds, autoconf); break; case RAIDFRAME_COPYBACK: - printf("Copyback.\n"); - do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK"); - if (verbose) { - sleep(3); /* XXX give the copyback a chance to start */ - printf("Copyback status:\n"); - do_meter(fd, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); + i = nfd; + while (i--) { + do_ioctl(fds[i].fd, RAIDFRAME_COPYBACK, NULL, + "RAIDFRAME_COPYBACK"); } + actionstr = "Copyback"; + meter = RAIDFRAME_CHECK_COPYBACK_STATUS_EXT; break; case RAIDFRAME_FAIL_DISK: - rf_fail_disk(fd, component, do_recon); + rf_fail_disk(fds, component, do_recon); break; case RAIDFRAME_SET_COMPONENT_LABEL: - set_component_label(fd, component); + set_component_label(fds, component); break; case RAIDFRAME_GET_COMPONENT_LABEL: - get_component_label(fd, component); + get_component_label(fds, component); break; case RAIDFRAME_INIT_LABELS: - init_component_labels(fd, serial_number); + init_component_labels(fds, serial_number); break; case RAIDFRAME_REWRITEPARITY: - printf("Initiating re-write of parity\n"); - do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, - "RAIDFRAME_REWRITEPARITY"); - if (verbose) { - sleep(3); /* XXX give it time to get started */ - printf("Parity Re-write status:\n"); - do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); + i = nfd; + while (i--) { + do_ioctl(fds[i].fd, RAIDFRAME_REWRITEPARITY, NULL, + "RAIDFRAME_REWRITEPARITY"); } + actionstr = "Parity Re-Write"; + meter = RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT; break; case RAIDFRAME_CHECK_RECON_STATUS_EXT: - check_status(fd, 1); + check_status(fds, nfd, 1); break; case RAIDFRAME_GET_INFO: if (do_output) - rf_output_configuration(fd, dev_name); + rf_output_configuration(fds, nfd); else - rf_get_device_status(fd); + rf_get_device_status(fds, nfd); break; case RAIDFRAME_REBUILD_IN_PLACE: - rebuild_in_place(fd, component); + rebuild_in_place(fds, component); break; case RAIDFRAME_CHECK_PARITY: - check_parity(fd, do_rewrite, dev_name); + check_parity(fds, nfd, do_rewrite); break; case RAIDFRAME_SHUTDOWN: - do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN"); + i = nfd; + while (i--) { + do_ioctl(fds[i].fd, RAIDFRAME_SHUTDOWN, NULL, + "RAIDFRAME_SHUTDOWN"); + } break; default: break; } - close(fd); + if (verbose && meter) { + sleep(3); /* XXX give the action a chance to start */ + printf("%s status:\n", actionstr); + do_meter(fds, nfd, meter); + } + + i = nfd; + while (i--) + close(fds[i].fd); + + free(fds); return (0); } @@ -338,8 +359,8 @@ do_ioctl(fd, command, arg, ioctl_name) static void -rf_configure(fd, config_file, force) - int fd; +rf_configure(fds, config_file, force) + fdidpair *fds; char *config_file; int force; { @@ -358,7 +379,7 @@ rf_configure(fd, config_file, force) */ generic = (void *) &cfg; - do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE"); + do_ioctl(fds->fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE"); } static const char * @@ -388,143 +409,160 @@ device_status(status) } static void -rf_get_device_status(fd) - int fd; +rf_get_device_status(fds, nfd) + fdidpair *fds; + int nfd; { RF_DeviceConfig_t device_config; void *cfg_ptr; int is_clean; - int i; + int i,j; cfg_ptr = &device_config; - do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); + i = nfd; + while (i--) { + do_ioctl(fds[i].fd, RAIDFRAME_GET_INFO, &cfg_ptr, + "RAIDFRAME_GET_INFO"); - printf("Components:\n"); - for (i = 0; i < device_config.ndevs; i++) { - printf("%20s: %s\n", device_config.devs[i].devname, - device_status(device_config.devs[i].status)); - } - if (device_config.nspares > 0) { - printf("Spares:\n"); - for (i = 0; i < device_config.nspares; i++) { - printf("%20s: %s\n", - device_config.spares[i].devname, - device_status(device_config.spares[i].status)); + printf("raid%d Components:\n", fds[i].id); + for (j = 0; j < device_config.ndevs; j++) { + printf("%20s: %s\n", device_config.devs[j].devname, + device_status(device_config.devs[j].status)); } - } else { - printf("No spares.\n"); - } - if (verbose) { - for(i=0; i < device_config.ndevs; i++) { - if (device_config.devs[i].status == rf_ds_optimal) { - get_component_label(fd, - device_config.devs[i].devname); - } else { - printf("%s status is: %s. Skipping label.\n", - device_config.devs[i].devname, - device_status(device_config.devs[i].status)); + if (device_config.nspares > 0) { + printf("Spares:\n"); + for (j = 0; j < device_config.nspares; i++) { + printf("%20s: %s\n", + device_config.spares[j].devname, + device_status(device_config.spares[j].status)); } + } else { + printf("No spares.\n"); } - - if (device_config.nspares > 0) { - for(i=0; i < device_config.nspares; i++) { - if ((device_config.spares[i].status == - rf_ds_optimal) || - (device_config.spares[i].status == - rf_ds_used_spare)) { - get_component_label(fd, - device_config.spares[i].devname); + if (verbose) { + for(j=0; j < device_config.ndevs; j++) { + if (device_config.devs[j].status == + rf_ds_optimal) { + get_component_label(&fds[i], + device_config.devs[j].devname); } else { - printf("%s status is: %s. Skipping label.\n", - device_config.spares[i].devname, - device_status(device_config.spares[i].status)); - } + printf("%s status is: %s. " + "Skipping label.\n", + device_config.devs[j].devname, + device_status(device_config.devs[j].status)); + } + } + + if (device_config.nspares > 0) { + for(j=0; j < device_config.nspares; j++) { + if ((device_config.spares[j].status == + rf_ds_optimal) || + (device_config.spares[j].status == + rf_ds_used_spare)) { + get_component_label(&fds[i], + device_config.spares[j].devname); + } else { + printf("%s status is: %s. " + "Skipping label.\n", + device_config.spares[j].devname, + device_status(device_config.spares[j].status)); + } + } } } - } - do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, - "RAIDFRAME_CHECK_PARITY"); - if (is_clean) { - printf("Parity status: clean\n"); - } else { - printf("Parity status: DIRTY\n"); + do_ioctl(fds[i].fd, RAIDFRAME_CHECK_PARITY, &is_clean, + "RAIDFRAME_CHECK_PARITY"); + if (is_clean) { + printf("Parity status: clean\n"); + } else { + printf("Parity status: DIRTY\n"); + } + check_status(&fds[i], 1, 0); } - check_status(fd, 0); } static void -rf_output_configuration(fd, name) - int fd; - const char *name; +rf_output_configuration(fds, nfd) + fdidpair *fds; + int nfd; { RF_DeviceConfig_t device_config; void *cfg_ptr; - int i; + int i,j; RF_ComponentLabel_t component_label; void *label_ptr; int component_num; int num_cols; + char name[PATH_MAX]; cfg_ptr = &device_config; - printf("# raidctl config file for %s\n", name); - printf("\n"); - do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); + i = nfd; + while (i--) { + snprintf(name, PATH_MAX, "/dev/raid%dc", fds[i].id); - printf("START array\n"); - printf("# numRow numCol numSpare\n"); - printf("%d %d %d\n", device_config.rows, device_config.cols, - device_config.nspares); - printf("\n"); + printf("# raidctl config file for %s\n", name); + printf("\n"); + do_ioctl(fds[i].fd, RAIDFRAME_GET_INFO, &cfg_ptr, + "RAIDFRAME_GET_INFO"); - printf("START disks\n"); - for(i = 0; i < device_config.ndevs; i++) - printf("%s\n", device_config.devs[i].devname); - printf("\n"); + printf("START array\n"); + printf("# numRow numCol numSpare\n"); + printf("%d %d %d\n", device_config.rows, device_config.cols, + device_config.nspares); + printf("\n"); - if (device_config.nspares > 0) { - printf("START spare\n"); - for(i = 0; i < device_config.nspares; i++) - printf("%s\n", device_config.spares[i].devname); + printf("START disks\n"); + for(j = 0; j < device_config.ndevs; j++) + printf("%s\n", device_config.devs[j].devname); printf("\n"); - } - for(i = 0; i < device_config.ndevs; i++) { - if (device_config.devs[i].status == rf_ds_optimal) - break; - } - if (i == device_config.ndevs) { - printf("# WARNING: no optimal components; using %s\n", - device_config.devs[0].devname); - i = 0; - } - get_component_number(fd, device_config.devs[i].devname, - &component_num, &num_cols); - memset(&component_label, 0, sizeof(RF_ComponentLabel_t)); - component_label.row = component_num / num_cols; - component_label.column = component_num % num_cols; - label_ptr = &component_label; - do_ioctl(fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, - "RAIDFRAME_GET_COMPONENT_LABEL"); + if (device_config.nspares > 0) { + printf("START spare\n"); + for(j = 0; j < device_config.nspares; j++) + printf("%s\n", device_config.spares[j].devname); + printf("\n"); + } - printf("START layout\n"); - printf( - "# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level_%c\n", - (char) component_label.parityConfig); - printf("%d %d %d %c\n", - component_label.sectPerSU, component_label.SUsPerPU, - component_label.SUsPerRU, (char) component_label.parityConfig); - printf("\n"); + for(j = 0; j < device_config.ndevs; j++) { + if (device_config.devs[j].status == rf_ds_optimal) + break; + } + if (j == device_config.ndevs) { + printf("# WARNING: no optimal components; using %s\n", + device_config.devs[0].devname); + j = 0; + } + get_component_number(&fds[i], device_config.devs[j].devname, + &component_num, &num_cols); + memset(&component_label, 0, sizeof(RF_ComponentLabel_t)); + component_label.row = component_num / num_cols; + component_label.column = component_num % num_cols; + label_ptr = &component_label; + do_ioctl(fds[i].fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, + "RAIDFRAME_GET_COMPONENT_LABEL"); + + printf("START layout\n"); + printf( + "# sectPerSU SUsPerParityUnit SUsPerReconUnit " + "RAID_level_%c\n", + (char) component_label.parityConfig); + printf("%d %d %d %c\n", + component_label.sectPerSU, component_label.SUsPerPU, + component_label.SUsPerRU, + (char) component_label.parityConfig); + printf("\n"); - printf("START queue\n"); - printf("fifo %d\n", device_config.maxqdepth); + printf("START queue\n"); + printf("fifo %d\n", device_config.maxqdepth); + } } static void -get_component_number(fd, component_name, component_number, num_columns) - int fd; +get_component_number(fds, component_name, component_number, num_columns) + fdidpair *fds; char *component_name; int *component_number; int *num_columns; @@ -538,7 +576,7 @@ get_component_number(fd, component_name, component_number, num_columns) /* Assuming a full path spec... */ cfg_ptr = &device_config; - do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); + do_ioctl(fds->fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); *num_columns = device_config.cols; @@ -570,8 +608,8 @@ get_component_number(fd, component_name, component_number, num_columns) } static void -rf_fail_disk(fd, component_to_fail, do_recon) - int fd; +rf_fail_disk(fds, component_to_fail, do_recon) + fdidpair *fds; char *component_to_fail; int do_recon; { @@ -579,7 +617,7 @@ rf_fail_disk(fd, component_to_fail, do_recon) int component_num; int num_cols; - get_component_number(fd, component_to_fail, &component_num, &num_cols); + get_component_number(fds, component_to_fail, &component_num, &num_cols); recon_request.row = component_num / num_cols; recon_request.col = component_num % num_cols; @@ -588,18 +626,18 @@ rf_fail_disk(fd, component_to_fail, do_recon) } else { recon_request.flags = RF_FDFLAGS_NONE; } - do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request, + do_ioctl(fds->fd, RAIDFRAME_FAIL_DISK, &recon_request, "RAIDFRAME_FAIL_DISK"); if (do_recon && verbose) { printf("Reconstruction status:\n"); sleep(3); /* XXX give reconstruction a chance to start */ - do_meter(fd, RAIDFRAME_CHECK_RECON_STATUS_EXT); + do_meter(fds, 1, RAIDFRAME_CHECK_RECON_STATUS_EXT); } } static void -get_component_label(fd, component) - int fd; +get_component_label(fds, component) + fdidpair *fds; char *component; { RF_ComponentLabel_t component_label; @@ -607,14 +645,14 @@ get_component_label(fd, component) int component_num; int num_cols; - get_component_number(fd, component, &component_num, &num_cols); + get_component_number(fds, component, &component_num, &num_cols); memset(&component_label, 0, sizeof(RF_ComponentLabel_t)); component_label.row = component_num / num_cols; component_label.column = component_num % num_cols; label_ptr = &component_label; - do_ioctl(fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, + do_ioctl(fds->fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, "RAIDFRAME_GET_COMPONENT_LABEL"); printf("Component label for %s:\n", component); @@ -643,15 +681,15 @@ get_component_label(fd, component) } static void -set_component_label(fd, component) - int fd; +set_component_label(fds, component) + fdidpair *fds; char *component; { RF_ComponentLabel_t component_label; int component_num; int num_cols; - get_component_number(fd, component, &component_num, &num_cols); + get_component_number(fds, component, &component_num, &num_cols); /* XXX This is currently here for testing, and future expandability */ @@ -665,14 +703,14 @@ set_component_label(fd, component) component_label.clean = 0; component_label.status = 1; - do_ioctl(fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label, + do_ioctl(fds->fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label, "RAIDFRAME_SET_COMPONENT_LABEL"); } static void -init_component_labels(fd, serial_number) - int fd; +init_component_labels(fds, serial_number) + fdidpair *fds; int serial_number; { RF_ComponentLabel_t component_label; @@ -687,14 +725,13 @@ init_component_labels(fd, serial_number) component_label.clean = 0; component_label.status = 0; - do_ioctl(fd, RAIDFRAME_INIT_LABELS, &component_label, + do_ioctl(fds->fd, RAIDFRAME_INIT_LABELS, &component_label, "RAIDFRAME_SET_COMPONENT_LABEL"); } static void -set_autoconfig(fd, raidID, autoconf) - int fd; - int raidID; +set_autoconfig(fds, autoconf) + fdidpair *fds; char *autoconf; { int auto_config; @@ -712,24 +749,24 @@ set_autoconfig(fd, raidID, autoconf) auto_config = 1; } - do_ioctl(fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config, + do_ioctl(fds->fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config, "RAIDFRAME_SET_AUTOCONFIG"); - do_ioctl(fd, RAIDFRAME_SET_ROOT, &root_config, + do_ioctl(fds->fd, RAIDFRAME_SET_ROOT, &root_config, "RAIDFRAME_SET_ROOT"); - printf("raid%d: Autoconfigure: %s\n", raidID, + printf("raid%d: Autoconfigure: %s\n", fds->id, auto_config ? "Yes" : "No"); if (root_config == 1) { - printf("raid%d: Root: %s\n", raidID, + printf("raid%d: Root: %s\n", fds->id, auto_config ? "Yes" : "No"); } } static void -add_hot_spare(fd, component) - int fd; +add_hot_spare(fds, component) + fdidpair *fds; char *component; { RF_SingleComponent_t hot_spare; @@ -739,20 +776,20 @@ add_hot_spare(fd, component) strlcpy(hot_spare.component_name, component, sizeof(hot_spare.component_name)); - do_ioctl(fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare, + do_ioctl(fds->fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare, "RAIDFRAME_ADD_HOT_SPARE"); } static void -remove_hot_spare(fd, component) - int fd; +remove_hot_spare(fds, component) + fdidpair *fds; char *component; { RF_SingleComponent_t hot_spare; int component_num; int num_cols; - get_component_number(fd, component, &component_num, &num_cols); + get_component_number(fds, component, &component_num, &num_cols); hot_spare.row = component_num / num_cols; hot_spare.column = component_num % num_cols; @@ -760,115 +797,159 @@ remove_hot_spare(fd, component) strlcpy(hot_spare.component_name, component, sizeof(hot_spare.component_name)); - do_ioctl(fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare, + do_ioctl(fds->fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare, "RAIDFRAME_REMOVE_HOT_SPARE"); } static void -rebuild_in_place(fd, component) - int fd; +rebuild_in_place(fds, component) + fdidpair *fds; char *component; { RF_SingleComponent_t comp; int component_num; int num_cols; - get_component_number(fd, component, &component_num, &num_cols); + get_component_number(fds, component, &component_num, &num_cols); comp.row = 0; comp.column = component_num; strlcpy(comp.component_name, component, sizeof(comp.component_name)); - do_ioctl(fd, RAIDFRAME_REBUILD_IN_PLACE, &comp, + do_ioctl(fds->fd, RAIDFRAME_REBUILD_IN_PLACE, &comp, "RAIDFRAME_REBUILD_IN_PLACE"); if (verbose) { printf("Reconstruction status:\n"); sleep(3); /* XXX give reconstruction a chance to start */ - do_meter(fd, RAIDFRAME_CHECK_RECON_STATUS_EXT); + do_meter(fds, 1, RAIDFRAME_CHECK_RECON_STATUS_EXT); } } static void -check_parity(fd, do_rewrite, dev_name) - int fd; +check_parity(fds, nfd, do_rewrite) + fdidpair *fds; + int nfd; int do_rewrite; - char *dev_name; { - int is_clean; + int i, is_clean, all_dirty; int percent_done; + char dev_name[PATH_MAX]; - is_clean = 0; - percent_done = 0; - do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, - "RAIDFRAME_CHECK_PARITY"); - if (is_clean) { - printf("%s: Parity status: clean\n", dev_name); - } else { - printf("%s: Parity status: DIRTY\n", dev_name); - if (do_rewrite) { - printf("%s: Initiating re-write of parity\n", - dev_name); - do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, - "RAIDFRAME_REWRITEPARITY"); - sleep(3); /* XXX give it time to get started. */ - if (verbose) { - printf("Parity Re-write status:\n"); - do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); + all_dirty = 0; + i = nfd; + while (i--) { + is_clean = 0; + percent_done = 0; + snprintf(dev_name, PATH_MAX, "raid%d", fds[i].id); + + do_ioctl(fds[i].fd, RAIDFRAME_CHECK_PARITY, &is_clean, + "RAIDFRAME_CHECK_PARITY"); + if (is_clean) { + printf("%s: Parity status: clean\n", dev_name); + } else { + all_dirty |= 1 << fds[i].id; + printf("%s: Parity status: DIRTY\n", dev_name); + if (do_rewrite) { + printf("%s: Initiating re-write of parity\n", + dev_name); + do_ioctl(fds[i].fd, RAIDFRAME_REWRITEPARITY, + NULL, "RAIDFRAME_REWRITEPARITY"); } else { - do_ioctl(fd, - RAIDFRAME_CHECK_PARITYREWRITE_STATUS, - &percent_done, - "RAIDFRAME_CHECK_PARITYREWRITE_STATUS" - ); - while (percent_done < 100) { - sleep(3); /* wait a bit... */ - do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, - &percent_done, "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); - } - + /* parity is wrong, and is not being fixed. */ + exit(1); } - printf("%s: Parity Re-write complete\n", dev_name); + } + } + + if (do_all) + strncpy(dev_name, "all raid", PATH_MAX); + + while (all_dirty) { + sleep(3); /* wait a bit... */ + if (verbose) { + printf("Parity Re-write status:\n"); + do_meter(fds, nfd, + RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); + all_dirty = 0; } else { - /* parity is wrong, and is not being fixed. */ - exit(1); + i = nfd; + while (i--) { + do_ioctl(fds[i].fd, + RAIDFRAME_CHECK_PARITYREWRITE_STATUS, + &percent_done, + "RAIDFRAME_CHECK_PARITYREWRITE_STATUS" + ); + if (percent_done == 100) { + all_dirty &= ~(1 << fds[i].id); + } + } } } + printf("%s: Parity Re-write complete\n", dev_name); } static void -check_status(fd, meter) - int fd; +check_status(fds, nfd, meter) + fdidpair *fds; + int nfd; int meter; { + int i; int recon_percent_done = 0; int parity_percent_done = 0; int copyback_percent_done = 0; + int do_recon = 0; + int do_parity = 0; + int do_copyback = 0; + + i = nfd; + while (i--) { + if (meter) { + printf("raid%d Status:\n", fds[i].id); + } + do_ioctl(fds[i].fd, RAIDFRAME_CHECK_RECON_STATUS, + &recon_percent_done, + "RAIDFRAME_CHECK_RECON_STATUS"); + printf("Reconstruction is %d%% complete.\n", + recon_percent_done); + if (recon_percent_done < 100) { + do_recon |= 1 << fds[i].id; + } + do_ioctl(fds[i].fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, + &parity_percent_done, + "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); + printf("Parity Re-write is %d%% complete.\n", + parity_percent_done); + if (parity_percent_done < 100) { + do_parity |= 1 << fds[i].id; + } + do_ioctl(fds[i].fd, RAIDFRAME_CHECK_COPYBACK_STATUS, + ©back_percent_done, + "RAIDFRAME_CHECK_COPYBACK_STATUS"); + printf("Copyback is %d%% complete.\n", + copyback_percent_done); + if (copyback_percent_done < 100) { + do_copyback |= 1 << fds[i].id; + } + } - do_ioctl(fd, RAIDFRAME_CHECK_RECON_STATUS, &recon_percent_done, - "RAIDFRAME_CHECK_RECON_STATUS"); - printf("Reconstruction is %d%% complete.\n", recon_percent_done); - do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, - &parity_percent_done, - "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); - printf("Parity Re-write is %d%% complete.\n", parity_percent_done); - do_ioctl(fd, RAIDFRAME_CHECK_COPYBACK_STATUS, ©back_percent_done, - "RAIDFRAME_CHECK_COPYBACK_STATUS"); - printf("Copyback is %d%% complete.\n", copyback_percent_done); - - if (meter) { - /* These 3 should be mutually exclusive at this point */ - if (recon_percent_done < 100) { - printf("Reconstruction status:\n"); - do_meter(fd, RAIDFRAME_CHECK_RECON_STATUS_EXT); - } else if (parity_percent_done < 100) { - printf("Parity Re-write status:\n"); - do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); - } else if (copyback_percent_done < 100) { - printf("Copyback status:\n"); - do_meter(fd, RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); + if (meter && verbose) { + /* These 3 should be mutually exclusive at this point */ + if (do_recon) { + printf("Reconstruction status:\n"); + do_meter(fds, nfd, + RAIDFRAME_CHECK_RECON_STATUS_EXT); + } else if (do_parity) { + printf("Parity Re-write status:\n"); + do_meter(fds, nfd, + RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); + } else if (do_copyback) { + printf("Copyback status:\n"); + do_meter(fds, nfd, + RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); } } } @@ -876,66 +957,91 @@ check_status(fd, meter) const char *tbits = "|/-\\"; static void -do_meter(fd, option) - int fd; +do_meter(fds, nfd, option) + fdidpair *fds; + int nfd; u_long option; { int percent_done; - int last_value; int start_value; - RF_ProgressInfo_t progressInfo; + RF_ProgressInfo_t *progressInfo; void *pInfoPtr; struct timeval start_time; struct timeval current_time; double elapsed; int elapsed_sec; int elapsed_usec; + int progress_total, progress_completed; int simple_eta, last_eta; double rate; int amount; int tbit_value; - int wait_for_more_data; char buffer[1024]; char bar_buffer[1024]; char eta_buffer[1024]; + int not_done; + int i; + + not_done = 0; + percent_done = 0; + tbit_value = 0; + start_value = 0; + progress_total = progress_completed = 0; + progressInfo = malloc(nfd * sizeof(RF_ProgressInfo_t)); + memset(&progressInfo[0], 0, nfd * sizeof(RF_ProgressInfo_t)); if (gettimeofday(&start_time, NULL)) err(1, "gettimeofday"); - memset(&progressInfo, 0, sizeof(RF_ProgressInfo_t)); - pInfoPtr = &progressInfo; - percent_done = 0; - do_ioctl(fd, option, &pInfoPtr, ""); - last_value = progressInfo.completed; - start_value = last_value; current_time = start_time; - - wait_for_more_data = 0; - tbit_value = 0; - while(progressInfo.completed < progressInfo.total) { - percent_done = (progressInfo.completed * 100) / - progressInfo.total; + i = nfd; + while (i--) { + pInfoPtr = &progressInfo[i]; + do_ioctl(fds[i].fd, option, &pInfoPtr, ""); + start_value += progressInfo[i].completed; + progress_total += progressInfo[i].total; + + if (progressInfo[i].completed < progressInfo[i].total) { + not_done |= 1 << i; + } + } + + while (not_done) { + progress_completed = 0; + percent_done = 0; + amount = 0; + + i = nfd; + while (i--) { + pInfoPtr = &progressInfo[i]; + do_ioctl(fds[i].fd, option, &pInfoPtr, ""); + progress_completed += progressInfo[i].completed; + + if (progressInfo[i].completed >= + progressInfo[i].total) { + not_done &= ~(1 << i); + } + } + percent_done = (progress_completed * 100) / progress_total; + amount = progress_completed - start_value; get_bar(bar_buffer, percent_done, 40); - - elapsed_sec = current_time.tv_sec - start_time.tv_sec; - elapsed_usec = current_time.tv_usec - start_time.tv_usec; + + elapsed_sec = current_time.tv_sec - + start_time.tv_sec; + elapsed_usec = current_time.tv_usec - + start_time.tv_usec; if (elapsed_usec < 0) { - elapsed_usec -= 1000000; - elapsed_sec++; + elapsed_usec += 1000000; + elapsed_sec--; } - + elapsed = (double) elapsed_sec + - (double) elapsed_usec / 1000000.0; - - amount = progressInfo.completed - start_value; + (double) elapsed_usec / 1000000.0; if (amount <= 0) { /* we don't do negatives (yet?) */ amount = 0; - wait_for_more_data = 1; - } else { - wait_for_more_data = 0; } if (elapsed == 0) @@ -944,9 +1050,10 @@ do_meter(fd, option) rate = amount / elapsed; if (rate > 0.0) { - simple_eta = (int) (((double)progressInfo.total - - (double) progressInfo.completed) - / rate); + simple_eta = (int) + (((double)progress_total - + (double) progress_completed) + / rate); } else { simple_eta = -1; } @@ -959,34 +1066,26 @@ do_meter(fd, option) get_time_string(eta_buffer, simple_eta); - snprintf(buffer, 1024, "\r%3d%% |%s| ETA: %s %c", - percent_done, bar_buffer, eta_buffer, - tbits[tbit_value]); + snprintf(buffer, 1024, + "\r\t%3d%% |%s| ETA: %s %c", + percent_done, bar_buffer, + eta_buffer, tbits[tbit_value]); write(fileno(stdout), buffer, strlen(buffer)); fflush(stdout); - /* resolution wasn't high enough... wait until we get another - timestamp and perhaps more "work" done. */ - - if (!wait_for_more_data) { - last_value = progressInfo.completed; - } - if (++tbit_value > 3) tbit_value = 0; - sleep(2); + if (not_done) + sleep(2); if (gettimeofday(¤t_time, NULL)) err(1, "gettimeofday"); - - do_ioctl(fd, option, &pInfoPtr, ""); - - } printf("\n"); } + /* 40 '*''s per line, then 40 ' ''s line. */ /* If you've got a screen wider than 160 characters, "tough" */ @@ -998,7 +1097,6 @@ const char stars[] = "****************************************" " " " " " " - " " " "; static void @@ -1055,6 +1153,102 @@ get_time_string(string, simple_time) } +static int +open_device(devfd, name) + fdidpair **devfd; + char *name; +{ + int nfd, rawpart, i; + struct stat st; + char **devname; + + if (strcmp(name, "all") == 0) { + do_all = 1; + nfd = get_all_devices(&devname, "raid"); + } else { + nfd = 1; + devname = malloc(sizeof(void*)); + devname[0] = malloc(PATH_MAX); + + if ((name[0] == '/') || (name[0] == '.')) { + /* they've (apparently) given a full path... */ + strlcpy(devname[0], name, PATH_MAX); + } else { + if (isdigit(name[strlen(name) - 1])) { + rawpart = getrawpartition(); + snprintf(devname[0], PATH_MAX, "%s%s%c", + _PATH_DEV, name, 'a' + rawpart); + } else { + snprintf(devname[0], PATH_MAX, "%s%s", + _PATH_DEV, name); + } + } + } + + if ((*devfd = malloc(nfd * sizeof(fdidpair))) == NULL) + errx(1, "malloc() error"); + + i = nfd; + while (i--) { + if (stat(devname[i], &st) != 0) + errx(errno, "stat failure on: %s", devname[i]); + if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) + errx(EINVAL, "invalid device: %s", devname[i]); + + if (((*devfd)[i].fd = open(devname[i], O_RDWR, 0640)) < 0) + errx(1, "unable to open device file: %s", devname[i]); + (*devfd)[i].id = RF_DEV2RAIDID(st.st_rdev); + + free(devname[i]); + } + + if (devname != NULL) + free(devname); + + return (nfd); +} + +static int +get_all_devices(diskarray, genericname) + char ***diskarray; + const char *genericname; +{ + int i, numdevs, mib[2]; + size_t len; + char *disks, *fp, *p; + + numdevs = 0; + + mib[0] = CTL_HW; + mib[1] = HW_DISKNAMES; + sysctl(mib, 2, NULL, &len, NULL, 0); + if ((disks = malloc(len + 1)) == NULL) + errx(1, "malloc() error"); + sysctl(mib, 2, disks, &len, NULL, 0); + disks[len] = '\0'; + + fp = disks; + while ((fp = strstr((const char*)fp, genericname)) != NULL) { + numdevs++; + fp++; + } + + *diskarray = (char**) malloc(numdevs * sizeof(void*)); + i = 0; + fp = disks; + while ((p = strsep(&fp, ",")) != NULL) { + if (strstr((const char*)p, genericname) != NULL) { + (*diskarray)[i] = (char*) malloc(strlen(p) + 6); + sprintf((*diskarray)[i++], "/dev/%s%c", p, + 'a' + getrawpartition()); + } + } + + free(disks); + + return (numdevs); +} + static void usage() { |