1 /* commands.c: vinum interface program, main commands */
3 * Copyright (c) 1997, 1998
4 * Nan Yang Computer Services Limited. All rights reserved.
6 * Written by Greg Lehey
8 * This software is distributed under the so-called ``Berkeley
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Company nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * This software is provided ``as is'', and any express or implied
24 * warranties, including, but not limited to, the implied warranties of
25 * merchantability and fitness for a particular purpose are disclaimed.
26 * In no event shall the company or contributors be liable for any
27 * direct, indirect, incidental, special, exemplary, or consequential
28 * damages (including, but not limited to, procurement of substitute
29 * goods or services; loss of use, data, or profits; or business
30 * interruption) however caused and on any theory of liability, whether
31 * in contract, strict liability, or tort (including negligence or
32 * otherwise) arising in any way out of the use of this software, even if
33 * advised of the possibility of such damage.
35 * $Id: commands.c,v 1.14 2000/11/14 20:01:23 grog Exp grog $
36 * $FreeBSD: src/sbin/vinum/commands.c,v 1.31.2.6 2003/06/06 05:13:29 grog Exp $
39 #define _KERNEL_STRUCTURES
54 #include <sys/ioctl.h>
55 #include <dev/raid/vinum/vinumhdr.h>
56 #include <dev/raid/vinum/request.h>
58 #include <sys/types.h>
59 #include <sys/linker.h>
60 #include <sys/module.h>
62 #include <readline/readline.h>
65 static void dorename(struct vinum_rename_msg
*msg
, const char *oldname
, const char *name
, int maxlen
);
66 static void reparse(char *buf
, char *tmp
);
69 vinum_create(int argc
, char *argv
[], char *arg0
[])
72 FILE *dfd
; /* file descriptor for the config file */
73 char buffer
[BUFSIZE
]; /* read config file in here */
74 char commandline
[BUFSIZE
]; /* issue command from here */
75 struct _ioctl_reply
*reply
;
76 int ioctltype
; /* for ioctl call */
77 char tempfile
[PATH_MAX
]; /* name of temp file for direct editing */
78 char *file
; /* file to read */
79 FILE *tf
; /* temp file */
81 if (argc
== 0) { /* no args, */
82 char *editor
; /* editor to start */
85 editor
= getenv("EDITOR");
87 editor
= "/usr/bin/vi";
88 sprintf(tempfile
, "/var/tmp/" VINUMMOD
".create.%d", getpid()); /* create a temp file */
89 tf
= fopen(tempfile
, "w"); /* open it */
91 fprintf(stderr
, "Can't open %s: %s\n", argv
[0], strerror(errno
));
94 printconfig(tf
, "# "); /* and put the current config it */
96 sprintf(commandline
, "%s %s", editor
, tempfile
); /* create an edit command */
97 status
= system(commandline
); /* do it */
99 fprintf(stderr
, "Can't edit config: status %d\n", status
);
103 } else if (argc
== 1)
106 fprintf(stderr
, "Expecting 1 parameter, not %d\n", argc
);
109 reply
= (struct _ioctl_reply
*) &buffer
;
110 dfd
= fopen(file
, "r");
111 if (dfd
== NULL
) { /* no go */
112 fprintf(stderr
, "Can't open %s: %s\n", file
, strerror(errno
));
115 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
116 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
119 file_line
= 0; /* start with line 1 */
120 /* Parse the configuration, and add it to the global configuration */
121 for (;;) { /* love this style(9) */
124 configline
= fgets(buffer
, BUFSIZE
, dfd
);
126 if (configline
== NULL
) {
128 perror("Can't read config file");
132 fprintf(hist
, "%s", buffer
);
133 file_line
++; /* count the lines */
135 reparse(buffer
, commandline
);
138 printf("%4d: %s", file_line
, buffer
);
139 strcpy(commandline
, buffer
); /* make a copy */
140 ioctl(superdev
, VINUM_CREATE
, buffer
);
141 if (reply
->error
!= 0) { /* error in config */
142 if (!vflag
) /* print this line anyway */
143 printf("%4d: %s", file_line
, commandline
);
144 fprintf(stdout
, "** %d %s: %s\n",
147 strerror(reply
->error
));
150 * XXX at the moment, we reset the config
151 * lock on error, so try to get it again.
152 * If we fail, don't cry again.
154 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) /* can't get config? */
158 fclose(dfd
); /* done with the config file */
159 ioctltype
= 0; /* saveconfig after update */
160 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
162 perror("Can't save Vinum config");
165 checkupdates(); /* make sure we're updating */
168 /* Read vinum config from a disk */
170 vinum_read(int argc
, char *argv
[], char *arg0
[])
173 char buffer
[BUFSIZE
]; /* read config file in here */
174 struct _ioctl_reply
*reply
;
177 reply
= (struct _ioctl_reply
*) &buffer
;
178 if (argc
< 1) { /* wrong arg count */
179 fprintf(stderr
, "Usage: read drive [drive ...]\n");
182 strcpy(buffer
, "read ");
183 for (i
= 0; i
< argc
; i
++) { /* each drive name */
184 strcat(buffer
, argv
[i
]);
188 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
189 fprintf(stderr
, "Can't configure: %s (%d)\n", strerror(errno
), errno
);
192 ioctl(superdev
, VINUM_CREATE
, &buffer
);
193 if (reply
->error
!= 0) { /* error in config */
194 fprintf(stdout
, "** %s: %s\n", reply
->msg
, strerror(reply
->error
));
195 error
= ioctl(superdev
, VINUM_RELEASECONFIG
, NULL
); /* save the config to disk */
197 perror("Can't save Vinum config");
199 error
= ioctl(superdev
, VINUM_RELEASECONFIG
, NULL
); /* save the config to disk */
201 perror("Can't save Vinum config");
204 checkupdates(); /* make sure we're updating */
209 vinum_debug(int argc
, char *argv
[], char *arg0
[])
211 struct debuginfo info
;
214 info
.param
= atoi(argv
[0]);
218 sleep(2); /* give a chance to leave the window */
220 ioctl(superdev
, VINUM_DEBUG
, (caddr_t
) & info
);
225 vinum_modify(int argc
, char *argv
[], char *arg0
[])
227 fprintf(stderr
, "Modify command is currently not implemented\n");
228 checkupdates(); /* make sure we're updating */
232 vinum_set(int argc
, char *argv
[], char *arg0
[])
234 fprintf(stderr
, "set is not implemented yet\n");
238 vinum_rm(int argc
, char *argv
[], char *arg0
[])
241 struct _ioctl_reply reply
;
242 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
244 if (argc
== 0) /* start everything */
245 fprintf(stderr
, "Usage: rm object [object...]\n");
246 else { /* start specified objects */
248 enum objecttype type
;
250 for (index
= 0; index
< argc
; index
++) {
251 object
= find_object(argv
[index
], &type
); /* look for it */
252 if (type
== invalid_object
)
253 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
255 message
->index
= object
; /* pass object number */
256 message
->type
= type
; /* and type of object */
257 message
->force
= force
; /* do we want to force the operation? */
258 message
->recurse
= recurse
; /* do we want to remove subordinates? */
259 ioctl(superdev
, VINUM_REMOVE
, message
);
260 if (reply
.error
!= 0) {
262 "Can't remove %s: %s (%d)\n",
264 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
267 fprintf(stderr
, "%s removed\n", argv
[index
]);
270 checkupdates(); /* make sure we're updating */
275 vinum_resetconfig(int argc
, char *argv
[], char *arg0
[])
280 if (! isatty (STDIN_FILENO
)) {
281 fprintf (stderr
, "Please enter this command from a tty device\n");
284 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
285 " All data will be lost. If you really want to do this, enter the text\n\n"
288 fgets(reply
, sizeof(reply
), stdin
);
289 if (strcmp(reply
, "NO FUTURE\n")) /* changed his mind */
290 printf("\n No change\n");
292 error
= ioctl(superdev
, VINUM_RESETCONFIG
, NULL
); /* trash config on disk */
295 fprintf(stderr
, "Can't reset configuration: objects are in use\n");
297 perror("Can't find vinum config");
299 make_devices(); /* recreate the /dev/vinum hierarchy */
300 printf("\b Vinum configuration obliterated\n");
301 start_daemon(); /* then restart the daemon */
304 checkupdates(); /* make sure we're updating */
307 /* Initialize subdisks */
309 vinum_init(int argc
, char *argv
[], char *arg0
[])
311 if (argc
> 0) { /* initialize plexes */
314 enum objecttype type
; /* type returned */
317 fflush(hist
); /* don't let all the kids do it. */
318 for (objindex
= 0; objindex
< argc
; objindex
++) {
319 objno
= find_object(argv
[objindex
], &type
); /* find the object */
321 printf("Can't find %s\n", argv
[objindex
]);
329 initplex(objno
, argv
[objindex
]);
333 initsd(objno
, dowait
);
337 printf("Can't initialize %s: wrong object type\n", argv
[objindex
]);
343 checkupdates(); /* make sure we're updating */
349 printf("Initializing volumes is not implemented yet\n");
353 initplex(int plexno
, char *name
)
356 int plexfh
= 0; /* file handle for plex */
358 char filename
[MAXPATHLEN
]; /* create a file name here */
360 /* Variables for use by children */
361 int failed
= 0; /* set if a child dies badly */
363 sprintf(filename
, VINUM_DIR
"/plex/%s", name
);
364 if ((plexfh
= open(filename
, O_RDWR
, S_IRWXU
)) < 0) { /* got a plex, open it */
366 * We don't actually write anything to the
367 * plex. We open it to ensure that nobody
368 * else tries to open it while we initialize
371 fprintf(stderr
, "can't open plex %s: %s\n", filename
, strerror(errno
));
375 pid
= fork(); /* into the background with you */
376 if (pid
!= 0) { /* I'm the parent, or we failed */
377 if (pid
< 0) /* failure */
378 printf("Couldn't fork: %s", strerror(errno
));
379 close(plexfh
); /* we don't need this any more */
384 * If we get here, we're either the first-level
385 * child (if we're not waiting) or we're going
388 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) { /* initialize each subdisk */
389 get_plex_sd_info(&sd
, plexno
, sdno
);
392 /* Now wait for them to complete */
396 if (((int) pid
== -1)
397 && (errno
== ECHILD
)) /* all gone */
399 if (WEXITSTATUS(status
) != 0) { /* oh, oh */
400 printf("child %d exited with status 0x%x\n", pid
, WEXITSTATUS(status
));
406 message
->index
= plexno
; /* pass object number */
407 message
->type
= plex_object
; /* and type of object */
408 message
->state
= object_up
;
409 message
->force
= 1; /* insist */
410 ioctl(superdev
, VINUM_SETSTATE
, message
);
412 syslog(LOG_INFO
| LOG_KERN
, "plex %s initialized", plex
.name
);
414 syslog(LOG_ERR
| LOG_KERN
, "couldn't initialize plex %s, %d processes died",
417 if (dowait
== 0) /* we're the waiting child, */
418 exit(0); /* we've done our dash */
421 /* Initialize a subdisk. */
423 initsd(int sdno
, int dowait
)
426 struct _ioctl_reply reply
;
427 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
428 char filename
[MAXPATHLEN
]; /* create a file name here */
430 /* Variables for use by children */
431 int sdfh
; /* and for subdisk */
434 pid
= fork(); /* into the background with you */
435 if (pid
> 0) /* I'm the parent */
437 else if (pid
< 0) { /* failure */
438 printf("couldn't fork for subdisk %d: %s", sdno
, strerror(errno
));
442 if (SSize
!= 0) { /* specified a size for init */
444 SSize
<<= DEV_BSHIFT
;
446 openlog("vinum", LOG_CONS
| LOG_PERROR
| LOG_PID
, LOG_KERN
);
447 get_sd_info(&sd
, sdno
);
448 sprintf(filename
, VINUM_DIR
"/sd/%s", sd
.name
);
449 setproctitle("initializing %s", filename
); /* show what we're doing */
450 syslog(LOG_INFO
| LOG_KERN
, "initializing subdisk %s", filename
);
451 if ((sdfh
= open(filename
, O_RDWR
, S_IRWXU
)) < 0) { /* no go */
452 syslog(LOG_ERR
| LOG_KERN
,
453 "can't open subdisk %s: %s",
458 /* Set the subdisk in initializing state */
459 message
->index
= sd
.sdno
; /* pass object number */
460 message
->type
= sd_object
; /* and type of object */
461 message
->state
= object_initializing
;
462 message
->verify
= vflag
; /* verify what we write? */
463 message
->force
= 1; /* insist */
464 ioctl(superdev
, VINUM_SETSTATE
, message
);
465 if ((SSize
> 0) /* specified a size for init */
467 SSize
<<= DEV_BSHIFT
;
470 "Can't initialize %s: %s (%d)\n",
472 strerror(reply
.error
),
477 if (interval
) /* pause between copies */
478 usleep(interval
* 1000);
479 message
->index
= sd
.sdno
; /* pass object number */
480 message
->type
= sd_object
; /* and type of object */
481 message
->state
= object_up
;
482 message
->verify
= vflag
; /* verify what we write? */
483 message
->blocksize
= SSize
;
484 ioctl(superdev
, VINUM_SETSTATE
, message
);
486 while (reply
.error
== EAGAIN
); /* until we're done */
489 "Can't initialize %s: %s (%d)\n",
491 strerror(reply
.error
),
493 get_sd_info(&sd
, sdno
);
494 if (sd
.state
!= sd_up
)
495 /* Set the subdisk down */
496 message
->index
= sd
.sdno
; /* pass object number */
497 message
->type
= sd_object
; /* and type of object */
498 message
->state
= object_down
;
499 message
->verify
= vflag
; /* verify what we write? */
500 message
->force
= 1; /* insist */
501 ioctl(superdev
, VINUM_SETSTATE
, message
);
504 printf("subdisk %s initialized\n", filename
);
510 vinum_start(int argc
, char *argv
[], char *arg0
[])
513 struct _ioctl_reply reply
;
514 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
516 if (argc
== 0) { /* start everything */
517 int devs
= getnumdevs();
518 struct statinfo statinfo
;
520 char *enamelist
; /* end of name list */
522 char **token
; /* list of tokens */
523 int tokens
; /* and their number */
525 bzero(&statinfo
, sizeof(struct statinfo
));
526 statinfo
.dinfo
= malloc(devs
* sizeof(struct statinfo
));
527 namelist
= malloc(devs
* (DEVSTAT_NAME_LEN
+ 8));
528 token
= malloc((devs
+ 1) * sizeof(char *));
529 if ((statinfo
.dinfo
== NULL
) || (namelist
== NULL
) || (token
== NULL
)) {
530 fprintf(stderr
, "Can't allocate memory for drive list\n");
533 bzero(statinfo
.dinfo
, sizeof(struct devinfo
));
535 tokens
= 0; /* no tokens yet */
536 if (getdevs(&statinfo
) < 0) { /* find out what devices we have */
537 perror("Can't get device list");
540 namelist
[0] = '\0'; /* start with empty namelist */
541 enamelist
= namelist
; /* point to the end of the list */
543 for (i
= 0; i
< devs
; i
++) {
544 struct devstat
*stat
= &statinfo
.dinfo
->devices
[i
];
546 if ((((stat
->device_type
& DEVSTAT_TYPE_MASK
) == DEVSTAT_TYPE_DIRECT
) /* disk device */
547 || ((stat
->device_type
& DEVSTAT_TYPE_MASK
) == DEVSTAT_TYPE_STORARRAY
)) /* storage array */
548 &&((stat
->device_type
& DEVSTAT_TYPE_IF_MASK
) != DEVSTAT_TYPE_IF_OTHER
) /* and not md */
549 &&((stat
->device_type
& DEVSTAT_TYPE_PASS
) == 0) /* and not passthrough */
550 &&((stat
->device_name
[0] != '\0'))) { /* and it has a name */
551 sprintf(enamelist
, "%s%s%d", _PATH_DEV
, stat
->device_name
, stat
->unit_number
);
552 token
[tokens
] = enamelist
; /* point to it */
553 tokens
++; /* one more token */
554 enamelist
= &enamelist
[strlen(enamelist
) + 1]; /* and start beyond the end */
557 free(statinfo
.dinfo
); /* don't need the list any more */
558 vinum_read(tokens
, token
, &token
[0]); /* start the system */
561 list_defective_objects(); /* and list anything that's down */
562 } else { /* start specified objects */
564 enum objecttype type
;
566 for (index
= 0; index
< argc
; index
++) {
567 object
= find_object(argv
[index
], &type
); /* look for it */
568 if (type
== invalid_object
)
569 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
571 int doit
= 0; /* set to 1 if we pass our tests */
574 if (drive
.state
== drive_up
) /* already up */
575 fprintf(stderr
, "%s is already up\n", drive
.label
.name
);
581 if (sd
.state
== sd_up
) /* already up */
582 fprintf(stderr
, "%s is already up\n", sd
.name
);
588 if (plex
.state
== plex_up
) /* already up */
589 fprintf(stderr
, "%s is already up\n", plex
.name
);
594 * First, see if we can bring it up
595 * just by asking. This might happen
596 * if somebody has used setupstate on
597 * the subdisks. If we don't do this,
598 * we'll return success, but the plex
599 * won't have changed state. Note
600 * that we don't check for errors
603 message
->index
= plex
.plexno
; /* pass object number */
604 message
->type
= plex_object
; /* it's a plex */
605 message
->state
= object_up
;
606 message
->force
= 0; /* don't force it */
607 ioctl(superdev
, VINUM_SETSTATE
, message
);
608 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
609 get_plex_sd_info(&sd
, object
, sdno
);
610 if ((sd
.state
>= sd_empty
)
611 && (sd
.state
<= sd_reviving
)) { /* candidate for start */
612 message
->index
= sd
.sdno
; /* pass object number */
613 message
->type
= sd_object
; /* it's a subdisk */
614 message
->state
= object_up
;
615 message
->force
= force
; /* don't force it, use a larger hammer */
618 * We don't do any checking here.
619 * The kernel module has a better
620 * understanding of these things,
623 if (SSize
!= 0) { /* specified a size for init */
625 SSize
<<= DEV_BSHIFT
;
626 message
->blocksize
= SSize
;
628 message
->blocksize
= DEFAULT_REVIVE_BLOCKSIZE
;
629 ioctl(superdev
, VINUM_SETSTATE
, message
);
630 if (reply
.error
!= 0) {
631 if (reply
.error
== EAGAIN
) /* we're reviving */
632 continue_revive(sd
.sdno
);
635 "Can't start %s: %s (%d)\n",
637 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
641 vinum_lsi(sd
.sdno
, 0);
648 if (vol
.state
== volume_up
) /* already up */
649 fprintf(stderr
, "%s is already up\n", vol
.name
);
659 message
->index
= object
; /* pass object number */
660 message
->type
= type
; /* and type of object */
661 message
->state
= object_up
;
662 message
->force
= force
; /* don't force it, use a larger hammer */
665 * We don't do any checking here.
666 * The kernel module has a better
667 * understanding of these things,
670 if (SSize
!= 0) { /* specified a size for init or revive */
672 SSize
<<= DEV_BSHIFT
;
673 message
->blocksize
= SSize
;
675 message
->blocksize
= 0;
676 ioctl(superdev
, VINUM_SETSTATE
, message
);
677 if (reply
.error
!= 0) {
678 if ((reply
.error
== EAGAIN
) /* we're reviving */
679 &&(type
== sd_object
))
680 continue_revive(object
);
683 "Can't start %s: %s (%d)\n",
685 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
689 vinum_li(object
, type
);
694 checkupdates(); /* make sure we're updating */
698 vinum_stop(int argc
, char *argv
[], char *arg0
[])
701 struct _ioctl_reply reply
;
702 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
704 if (checkupdates() && (!force
)) /* not updating? */
706 message
->force
= force
; /* should we force the transition? */
707 if (argc
== 0) { /* stop vinum */
708 int fileid
= 0; /* ID of Vinum kld */
710 close(superdev
); /* we can't stop if we have vinum open */
711 sleep(1); /* wait for the daemon to let go */
712 fileid
= kldfind(VINUMMOD
);
713 if ((fileid
< 0) /* no go */
714 ||(kldunload(fileid
) < 0))
715 perror("Can't unload " VINUMMOD
);
717 fprintf(stderr
, VINUMMOD
" unloaded\n");
721 /* If we got here, the stop failed. Reopen the superdevice. */
722 superdev
= open(VINUM_SUPERDEV_NAME
, O_RDWR
); /* reopen vinum superdevice */
724 perror("Can't reopen Vinum superdevice");
727 } else { /* stop specified objects */
729 enum objecttype type
;
731 for (i
= 0; i
< argc
; i
++) {
732 object
= find_object(argv
[i
], &type
); /* look for it */
733 if (type
== invalid_object
)
734 fprintf(stderr
, "Can't find object: %s\n", argv
[i
]);
736 message
->index
= object
; /* pass object number */
737 message
->type
= type
; /* and type of object */
738 message
->state
= object_down
;
739 ioctl(superdev
, VINUM_SETSTATE
, message
);
740 if (reply
.error
!= 0)
742 "Can't stop %s: %s (%d)\n",
744 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
747 vinum_li(object
, type
);
754 vinum_label(int argc
, char *argv
[], char *arg0
[])
757 struct _ioctl_reply reply
;
758 int *message
= (int *) &reply
;
760 if (argc
== 0) /* start everything */
761 fprintf(stderr
, "label: please specify one or more volume names\n");
762 else { /* start specified objects */
764 enum objecttype type
;
766 for (i
= 0; i
< argc
; i
++) {
767 object
= find_object(argv
[i
], &type
); /* look for it */
768 if (type
== invalid_object
)
769 fprintf(stderr
, "Can't find object: %s\n", argv
[i
]);
770 else if (type
!= volume_object
) /* it exists, but it isn't a volume */
771 fprintf(stderr
, "%s is not a volume\n", argv
[i
]);
773 message
[0] = object
; /* pass object number */
774 ioctl(superdev
, VINUM_LABEL
, message
);
775 if (reply
.error
!= 0)
777 "Can't label %s: %s (%d)\n",
779 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
782 vinum_li(object
, type
);
786 checkupdates(); /* not updating? */
790 reset_volume_stats(int volno
, int recurse
)
792 struct vinum_ioctl_msg msg
;
793 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
796 msg
.type
= volume_object
;
797 /* XXX get these numbers right if we ever
798 * actually return errors */
799 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
800 fprintf(stderr
, "Can't reset stats for volume %d: %s\n", volno
, reply
->msg
);
801 longjmp(command_fail
, -1);
802 } else if (recurse
) {
806 get_volume_info(&vol
, volno
);
807 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++)
808 reset_plex_stats(vol
.plex
[plexno
], recurse
);
813 reset_plex_stats(int plexno
, int recurse
)
815 struct vinum_ioctl_msg msg
;
816 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
819 msg
.type
= plex_object
;
820 /* XXX get these numbers right if we ever
821 * actually return errors */
822 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
823 fprintf(stderr
, "Can't reset stats for plex %d: %s\n", plexno
, reply
->msg
);
824 longjmp(command_fail
, -1);
825 } else if (recurse
) {
830 get_plex_info(&plex
, plexno
);
831 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
832 get_plex_sd_info(&sd
, plex
.plexno
, sdno
);
833 reset_sd_stats(sd
.sdno
, recurse
);
839 reset_sd_stats(int sdno
, int recurse
)
841 struct vinum_ioctl_msg msg
;
842 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
845 msg
.type
= sd_object
;
846 /* XXX get these numbers right if we ever
847 * actually return errors */
848 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
849 fprintf(stderr
, "Can't reset stats for subdisk %d: %s\n", sdno
, reply
->msg
);
850 longjmp(command_fail
, -1);
851 } else if (recurse
) {
852 get_sd_info(&sd
, sdno
); /* get the info */
853 reset_drive_stats(sd
.driveno
); /* and clear the drive */
858 reset_drive_stats(int driveno
)
860 struct vinum_ioctl_msg msg
;
861 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
864 msg
.type
= drive_object
;
865 /* XXX get these numbers right if we ever
866 * actually return errors */
867 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
868 fprintf(stderr
, "Can't reset stats for drive %d: %s\n", driveno
, reply
->msg
);
869 longjmp(command_fail
, -1);
874 vinum_resetstats(int argc
, char *argv
[], char *argv0
[])
878 enum objecttype type
;
880 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
881 perror("Can't get vinum config");
885 for (objno
= 0; objno
< vinum_conf
.volumes_allocated
; objno
++)
886 reset_volume_stats(objno
, 1); /* clear everything recursively */
888 for (i
= 0; i
< argc
; i
++) {
889 objno
= find_object(argv
[i
], &type
);
890 if (objno
>= 0) { /* not invalid */
893 reset_drive_stats(objno
);
897 reset_sd_stats(objno
, recurse
);
901 reset_plex_stats(objno
, recurse
);
905 reset_volume_stats(objno
, recurse
);
908 case invalid_object
: /* can't get this */
916 /* Attach a subdisk to a plex, or a plex to a volume.
917 * attach subdisk plex [offset] [rename]
918 * attach plex volume [rename]
921 vinum_attach(int argc
, char *argv
[], char *argv0
[])
924 enum objecttype supertype
;
925 struct vinum_ioctl_msg msg
;
926 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
927 const char *objname
= argv
[0];
928 const char *supername
= argv
[1];
931 char oldname
[MAXNAME
+ 8];
932 char newname
[MAXNAME
+ 8];
933 int rename
= 0; /* set if we want to rename the object */
938 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
939 "\tattach <plex> <volume> [rename]\n");
942 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
943 perror("Can't get vinum config");
946 msg
.index
= find_object(objname
, &msg
.type
); /* find the object to attach */
947 msg
.otherobject
= find_object(supername
, &supertype
); /* and the object to attach to */
948 msg
.force
= force
; /* did we specify the use of force? */
949 msg
.recurse
= recurse
;
950 msg
.offset
= -1; /* and no offset */
952 for (i
= 2; i
< argc
; i
++) {
953 if (!strcmp(argv
[i
], "rename")) {
955 msg
.rename
= 1; /* do renaming */
956 } else if (!isdigit(argv
[i
][0])) { /* not an offset */
957 fprintf(stderr
, "Unknown attribute: %s\n", supername
);
960 msg
.offset
= sizespec(argv
[i
]);
965 find_object(argv
[1], &supertype
);
966 if (supertype
!= plex_object
) { /* huh? */
967 fprintf(stderr
, "%s can only be attached to a plex\n", objname
);
970 if ((plex
.organization
!= plex_concat
) /* not a cat plex, */
972 fprintf(stderr
, "Can't attach subdisks to a %s plex\n", plex_org(plex
.organization
));
975 sdno
= msg
.index
; /* note the subdisk number for later */
979 find_object(argv
[1], &supertype
);
980 if (supertype
!= volume_object
) { /* huh? */
981 fprintf(stderr
, "%s can only be attached to a volume\n", objname
);
988 fprintf(stderr
, "Can only attach subdisks and plexes\n");
992 fprintf(stderr
, "%s is not a Vinum object\n", objname
);
996 ioctl(superdev
, VINUM_ATTACH
, &msg
);
997 if (reply
->error
!= 0) {
998 if (reply
->error
== EAGAIN
) /* reviving */
999 continue_revive(sdno
); /* continue the revive */
1002 "Can't attach %s to %s: %s (%d)\n",
1005 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1013 /* we've overwritten msg with the
1014 * ioctl reply, start again */
1015 msg
.index
= find_object(objname
, &msg
.type
); /* find the object to rename */
1018 get_sd_info(&sd
, msg
.index
);
1019 get_plex_info(&plex
, sd
.plexno
);
1020 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1021 if (plex
.sdnos
[sdno
] == msg
.index
) /* found our subdisk */
1024 sprintf(newname
, "%s.s%d", plex
.name
, sdno
);
1025 sprintf(oldname
, "%s", sd
.name
);
1026 vinum_rename_2(oldname
, newname
);
1030 get_plex_info(&plex
, msg
.index
);
1031 get_volume_info(&vol
, plex
.volno
);
1032 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++) {
1033 if (vol
.plex
[plexno
] == msg
.index
) /* found our subdisk */
1036 sprintf(newname
, "%s.p%d", vol
.name
, plexno
);
1037 sprintf(oldname
, "%s", plex
.name
);
1038 vinum_rename_2(oldname
, newname
); /* this may recurse */
1041 default: /* can't get here */
1045 checkupdates(); /* make sure we're updating */
1048 /* Detach a subdisk from a plex, or a plex from a volume.
1049 * detach subdisk plex [rename]
1050 * detach plex volume [rename]
1053 vinum_detach(int argc
, char *argv
[], char *argv0
[])
1055 struct vinum_ioctl_msg msg
;
1056 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
1061 "Usage: \tdetach <subdisk> [rename]\n"
1062 "\tdetach <plex> [rename]\n");
1065 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1066 perror("Can't get vinum config");
1069 msg
.index
= find_object(argv
[0], &msg
.type
); /* find the object to detach */
1070 msg
.force
= force
; /* did we specify the use of force? */
1071 msg
.rename
= 0; /* don't specify new name */
1072 msg
.recurse
= recurse
; /* but recurse if we have to */
1074 /* XXX are we going to keep this?
1075 * Don't document it yet, since the
1076 * kernel side of things doesn't
1079 if (!strcmp(argv
[1], "rename"))
1080 msg
.rename
= 1; /* do renaming */
1082 fprintf(stderr
, "Unknown attribute: %s\n", argv
[1]);
1086 if ((msg
.type
!= sd_object
)
1087 && (msg
.type
!= plex_object
)) {
1088 fprintf(stderr
, "Can only detach subdisks and plexes\n");
1091 ioctl(superdev
, VINUM_DETACH
, &msg
);
1092 if (reply
->error
!= 0)
1094 "Can't detach %s: %s (%d)\n",
1096 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1098 checkupdates(); /* make sure we're updating */
1102 * Reparse a line from the configuration file
1105 reparse(char *buf
, char *tmp
)
1108 const char *ws
= " \t\r\n";
1113 ptr
= strtok(tmp
, ws
);
1114 if (ptr
== NULL
|| *ptr
== '#')
1116 if (strcmp(ptr
, "drive") != 0)
1119 while ((ptr
= strtok(NULL
, ws
)) != NULL
) {
1122 ptr
= getdevpath(ptr
, 0);
1123 } else if (doskip
) {
1125 } else if (strcmp(ptr
, "drive") == 0) {
1127 } else if (strcmp(ptr
, "device") == 0) {
1136 dorename(struct vinum_rename_msg
*msg
, const char *oldname
, const char *name
, int maxlen
)
1138 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) msg
;
1140 if (strlen(name
) > maxlen
) {
1141 fprintf(stderr
, "%s is too long\n", name
);
1144 strcpy(msg
->newname
, name
);
1145 ioctl(superdev
, VINUM_RENAME
, msg
);
1146 if (reply
->error
!= 0)
1148 "Can't rename %s to %s: %s (%d)\n",
1151 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1155 /* Rename an object:
1156 * rename <object> "newname"
1159 vinum_rename_2(char *oldname
, char *newname
)
1161 struct vinum_rename_msg msg
;
1165 msg
.index
= find_object(oldname
, &msg
.type
); /* find the object to rename */
1166 msg
.recurse
= recurse
;
1168 /* Ugh. Determine how long the name may be */
1171 dorename(&msg
, oldname
, newname
, MAXDRIVENAME
);
1175 dorename(&msg
, oldname
, newname
, MAXSDNAME
);
1180 dorename(&msg
, oldname
, newname
, MAXPLEXNAME
);
1184 get_plex_info(&plex
, plexno
); /* find out who we are */
1185 msg
.type
= sd_object
;
1186 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1187 char sdname
[MAXPLEXNAME
+ 8];
1189 get_plex_sd_info(&sd
, plex
.plexno
, sdno
); /* get info about the subdisk */
1190 sprintf(sdname
, "%s.s%d", newname
, sdno
);
1191 msg
.index
= sd
.sdno
; /* number of the subdisk */
1192 dorename(&msg
, sd
.name
, sdname
, MAXSDNAME
);
1199 dorename(&msg
, oldname
, newname
, MAXVOLNAME
);
1204 get_volume_info(&vol
, volno
); /* find out who we are */
1205 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++) {
1206 char plexname
[MAXVOLNAME
+ 8];
1208 msg
.type
= plex_object
;
1209 sprintf(plexname
, "%s.p%d", newname
, plexno
);
1210 msg
.index
= vol
.plex
[plexno
]; /* number of the plex */
1211 dorename(&msg
, plex
.name
, plexname
, MAXPLEXNAME
);
1212 get_plex_info(&plex
, vol
.plex
[plexno
]); /* find out who we are */
1213 msg
.type
= sd_object
;
1214 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1215 char sdname
[MAXPLEXNAME
+ 8];
1217 get_plex_sd_info(&sd
, plex
.plexno
, sdno
); /* get info about the subdisk */
1218 sprintf(sdname
, "%s.s%d", plexname
, sdno
);
1219 msg
.index
= sd
.sdno
; /* number of the subdisk */
1220 dorename(&msg
, sd
.name
, sdname
, MAXSDNAME
);
1227 fprintf(stderr
, "%s is not a Vinum object\n", oldname
);
1233 vinum_rename(int argc
, char *argv
[], char *argv0
[])
1236 fprintf(stderr
, "Usage: \trename <object> <new name>\n");
1239 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1240 perror("Can't get vinum config");
1243 vinum_rename_2(argv
[0], argv
[1]);
1244 checkupdates(); /* make sure we're updating */
1250 * mv <dest> <src> ...
1253 vinum_mv(int argc
, char *argv
[], char *argv0
[])
1255 int i
; /* loop index */
1258 enum objecttype srct
;
1259 enum objecttype destt
;
1261 struct _ioctl_reply reply
;
1262 struct vinum_ioctl_msg
*msg
= (struct vinum_ioctl_msg
*) &reply
;
1265 fprintf(stderr
, "Usage: \tmove <dest> <src> ...\n");
1268 /* Get current config */
1269 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1270 perror("Cannot get vinum config\n");
1273 /* Get our destination */
1274 destobj
= find_object(argv
[0], &destt
);
1275 if (destobj
== -1) {
1276 fprintf(stderr
, "Can't find %s\n", argv
[0]);
1279 /* Verify that the target is a drive */
1280 if (destt
!= drive_object
) {
1281 fprintf(stderr
, "%s is not a drive\n", argv
[0]);
1284 for (i
= 1; i
< argc
; i
++) { /* for all the sources */
1285 srcobj
= find_object(argv
[i
], &srct
);
1287 fprintf(stderr
, "Can't find %s\n", argv
[i
]);
1290 msg
->index
= destobj
;
1291 switch (srct
) { /* Handle the source object */
1292 case drive_object
: /* Move all subdisks on the drive to dst. */
1293 get_drive_info(&drive
, srcobj
); /* get info on drive */
1294 for (sdno
= 0; sdno
< vinum_conf
.subdisks_allocated
; ++sdno
) {
1295 get_sd_info(&sd
, sdno
);
1296 if (sd
.driveno
== srcobj
) {
1297 msg
->index
= destobj
;
1298 msg
->otherobject
= sd
.sdno
;
1299 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1301 "Can't move %s (part of %s) to %s: %s (%d)\n",
1305 strerror(reply
.error
),
1312 msg
->otherobject
= srcobj
;
1313 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1315 "Can't move %s to %s: %s (%d)\n",
1318 strerror(reply
.error
),
1323 get_plex_info(&plex
, srcobj
);
1324 for (sdno
= 0; sdno
< plex
.subdisks
; ++sdno
) {
1325 get_plex_sd_info(&sd
, plex
.plexno
, sdno
);
1326 msg
->index
= destobj
;
1327 msg
->otherobject
= sd
.sdno
;
1328 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1330 "Can't move %s (part of %s) to %s: %s (%d)\n",
1334 strerror(reply
.error
),
1340 case invalid_object
:
1342 fprintf(stderr
, "Can't move %s (inappropriate object).\n", argv
[i
]);
1347 "Can't move %s to %s: %s (%d)\n",
1350 strerror(reply
.error
),
1353 checkupdates(); /* make sure we're updating */
1357 * Replace objects. Not implemented, may never be.
1360 vinum_replace(int argc
, char *argv
[], char *argv0
[])
1362 fprintf(stderr
, "'replace' not implemented yet. Use 'move' instead\n");
1365 /* Primitive help function */
1367 vinum_help(int argc
, char *argv
[], char *argv0
[])
1372 "create [-f description-file]\n"
1373 " Create a volume as described in description-file\n"
1374 "attach plex volume [rename]\n"
1375 "attach subdisk plex [offset] [rename]\n"
1376 " Attach a plex to a volume, or a subdisk to a plex.\n"
1378 " Cause the volume manager to enter the kernel debugger.\n"
1380 " Set debugging flags.\n"
1381 "detach [plex | subdisk]\n"
1382 " Detach a plex or subdisk from the volume or plex to which it is\n"
1385 " List information about volume manager state.\n"
1386 "init [-v] [-w] plex\n"
1387 " Initialize a plex by writing zeroes to all its subdisks.\n"
1389 " Create a volume label\n"
1390 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1391 " List information about specified objects\n"
1392 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1393 " List information about specified objects (alternative to\n"
1395 "ld [-r] [-s] [-v] [-V] [volume]\n"
1396 " List information about drives\n"
1397 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1398 " List information about subdisks\n"
1399 "lp [-r] [-s] [-v] [-V] [plex]\n"
1400 " List information about plexes\n"
1401 "lv [-r] [-s] [-v] [-V] [volume]\n"
1402 " List information about volumes\n"
1403 "printconfig [file]\n"
1404 " Write a copy of the current configuration to file.\n"
1406 " Remake the device nodes in " _PATH_DEV
"vinum.\n"
1407 "move drive [subdisk | plex | drive]\n"
1408 " Move the subdisks of the specified object(s) to drive.\n"
1410 " Exit the vinum program when running in interactive mode. Nor-\n"
1411 " mally this would be done by entering the EOF character.\n"
1412 "read disk [disk...]\n"
1413 " Read the vinum configuration from the specified disks.\n"
1414 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1415 " Change the name of the specified object.\n"
1417 " Reset the complete vinum configuration.\n"
1418 "resetstats [-r] [volume | plex | subdisk]\n"
1419 " Reset statistisc counters for the specified objects, or for all\n"
1420 " objects if none are specified.\n"
1421 "rm [-f] [-r] volume | plex | subdisk\n"
1422 " Remove an object\n"
1424 " Save vinum configuration to disk.\n"
1425 "setdaemon [value]\n"
1426 " Set daemon configuration.\n"
1428 " Read configuration from all vinum drives.\n"
1429 "start [volume | plex | subdisk]\n"
1430 " Allow the system to access the objects\n"
1431 "stop [-f] [volume | plex | subdisk]\n"
1432 " Terminate access to the objects, or stop vinum if no parameters\n"
1438 /* Set daemon options.
1439 * XXX quick and dirty: use a bitmap, which requires
1440 * knowing which bit does what. FIXME */
1442 vinum_setdaemon(int argc
, char *argv
[], char *argv0
[])
1448 if (ioctl(superdev
, VINUM_GETDAEMON
, &options
) < 0)
1449 fprintf(stderr
, "Can't get daemon options: %s (%d)\n", strerror(errno
), errno
);
1451 printf("Options mask: %d\n", options
);
1455 options
= atoi(argv
[0]);
1456 if (ioctl(superdev
, VINUM_SETDAEMON
, &options
) < 0)
1457 fprintf(stderr
, "Can't set daemon options: %s (%d)\n", strerror(errno
), errno
);
1461 fprintf(stderr
, "Usage: \tsetdaemon [<bitmask>]\n");
1463 checkupdates(); /* make sure we're updating */
1471 if (ioctl(superdev
, VINUM_GETDAEMON
, &options
) < 0)
1472 fprintf(stderr
, "Can't get daemon options: %s (%d)\n", strerror(errno
), errno
);
1473 if (options
& daemon_noupdate
) {
1474 fprintf(stderr
, "*** Warning: configuration updates are disabled. ***\n");
1480 /* Save config info */
1482 vinum_saveconfig(int argc
, char *argv
[], char *argv0
[])
1487 printf("Usage: saveconfig\n");
1490 ioctltype
= 1; /* user saveconfig */
1491 if (ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
) < 0)
1492 fprintf(stderr
, "Can't save configuration: %s (%d)\n", strerror(errno
), errno
);
1493 checkupdates(); /* make sure we're updating */
1497 * Create a volume name for the quick and dirty
1498 * commands. It will be of the form "vinum#",
1499 * where # is a small positive number.
1504 int v
; /* volume number */
1505 static char volumename
[MAXVOLNAME
]; /* name to create */
1506 enum objecttype type
;
1508 objectname
= volumename
; /* point to it */
1510 sprintf(objectname
, "vinum%d", v
); /* create the name */
1511 if (find_object(objectname
, &type
) == -1) /* does it exist? */
1512 return; /* no, it's ours */
1517 * Create a drive for the quick and dirty
1518 * commands. The name will be of the form
1519 * vinumdrive#, where # is a small positive
1520 * number. Return the name of the drive.
1523 create_drive(char *devicename
)
1525 int d
; /* volume number */
1526 static char drivename
[MAXDRIVENAME
]; /* name to create */
1527 enum objecttype type
;
1528 struct _ioctl_reply
*reply
;
1530 devicename
= getdevpath(devicename
, 0);
1533 * We're never likely to get anything
1534 * like 10000 drives. The only reason for
1535 * this limit is to stop the thing
1536 * looping if we have a bug somewhere.
1538 for (d
= 0; d
< 100000; d
++) { /* look for a free drive number */
1539 sprintf(drivename
, "vinumdrive%d", d
); /* create the name */
1540 if (find_object(drivename
, &type
) == -1) { /* does it exist? */
1541 char command
[MAXDRIVENAME
* 2];
1543 sprintf(command
, "drive %s device %s", drivename
, devicename
); /* create a create command */
1545 printf("drive %s device %s\n", drivename
, devicename
); /* create a create command */
1546 ioctl(superdev
, VINUM_CREATE
, command
);
1547 reply
= (struct _ioctl_reply
*) &command
;
1548 if (reply
->error
!= 0) { /* error in config */
1551 "Can't create drive %s, device %s: %s\n",
1557 "Can't create drive %s, device %s: %s (%d)\n",
1560 strerror(reply
->error
),
1562 longjmp(command_fail
, -1); /* give up */
1564 find_object(drivename
, &type
);
1566 return &drive
; /* return the name of the drive */
1569 fprintf(stderr
, "Can't generate a drive name\n");
1576 * Create a volume with a single concatenated plex from
1577 * as much space as we can get on the specified drives.
1578 * If the drives aren't Vinum drives, make them so.
1581 vinum_concat(int argc
, char *argv
[], char *argv0
[])
1583 int o
; /* object number */
1584 char buffer
[BUFSIZE
];
1585 struct drive
*drive
; /* drive we're currently looking at */
1586 struct _ioctl_reply
*reply
;
1589 enum objecttype type
;
1591 reply
= (struct _ioctl_reply
*) &buffer
;
1592 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1593 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1596 if (!objectname
) /* we need a name for our object */
1598 sprintf(buffer
, "volume %s", objectname
);
1600 printf("volume %s\n", objectname
);
1601 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1602 if (reply
->error
!= 0) { /* error in config */
1605 "Can't create volume %s: %s\n",
1610 "Can't create volume %s: %s (%d)\n",
1612 strerror(reply
->error
),
1614 longjmp(command_fail
, -1); /* give up */
1616 sprintf(buffer
, "plex name %s.p0 org concat", objectname
);
1618 printf(" plex name %s.p0 org concat\n", objectname
);
1619 ioctl(superdev
, VINUM_CREATE
, buffer
);
1620 if (reply
->error
!= 0) { /* error in config */
1623 "Can't create plex %s.p0: %s\n",
1628 "Can't create plex %s.p0: %s (%d)\n",
1630 strerror(reply
->error
),
1632 longjmp(command_fail
, -1); /* give up */
1634 for (o
= 0; o
< argc
; o
++) {
1635 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1636 drive
= create_drive(argv
[o
]); /* create it */
1637 sprintf(buffer
, "sd name %s.p0.s%d drive %s size 0", objectname
, o
, drive
->label
.name
);
1639 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname
, o
, drive
->label
.name
);
1640 ioctl(superdev
, VINUM_CREATE
, buffer
);
1641 if (reply
->error
!= 0) { /* error in config */
1644 "Can't create subdisk %s.p0.s%d: %s\n",
1650 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1653 strerror(reply
->error
),
1655 longjmp(command_fail
, -1); /* give up */
1659 /* done, save the config */
1660 ioctltype
= 0; /* saveconfig after update */
1661 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1663 perror("Can't save Vinum config");
1664 find_object(objectname
, &type
); /* find the index of the volume */
1666 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1669 vflag
--; /* XXX don't give too much detail */
1670 find_object(objectname
, &type
); /* point to the volume */
1671 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1677 * Create a volume with a single striped plex from
1678 * as much space as we can get on the specified drives.
1679 * If the drives aren't Vinum drives, make them so.
1682 vinum_stripe(int argc
, char *argv
[], char *argv0
[])
1684 int o
; /* object number */
1685 char buffer
[BUFSIZE
];
1686 struct drive
*drive
; /* drive we're currently looking at */
1687 struct _ioctl_reply
*reply
;
1690 enum objecttype type
;
1692 int fe
; /* freelist entry index */
1694 struct drive_freelist freelist
;
1695 struct ferq
{ /* request to pass to ioctl */
1700 u_int64_t bigchunk
; /* biggest chunk in freelist */
1703 reply
= (struct _ioctl_reply
*) &buffer
;
1706 * First, check our drives.
1709 fprintf(stderr
, "You need at least two drives to create a striped plex\n");
1712 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1713 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1716 if (!objectname
) /* we need a name for our object */
1718 for (o
= 0; o
< argc
; o
++) {
1719 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1720 drive
= create_drive(argv
[o
]); /* create it */
1721 /* Now find the largest chunk available on the drive */
1722 bigchunk
= 0; /* ain't found nothin' yet */
1723 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
1724 freeunion
.ferq
.driveno
= drive
->driveno
;
1725 freeunion
.ferq
.fe
= fe
;
1726 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
1728 "Can't get free list element %d: %s\n",
1731 longjmp(command_fail
, -1);
1733 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
1735 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
1738 /* Now create the volume */
1739 sprintf(buffer
, "volume %s", objectname
);
1741 printf("volume %s\n", objectname
);
1742 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1743 if (reply
->error
!= 0) { /* error in config */
1746 "Can't create volume %s: %s\n",
1751 "Can't create volume %s: %s (%d)\n",
1753 strerror(reply
->error
),
1755 longjmp(command_fail
, -1); /* give up */
1757 sprintf(buffer
, "plex name %s.p0 org striped 256k", objectname
);
1759 printf(" plex name %s.p0 org striped 256k\n", objectname
);
1760 ioctl(superdev
, VINUM_CREATE
, buffer
);
1761 if (reply
->error
!= 0) { /* error in config */
1764 "Can't create plex %s.p0: %s\n",
1769 "Can't create plex %s.p0: %s (%d)\n",
1771 strerror(reply
->error
),
1773 longjmp(command_fail
, -1); /* give up */
1775 for (o
= 0; o
< argc
; o
++) {
1776 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
1778 "sd name %s.p0.s%d drive %s size %lldb",
1782 (long long) maxsize
);
1784 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1788 (long long) maxsize
);
1789 ioctl(superdev
, VINUM_CREATE
, buffer
);
1790 if (reply
->error
!= 0) { /* error in config */
1793 "Can't create subdisk %s.p0.s%d: %s\n",
1799 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1802 strerror(reply
->error
),
1804 longjmp(command_fail
, -1); /* give up */
1808 /* done, save the config */
1809 ioctltype
= 0; /* saveconfig after update */
1810 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1812 perror("Can't save Vinum config");
1813 find_object(objectname
, &type
); /* find the index of the volume */
1815 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1818 vflag
--; /* XXX don't give too much detail */
1819 find_object(objectname
, &type
); /* point to the volume */
1820 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1825 * Create a volume with a single RAID-4 plex from
1826 * as much space as we can get on the specified drives.
1827 * If the drives aren't Vinum drives, make them so.
1830 vinum_raid4(int argc
, char *argv
[], char *argv0
[])
1832 int o
; /* object number */
1833 char buffer
[BUFSIZE
];
1834 struct drive
*drive
; /* drive we're currently looking at */
1835 struct _ioctl_reply
*reply
;
1838 enum objecttype type
;
1840 int fe
; /* freelist entry index */
1842 struct drive_freelist freelist
;
1843 struct ferq
{ /* request to pass to ioctl */
1848 u_int64_t bigchunk
; /* biggest chunk in freelist */
1851 reply
= (struct _ioctl_reply
*) &buffer
;
1854 * First, check our drives.
1857 fprintf(stderr
, "You need at least three drives to create a RAID-4 plex\n");
1860 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1861 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1864 if (!objectname
) /* we need a name for our object */
1866 for (o
= 0; o
< argc
; o
++) {
1867 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1868 drive
= create_drive(argv
[o
]); /* create it */
1869 /* Now find the largest chunk available on the drive */
1870 bigchunk
= 0; /* ain't found nothin' yet */
1871 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
1872 freeunion
.ferq
.driveno
= drive
->driveno
;
1873 freeunion
.ferq
.fe
= fe
;
1874 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
1876 "Can't get free list element %d: %s\n",
1879 longjmp(command_fail
, -1);
1881 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
1883 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
1886 /* Now create the volume */
1887 sprintf(buffer
, "volume %s", objectname
);
1889 printf("volume %s\n", objectname
);
1890 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1891 if (reply
->error
!= 0) { /* error in config */
1894 "Can't create volume %s: %s\n",
1899 "Can't create volume %s: %s (%d)\n",
1901 strerror(reply
->error
),
1903 longjmp(command_fail
, -1); /* give up */
1905 sprintf(buffer
, "plex name %s.p0 org raid4 256k", objectname
);
1907 printf(" plex name %s.p0 org raid4 256k\n", objectname
);
1908 ioctl(superdev
, VINUM_CREATE
, buffer
);
1909 if (reply
->error
!= 0) { /* error in config */
1912 "Can't create plex %s.p0: %s\n",
1917 "Can't create plex %s.p0: %s (%d)\n",
1919 strerror(reply
->error
),
1921 longjmp(command_fail
, -1); /* give up */
1923 for (o
= 0; o
< argc
; o
++) {
1924 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
1926 "sd name %s.p0.s%d drive %s size %lldb",
1930 (long long) maxsize
);
1932 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1936 (long long) maxsize
);
1937 ioctl(superdev
, VINUM_CREATE
, buffer
);
1938 if (reply
->error
!= 0) { /* error in config */
1941 "Can't create subdisk %s.p0.s%d: %s\n",
1947 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1950 strerror(reply
->error
),
1952 longjmp(command_fail
, -1); /* give up */
1956 /* done, save the config */
1957 ioctltype
= 0; /* saveconfig after update */
1958 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1960 perror("Can't save Vinum config");
1961 find_object(objectname
, &type
); /* find the index of the volume */
1963 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1966 vflag
--; /* XXX don't give too much detail */
1967 find_object(objectname
, &type
); /* point to the volume */
1968 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1973 * Create a volume with a single RAID-4 plex from
1974 * as much space as we can get on the specified drives.
1975 * If the drives aren't Vinum drives, make them so.
1978 vinum_raid5(int argc
, char *argv
[], char *argv0
[])
1980 int o
; /* object number */
1981 char buffer
[BUFSIZE
];
1982 struct drive
*drive
; /* drive we're currently looking at */
1983 struct _ioctl_reply
*reply
;
1986 enum objecttype type
;
1988 int fe
; /* freelist entry index */
1990 struct drive_freelist freelist
;
1991 struct ferq
{ /* request to pass to ioctl */
1996 u_int64_t bigchunk
; /* biggest chunk in freelist */
1999 reply
= (struct _ioctl_reply
*) &buffer
;
2002 * First, check our drives.
2005 fprintf(stderr
, "You need at least three drives to create a RAID-5 plex\n");
2008 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
2009 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
2012 if (!objectname
) /* we need a name for our object */
2014 for (o
= 0; o
< argc
; o
++) {
2015 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
2016 drive
= create_drive(argv
[o
]); /* create it */
2017 /* Now find the largest chunk available on the drive */
2018 bigchunk
= 0; /* ain't found nothin' yet */
2019 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
2020 freeunion
.ferq
.driveno
= drive
->driveno
;
2021 freeunion
.ferq
.fe
= fe
;
2022 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
2024 "Can't get free list element %d: %s\n",
2027 longjmp(command_fail
, -1);
2029 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
2031 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
2034 /* Now create the volume */
2035 sprintf(buffer
, "volume %s", objectname
);
2037 printf("volume %s\n", objectname
);
2038 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
2039 if (reply
->error
!= 0) { /* error in config */
2042 "Can't create volume %s: %s\n",
2047 "Can't create volume %s: %s (%d)\n",
2049 strerror(reply
->error
),
2051 longjmp(command_fail
, -1); /* give up */
2053 sprintf(buffer
, "plex name %s.p0 org raid5 256k", objectname
);
2055 printf(" plex name %s.p0 org raid5 256k\n", objectname
);
2056 ioctl(superdev
, VINUM_CREATE
, buffer
);
2057 if (reply
->error
!= 0) { /* error in config */
2060 "Can't create plex %s.p0: %s\n",
2065 "Can't create plex %s.p0: %s (%d)\n",
2067 strerror(reply
->error
),
2069 longjmp(command_fail
, -1); /* give up */
2071 for (o
= 0; o
< argc
; o
++) {
2072 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
2074 "sd name %s.p0.s%d drive %s size %lldb",
2078 (long long) maxsize
);
2080 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2084 (long long) maxsize
);
2085 ioctl(superdev
, VINUM_CREATE
, buffer
);
2086 if (reply
->error
!= 0) { /* error in config */
2089 "Can't create subdisk %s.p0.s%d: %s\n",
2095 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2098 strerror(reply
->error
),
2100 longjmp(command_fail
, -1); /* give up */
2104 /* done, save the config */
2105 ioctltype
= 0; /* saveconfig after update */
2106 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
2108 perror("Can't save Vinum config");
2109 find_object(objectname
, &type
); /* find the index of the volume */
2111 make_vol_dev(vol
.volno
, 1); /* and create the devices */
2114 vflag
--; /* XXX don't give too much detail */
2115 find_object(objectname
, &type
); /* point to the volume */
2116 vinum_lvi(vol
.volno
, 1); /* and print info about it */
2121 * Create a volume with a two plexes from as much space
2122 * as we can get on the specified drives. If the
2123 * drives aren't Vinum drives, make them so.
2125 * The number of drives must be even, and at least 4
2126 * for a striped plex. Specify striped plexes with the
2127 * -s flag; otherwise they will be concatenated. It's
2128 * possible that the two plexes may differ in length.
2131 vinum_mirror(int argc
, char *argv
[], char *argv0
[])
2133 int o
; /* object number */
2134 int p
; /* plex number */
2135 char buffer
[BUFSIZE
];
2136 struct drive
*drive
; /* drive we're currently looking at */
2137 struct _ioctl_reply
*reply
;
2140 enum objecttype type
;
2141 off_t maxsize
[2]; /* maximum subdisk size for striped plexes */
2142 int fe
; /* freelist entry index */
2144 struct drive_freelist freelist
;
2145 struct ferq
{ /* request to pass to ioctl */
2150 u_int64_t bigchunk
; /* biggest chunk in freelist */
2152 if (sflag
) /* striped, */
2153 maxsize
[0] = maxsize
[1] = QUAD_MAX
; /* we need to calculate sd size */
2155 maxsize
[0] = maxsize
[1] = 0; /* let the kernel routines do it */
2157 reply
= (struct _ioctl_reply
*) &buffer
;
2160 * First, check our drives.
2163 fprintf(stderr
, "You need an even number of drives to create a mirrored volume\n");
2166 if (sflag
&& (argc
< 4)) {
2167 fprintf(stderr
, "You need at least 4 drives to create a mirrored, striped volume\n");
2170 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
2171 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
2174 if (!objectname
) /* we need a name for our object */
2176 for (o
= 0; o
< argc
; o
++) {
2177 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
2178 drive
= create_drive(argv
[o
]); /* create it */
2179 if (sflag
) { /* striping, */
2180 /* Find the largest chunk available on the drive */
2181 bigchunk
= 0; /* ain't found nothin' yet */
2182 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
2183 freeunion
.ferq
.driveno
= drive
->driveno
;
2184 freeunion
.ferq
.fe
= fe
;
2185 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
2187 "Can't get free list element %d: %s\n",
2190 longjmp(command_fail
, -1);
2192 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
2194 maxsize
[o
& 1] = min(maxsize
[o
& 1], bigchunk
); /* get the maximum size of a subdisk */
2198 /* Now create the volume */
2199 sprintf(buffer
, "volume %s setupstate", objectname
);
2201 printf("volume %s setupstate\n", objectname
);
2202 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
2203 if (reply
->error
!= 0) { /* error in config */
2206 "Can't create volume %s: %s\n",
2211 "Can't create volume %s: %s (%d)\n",
2213 strerror(reply
->error
),
2215 longjmp(command_fail
, -1); /* give up */
2217 for (p
= 0; p
< 2; p
++) { /* create each plex */
2219 sprintf(buffer
, "plex name %s.p%d org striped 256k", objectname
, p
);
2221 printf(" plex name %s.p%d org striped 256k\n", objectname
, p
);
2222 } else { /* concat */
2223 sprintf(buffer
, "plex name %s.p%d org concat", objectname
, p
);
2225 printf(" plex name %s.p%d org concat\n", objectname
, p
);
2227 ioctl(superdev
, VINUM_CREATE
, buffer
);
2228 if (reply
->error
!= 0) { /* error in config */
2231 "Can't create plex %s.p%d: %s\n",
2237 "Can't create plex %s.p%d: %s (%d)\n",
2240 strerror(reply
->error
),
2242 longjmp(command_fail
, -1); /* give up */
2244 /* Now look at the subdisks */
2245 for (o
= p
; o
< argc
; o
+= 2) { /* every second one */
2246 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
2248 "sd name %s.p%d.s%d drive %s size %lldb",
2253 (long long) maxsize
[p
]);
2255 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2260 (long long) maxsize
[p
]);
2261 ioctl(superdev
, VINUM_CREATE
, buffer
);
2262 if (reply
->error
!= 0) { /* error in config */
2265 "Can't create subdisk %s.p%d.s%d: %s\n",
2272 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2276 strerror(reply
->error
),
2278 longjmp(command_fail
, -1); /* give up */
2283 /* done, save the config */
2284 ioctltype
= 0; /* saveconfig after update */
2285 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
2287 perror("Can't save Vinum config");
2288 find_object(objectname
, &type
); /* find the index of the volume */
2290 make_vol_dev(vol
.volno
, 1); /* and create the devices */
2293 vflag
--; /* XXX don't give too much detail */
2294 sflag
= 0; /* no stats, please */
2295 find_object(objectname
, &type
); /* point to the volume */
2296 vinum_lvi(vol
.volno
, 1); /* and print info about it */
2301 vinum_readpol(int argc
, char *argv
[], char *argv0
[])
2304 struct _ioctl_reply reply
;
2305 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2306 enum objecttype type
;
2311 if (argc
== 0) { /* start everything */
2312 fprintf(stderr
, "Usage: readpol <volume> <plex>|round\n");
2315 object
= find_object(argv
[1], &type
); /* look for it */
2316 if (type
!= volume_object
) {
2317 fprintf(stderr
, "%s is not a volume\n", argv
[1]);
2320 get_volume_info(&vol
, object
);
2321 if (strcmp(argv
[2], "round")) { /* not 'round' */
2322 object
= find_object(argv
[2], &type
); /* look for it */
2323 if (type
!= plex_object
) {
2324 fprintf(stderr
, "%s is not a plex\n", argv
[2]);
2327 get_plex_info(&plex
, object
);
2328 plexno
= plex
.plexno
;
2333 message
->index
= vol
.volno
;
2334 message
->otherobject
= plexno
;
2335 if (ioctl(superdev
, VINUM_READPOL
, message
) < 0)
2336 fprintf(stderr
, "Can't set read policy: %s (%d)\n", strerror(errno
), errno
);
2338 vinum_lpi(plexno
, recurse
);
2342 * Brute force set state function. Don't look at
2343 * any dependencies, just do it.
2346 vinum_setstate(int argc
, char *argv
[], char *argv0
[])
2349 struct _ioctl_reply reply
;
2350 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2352 enum objecttype type
;
2355 for (index
= 1; index
< argc
; index
++) {
2356 object
= find_object(argv
[index
], &type
); /* look for it */
2357 if (type
== invalid_object
)
2358 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
2360 int doit
= 0; /* set to 1 if we pass our tests */
2363 state
= DriveState(argv
[0]); /* get the state */
2364 if (drive
.state
== state
) /* already in that state */
2365 fprintf(stderr
, "%s is already %s\n", drive
.label
.name
, argv
[0]);
2371 state
= SdState(argv
[0]); /* get the state */
2372 if (sd
.state
== state
) /* already in that state */
2373 fprintf(stderr
, "%s is already %s\n", sd
.name
, argv
[0]);
2379 state
= PlexState(argv
[0]); /* get the state */
2380 if (plex
.state
== state
) /* already in that state */
2381 fprintf(stderr
, "%s is already %s\n", plex
.name
, argv
[0]);
2387 state
= VolState(argv
[0]); /* get the state */
2388 if (vol
.state
== state
) /* already in that state */
2389 fprintf(stderr
, "%s is already %s\n", vol
.name
, argv
[0]);
2395 state
= 0; /* to keep the compiler happy */
2399 fprintf(stderr
, "Invalid state for object: %s\n", argv
[0]);
2401 message
->index
= object
; /* pass object number */
2402 message
->type
= type
; /* and type of object */
2403 message
->state
= state
;
2404 message
->force
= force
; /* don't force it, use a larger hammer */
2405 ioctl(superdev
, VINUM_SETSTATE_FORCE
, message
);
2406 if (reply
.error
!= 0)
2408 "Can't start %s: %s (%d)\n",
2410 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
2413 vinum_li(object
, type
);
2420 vinum_checkparity(int argc
, char *argv
[], char *argv0
[])
2422 Verbose
= vflag
; /* accept -v for verbose */
2423 if (argc
== 0) /* no parameters? */
2424 fprintf(stderr
, "Usage: checkparity object [object...]\n");
2426 parityops(argc
, argv
, checkparity
);
2430 vinum_rebuildparity(int argc
, char *argv
[], char *argv0
[])
2432 if (argc
== 0) /* no parameters? */
2433 fprintf(stderr
, "Usage: rebuildparity object [object...]\n");
2435 parityops(argc
, argv
, vflag
? rebuildandcheckparity
: rebuildparity
);
2439 * Common code for rebuildparity and checkparity.
2440 * We bend the meanings of some flags here:
2442 * -v: Report incorrect parity on rebuild.
2443 * -V: Show running count of position being checked.
2444 * -f: Start from beginning of the plex.
2447 parityops(int argc
, char *argv
[], enum parityop op
)
2451 struct _ioctl_reply reply
;
2452 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2454 enum objecttype type
;
2458 if (op
== checkparity
)
2462 for (index
= 0; index
< argc
; index
++) {
2463 object
= find_object(argv
[index
], &type
); /* look for it */
2464 if (type
!= plex_object
)
2465 fprintf(stderr
, "%s is not a plex\n", argv
[index
]);
2467 get_plex_info(&plex
, object
);
2468 if (!isparity((&plex
)))
2469 fprintf(stderr
, "%s is not a RAID-4 or RAID-5 plex\n", argv
[index
]);
2472 message
->index
= object
; /* pass object number */
2473 message
->type
= type
; /* and type of object */
2474 message
->op
= op
; /* what to do */
2476 message
->offset
= 0; /* start at the beginning */
2478 message
->offset
= plex
.checkblock
; /* continue where we left off */
2479 force
= 0; /* don't reset after the first time */
2480 ioctl(superdev
, VINUM_PARITYOP
, message
);
2481 get_plex_info(&plex
, object
);
2483 block
= (plex
.checkblock
<< DEV_BSHIFT
) * (plex
.subdisks
- 1);
2485 printf("\r%s at %s (%d%%) ",
2487 roughlength(block
, 1),
2488 ((int) (block
* 100 / plex
.length
) >> DEV_BSHIFT
));
2489 if ((reply
.error
== EAGAIN
)
2490 && (reply
.msg
[0])) /* got a comment back */
2491 fputs(reply
.msg
, stderr
); /* show it */
2495 while (reply
.error
== EAGAIN
);
2496 if (reply
.error
!= 0) {
2498 fputs(reply
.msg
, stderr
);
2503 strerror(reply
.error
));
2504 } else if (Verbose
) {
2505 if (op
== checkparity
)
2506 fprintf(stderr
, "%s has correct parity\n", argv
[index
]);
2508 fprintf(stderr
, "Rebuilt parity on %s\n", argv
[index
]);