- add '-v' (Verbose) option, which, most notably, provides

a spiffy lukemftp-inspired progress bar for parity re-writing,
reconstructs, copybacks, et al.

- make 'raidctl -P' wait until the parity has been updated before exiting
(it waited previously, but only because the parity re-write ioctl wouldn't
exit until the parity was successfully re-written)
This commit is contained in:
oster 2000-01-05 03:02:41 +00:00
parent 77ab4d1598
commit c714a07d22
2 changed files with 339 additions and 43 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: raidctl.8,v 1.10 1999/11/19 22:48:02 kristerw Exp $
.\" $NetBSD: raidctl.8,v 1.11 2000/01/05 03:02:41 oster Exp $
.\"
.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -68,36 +68,52 @@
.Nd configuration utility for the RAIDframe disk driver
.Sh SYNOPSIS
.Nm ""
.Op Fl v
.Fl a Ar component Ar dev
.Nm ""
.Op Fl v
.Fl B Ar dev
.Nm ""
.Op Fl v
.Fl c Ar config_file Ar dev
.Nm ""
.Op Fl v
.Fl C Ar config_file Ar dev
.Nm ""
.Op Fl v
.Fl f Ar component Ar dev
.Nm ""
.Op Fl v
.Fl F Ar component Ar dev
.Nm ""
.Op Fl v
.Fl g Ar component Ar dev
.Nm ""
.Op Fl v
.Fl i Ar dev
.Nm ""
.Op Fl v
.Fl I Ar serial_number Ar dev
.Nm ""
.Op Fl v
.Fl p Ar dev
.Nm ""
.Op Fl v
.Fl P Ar dev
.Nm ""
.Op Fl v
.Fl r Ar component Ar dev
.Nm ""
.Op Fl v
.Fl R Ar component Ar dev
.Nm ""
.Op Fl v
.Fl s Ar dev
.Nm ""
.Op Fl v
.Fl S Ar dev
.Nm ""
.Op Fl v
.Fl u Ar dev
.Sh DESCRIPTION
.Nm ""
@ -191,6 +207,9 @@ Check the status of component reconstruction. The output indicates
the amount of progress achieved in reconstructing a failed component.
.It Fl u Ar dev
Unconfigure the RAIDframe device.
.It Fl v
Be more verbose. For operations such as reconstructions, parity
re-writing, and copybacks, provide a progress indicator.
.El
.Pp
The device used by

View File

