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 $
37 * $DragonFly: src/sbin/vinum/commands.c,v 1.10 2008/06/05 18:06:31 swildner Exp $
40 #define _KERNEL_STRUCTURES
55 #include <sys/ioctl.h>
56 #include <dev/raid/vinum/vinumhdr.h>
57 #include <dev/raid/vinum/request.h>
59 #include <sys/types.h>
60 #include <sys/linker.h>
61 #include <sys/module.h>
63 #include <readline/readline.h>
66 static void dorename(struct vinum_rename_msg
*msg
, const char *oldname
, const char *name
, int maxlen
);
67 static void reparse(char *buf
, char *tmp
);
70 vinum_create(int argc
, char *argv
[], char *arg0
[])
73 FILE *dfd
; /* file descriptor for the config file */
74 char buffer
[BUFSIZE
]; /* read config file in here */
75 char commandline
[BUFSIZE
]; /* issue command from here */
76 struct _ioctl_reply
*reply
;
77 int ioctltype
; /* for ioctl call */
78 char tempfile
[PATH_MAX
]; /* name of temp file for direct editing */
79 char *file
; /* file to read */
80 FILE *tf
; /* temp file */
82 if (argc
== 0) { /* no args, */
83 char *editor
; /* editor to start */
86 editor
= getenv("EDITOR");
88 editor
= "/usr/bin/vi";
89 sprintf(tempfile
, "/var/tmp/" VINUMMOD
".create.%d", getpid()); /* create a temp file */
90 tf
= fopen(tempfile
, "w"); /* open it */
92 fprintf(stderr
, "Can't open %s: %s\n", argv
[0], strerror(errno
));
95 printconfig(tf
, "# "); /* and put the current config it */
97 sprintf(commandline
, "%s %s", editor
, tempfile
); /* create an edit command */
98 status
= system(commandline
); /* do it */
100 fprintf(stderr
, "Can't edit config: status %d\n", status
);
104 } else if (argc
== 1)
107 fprintf(stderr
, "Expecting 1 parameter, not %d\n", argc
);
110 reply
= (struct _ioctl_reply
*) &buffer
;
111 dfd
= fopen(file
, "r");
112 if (dfd
== NULL
) { /* no go */
113 fprintf(stderr
, "Can't open %s: %s\n", file
, strerror(errno
));
116 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
117 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
120 file_line
= 0; /* start with line 1 */
121 /* Parse the configuration, and add it to the global configuration */
122 for (;;) { /* love this style(9) */
125 configline
= fgets(buffer
, BUFSIZE
, dfd
);
127 if (configline
== NULL
) {
129 perror("Can't read config file");
133 fprintf(hist
, "%s", buffer
);
134 file_line
++; /* count the lines */
136 reparse(buffer
, commandline
);
139 printf("%4d: %s", file_line
, buffer
);
140 strcpy(commandline
, buffer
); /* make a copy */
141 ioctl(superdev
, VINUM_CREATE
, buffer
);
142 if (reply
->error
!= 0) { /* error in config */
143 if (!vflag
) /* print this line anyway */
144 printf("%4d: %s", file_line
, commandline
);
145 fprintf(stdout
, "** %d %s: %s\n",
148 strerror(reply
->error
));
151 * XXX at the moment, we reset the config
152 * lock on error, so try to get it again.
153 * If we fail, don't cry again.
155 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) /* can't get config? */
159 fclose(dfd
); /* done with the config file */
160 ioctltype
= 0; /* saveconfig after update */
161 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
163 perror("Can't save Vinum config");
166 checkupdates(); /* make sure we're updating */
169 /* Read vinum config from a disk */
171 vinum_read(int argc
, char *argv
[], char *arg0
[])
174 char buffer
[BUFSIZE
]; /* read config file in here */
175 struct _ioctl_reply
*reply
;
178 reply
= (struct _ioctl_reply
*) &buffer
;
179 if (argc
< 1) { /* wrong arg count */
180 fprintf(stderr
, "Usage: read drive [drive ...]\n");
183 strcpy(buffer
, "read ");
184 for (i
= 0; i
< argc
; i
++) { /* each drive name */
185 strcat(buffer
, argv
[i
]);
189 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
190 fprintf(stderr
, "Can't configure: %s (%d)\n", strerror(errno
), errno
);
193 ioctl(superdev
, VINUM_CREATE
, &buffer
);
194 if (reply
->error
!= 0) { /* error in config */
195 fprintf(stdout
, "** %s: %s\n", reply
->msg
, strerror(reply
->error
));
196 error
= ioctl(superdev
, VINUM_RELEASECONFIG
, NULL
); /* save the config to disk */
198 perror("Can't save Vinum config");
200 error
= ioctl(superdev
, VINUM_RELEASECONFIG
, NULL
); /* save the config to disk */
202 perror("Can't save Vinum config");
205 checkupdates(); /* make sure we're updating */
210 vinum_debug(int argc
, char *argv
[], char *arg0
[])
212 struct debuginfo info
;
215 info
.param
= atoi(argv
[0]);
219 sleep(2); /* give a chance to leave the window */
221 ioctl(superdev
, VINUM_DEBUG
, (caddr_t
) & info
);
226 vinum_modify(int argc
, char *argv
[], char *arg0
[])
228 fprintf(stderr
, "Modify command is currently not implemented\n");
229 checkupdates(); /* make sure we're updating */
233 vinum_set(int argc
, char *argv
[], char *arg0
[])
235 fprintf(stderr
, "set is not implemented yet\n");
239 vinum_rm(int argc
, char *argv
[], char *arg0
[])
242 struct _ioctl_reply reply
;
243 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
245 if (argc
== 0) /* start everything */
246 fprintf(stderr
, "Usage: rm object [object...]\n");
247 else { /* start specified objects */
249 enum objecttype type
;
251 for (index
= 0; index
< argc
; index
++) {
252 object
= find_object(argv
[index
], &type
); /* look for it */
253 if (type
== invalid_object
)
254 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
256 message
->index
= object
; /* pass object number */
257 message
->type
= type
; /* and type of object */
258 message
->force
= force
; /* do we want to force the operation? */
259 message
->recurse
= recurse
; /* do we want to remove subordinates? */
260 ioctl(superdev
, VINUM_REMOVE
, message
);
261 if (reply
.error
!= 0) {
263 "Can't remove %s: %s (%d)\n",
265 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
268 fprintf(stderr
, "%s removed\n", argv
[index
]);
271 checkupdates(); /* make sure we're updating */
276 vinum_resetconfig(int argc
, char *argv
[], char *arg0
[])
281 if (! isatty (STDIN_FILENO
)) {
282 fprintf (stderr
, "Please enter this command from a tty device\n");
285 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
286 " All data will be lost. If you really want to do this, enter the text\n\n"
289 fgets(reply
, sizeof(reply
), stdin
);
290 if (strcmp(reply
, "NO FUTURE\n")) /* changed his mind */
291 printf("\n No change\n");
293 error
= ioctl(superdev
, VINUM_RESETCONFIG
, NULL
); /* trash config on disk */
296 fprintf(stderr
, "Can't reset configuration: objects are in use\n");
298 perror("Can't find vinum config");
300 make_devices(); /* recreate the /dev/vinum hierarchy */
301 printf("\b Vinum configuration obliterated\n");
302 start_daemon(); /* then restart the daemon */
305 checkupdates(); /* make sure we're updating */
308 /* Initialize subdisks */
310 vinum_init(int argc
, char *argv
[], char *arg0
[])
312 if (argc
> 0) { /* initialize plexes */
315 enum objecttype type
; /* type returned */
318 fflush(hist
); /* don't let all the kids do it. */
319 for (objindex
= 0; objindex
< argc
; objindex
++) {
320 objno
= find_object(argv
[objindex
], &type
); /* find the object */
322 printf("Can't find %s\n", argv
[objindex
]);
330 initplex(objno
, argv
[objindex
]);
334 initsd(objno
, dowait
);
338 printf("Can't initialize %s: wrong object type\n", argv
[objindex
]);
344 checkupdates(); /* make sure we're updating */
350 printf("Initializing volumes is not implemented yet\n");
354 initplex(int plexno
, char *name
)
357 int plexfh
= 0; /* file handle for plex */
359 char filename
[MAXPATHLEN
]; /* create a file name here */
361 /* Variables for use by children */
362 int failed
= 0; /* set if a child dies badly */
364 sprintf(filename
, VINUM_DIR
"/plex/%s", name
);
365 if ((plexfh
= open(filename
, O_RDWR
, S_IRWXU
)) < 0) { /* got a plex, open it */
367 * We don't actually write anything to the
368 * plex. We open it to ensure that nobody
369 * else tries to open it while we initialize
372 fprintf(stderr
, "can't open plex %s: %s\n", filename
, strerror(errno
));
376 pid
= fork(); /* into the background with you */
377 if (pid
!= 0) { /* I'm the parent, or we failed */
378 if (pid
< 0) /* failure */
379 printf("Couldn't fork: %s", strerror(errno
));
380 close(plexfh
); /* we don't need this any more */
385 * If we get here, we're either the first-level
386 * child (if we're not waiting) or we're going
389 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) { /* initialize each subdisk */
390 get_plex_sd_info(&sd
, plexno
, sdno
);
393 /* Now wait for them to complete */
397 if (((int) pid
== -1)
398 && (errno
== ECHILD
)) /* all gone */
400 if (WEXITSTATUS(status
) != 0) { /* oh, oh */
401 printf("child %d exited with status 0x%x\n", pid
, WEXITSTATUS(status
));
407 message
->index
= plexno
; /* pass object number */
408 message
->type
= plex_object
; /* and type of object */
409 message
->state
= object_up
;
410 message
->force
= 1; /* insist */
411 ioctl(superdev
, VINUM_SETSTATE
, message
);
413 syslog(LOG_INFO
| LOG_KERN
, "plex %s initialized", plex
.name
);
415 syslog(LOG_ERR
| LOG_KERN
, "couldn't initialize plex %s, %d processes died",
418 if (dowait
== 0) /* we're the waiting child, */
419 exit(0); /* we've done our dash */
422 /* Initialize a subdisk. */
424 initsd(int sdno
, int dowait
)
427 struct _ioctl_reply reply
;
428 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
429 char filename
[MAXPATHLEN
]; /* create a file name here */
431 /* Variables for use by children */
432 int sdfh
; /* and for subdisk */
433 int initsize
; /* actual size to write */
434 int64_t sdsize
; /* size of subdisk */
437 pid
= fork(); /* into the background with you */
438 if (pid
> 0) /* I'm the parent */
440 else if (pid
< 0) { /* failure */
441 printf("couldn't fork for subdisk %d: %s", sdno
, strerror(errno
));
445 if (SSize
!= 0) { /* specified a size for init */
447 SSize
<<= DEV_BSHIFT
;
448 initsize
= min(SSize
, MAXPLEXINITSIZE
);
450 initsize
= PLEXINITSIZE
;
451 openlog("vinum", LOG_CONS
| LOG_PERROR
| LOG_PID
, LOG_KERN
);
452 get_sd_info(&sd
, sdno
);
453 sdsize
= sd
.sectors
* DEV_BSIZE
; /* size of subdisk in bytes */
454 sprintf(filename
, VINUM_DIR
"/sd/%s", sd
.name
);
455 setproctitle("initializing %s", filename
); /* show what we're doing */
456 syslog(LOG_INFO
| LOG_KERN
, "initializing subdisk %s", filename
);
457 if ((sdfh
= open(filename
, O_RDWR
, S_IRWXU
)) < 0) { /* no go */
458 syslog(LOG_ERR
| LOG_KERN
,
459 "can't open subdisk %s: %s",
464 /* Set the subdisk in initializing state */
465 message
->index
= sd
.sdno
; /* pass object number */
466 message
->type
= sd_object
; /* and type of object */
467 message
->state
= object_initializing
;
468 message
->verify
= vflag
; /* verify what we write? */
469 message
->force
= 1; /* insist */
470 ioctl(superdev
, VINUM_SETSTATE
, message
);
471 if ((SSize
> 0) /* specified a size for init */
473 SSize
<<= DEV_BSHIFT
;
476 "Can't initialize %s: %s (%d)\n",
478 strerror(reply
.error
),
483 if (interval
) /* pause between copies */
484 usleep(interval
* 1000);
485 message
->index
= sd
.sdno
; /* pass object number */
486 message
->type
= sd_object
; /* and type of object */
487 message
->state
= object_up
;
488 message
->verify
= vflag
; /* verify what we write? */
489 message
->blocksize
= SSize
;
490 ioctl(superdev
, VINUM_SETSTATE
, message
);
492 while (reply
.error
== EAGAIN
); /* until we're done */
495 "Can't initialize %s: %s (%d)\n",
497 strerror(reply
.error
),
499 get_sd_info(&sd
, sdno
);
500 if (sd
.state
!= sd_up
)
501 /* Set the subdisk down */
502 message
->index
= sd
.sdno
; /* pass object number */
503 message
->type
= sd_object
; /* and type of object */
504 message
->state
= object_down
;
505 message
->verify
= vflag
; /* verify what we write? */
506 message
->force
= 1; /* insist */
507 ioctl(superdev
, VINUM_SETSTATE
, message
);
510 printf("subdisk %s initialized\n", filename
);
516 vinum_start(int argc
, char *argv
[], char *arg0
[])
519 struct _ioctl_reply reply
;
520 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
522 if (argc
== 0) { /* start everything */
523 int devs
= getnumdevs();
524 struct statinfo statinfo
;
526 char *enamelist
; /* end of name list */
528 char **token
; /* list of tokens */
529 int tokens
; /* and their number */
531 bzero(&statinfo
, sizeof(struct statinfo
));
532 statinfo
.dinfo
= malloc(devs
* sizeof(struct statinfo
));
533 namelist
= malloc(devs
* (DEVSTAT_NAME_LEN
+ 8));
534 token
= malloc((devs
+ 1) * sizeof(char *));
535 if ((statinfo
.dinfo
== NULL
) || (namelist
== NULL
) || (token
== NULL
)) {
536 fprintf(stderr
, "Can't allocate memory for drive list\n");
539 bzero(statinfo
.dinfo
, sizeof(struct devinfo
));
541 tokens
= 0; /* no tokens yet */
542 if (getdevs(&statinfo
) < 0) { /* find out what devices we have */
543 perror("Can't get device list");
546 namelist
[0] = '\0'; /* start with empty namelist */
547 enamelist
= namelist
; /* point to the end of the list */
549 for (i
= 0; i
< devs
; i
++) {
550 struct devstat
*stat
= &statinfo
.dinfo
->devices
[i
];
552 if ((((stat
->device_type
& DEVSTAT_TYPE_MASK
) == DEVSTAT_TYPE_DIRECT
) /* disk device */
553 || ((stat
->device_type
& DEVSTAT_TYPE_MASK
) == DEVSTAT_TYPE_STORARRAY
)) /* storage array */
554 &&((stat
->device_type
& DEVSTAT_TYPE_IF_MASK
) != DEVSTAT_TYPE_IF_OTHER
) /* and not md */
555 &&((stat
->device_type
& DEVSTAT_TYPE_PASS
) == 0) /* and not passthrough */
556 &&((stat
->device_name
[0] != '\0'))) { /* and it has a name */
557 sprintf(enamelist
, "%s%s%d", _PATH_DEV
, stat
->device_name
, stat
->unit_number
);
558 token
[tokens
] = enamelist
; /* point to it */
559 tokens
++; /* one more token */
560 enamelist
= &enamelist
[strlen(enamelist
) + 1]; /* and start beyond the end */
563 free(statinfo
.dinfo
); /* don't need the list any more */
564 vinum_read(tokens
, token
, &token
[0]); /* start the system */
567 list_defective_objects(); /* and list anything that's down */
568 } else { /* start specified objects */
570 enum objecttype type
;
572 for (index
= 0; index
< argc
; index
++) {
573 object
= find_object(argv
[index
], &type
); /* look for it */
574 if (type
== invalid_object
)
575 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
577 int doit
= 0; /* set to 1 if we pass our tests */
580 if (drive
.state
== drive_up
) /* already up */
581 fprintf(stderr
, "%s is already up\n", drive
.label
.name
);
587 if (sd
.state
== sd_up
) /* already up */
588 fprintf(stderr
, "%s is already up\n", sd
.name
);
594 if (plex
.state
== plex_up
) /* already up */
595 fprintf(stderr
, "%s is already up\n", plex
.name
);
600 * First, see if we can bring it up
601 * just by asking. This might happen
602 * if somebody has used setupstate on
603 * the subdisks. If we don't do this,
604 * we'll return success, but the plex
605 * won't have changed state. Note
606 * that we don't check for errors
609 message
->index
= plex
.plexno
; /* pass object number */
610 message
->type
= plex_object
; /* it's a plex */
611 message
->state
= object_up
;
612 message
->force
= 0; /* don't force it */
613 ioctl(superdev
, VINUM_SETSTATE
, message
);
614 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
615 get_plex_sd_info(&sd
, object
, sdno
);
616 if ((sd
.state
>= sd_empty
)
617 && (sd
.state
<= sd_reviving
)) { /* candidate for start */
618 message
->index
= sd
.sdno
; /* pass object number */
619 message
->type
= sd_object
; /* it's a subdisk */
620 message
->state
= object_up
;
621 message
->force
= force
; /* don't force it, use a larger hammer */
624 * We don't do any checking here.
625 * The kernel module has a better
626 * understanding of these things,
629 if (SSize
!= 0) { /* specified a size for init */
631 SSize
<<= DEV_BSHIFT
;
632 message
->blocksize
= SSize
;
634 message
->blocksize
= DEFAULT_REVIVE_BLOCKSIZE
;
635 ioctl(superdev
, VINUM_SETSTATE
, message
);
636 if (reply
.error
!= 0) {
637 if (reply
.error
== EAGAIN
) /* we're reviving */
638 continue_revive(sd
.sdno
);
641 "Can't start %s: %s (%d)\n",
643 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
647 vinum_lsi(sd
.sdno
, 0);
654 if (vol
.state
== volume_up
) /* already up */
655 fprintf(stderr
, "%s is already up\n", vol
.name
);
665 message
->index
= object
; /* pass object number */
666 message
->type
= type
; /* and type of object */
667 message
->state
= object_up
;
668 message
->force
= force
; /* don't force it, use a larger hammer */
671 * We don't do any checking here.
672 * The kernel module has a better
673 * understanding of these things,
676 if (SSize
!= 0) { /* specified a size for init or revive */
678 SSize
<<= DEV_BSHIFT
;
679 message
->blocksize
= SSize
;
681 message
->blocksize
= 0;
682 ioctl(superdev
, VINUM_SETSTATE
, message
);
683 if (reply
.error
!= 0) {
684 if ((reply
.error
== EAGAIN
) /* we're reviving */
685 &&(type
== sd_object
))
686 continue_revive(object
);
689 "Can't start %s: %s (%d)\n",
691 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
695 vinum_li(object
, type
);
700 checkupdates(); /* make sure we're updating */
704 vinum_stop(int argc
, char *argv
[], char *arg0
[])
707 struct _ioctl_reply reply
;
708 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
710 if (checkupdates() && (!force
)) /* not updating? */
712 message
->force
= force
; /* should we force the transition? */
713 if (argc
== 0) { /* stop vinum */
714 int fileid
= 0; /* ID of Vinum kld */
716 close(superdev
); /* we can't stop if we have vinum open */
717 sleep(1); /* wait for the daemon to let go */
718 fileid
= kldfind(VINUMMOD
);
719 if ((fileid
< 0) /* no go */
720 ||(kldunload(fileid
) < 0))
721 perror("Can't unload " VINUMMOD
);
723 fprintf(stderr
, VINUMMOD
" unloaded\n");
727 /* If we got here, the stop failed. Reopen the superdevice. */
728 superdev
= open(VINUM_SUPERDEV_NAME
, O_RDWR
); /* reopen vinum superdevice */
730 perror("Can't reopen Vinum superdevice");
733 } else { /* stop specified objects */
735 enum objecttype type
;
737 for (i
= 0; i
< argc
; i
++) {
738 object
= find_object(argv
[i
], &type
); /* look for it */
739 if (type
== invalid_object
)
740 fprintf(stderr
, "Can't find object: %s\n", argv
[i
]);
742 message
->index
= object
; /* pass object number */
743 message
->type
= type
; /* and type of object */
744 message
->state
= object_down
;
745 ioctl(superdev
, VINUM_SETSTATE
, message
);
746 if (reply
.error
!= 0)
748 "Can't stop %s: %s (%d)\n",
750 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
753 vinum_li(object
, type
);
760 vinum_label(int argc
, char *argv
[], char *arg0
[])
763 struct _ioctl_reply reply
;
764 int *message
= (int *) &reply
;
766 if (argc
== 0) /* start everything */
767 fprintf(stderr
, "label: please specify one or more volume names\n");
768 else { /* start specified objects */
770 enum objecttype type
;
772 for (i
= 0; i
< argc
; i
++) {
773 object
= find_object(argv
[i
], &type
); /* look for it */
774 if (type
== invalid_object
)
775 fprintf(stderr
, "Can't find object: %s\n", argv
[i
]);
776 else if (type
!= volume_object
) /* it exists, but it isn't a volume */
777 fprintf(stderr
, "%s is not a volume\n", argv
[i
]);
779 message
[0] = object
; /* pass object number */
780 ioctl(superdev
, VINUM_LABEL
, message
);
781 if (reply
.error
!= 0)
783 "Can't label %s: %s (%d)\n",
785 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
788 vinum_li(object
, type
);
792 checkupdates(); /* not updating? */
796 reset_volume_stats(int volno
, int recurse
)
798 struct vinum_ioctl_msg msg
;
799 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
802 msg
.type
= volume_object
;
803 /* XXX get these numbers right if we ever
804 * actually return errors */
805 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
806 fprintf(stderr
, "Can't reset stats for volume %d: %s\n", volno
, reply
->msg
);
807 longjmp(command_fail
, -1);
808 } else if (recurse
) {
812 get_volume_info(&vol
, volno
);
813 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++)
814 reset_plex_stats(vol
.plex
[plexno
], recurse
);
819 reset_plex_stats(int plexno
, int recurse
)
821 struct vinum_ioctl_msg msg
;
822 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
825 msg
.type
= plex_object
;
826 /* XXX get these numbers right if we ever
827 * actually return errors */
828 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
829 fprintf(stderr
, "Can't reset stats for plex %d: %s\n", plexno
, reply
->msg
);
830 longjmp(command_fail
, -1);
831 } else if (recurse
) {
836 get_plex_info(&plex
, plexno
);
837 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
838 get_plex_sd_info(&sd
, plex
.plexno
, sdno
);
839 reset_sd_stats(sd
.sdno
, recurse
);
845 reset_sd_stats(int sdno
, int recurse
)
847 struct vinum_ioctl_msg msg
;
848 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
851 msg
.type
= sd_object
;
852 /* XXX get these numbers right if we ever
853 * actually return errors */
854 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
855 fprintf(stderr
, "Can't reset stats for subdisk %d: %s\n", sdno
, reply
->msg
);
856 longjmp(command_fail
, -1);
857 } else if (recurse
) {
858 get_sd_info(&sd
, sdno
); /* get the info */
859 reset_drive_stats(sd
.driveno
); /* and clear the drive */
864 reset_drive_stats(int driveno
)
866 struct vinum_ioctl_msg msg
;
867 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
870 msg
.type
= drive_object
;
871 /* XXX get these numbers right if we ever
872 * actually return errors */
873 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
874 fprintf(stderr
, "Can't reset stats for drive %d: %s\n", driveno
, reply
->msg
);
875 longjmp(command_fail
, -1);
880 vinum_resetstats(int argc
, char *argv
[], char *argv0
[])
884 enum objecttype type
;
886 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
887 perror("Can't get vinum config");
891 for (objno
= 0; objno
< vinum_conf
.volumes_allocated
; objno
++)
892 reset_volume_stats(objno
, 1); /* clear everything recursively */
894 for (i
= 0; i
< argc
; i
++) {
895 objno
= find_object(argv
[i
], &type
);
896 if (objno
>= 0) { /* not invalid */
899 reset_drive_stats(objno
);
903 reset_sd_stats(objno
, recurse
);
907 reset_plex_stats(objno
, recurse
);
911 reset_volume_stats(objno
, recurse
);
914 case invalid_object
: /* can't get this */
922 /* Attach a subdisk to a plex, or a plex to a volume.
923 * attach subdisk plex [offset] [rename]
924 * attach plex volume [rename]
927 vinum_attach(int argc
, char *argv
[], char *argv0
[])
930 enum objecttype supertype
;
931 struct vinum_ioctl_msg msg
;
932 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
933 const char *objname
= argv
[0];
934 const char *supername
= argv
[1];
937 char oldname
[MAXNAME
+ 8];
938 char newname
[MAXNAME
+ 8];
939 int rename
= 0; /* set if we want to rename the object */
944 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
945 "\tattach <plex> <volume> [rename]\n");
948 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
949 perror("Can't get vinum config");
952 msg
.index
= find_object(objname
, &msg
.type
); /* find the object to attach */
953 msg
.otherobject
= find_object(supername
, &supertype
); /* and the object to attach to */
954 msg
.force
= force
; /* did we specify the use of force? */
955 msg
.recurse
= recurse
;
956 msg
.offset
= -1; /* and no offset */
958 for (i
= 2; i
< argc
; i
++) {
959 if (!strcmp(argv
[i
], "rename")) {
961 msg
.rename
= 1; /* do renaming */
962 } else if (!isdigit(argv
[i
][0])) { /* not an offset */
963 fprintf(stderr
, "Unknown attribute: %s\n", supername
);
966 msg
.offset
= sizespec(argv
[i
]);
971 find_object(argv
[1], &supertype
);
972 if (supertype
!= plex_object
) { /* huh? */
973 fprintf(stderr
, "%s can only be attached to a plex\n", objname
);
976 if ((plex
.organization
!= plex_concat
) /* not a cat plex, */
978 fprintf(stderr
, "Can't attach subdisks to a %s plex\n", plex_org(plex
.organization
));
981 sdno
= msg
.index
; /* note the subdisk number for later */
985 find_object(argv
[1], &supertype
);
986 if (supertype
!= volume_object
) { /* huh? */
987 fprintf(stderr
, "%s can only be attached to a volume\n", objname
);
994 fprintf(stderr
, "Can only attach subdisks and plexes\n");
998 fprintf(stderr
, "%s is not a Vinum object\n", objname
);
1002 ioctl(superdev
, VINUM_ATTACH
, &msg
);
1003 if (reply
->error
!= 0) {
1004 if (reply
->error
== EAGAIN
) /* reviving */
1005 continue_revive(sdno
); /* continue the revive */
1008 "Can't attach %s to %s: %s (%d)\n",
1011 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1019 /* we've overwritten msg with the
1020 * ioctl reply, start again */
1021 msg
.index
= find_object(objname
, &msg
.type
); /* find the object to rename */
1024 get_sd_info(&sd
, msg
.index
);
1025 get_plex_info(&plex
, sd
.plexno
);
1026 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1027 if (plex
.sdnos
[sdno
] == msg
.index
) /* found our subdisk */
1030 sprintf(newname
, "%s.s%d", plex
.name
, sdno
);
1031 sprintf(oldname
, "%s", sd
.name
);
1032 vinum_rename_2(oldname
, newname
);
1036 get_plex_info(&plex
, msg
.index
);
1037 get_volume_info(&vol
, plex
.volno
);
1038 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++) {
1039 if (vol
.plex
[plexno
] == msg
.index
) /* found our subdisk */
1042 sprintf(newname
, "%s.p%d", vol
.name
, plexno
);
1043 sprintf(oldname
, "%s", plex
.name
);
1044 vinum_rename_2(oldname
, newname
); /* this may recurse */
1047 default: /* can't get here */
1051 checkupdates(); /* make sure we're updating */
1054 /* Detach a subdisk from a plex, or a plex from a volume.
1055 * detach subdisk plex [rename]
1056 * detach plex volume [rename]
1059 vinum_detach(int argc
, char *argv
[], char *argv0
[])
1061 struct vinum_ioctl_msg msg
;
1062 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
1067 "Usage: \tdetach <subdisk> [rename]\n"
1068 "\tdetach <plex> [rename]\n");
1071 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1072 perror("Can't get vinum config");
1075 msg
.index
= find_object(argv
[0], &msg
.type
); /* find the object to detach */
1076 msg
.force
= force
; /* did we specify the use of force? */
1077 msg
.rename
= 0; /* don't specify new name */
1078 msg
.recurse
= recurse
; /* but recurse if we have to */
1080 /* XXX are we going to keep this?
1081 * Don't document it yet, since the
1082 * kernel side of things doesn't
1085 if (!strcmp(argv
[1], "rename"))
1086 msg
.rename
= 1; /* do renaming */
1088 fprintf(stderr
, "Unknown attribute: %s\n", argv
[1]);
1092 if ((msg
.type
!= sd_object
)
1093 && (msg
.type
!= plex_object
)) {
1094 fprintf(stderr
, "Can only detach subdisks and plexes\n");
1097 ioctl(superdev
, VINUM_DETACH
, &msg
);
1098 if (reply
->error
!= 0)
1100 "Can't detach %s: %s (%d)\n",
1102 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1104 checkupdates(); /* make sure we're updating */
1108 * Reparse a line from the configuration file
1111 reparse(char *buf
, char *tmp
)
1114 const char *ws
= " \t\r\n";
1119 ptr
= strtok(tmp
, ws
);
1120 if (ptr
== NULL
|| *ptr
== '#')
1122 if (strcmp(ptr
, "drive") != 0)
1125 while ((ptr
= strtok(NULL
, ws
)) != NULL
) {
1128 ptr
= getdevpath(ptr
, 0);
1129 } else if (doskip
) {
1131 } else if (strcmp(ptr
, "drive") == 0) {
1133 } else if (strcmp(ptr
, "device") == 0) {
1142 dorename(struct vinum_rename_msg
*msg
, const char *oldname
, const char *name
, int maxlen
)
1144 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) msg
;
1146 if (strlen(name
) > maxlen
) {
1147 fprintf(stderr
, "%s is too long\n", name
);
1150 strcpy(msg
->newname
, name
);
1151 ioctl(superdev
, VINUM_RENAME
, msg
);
1152 if (reply
->error
!= 0)
1154 "Can't rename %s to %s: %s (%d)\n",
1157 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1161 /* Rename an object:
1162 * rename <object> "newname"
1165 vinum_rename_2(char *oldname
, char *newname
)
1167 struct vinum_rename_msg msg
;
1171 msg
.index
= find_object(oldname
, &msg
.type
); /* find the object to rename */
1172 msg
.recurse
= recurse
;
1174 /* Ugh. Determine how long the name may be */
1177 dorename(&msg
, oldname
, newname
, MAXDRIVENAME
);
1181 dorename(&msg
, oldname
, newname
, MAXSDNAME
);
1186 dorename(&msg
, oldname
, newname
, MAXPLEXNAME
);
1190 get_plex_info(&plex
, plexno
); /* find out who we are */
1191 msg
.type
= sd_object
;
1192 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1193 char sdname
[MAXPLEXNAME
+ 8];
1195 get_plex_sd_info(&sd
, plex
.plexno
, sdno
); /* get info about the subdisk */
1196 sprintf(sdname
, "%s.s%d", newname
, sdno
);
1197 msg
.index
= sd
.sdno
; /* number of the subdisk */
1198 dorename(&msg
, sd
.name
, sdname
, MAXSDNAME
);
1205 dorename(&msg
, oldname
, newname
, MAXVOLNAME
);
1210 get_volume_info(&vol
, volno
); /* find out who we are */
1211 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++) {
1212 char plexname
[MAXVOLNAME
+ 8];
1214 msg
.type
= plex_object
;
1215 sprintf(plexname
, "%s.p%d", newname
, plexno
);
1216 msg
.index
= vol
.plex
[plexno
]; /* number of the plex */
1217 dorename(&msg
, plex
.name
, plexname
, MAXPLEXNAME
);
1218 get_plex_info(&plex
, vol
.plex
[plexno
]); /* find out who we are */
1219 msg
.type
= sd_object
;
1220 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1221 char sdname
[MAXPLEXNAME
+ 8];
1223 get_plex_sd_info(&sd
, plex
.plexno
, sdno
); /* get info about the subdisk */
1224 sprintf(sdname
, "%s.s%d", plexname
, sdno
);
1225 msg
.index
= sd
.sdno
; /* number of the subdisk */
1226 dorename(&msg
, sd
.name
, sdname
, MAXSDNAME
);
1233 fprintf(stderr
, "%s is not a Vinum object\n", oldname
);
1239 vinum_rename(int argc
, char *argv
[], char *argv0
[])
1242 fprintf(stderr
, "Usage: \trename <object> <new name>\n");
1245 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1246 perror("Can't get vinum config");
1249 vinum_rename_2(argv
[0], argv
[1]);
1250 checkupdates(); /* make sure we're updating */
1256 * mv <dest> <src> ...
1259 vinum_mv(int argc
, char *argv
[], char *argv0
[])
1261 int i
; /* loop index */
1264 enum objecttype srct
;
1265 enum objecttype destt
;
1267 struct _ioctl_reply reply
;
1268 struct vinum_ioctl_msg
*msg
= (struct vinum_ioctl_msg
*) &reply
;
1271 fprintf(stderr
, "Usage: \tmove <dest> <src> ...\n");
1274 /* Get current config */
1275 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1276 perror("Cannot get vinum config\n");
1279 /* Get our destination */
1280 destobj
= find_object(argv
[0], &destt
);
1281 if (destobj
== -1) {
1282 fprintf(stderr
, "Can't find %s\n", argv
[0]);
1285 /* Verify that the target is a drive */
1286 if (destt
!= drive_object
) {
1287 fprintf(stderr
, "%s is not a drive\n", argv
[0]);
1290 for (i
= 1; i
< argc
; i
++) { /* for all the sources */
1291 srcobj
= find_object(argv
[i
], &srct
);
1293 fprintf(stderr
, "Can't find %s\n", argv
[i
]);
1296 msg
->index
= destobj
;
1297 switch (srct
) { /* Handle the source object */
1298 case drive_object
: /* Move all subdisks on the drive to dst. */
1299 get_drive_info(&drive
, srcobj
); /* get info on drive */
1300 for (sdno
= 0; sdno
< vinum_conf
.subdisks_allocated
; ++sdno
) {
1301 get_sd_info(&sd
, sdno
);
1302 if (sd
.driveno
== srcobj
) {
1303 msg
->index
= destobj
;
1304 msg
->otherobject
= sd
.sdno
;
1305 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1307 "Can't move %s (part of %s) to %s: %s (%d)\n",
1311 strerror(reply
.error
),
1318 msg
->otherobject
= srcobj
;
1319 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1321 "Can't move %s to %s: %s (%d)\n",
1324 strerror(reply
.error
),
1329 get_plex_info(&plex
, srcobj
);
1330 for (sdno
= 0; sdno
< plex
.subdisks
; ++sdno
) {
1331 get_plex_sd_info(&sd
, plex
.plexno
, sdno
);
1332 msg
->index
= destobj
;
1333 msg
->otherobject
= sd
.sdno
;
1334 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1336 "Can't move %s (part of %s) to %s: %s (%d)\n",
1340 strerror(reply
.error
),
1346 case invalid_object
:
1348 fprintf(stderr
, "Can't move %s (inappropriate object).\n", argv
[i
]);
1353 "Can't move %s to %s: %s (%d)\n",
1356 strerror(reply
.error
),
1359 checkupdates(); /* make sure we're updating */
1363 * Replace objects. Not implemented, may never be.
1366 vinum_replace(int argc
, char *argv
[], char *argv0
[])
1368 fprintf(stderr
, "'replace' not implemented yet. Use 'move' instead\n");
1371 /* Primitive help function */
1373 vinum_help(int argc
, char *argv
[], char *argv0
[])
1378 "create [-f description-file]\n"
1379 " Create a volume as described in description-file\n"
1380 "attach plex volume [rename]\n"
1381 "attach subdisk plex [offset] [rename]\n"
1382 " Attach a plex to a volume, or a subdisk to a plex.\n"
1384 " Cause the volume manager to enter the kernel debugger.\n"
1386 " Set debugging flags.\n"
1387 "detach [plex | subdisk]\n"
1388 " Detach a plex or subdisk from the volume or plex to which it is\n"
1391 " List information about volume manager state.\n"
1392 "init [-v] [-w] plex\n"
1393 " Initialize a plex by writing zeroes to all its subdisks.\n"
1395 " Create a volume label\n"
1396 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1397 " List information about specified objects\n"
1398 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1399 " List information about specified objects (alternative to\n"
1401 "ld [-r] [-s] [-v] [-V] [volume]\n"
1402 " List information about drives\n"
1403 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1404 " List information about subdisks\n"
1405 "lp [-r] [-s] [-v] [-V] [plex]\n"
1406 " List information about plexes\n"
1407 "lv [-r] [-s] [-v] [-V] [volume]\n"
1408 " List information about volumes\n"
1409 "printconfig [file]\n"
1410 " Write a copy of the current configuration to file.\n"
1412 " Remake the device nodes in " _PATH_DEV
"vinum.\n"
1413 "move drive [subdisk | plex | drive]\n"
1414 " Move the subdisks of the specified object(s) to drive.\n"
1416 " Exit the vinum program when running in interactive mode. Nor-\n"
1417 " mally this would be done by entering the EOF character.\n"
1418 "read disk [disk...]\n"
1419 " Read the vinum configuration from the specified disks.\n"
1420 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1421 " Change the name of the specified object.\n"
1423 " Reset the complete vinum configuration.\n"
1424 "resetstats [-r] [volume | plex | subdisk]\n"
1425 " Reset statistisc counters for the specified objects, or for all\n"
1426 " objects if none are specified.\n"
1427 "rm [-f] [-r] volume | plex | subdisk\n"
1428 " Remove an object\n"
1430 " Save vinum configuration to disk.\n"
1431 "setdaemon [value]\n"
1432 " Set daemon configuration.\n"
1434 " Read configuration from all vinum drives.\n"
1435 "start [volume | plex | subdisk]\n"
1436 " Allow the system to access the objects\n"
1437 "stop [-f] [volume | plex | subdisk]\n"
1438 " Terminate access to the objects, or stop vinum if no parameters\n"
1444 /* Set daemon options.
1445 * XXX quick and dirty: use a bitmap, which requires
1446 * knowing which bit does what. FIXME */
1448 vinum_setdaemon(int argc
, char *argv
[], char *argv0
[])
1454 if (ioctl(superdev
, VINUM_GETDAEMON
, &options
) < 0)
1455 fprintf(stderr
, "Can't get daemon options: %s (%d)\n", strerror(errno
), errno
);
1457 printf("Options mask: %d\n", options
);
1461 options
= atoi(argv
[0]);
1462 if (ioctl(superdev
, VINUM_SETDAEMON
, &options
) < 0)
1463 fprintf(stderr
, "Can't set daemon options: %s (%d)\n", strerror(errno
), errno
);
1467 fprintf(stderr
, "Usage: \tsetdaemon [<bitmask>]\n");
1469 checkupdates(); /* make sure we're updating */
1477 if (ioctl(superdev
, VINUM_GETDAEMON
, &options
) < 0)
1478 fprintf(stderr
, "Can't get daemon options: %s (%d)\n", strerror(errno
), errno
);
1479 if (options
& daemon_noupdate
) {
1480 fprintf(stderr
, "*** Warning: configuration updates are disabled. ***\n");
1486 /* Save config info */
1488 vinum_saveconfig(int argc
, char *argv
[], char *argv0
[])
1493 printf("Usage: saveconfig\n");
1496 ioctltype
= 1; /* user saveconfig */
1497 if (ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
) < 0)
1498 fprintf(stderr
, "Can't save configuration: %s (%d)\n", strerror(errno
), errno
);
1499 checkupdates(); /* make sure we're updating */
1503 * Create a volume name for the quick and dirty
1504 * commands. It will be of the form "vinum#",
1505 * where # is a small positive number.
1510 int v
; /* volume number */
1511 static char volumename
[MAXVOLNAME
]; /* name to create */
1512 enum objecttype type
;
1514 objectname
= volumename
; /* point to it */
1516 sprintf(objectname
, "vinum%d", v
); /* create the name */
1517 if (find_object(objectname
, &type
) == -1) /* does it exist? */
1518 return; /* no, it's ours */
1523 * Create a drive for the quick and dirty
1524 * commands. The name will be of the form
1525 * vinumdrive#, where # is a small positive
1526 * number. Return the name of the drive.
1529 create_drive(char *devicename
)
1531 int d
; /* volume number */
1532 static char drivename
[MAXDRIVENAME
]; /* name to create */
1533 enum objecttype type
;
1534 struct _ioctl_reply
*reply
;
1536 devicename
= getdevpath(devicename
, 0);
1539 * We're never likely to get anything
1540 * like 10000 drives. The only reason for
1541 * this limit is to stop the thing
1542 * looping if we have a bug somewhere.
1544 for (d
= 0; d
< 100000; d
++) { /* look for a free drive number */
1545 sprintf(drivename
, "vinumdrive%d", d
); /* create the name */
1546 if (find_object(drivename
, &type
) == -1) { /* does it exist? */
1547 char command
[MAXDRIVENAME
* 2];
1549 sprintf(command
, "drive %s device %s", drivename
, devicename
); /* create a create command */
1551 printf("drive %s device %s\n", drivename
, devicename
); /* create a create command */
1552 ioctl(superdev
, VINUM_CREATE
, command
);
1553 reply
= (struct _ioctl_reply
*) &command
;
1554 if (reply
->error
!= 0) { /* error in config */
1557 "Can't create drive %s, device %s: %s\n",
1563 "Can't create drive %s, device %s: %s (%d)\n",
1566 strerror(reply
->error
),
1568 longjmp(command_fail
, -1); /* give up */
1570 find_object(drivename
, &type
);
1572 return &drive
; /* return the name of the drive */
1575 fprintf(stderr
, "Can't generate a drive name\n");
1582 * Create a volume with a single concatenated plex from
1583 * as much space as we can get on the specified drives.
1584 * If the drives aren't Vinum drives, make them so.
1587 vinum_concat(int argc
, char *argv
[], char *argv0
[])
1589 int o
; /* object number */
1590 char buffer
[BUFSIZE
];
1591 struct drive
*drive
; /* drive we're currently looking at */
1592 struct _ioctl_reply
*reply
;
1595 enum objecttype type
;
1597 reply
= (struct _ioctl_reply
*) &buffer
;
1598 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1599 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1602 if (!objectname
) /* we need a name for our object */
1604 sprintf(buffer
, "volume %s", objectname
);
1606 printf("volume %s\n", objectname
);
1607 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1608 if (reply
->error
!= 0) { /* error in config */
1611 "Can't create volume %s: %s\n",
1616 "Can't create volume %s: %s (%d)\n",
1618 strerror(reply
->error
),
1620 longjmp(command_fail
, -1); /* give up */
1622 sprintf(buffer
, "plex name %s.p0 org concat", objectname
);
1624 printf(" plex name %s.p0 org concat\n", objectname
);
1625 ioctl(superdev
, VINUM_CREATE
, buffer
);
1626 if (reply
->error
!= 0) { /* error in config */
1629 "Can't create plex %s.p0: %s\n",
1634 "Can't create plex %s.p0: %s (%d)\n",
1636 strerror(reply
->error
),
1638 longjmp(command_fail
, -1); /* give up */
1640 for (o
= 0; o
< argc
; o
++) {
1641 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1642 drive
= create_drive(argv
[o
]); /* create it */
1643 sprintf(buffer
, "sd name %s.p0.s%d drive %s size 0", objectname
, o
, drive
->label
.name
);
1645 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname
, o
, drive
->label
.name
);
1646 ioctl(superdev
, VINUM_CREATE
, buffer
);
1647 if (reply
->error
!= 0) { /* error in config */
1650 "Can't create subdisk %s.p0.s%d: %s\n",
1656 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1659 strerror(reply
->error
),
1661 longjmp(command_fail
, -1); /* give up */
1665 /* done, save the config */
1666 ioctltype
= 0; /* saveconfig after update */
1667 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1669 perror("Can't save Vinum config");
1670 find_object(objectname
, &type
); /* find the index of the volume */
1672 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1675 vflag
--; /* XXX don't give too much detail */
1676 find_object(objectname
, &type
); /* point to the volume */
1677 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1683 * Create a volume with a single striped plex from
1684 * as much space as we can get on the specified drives.
1685 * If the drives aren't Vinum drives, make them so.
1688 vinum_stripe(int argc
, char *argv
[], char *argv0
[])
1690 int o
; /* object number */
1691 char buffer
[BUFSIZE
];
1692 struct drive
*drive
; /* drive we're currently looking at */
1693 struct _ioctl_reply
*reply
;
1696 enum objecttype type
;
1698 int fe
; /* freelist entry index */
1700 struct drive_freelist freelist
;
1701 struct ferq
{ /* request to pass to ioctl */
1706 u_int64_t bigchunk
; /* biggest chunk in freelist */
1709 reply
= (struct _ioctl_reply
*) &buffer
;
1712 * First, check our drives.
1715 fprintf(stderr
, "You need at least two drives to create a striped plex\n");
1718 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1719 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1722 if (!objectname
) /* we need a name for our object */
1724 for (o
= 0; o
< argc
; o
++) {
1725 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1726 drive
= create_drive(argv
[o
]); /* create it */
1727 /* Now find the largest chunk available on the drive */
1728 bigchunk
= 0; /* ain't found nothin' yet */
1729 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
1730 freeunion
.ferq
.driveno
= drive
->driveno
;
1731 freeunion
.ferq
.fe
= fe
;
1732 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
1734 "Can't get free list element %d: %s\n",
1737 longjmp(command_fail
, -1);
1739 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
1741 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
1744 /* Now create the volume */
1745 sprintf(buffer
, "volume %s", objectname
);
1747 printf("volume %s\n", objectname
);
1748 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1749 if (reply
->error
!= 0) { /* error in config */
1752 "Can't create volume %s: %s\n",
1757 "Can't create volume %s: %s (%d)\n",
1759 strerror(reply
->error
),
1761 longjmp(command_fail
, -1); /* give up */
1763 sprintf(buffer
, "plex name %s.p0 org striped 256k", objectname
);
1765 printf(" plex name %s.p0 org striped 256k\n", objectname
);
1766 ioctl(superdev
, VINUM_CREATE
, buffer
);
1767 if (reply
->error
!= 0) { /* error in config */
1770 "Can't create plex %s.p0: %s\n",
1775 "Can't create plex %s.p0: %s (%d)\n",
1777 strerror(reply
->error
),
1779 longjmp(command_fail
, -1); /* give up */
1781 for (o
= 0; o
< argc
; o
++) {
1782 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
1784 "sd name %s.p0.s%d drive %s size %lldb",
1788 (long long) maxsize
);
1790 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1794 (long long) maxsize
);
1795 ioctl(superdev
, VINUM_CREATE
, buffer
);
1796 if (reply
->error
!= 0) { /* error in config */
1799 "Can't create subdisk %s.p0.s%d: %s\n",
1805 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1808 strerror(reply
->error
),
1810 longjmp(command_fail
, -1); /* give up */
1814 /* done, save the config */
1815 ioctltype
= 0; /* saveconfig after update */
1816 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1818 perror("Can't save Vinum config");
1819 find_object(objectname
, &type
); /* find the index of the volume */
1821 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1824 vflag
--; /* XXX don't give too much detail */
1825 find_object(objectname
, &type
); /* point to the volume */
1826 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1831 * Create a volume with a single RAID-4 plex from
1832 * as much space as we can get on the specified drives.
1833 * If the drives aren't Vinum drives, make them so.
1836 vinum_raid4(int argc
, char *argv
[], char *argv0
[])
1838 int o
; /* object number */
1839 char buffer
[BUFSIZE
];
1840 struct drive
*drive
; /* drive we're currently looking at */
1841 struct _ioctl_reply
*reply
;
1844 enum objecttype type
;
1846 int fe
; /* freelist entry index */
1848 struct drive_freelist freelist
;
1849 struct ferq
{ /* request to pass to ioctl */
1854 u_int64_t bigchunk
; /* biggest chunk in freelist */
1857 reply
= (struct _ioctl_reply
*) &buffer
;
1860 * First, check our drives.
1863 fprintf(stderr
, "You need at least three drives to create a RAID-4 plex\n");
1866 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1867 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1870 if (!objectname
) /* we need a name for our object */
1872 for (o
= 0; o
< argc
; o
++) {
1873 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1874 drive
= create_drive(argv
[o
]); /* create it */
1875 /* Now find the largest chunk available on the drive */
1876 bigchunk
= 0; /* ain't found nothin' yet */
1877 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
1878 freeunion
.ferq
.driveno
= drive
->driveno
;
1879 freeunion
.ferq
.fe
= fe
;
1880 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
1882 "Can't get free list element %d: %s\n",
1885 longjmp(command_fail
, -1);
1887 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
1889 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
1892 /* Now create the volume */
1893 sprintf(buffer
, "volume %s", objectname
);
1895 printf("volume %s\n", objectname
);
1896 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1897 if (reply
->error
!= 0) { /* error in config */
1900 "Can't create volume %s: %s\n",
1905 "Can't create volume %s: %s (%d)\n",
1907 strerror(reply
->error
),
1909 longjmp(command_fail
, -1); /* give up */
1911 sprintf(buffer
, "plex name %s.p0 org raid4 256k", objectname
);
1913 printf(" plex name %s.p0 org raid4 256k\n", objectname
);
1914 ioctl(superdev
, VINUM_CREATE
, buffer
);
1915 if (reply
->error
!= 0) { /* error in config */
1918 "Can't create plex %s.p0: %s\n",
1923 "Can't create plex %s.p0: %s (%d)\n",
1925 strerror(reply
->error
),
1927 longjmp(command_fail
, -1); /* give up */
1929 for (o
= 0; o
< argc
; o
++) {
1930 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
1932 "sd name %s.p0.s%d drive %s size %lldb",
1936 (long long) maxsize
);
1938 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1942 (long long) maxsize
);
1943 ioctl(superdev
, VINUM_CREATE
, buffer
);
1944 if (reply
->error
!= 0) { /* error in config */
1947 "Can't create subdisk %s.p0.s%d: %s\n",
1953 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1956 strerror(reply
->error
),
1958 longjmp(command_fail
, -1); /* give up */
1962 /* done, save the config */
1963 ioctltype
= 0; /* saveconfig after update */
1964 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1966 perror("Can't save Vinum config");
1967 find_object(objectname
, &type
); /* find the index of the volume */
1969 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1972 vflag
--; /* XXX don't give too much detail */
1973 find_object(objectname
, &type
); /* point to the volume */
1974 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1979 * Create a volume with a single RAID-4 plex from
1980 * as much space as we can get on the specified drives.
1981 * If the drives aren't Vinum drives, make them so.
1984 vinum_raid5(int argc
, char *argv
[], char *argv0
[])
1986 int o
; /* object number */
1987 char buffer
[BUFSIZE
];
1988 struct drive
*drive
; /* drive we're currently looking at */
1989 struct _ioctl_reply
*reply
;
1992 enum objecttype type
;
1994 int fe
; /* freelist entry index */
1996 struct drive_freelist freelist
;
1997 struct ferq
{ /* request to pass to ioctl */
2002 u_int64_t bigchunk
; /* biggest chunk in freelist */
2005 reply
= (struct _ioctl_reply
*) &buffer
;
2008 * First, check our drives.
2011 fprintf(stderr
, "You need at least three drives to create a RAID-5 plex\n");
2014 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
2015 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
2018 if (!objectname
) /* we need a name for our object */
2020 for (o
= 0; o
< argc
; o
++) {
2021 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
2022 drive
= create_drive(argv
[o
]); /* create it */
2023 /* Now find the largest chunk available on the drive */
2024 bigchunk
= 0; /* ain't found nothin' yet */
2025 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
2026 freeunion
.ferq
.driveno
= drive
->driveno
;
2027 freeunion
.ferq
.fe
= fe
;
2028 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
2030 "Can't get free list element %d: %s\n",
2033 longjmp(command_fail
, -1);
2035 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
2037 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
2040 /* Now create the volume */
2041 sprintf(buffer
, "volume %s", objectname
);
2043 printf("volume %s\n", objectname
);
2044 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
2045 if (reply
->error
!= 0) { /* error in config */
2048 "Can't create volume %s: %s\n",
2053 "Can't create volume %s: %s (%d)\n",
2055 strerror(reply
->error
),
2057 longjmp(command_fail
, -1); /* give up */
2059 sprintf(buffer
, "plex name %s.p0 org raid5 256k", objectname
);
2061 printf(" plex name %s.p0 org raid5 256k\n", objectname
);
2062 ioctl(superdev
, VINUM_CREATE
, buffer
);
2063 if (reply
->error
!= 0) { /* error in config */
2066 "Can't create plex %s.p0: %s\n",
2071 "Can't create plex %s.p0: %s (%d)\n",
2073 strerror(reply
->error
),
2075 longjmp(command_fail
, -1); /* give up */
2077 for (o
= 0; o
< argc
; o
++) {
2078 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
2080 "sd name %s.p0.s%d drive %s size %lldb",
2084 (long long) maxsize
);
2086 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2090 (long long) maxsize
);
2091 ioctl(superdev
, VINUM_CREATE
, buffer
);
2092 if (reply
->error
!= 0) { /* error in config */
2095 "Can't create subdisk %s.p0.s%d: %s\n",
2101 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2104 strerror(reply
->error
),
2106 longjmp(command_fail
, -1); /* give up */
2110 /* done, save the config */
2111 ioctltype
= 0; /* saveconfig after update */
2112 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
2114 perror("Can't save Vinum config");
2115 find_object(objectname
, &type
); /* find the index of the volume */
2117 make_vol_dev(vol
.volno
, 1); /* and create the devices */
2120 vflag
--; /* XXX don't give too much detail */
2121 find_object(objectname
, &type
); /* point to the volume */
2122 vinum_lvi(vol
.volno
, 1); /* and print info about it */
2127 * Create a volume with a two plexes from as much space
2128 * as we can get on the specified drives. If the
2129 * drives aren't Vinum drives, make them so.
2131 * The number of drives must be even, and at least 4
2132 * for a striped plex. Specify striped plexes with the
2133 * -s flag; otherwise they will be concatenated. It's
2134 * possible that the two plexes may differ in length.
2137 vinum_mirror(int argc
, char *argv
[], char *argv0
[])
2139 int o
; /* object number */
2140 int p
; /* plex number */
2141 char buffer
[BUFSIZE
];
2142 struct drive
*drive
; /* drive we're currently looking at */
2143 struct _ioctl_reply
*reply
;
2146 enum objecttype type
;
2147 off_t maxsize
[2]; /* maximum subdisk size for striped plexes */
2148 int fe
; /* freelist entry index */
2150 struct drive_freelist freelist
;
2151 struct ferq
{ /* request to pass to ioctl */
2156 u_int64_t bigchunk
; /* biggest chunk in freelist */
2158 if (sflag
) /* striped, */
2159 maxsize
[0] = maxsize
[1] = QUAD_MAX
; /* we need to calculate sd size */
2161 maxsize
[0] = maxsize
[1] = 0; /* let the kernel routines do it */
2163 reply
= (struct _ioctl_reply
*) &buffer
;
2166 * First, check our drives.
2169 fprintf(stderr
, "You need an even number of drives to create a mirrored volume\n");
2172 if (sflag
&& (argc
< 4)) {
2173 fprintf(stderr
, "You need at least 4 drives to create a mirrored, striped volume\n");
2176 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
2177 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
2180 if (!objectname
) /* we need a name for our object */
2182 for (o
= 0; o
< argc
; o
++) {
2183 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
2184 drive
= create_drive(argv
[o
]); /* create it */
2185 if (sflag
) { /* striping, */
2186 /* Find the largest chunk available on the drive */
2187 bigchunk
= 0; /* ain't found nothin' yet */
2188 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
2189 freeunion
.ferq
.driveno
= drive
->driveno
;
2190 freeunion
.ferq
.fe
= fe
;
2191 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
2193 "Can't get free list element %d: %s\n",
2196 longjmp(command_fail
, -1);
2198 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
2200 maxsize
[o
& 1] = min(maxsize
[o
& 1], bigchunk
); /* get the maximum size of a subdisk */
2204 /* Now create the volume */
2205 sprintf(buffer
, "volume %s setupstate", objectname
);
2207 printf("volume %s setupstate\n", objectname
);
2208 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
2209 if (reply
->error
!= 0) { /* error in config */
2212 "Can't create volume %s: %s\n",
2217 "Can't create volume %s: %s (%d)\n",
2219 strerror(reply
->error
),
2221 longjmp(command_fail
, -1); /* give up */
2223 for (p
= 0; p
< 2; p
++) { /* create each plex */
2225 sprintf(buffer
, "plex name %s.p%d org striped 256k", objectname
, p
);
2227 printf(" plex name %s.p%d org striped 256k\n", objectname
, p
);
2228 } else { /* concat */
2229 sprintf(buffer
, "plex name %s.p%d org concat", objectname
, p
);
2231 printf(" plex name %s.p%d org concat\n", objectname
, p
);
2233 ioctl(superdev
, VINUM_CREATE
, buffer
);
2234 if (reply
->error
!= 0) { /* error in config */
2237 "Can't create plex %s.p%d: %s\n",
2243 "Can't create plex %s.p%d: %s (%d)\n",
2246 strerror(reply
->error
),
2248 longjmp(command_fail
, -1); /* give up */
2250 /* Now look at the subdisks */
2251 for (o
= p
; o
< argc
; o
+= 2) { /* every second one */
2252 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
2254 "sd name %s.p%d.s%d drive %s size %lldb",
2259 (long long) maxsize
[p
]);
2261 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2266 (long long) maxsize
[p
]);
2267 ioctl(superdev
, VINUM_CREATE
, buffer
);
2268 if (reply
->error
!= 0) { /* error in config */
2271 "Can't create subdisk %s.p%d.s%d: %s\n",
2278 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2282 strerror(reply
->error
),
2284 longjmp(command_fail
, -1); /* give up */
2289 /* done, save the config */
2290 ioctltype
= 0; /* saveconfig after update */
2291 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
2293 perror("Can't save Vinum config");
2294 find_object(objectname
, &type
); /* find the index of the volume */
2296 make_vol_dev(vol
.volno
, 1); /* and create the devices */
2299 vflag
--; /* XXX don't give too much detail */
2300 sflag
= 0; /* no stats, please */
2301 find_object(objectname
, &type
); /* point to the volume */
2302 vinum_lvi(vol
.volno
, 1); /* and print info about it */
2307 vinum_readpol(int argc
, char *argv
[], char *argv0
[])
2310 struct _ioctl_reply reply
;
2311 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2312 enum objecttype type
;
2317 if (argc
== 0) { /* start everything */
2318 fprintf(stderr
, "Usage: readpol <volume> <plex>|round\n");
2321 object
= find_object(argv
[1], &type
); /* look for it */
2322 if (type
!= volume_object
) {
2323 fprintf(stderr
, "%s is not a volume\n", argv
[1]);
2326 get_volume_info(&vol
, object
);
2327 if (strcmp(argv
[2], "round")) { /* not 'round' */
2328 object
= find_object(argv
[2], &type
); /* look for it */
2329 if (type
!= plex_object
) {
2330 fprintf(stderr
, "%s is not a plex\n", argv
[2]);
2333 get_plex_info(&plex
, object
);
2334 plexno
= plex
.plexno
;
2339 message
->index
= vol
.volno
;
2340 message
->otherobject
= plexno
;
2341 if (ioctl(superdev
, VINUM_READPOL
, message
) < 0)
2342 fprintf(stderr
, "Can't set read policy: %s (%d)\n", strerror(errno
), errno
);
2344 vinum_lpi(plexno
, recurse
);
2348 * Brute force set state function. Don't look at
2349 * any dependencies, just do it.
2352 vinum_setstate(int argc
, char *argv
[], char *argv0
[])
2355 struct _ioctl_reply reply
;
2356 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2358 enum objecttype type
;
2361 for (index
= 1; index
< argc
; index
++) {
2362 object
= find_object(argv
[index
], &type
); /* look for it */
2363 if (type
== invalid_object
)
2364 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
2366 int doit
= 0; /* set to 1 if we pass our tests */
2369 state
= DriveState(argv
[0]); /* get the state */
2370 if (drive
.state
== state
) /* already in that state */
2371 fprintf(stderr
, "%s is already %s\n", drive
.label
.name
, argv
[0]);
2377 state
= SdState(argv
[0]); /* get the state */
2378 if (sd
.state
== state
) /* already in that state */
2379 fprintf(stderr
, "%s is already %s\n", sd
.name
, argv
[0]);
2385 state
= PlexState(argv
[0]); /* get the state */
2386 if (plex
.state
== state
) /* already in that state */
2387 fprintf(stderr
, "%s is already %s\n", plex
.name
, argv
[0]);
2393 state
= VolState(argv
[0]); /* get the state */
2394 if (vol
.state
== state
) /* already in that state */
2395 fprintf(stderr
, "%s is already %s\n", vol
.name
, argv
[0]);
2401 state
= 0; /* to keep the compiler happy */
2405 fprintf(stderr
, "Invalid state for object: %s\n", argv
[0]);
2407 message
->index
= object
; /* pass object number */
2408 message
->type
= type
; /* and type of object */
2409 message
->state
= state
;
2410 message
->force
= force
; /* don't force it, use a larger hammer */
2411 ioctl(superdev
, VINUM_SETSTATE_FORCE
, message
);
2412 if (reply
.error
!= 0)
2414 "Can't start %s: %s (%d)\n",
2416 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
2419 vinum_li(object
, type
);
2426 vinum_checkparity(int argc
, char *argv
[], char *argv0
[])
2428 Verbose
= vflag
; /* accept -v for verbose */
2429 if (argc
== 0) /* no parameters? */
2430 fprintf(stderr
, "Usage: checkparity object [object...]\n");
2432 parityops(argc
, argv
, checkparity
);
2436 vinum_rebuildparity(int argc
, char *argv
[], char *argv0
[])
2438 if (argc
== 0) /* no parameters? */
2439 fprintf(stderr
, "Usage: rebuildparity object [object...]\n");
2441 parityops(argc
, argv
, vflag
? rebuildandcheckparity
: rebuildparity
);
2445 * Common code for rebuildparity and checkparity.
2446 * We bend the meanings of some flags here:
2448 * -v: Report incorrect parity on rebuild.
2449 * -V: Show running count of position being checked.
2450 * -f: Start from beginning of the plex.
2453 parityops(int argc
, char *argv
[], enum parityop op
)
2457 struct _ioctl_reply reply
;
2458 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2460 enum objecttype type
;
2464 if (op
== checkparity
)
2468 for (index
= 0; index
< argc
; index
++) {
2469 object
= find_object(argv
[index
], &type
); /* look for it */
2470 if (type
!= plex_object
)
2471 fprintf(stderr
, "%s is not a plex\n", argv
[index
]);
2473 get_plex_info(&plex
, object
);
2474 if (!isparity((&plex
)))
2475 fprintf(stderr
, "%s is not a RAID-4 or RAID-5 plex\n", argv
[index
]);
2478 message
->index
= object
; /* pass object number */
2479 message
->type
= type
; /* and type of object */
2480 message
->op
= op
; /* what to do */
2482 message
->offset
= 0; /* start at the beginning */
2484 message
->offset
= plex
.checkblock
; /* continue where we left off */
2485 force
= 0; /* don't reset after the first time */
2486 ioctl(superdev
, VINUM_PARITYOP
, message
);
2487 get_plex_info(&plex
, object
);
2489 block
= (plex
.checkblock
<< DEV_BSHIFT
) * (plex
.subdisks
- 1);
2491 printf("\r%s at %s (%d%%) ",
2493 roughlength(block
, 1),
2494 ((int) (block
* 100 / plex
.length
) >> DEV_BSHIFT
));
2495 if ((reply
.error
== EAGAIN
)
2496 && (reply
.msg
[0])) /* got a comment back */
2497 fputs(reply
.msg
, stderr
); /* show it */
2501 while (reply
.error
== EAGAIN
);
2502 if (reply
.error
!= 0) {
2504 fputs(reply
.msg
, stderr
);
2509 strerror(reply
.error
));
2510 } else if (Verbose
) {
2511 if (op
== checkparity
)
2512 fprintf(stderr
, "%s has correct parity\n", argv
[index
]);
2514 fprintf(stderr
, "Rebuilt parity on %s\n", argv
[index
]);
2521 /* Local Variables: */
2522 /* fill-column: 50 */