@ -1,4 +1,4 @@
/* $NetBSD: raidctl.c,v 1.9 1999/08/15 03:18:19 oster Exp $ */
/* $NetBSD: raidctl.c,v 1.10 2000/01/05 03:02:41 oster Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
* All rights reserved.
@ -66,7 +66,7 @@
extern char *__progname;
int main __P((int, char *[]));
static void do_ioctl __P((int, unsigned long, void *, char *));
void do_ioctl __P((int, unsigned long, void *, char *));
static void rf_configure __P((int, char*, int));
static char *device_status __P((RF_DiskStatus_t));
static void rf_get_device_status __P((int));
@ -79,6 +79,13 @@ static void init_component_labels __P((int, int));
static void add_hot_spare __P((int, char *));
static void remove_hot_spare __P((int, char *));
static void rebuild_in_place __P((int, char *));
static void check_status __P((int));
static void check_parity __P((int,int,char *));
static void do_meter __P((int, int));
static void get_bar __P((char *, double, int));
static void get_time_string __P((char *, int));
int verbose = 0;
int
main(argc,argv)
@ -99,7 +106,6 @@ main(argc,argv)
int is_clean;
int raidID;
int rawpart;
int recon_percent_done;
int serial_number;
struct stat st;
int fd;
@ -112,7 +118,7 @@ main(argc,argv)
is_clean = 0;
force = 0;
while ((ch = getopt(argc, argv, "a:Bc:C:f:F:g:iI:l:r:R:sSpPu")) != -1)
while ((ch = getopt(argc, argv, "a:Bc:C:f:F:g:iI:l:r:R:sSpPuv")) != -1)
switch(ch) {
case 'a':
action = RAIDFRAME_ADD_HOT_SPARE;
@ -181,7 +187,7 @@ main(argc,argv)
num_options++;
break;
case 'S':
action = RAIDFRAME_CHECKRECON;
action = RAIDFRAME_CHECK_RECON_STATUS;
num_options++;
break;
case 'p':
@ -197,6 +203,12 @@ main(argc,argv)
action = RAIDFRAME_SHUTDOWN;
num_options++;
break;
case 'v':
verbose = 1;
/* Don't bump num_options, as '-v' is not
an option like the others */
/* num_options++; */
break;
default:
usage();
}
@ -254,6 +266,11 @@ main(argc,argv)
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);
}
break;
case RAIDFRAME_FAIL_DISK:
rf_fail_disk(fd,component,do_recon);
@ -271,12 +288,14 @@ main(argc,argv)
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);
}
break;
case RAIDFRAME_CHECKRECON:
do_ioctl(fd, RAIDFRAME_CHECKRECON, &recon_percent_done,
"RAIDFRAME_CHECKRECON");
printf("Reconstruction is %d%% complete.\n",
recon_percent_done);
case RAIDFRAME_CHECK_RECON_STATUS:
check_status(fd);
break;
case RAIDFRAME_GET_INFO:
rf_get_device_status(fd);
@ -285,23 +304,7 @@ main(argc,argv)
rebuild_in_place(fd,component);
break;
case RAIDFRAME_CHECK_PARITY:
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");
} else {
/* parity is wrong, and is not being fixed.
Exit w/ an error. */
exit(1);
}
}
check_parity(fd,do_rewrite,dev_name);
break;
case RAIDFRAME_SHUTDOWN:
do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN");
@ -314,7 +317,7 @@ main(argc,argv)
exit(0);
}
static void
void
do_ioctl(fd, command, arg, ioctl_name)
int fd;
unsigned long command;
@ -323,6 +326,7 @@ do_ioctl(fd, command, arg, ioctl_name)
{
if (ioctl(fd, command, arg) < 0) {
warn("ioctl (%s) failed", ioctl_name);
printf("ioctl (%s) failed", ioctl_name);
exit(1);
}
}
@ -427,6 +431,7 @@ rf_get_device_status(fd)
} else {
printf("Parity status: DIRTY\n");
}
check_status(fd);
}
static void
@ -486,6 +491,11 @@ rf_fail_disk(fd, component_to_fail, do_recon)
}
do_ioctl(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);
}
}
static void
@ -623,25 +633,292 @@ rebuild_in_place( fd, component )
do_ioctl( 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);
}
}
static void
check_parity( fd, do_rewrite, dev_name )
int fd;
int do_rewrite;
char *dev_name;
{
int is_clean;
int percent_done;
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);
} else {
do_ioctl(fd,
RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
&percent_done,
"RAIDFRAME_CHECK_PARITYREWRITE_STATUS"
);
while( percent_done < 100 ) {
do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
&percent_done, "RAIDFRAME_CHECK_PARITYREWRITE_STATUS");
}
}
printf("%s: Parity Re-write complete\n",
dev_name);
} else {
/* parity is wrong, and is not being fixed.
Exit w/ an error. */
exit(1);
}
}
}
static void
check_status( fd )
int fd;
{
int recon_percent_done = 0;
int parity_percent_done = 0;
int copyback_percent_done = 0;
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, &copyback_percent_done,
"RAIDFRAME_CHECK_COPYBACK_STATUS");
printf("Copyback is %d%% complete.\n", copyback_percent_done);
/* 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);
} else if (parity_percent_done < 100) {
printf("Parity Re-write status:\n");
do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS);
} else if (copyback_percent_done < 100) {
printf("Copyback status:\n");
do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS);
}
}
char *tbits = "|/-\\";
static void
do_meter( fd, option )
int fd;
int option;
{
int percent_done;
int last_percent;
int start_percent;
struct timeval start_time;
struct timeval last_time;
struct timeval current_time;
double elapsed;
int elapsed_sec;
int elapsed_usec;
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];
if (gettimeofday(&start_time,NULL)) {
fprintf(stderr,"%s: gettimeofday failed!?!?\n",__progname);
exit(errno);
}
percent_done = 0;
do_ioctl( fd, option, &percent_done, "");
last_percent = percent_done;
start_percent = percent_done;
last_time = start_time;
current_time = start_time;
wait_for_more_data = 0;
tbit_value = 0;
while(percent_done < 100) {
get_bar(bar_buffer, percent_done, 40);
elapsed_sec = current_time.tv_sec - last_time.tv_sec;
elapsed_usec = current_time.tv_usec - last_time.tv_usec;
if (elapsed_usec < 0) {
elapsed_usec-=1000000;
elapsed_sec++;
}
elapsed = (double) elapsed_sec +
(double) elapsed_usec / 1000000.0;
if (elapsed <= 0.0) {
elapsed = 0.0001; /* XXX */
}
amount = percent_done - last_percent;
if (amount <= 0) { /* we don't do negatives (yet?) */
amount = 0;
wait_for_more_data = 1;
} else {
wait_for_more_data = 0;
}
rate = amount / elapsed;
if (rate > 0.0) {
simple_eta = (int) ((100.0 - (double) last_percent ) / rate);
} else {
simple_eta = -1;
}
if (simple_eta <=0) {
simple_eta = last_eta;
} else {
last_eta = simple_eta;
}
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]);
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_time = current_time;
last_percent = percent_done;
}
if (++tbit_value>3)
tbit_value = 0;
sleep(2);
if (gettimeofday(&current_time,NULL)) {
fprintf(stderr,"%s: gettimeofday failed!?!?\n",
__progname);
exit(errno);
}
do_ioctl( fd, option, &percent_done, "");
}
printf("\n");
}
/* 40 '*''s per line, then 40 ' ''s line. */
/* If you've got a screen wider than 160 characters, "tough" */
#define STAR_MIDPOINT 4*40
const char stars[] = "****************************************"
"****************************************"
"****************************************"
"****************************************"
" "
" "
" "
" "
" ";
static void
get_bar(string,percent,max_strlen)
char *string;
double percent;
int max_strlen;
{
int offset;
if (max_strlen > STAR_MIDPOINT) {
max_strlen = STAR_MIDPOINT;
}
offset = STAR_MIDPOINT -
(int)((percent * max_strlen)/ 100);
if (offset < 0)
offset = 0;
snprintf(string,max_strlen,"%s",&stars[offset]);
}
static void
get_time_string(string,simple_time)
char *string;
int simple_time;
{
int minutes, seconds, hours;
char hours_buffer[5];
char minutes_buffer[5];
char seconds_buffer[5];
if (simple_time >= 0) {
minutes = (int) simple_time / 60;
seconds = ((int)simple_time - 60*minutes);
hours = minutes / 60;
minutes = minutes - 60*hours;
if (hours > 0) {
snprintf(hours_buffer,5,"%02d:",hours);
} else {
snprintf(hours_buffer,5," ");
}
snprintf(minutes_buffer,5,"%02d:",minutes);
snprintf(seconds_buffer,5,"%02d",seconds);
snprintf(string,1024,"%s%s%s",
hours_buffer, minutes_buffer, seconds_buffer);
} else {
snprintf(string,1024," --:--");
}
}
static void
usage()
{
fprintf(stderr, "usage: %s -a component dev\n", __progname);
fprintf(stderr, " %s -B dev\n", __progname);
fprintf(stderr, " %s -c config_file dev\n", __progname);
fprintf(stderr, " %s -C config_file dev\n", __progname);
fprintf(stderr, " %s -f component dev\n", __progname);
fprintf(stderr, " %s -F component dev\n", __progname);
fprintf(stderr, " %s -g component dev\n", __progname);
fprintf(stderr, " %s -i dev\n", __progname);
fprintf(stderr, " %s -I serial_number dev\n", __progname);
fprintf(stderr, " %s -r component dev\n", __progname);
fprintf(stderr, " %s -R component dev\n", __progname);
fprintf(stderr, " %s -s dev\n", __progname);
fprintf(stderr, " %s -S dev\n", __progname);
fprintf(stderr, " %s -u dev\n", __progname);
fprintf(stderr, "usage: %s [-v] -a component dev\n", __progname);
fprintf(stderr, " %s [-v] -B dev\n", __progname);
fprintf(stderr, " %s [-v] -c config_file dev\n", __progname);
fprintf(stderr, " %s [-v] -C config_file dev\n", __progname);
fprintf(stderr, " %s [-v] -f component dev\n", __progname);
fprintf(stderr, " %s [-v] -F component dev\n", __progname);
fprintf(stderr, " %s [-v] -g component dev\n", __progname);
fprintf(stderr, " %s [-v] -i dev\n", __progname);
fprintf(stderr, " %s [-v] -I serial_number dev\n", __progname);
fprintf(stderr, " %s [-v] -r component dev\n", __progname);
fprintf(stderr, " %s [-v] -R component dev\n", __progname);
fprintf(stderr, " %s [-v] -s dev\n", __progname);
fprintf(stderr, " %s [-v] -S dev\n", __progname);
fprintf(stderr, " %s [-v] -u dev\n", __progname);
#if 0
fprintf(stderr, "usage: %s %s\n", __progname,
"-a | -f | -F | -g | -r | -R component dev");