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. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Nan Yang Computer
23 * 4. Neither the name of the Company nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * This software is provided ``as is'', and any express or implied
28 * warranties, including, but not limited to, the implied warranties of
29 * merchantability and fitness for a particular purpose are disclaimed.
30 * In no event shall the company or contributors be liable for any
31 * direct, indirect, incidental, special, exemplary, or consequential
32 * damages (including, but not limited to, procurement of substitute
33 * goods or services; loss of use, data, or profits; or business
34 * interruption) however caused and on any theory of liability, whether
35 * in contract, strict liability, or tort (including negligence or
36 * otherwise) arising in any way out of the use of this software, even if
37 * advised of the possibility of such damage.
39 * $Id: commands.c,v 1.15 2001/05/22 08:40:21 grog Exp grog $
55 #include <sys/ioctl.h>
57 #include <sys/types.h>
58 #include <sys/linker.h>
59 #include <sys/module.h>
61 #include <readline/history.h>
62 #include <readline/readline.h>
65 static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen);
68 vinum_create(int argc, char *argv[], char *arg0[])
71 FILE *dfd; /* file descriptor for the config file */
72 char buffer[BUFSIZE]; /* read config file in here */
73 char commandline[BUFSIZE]; /* issue command from here */
74 struct _ioctl_reply *reply;
75 int ioctltype; /* for ioctl call */
76 char tempfile[PATH_MAX]; /* name of temp file for direct editing */
77 char *file; /* file to read */
78 FILE *tf; /* temp file */
80 if (argc == 0) { /* no args, */
81 char *editor; /* editor to start */
84 editor = getenv("EDITOR");
86 editor = "/usr/bin/vi";
87 sprintf(tempfile, "/var/tmp/" VINUMMOD ".create.%d", getpid()); /* create a temp file */
88 tf = fopen(tempfile, "w"); /* open it */
90 fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno));
93 printconfig(tf, "# "); /* and put the current config it */
95 sprintf(commandline, "%s %s", editor, tempfile); /* create an edit command */
96 status = system(commandline); /* do it */
98 fprintf(stderr, "Can't edit config: status %d\n", status);
102 } else if (argc == 1)
105 fprintf(stderr, "Expecting 1 parameter, not %d\n", argc);
108 reply = (struct _ioctl_reply *) &buffer;
109 dfd = fopen(file, "r");
110 if (dfd == NULL) { /* no go */
111 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
114 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
115 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
118 file_line = 0; /* start with line 1 */
119 /* Parse the configuration, and add it to the global configuration */
120 for (;;) { /* love this style(9) */
123 configline = fgets(buffer, BUFSIZE, dfd);
125 fprintf(history, "%s", buffer);
127 if (configline == NULL) {
129 perror("Can't read config file");
132 file_line++; /* count the lines */
134 printf("%4d: %s", file_line, buffer);
135 strcpy(commandline, buffer); /* make a copy */
136 ioctl(superdev, VINUM_CREATE, buffer);
137 if (reply->error != 0) { /* error in config */
138 if (!vflag) /* print this line anyway */
139 printf("%4d: %s", file_line, commandline);
140 fprintf(stdout, "** %d %s: %s\n",
143 strerror(reply->error));
146 * XXX at the moment, we reset the config
147 * lock on error, so try to get it again.
148 * If we fail, don't cry again.
150 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */
154 fclose(dfd); /* done with the config file */
155 ioctltype = 0; /* saveconfig after update */
156 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
158 perror("Can't save Vinum config");
162 checkupdates(); /* make sure we're updating */
165 /* Read vinum config from a disk */
167 vinum_read(int argc, char *argv[], char *arg0[])
170 char buffer[BUFSIZE]; /* read config file in here */
171 struct _ioctl_reply *reply;
174 reply = (struct _ioctl_reply *) &buffer;
175 if (argc < 1) { /* wrong arg count */
176 fprintf(stderr, "Usage: read drive [drive ...]\n");
179 strcpy(buffer, "read ");
180 for (i = 0; i < argc; i++) { /* each drive name */
181 strcat(buffer, argv[i]);
185 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
186 fprintf(stderr, "Can't configure: %s (%d)\n", strerror(errno), errno);
189 ioctl(superdev, VINUM_CREATE, &buffer);
190 if (reply->error != 0) { /* error in config */
191 fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error));
192 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
194 perror("Can't save Vinum config");
196 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
198 perror("Can't save Vinum config");
202 checkupdates(); /* make sure we're updating */
206 vinum_debug(int argc, char *argv[], char *arg0[])
208 struct debuginfo info;
210 if (vinum_conf.flags & VF_HASDEBUG) {
212 info.param = atoi(argv[0]);
216 sleep(2); /* give a chance to leave the window */
218 ioctl(superdev, VINUM_DEBUG, (caddr_t) & info);
219 } else /* no debug in kernel module */
220 fprintf(stderr, "Kernel module does not have debug support\n");
224 vinum_modify(int argc, char *argv[], char *arg0[])
226 fprintf(stderr, "Modify command is currently not implemented\n");
227 checkupdates(); /* make sure we're updating */
231 vinum_set(int argc, char *argv[], char *arg0[])
233 fprintf(stderr, "set is not implemented yet\n");
237 vinum_rm(int argc, char *argv[], char *arg0[])
240 struct _ioctl_reply reply;
241 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
243 if (argc == 0) /* start everything */
244 fprintf(stderr, "Usage: rm object [object...]\n");
245 else { /* start specified objects */
247 enum objecttype type;
249 for (index = 0; index < argc; index++) {
250 object = find_object(argv[index], &type); /* look for it */
251 if (type == invalid_object)
252 fprintf(stderr, "Can't find object: %s\n", argv[index]);
254 message->index = object; /* pass object number */
255 message->type = type; /* and type of object */
256 message->force = force; /* do we want to force the operation? */
257 message->recurse = recurse; /* do we want to remove subordinates? */
258 ioctl(superdev, VINUM_REMOVE, message);
259 if (reply.error != 0) {
261 "Can't remove %s: %s (%d)\n",
263 reply.msg[0] ? reply.msg : strerror(reply.error),
266 fprintf(stderr, "%s removed\n", argv[index]);
269 checkupdates(); /* make sure we're updating */
274 vinum_resetconfig(int argc, char *argv[], char *arg0[])
279 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
280 " All data will be lost. If you really want to do this, enter the text\n\n"
283 fgets(reply, sizeof(reply), stdin);
284 if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */
285 printf("\n No change\n");
287 error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */
290 fprintf(stderr, "Can't reset configuration: objects are in use\n");
292 perror("Can't find vinum config");
295 make_devices(); /* recreate the /dev/vinum hierarchy */
296 printf("\b Vinum configuration obliterated\n");
297 start_daemon(); /* then restart the daemon */
300 checkupdates(); /* make sure we're updating */
303 /* Initialize subdisks */
305 vinum_init(int argc, char *argv[], char *arg0[])
307 if (argc > 0) { /* initialize plexes */
310 enum objecttype type; /* type returned */
313 fflush(history); /* don't let all the kids do it. */
314 for (objindex = 0; objindex < argc; objindex++) {
315 objno = find_object(argv[objindex], &type); /* find the object */
317 printf("Can't find %s\n", argv[objindex]);
325 initplex(objno, argv[objindex]);
329 initsd(objno, dowait);
333 printf("Can't initialize %s: wrong object type\n", argv[objindex]);
339 checkupdates(); /* make sure we're updating */
345 printf("Initializing volumes is not implemented yet\n");
349 initplex(int plexno, char *name)
352 int plexfh = NULL; /* file handle for plex */
354 char filename[MAXPATHLEN]; /* create a file name here */
356 /* Variables for use by children */
357 int failed = 0; /* set if a child dies badly */
359 sprintf(filename, VINUM_DIR "/plex/%s", name);
360 if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */
362 * We don't actually write anything to the
363 * plex. We open it to ensure that nobody
364 * else tries to open it while we initialize
367 fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno));
371 pid = fork(); /* into the background with you */
372 if (pid != 0) { /* I'm the parent, or we failed */
373 if (pid < 0) /* failure */
374 printf("Couldn't fork: %s", strerror(errno));
375 close(plexfh); /* we don't need this any more */
380 * If we get here, we're either the first-level
381 * child (if we're not waiting) or we're going
384 for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */
385 get_plex_sd_info(&sd, plexno, sdno);
388 /* Now wait for them to complete */
392 if (((int) pid == -1)
393 && (errno == ECHILD)) /* all gone */
395 if (WEXITSTATUS(status) != 0) { /* oh, oh */
396 printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status));
402 message->index = plexno; /* pass object number */
403 message->type = plex_object; /* and type of object */
404 message->state = object_up;
405 message->force = 1; /* insist */
406 ioctl(superdev, VINUM_SETSTATE, message);
408 syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name);
410 syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died",
413 if (dowait == 0) /* we're the waiting child, */
414 exit(0); /* we've done our dash */
417 /* Initialize a subdisk. */
419 initsd(int sdno, int dowait)
422 struct _ioctl_reply reply;
423 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
424 char filename[MAXPATHLEN]; /* create a file name here */
426 /* Variables for use by children */
427 int sdfh; /* and for subdisk */
428 int initsize; /* actual size to write */
429 int64_t sdsize; /* size of subdisk */
432 pid = fork(); /* into the background with you */
433 if (pid > 0) /* I'm the parent */
435 else if (pid < 0) { /* failure */
436 printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno));
440 if (SSize != 0) { /* specified a size for init */
442 SSize <<= DEV_BSHIFT;
443 initsize = min(SSize, MAXPLEXINITSIZE);
445 initsize = PLEXINITSIZE;
446 openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
447 get_sd_info(&sd, sdno);
448 sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */
449 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
450 setproctitle("initializing %s", filename); /* show what we're doing */
451 syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename);
452 if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */
453 syslog(LOG_ERR | LOG_KERN,
454 "can't open subdisk %s: %s",
459 /* Set the subdisk in initializing state */
460 message->index = sd.sdno; /* pass object number */
461 message->type = sd_object; /* and type of object */
462 message->state = object_initializing;
463 message->verify = vflag; /* verify what we write? */
464 message->force = 1; /* insist */
465 ioctl(superdev, VINUM_SETSTATE, message);
466 if ((SSize > 0) /* specified a size for init */
468 SSize <<= DEV_BSHIFT;
471 "Can't initialize %s: %s (%d)\n",
473 strerror(reply.error),
478 if (interval) /* pause between copies */
479 usleep(interval * 1000);
480 message->index = sd.sdno; /* pass object number */
481 message->type = sd_object; /* and type of object */
482 message->state = object_up;
483 message->verify = vflag; /* verify what we write? */
484 message->blocksize = SSize;
485 ioctl(superdev, VINUM_SETSTATE, message);
487 while (reply.error == EAGAIN); /* until we're done */
490 "Can't initialize %s: %s (%d)\n",
492 strerror(reply.error),
494 get_sd_info(&sd, sdno);
495 if (sd.state != sd_up)
496 /* Set the subdisk down */
497 message->index = sd.sdno; /* pass object number */
498 message->type = sd_object; /* and type of object */
499 message->state = object_down;
500 message->verify = vflag; /* verify what we write? */
501 message->force = 1; /* insist */
502 ioctl(superdev, VINUM_SETSTATE, message);
505 printf("subdisk %s initialized\n", filename);
511 vinum_start(int argc, char *argv[], char *arg0[])
514 struct _ioctl_reply reply;
515 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
517 if (argc == 0) { /* start everything */
518 int devs = getnumdevs();
519 struct statinfo statinfo;
521 char *enamelist; /* end of name list */
523 char **token; /* list of tokens */
524 int tokens; /* and their number */
526 bzero(&statinfo, sizeof(struct statinfo));
527 statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
528 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
529 token = malloc((devs + 1) * sizeof(char *));
530 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
531 fprintf(stderr, "Can't allocate memory for drive list\n");
534 bzero(statinfo.dinfo, sizeof(struct devinfo));
536 tokens = 0; /* no tokens yet */
537 if (getdevs(&statinfo) < 0) { /* find out what devices we have */
538 perror("Can't get device list");
541 namelist[0] = '\0'; /* start with empty namelist */
542 enamelist = namelist; /* point to the end of the list */
544 for (i = 0; i < devs; i++) {
545 struct devstat *stat = &statinfo.dinfo->devices[i];
547 if (((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
548 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
549 &&((stat->device_name[0] != '\0'))) { /* and it has a name */
550 sprintf(enamelist, _PATH_DEV "%s%d", stat->device_name, stat->unit_number);
551 token[tokens] = enamelist; /* point to it */
552 tokens++; /* one more token */
553 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
556 free(statinfo.dinfo); /* don't need the list any more */
557 vinum_read(tokens, token, &token[0]); /* start the system */
560 list_defective_objects(); /* and list anything that's down */
561 } else { /* start specified objects */
563 enum objecttype type;
565 for (index = 0; index < argc; index++) {
566 object = find_object(argv[index], &type); /* look for it */
567 if (type == invalid_object)
568 fprintf(stderr, "Can't find object: %s\n", argv[index]);
570 int doit = 0; /* set to 1 if we pass our tests */
573 if (drive.state == drive_up) /* already up */
574 fprintf(stderr, "%s is already up\n", drive.label.name);
580 if (sd.state == sd_up) /* already up */
581 fprintf(stderr, "%s is already up\n", sd.name);
587 if (plex.state == plex_up) /* already up */
588 fprintf(stderr, "%s is already up\n", plex.name);
593 * First, see if we can bring it up
594 * just by asking. This might happen
595 * if somebody has used setupstate on
596 * the subdisks. If we don't do this,
597 * we'll return success, but the plex
598 * won't have changed state. Note
599 * that we don't check for errors
602 message->index = plex.plexno; /* pass object number */
603 message->type = plex_object; /* it's a plex */
604 message->state = object_up;
605 message->force = 0; /* don't force it */
606 ioctl(superdev, VINUM_SETSTATE, message);
607 for (sdno = 0; sdno < plex.subdisks; sdno++) {
608 get_plex_sd_info(&sd, object, sdno);
609 if ((sd.state >= sd_empty)
610 && (sd.state <= sd_reviving)) { /* candidate for start */
611 message->index = sd.sdno; /* pass object number */
612 message->type = sd_object; /* it's a subdisk */
613 message->state = object_up;
614 message->force = force; /* don't force it, use a larger hammer */
617 * We don't do any checking here.
618 * The kernel module has a better
619 * understanding of these things,
622 if (SSize != 0) { /* specified a size for init */
624 SSize <<= DEV_BSHIFT;
625 message->blocksize = SSize;
627 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
628 ioctl(superdev, VINUM_SETSTATE, message);
629 if (reply.error != 0) {
630 if (reply.error == EAGAIN) /* we're reviving */
631 continue_revive(sd.sdno);
634 "Can't start %s: %s (%d)\n",
636 reply.msg[0] ? reply.msg : strerror(reply.error),
640 vinum_lsi(sd.sdno, 0);
647 if (vol.state == volume_up) /* already up */
648 fprintf(stderr, "%s is already up\n", vol.name);
657 message->index = object; /* pass object number */
658 message->type = type; /* and type of object */
659 message->state = object_up;
660 message->force = force; /* don't force it, use a larger hammer */
663 * We don't do any checking here.
664 * The kernel module has a better
665 * understanding of these things,
668 if (SSize != 0) { /* specified a size for init or revive */
670 SSize <<= DEV_BSHIFT;
671 message->blocksize = SSize;
673 message->blocksize = 0;
674 ioctl(superdev, VINUM_SETSTATE, message);
675 if (reply.error != 0) {
676 if ((reply.error == EAGAIN) /* we're reviving */
677 &&(type == sd_object))
678 continue_revive(object);
681 "Can't start %s: %s (%d)\n",
683 reply.msg[0] ? reply.msg : strerror(reply.error),
687 vinum_li(object, type);
692 checkupdates(); /* make sure we're updating */
696 vinum_stop(int argc, char *argv[], char *arg0[])
699 struct _ioctl_reply reply;
700 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
702 if (checkupdates() && (!force)) /* not updating? */
704 message->force = force; /* should we force the transition? */
705 if (argc == 0) { /* stop vinum */
706 int fileid = 0; /* ID of Vinum kld */
708 close(superdev); /* we can't stop if we have vinum open */
709 sleep(1); /* wait for the daemon to let go */
710 fileid = kldfind(VINUMMOD);
711 if ((fileid < 0) /* no go */
712 ||(kldunload(fileid) < 0))
713 perror("Can't unload " VINUMMOD);
715 fprintf(stderr, VINUMMOD " unloaded\n");
719 /* If we got here, the stop failed. Reopen the superdevice. */
720 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */
722 perror("Can't reopen Vinum superdevice");
725 } else { /* stop specified objects */
727 enum objecttype type;
729 for (i = 0; i < argc; i++) {
730 object = find_object(argv[i], &type); /* look for it */
731 if (type == invalid_object)
732 fprintf(stderr, "Can't find object: %s\n", argv[i]);
734 message->index = object; /* pass object number */
735 message->type = type; /* and type of object */
736 message->state = object_down;
737 ioctl(superdev, VINUM_SETSTATE, message);
738 if (reply.error != 0)
740 "Can't stop %s: %s (%d)\n",
742 reply.msg[0] ? reply.msg : strerror(reply.error),
745 vinum_li(object, type);
752 vinum_label(int argc, char *argv[], char *arg0[])
755 struct _ioctl_reply reply;
756 int *message = (int *) &reply;
758 if (argc == 0) /* start everything */
759 fprintf(stderr, "label: please specify one or more volume names\n");
760 else { /* start specified objects */
762 enum objecttype type;
764 for (i = 0; i < argc; i++) {
765 object = find_object(argv[i], &type); /* look for it */
766 if (type == invalid_object)
767 fprintf(stderr, "Can't find object: %s\n", argv[i]);
768 else if (type != volume_object) /* it exists, but it isn't a volume */
769 fprintf(stderr, "%s is not a volume\n", argv[i]);
771 message[0] = object; /* pass object number */
772 ioctl(superdev, VINUM_LABEL, message);
773 if (reply.error != 0)
775 "Can't label %s: %s (%d)\n",
777 reply.msg[0] ? reply.msg : strerror(reply.error),
780 vinum_li(object, type);
784 checkupdates(); /* not updating? */
788 reset_volume_stats(int volno, int recurse)
790 struct vinum_ioctl_msg msg;
791 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
794 msg.type = volume_object;
795 /* XXX get these numbers right if we ever
796 * actually return errors */
797 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
798 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
799 longjmp(command_fail, -1);
800 } else if (recurse) {
804 get_volume_info(&vol, volno);
805 for (plexno = 0; plexno < vol.plexes; plexno++)
806 reset_plex_stats(vol.plex[plexno], recurse);
811 reset_plex_stats(int plexno, int recurse)
813 struct vinum_ioctl_msg msg;
814 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
817 msg.type = plex_object;
818 /* XXX get these numbers right if we ever
819 * actually return errors */
820 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
821 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
822 longjmp(command_fail, -1);
823 } else if (recurse) {
828 get_plex_info(&plex, plexno);
829 for (sdno = 0; sdno < plex.subdisks; sdno++) {
830 get_plex_sd_info(&sd, plex.plexno, sdno);
831 reset_sd_stats(sd.sdno, recurse);
837 reset_sd_stats(int sdno, int recurse)
839 struct vinum_ioctl_msg msg;
840 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
843 msg.type = sd_object;
844 /* XXX get these numbers right if we ever
845 * actually return errors */
846 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
847 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
848 longjmp(command_fail, -1);
849 } else if (recurse) {
850 get_sd_info(&sd, sdno); /* get the info */
851 reset_drive_stats(sd.driveno); /* and clear the drive */
856 reset_drive_stats(int driveno)
858 struct vinum_ioctl_msg msg;
859 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
862 msg.type = drive_object;
863 /* XXX get these numbers right if we ever
864 * actually return errors */
865 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
866 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
867 longjmp(command_fail, -1);
872 vinum_resetstats(int argc, char *argv[], char *argv0[])
876 enum objecttype type;
878 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
879 perror("Can't get vinum config");
883 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
884 reset_volume_stats(objno, 1); /* clear everything recursively */
886 for (i = 0; i < argc; i++) {
887 objno = find_object(argv[i], &type);
888 if (objno >= 0) { /* not invalid */
891 reset_drive_stats(objno);
895 reset_sd_stats(objno, recurse);
899 reset_plex_stats(objno, recurse);
903 reset_volume_stats(objno, recurse);
906 case invalid_object: /* can't get this */
914 /* Attach a subdisk to a plex, or a plex to a volume.
915 * attach subdisk plex [offset] [rename]
916 * attach plex volume [rename]
919 vinum_attach(int argc, char *argv[], char *argv0[])
922 enum objecttype supertype;
923 struct vinum_ioctl_msg msg;
924 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
925 const char *objname = argv[0];
926 const char *supername = argv[1];
929 char oldname[MAXNAME + 8];
930 char newname[MAXNAME + 8];
931 int rename = 0; /* set if we want to rename the object */
936 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
937 "\tattach <plex> <volume> [rename]\n");
940 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
941 perror("Can't get vinum config");
944 msg.index = find_object(objname, &msg.type); /* find the object to attach */
945 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */
946 msg.force = force; /* did we specify the use of force? */
947 msg.recurse = recurse;
948 msg.offset = -1; /* and no offset */
950 for (i = 2; i < argc; i++) {
951 if (!strcmp(argv[i], "rename")) {
953 msg.rename = 1; /* do renaming */
954 } else if (!isdigit(argv[i][0])) { /* not an offset */
955 fprintf(stderr, "Unknown attribute: %s\n", supername);
958 msg.offset = sizespec(argv[i]);
963 find_object(argv[1], &supertype);
964 if (supertype != plex_object) { /* huh? */
965 fprintf(stderr, "%s can only be attached to a plex\n", objname);
968 if ((plex.organization != plex_concat) /* not a cat plex, */
970 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
973 sdno = msg.index; /* note the subdisk number for later */
977 find_object(argv[1], &supertype);
978 if (supertype != volume_object) { /* huh? */
979 fprintf(stderr, "%s can only be attached to a volume\n", objname);
986 fprintf(stderr, "Can only attach subdisks and plexes\n");
990 fprintf(stderr, "%s is not a Vinum object\n", objname);
994 ioctl(superdev, VINUM_ATTACH, &msg);
995 if (reply->error != 0) {
996 if (reply->error == EAGAIN) /* reviving */
997 continue_revive(sdno); /* continue the revive */
1000 "Can't attach %s to %s: %s (%d)\n",
1003 reply->msg[0] ? reply->msg : strerror(reply->error),
1011 /* we've overwritten msg with the
1012 * ioctl reply, start again */
1013 msg.index = find_object(objname, &msg.type); /* find the object to rename */
1016 get_sd_info(&sd, msg.index);
1017 get_plex_info(&plex, sd.plexno);
1018 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1019 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */
1022 sprintf(newname, "%s.s%d", plex.name, sdno);
1023 sprintf(oldname, "%s", sd.name);
1024 vinum_rename_2(oldname, newname);
1028 get_plex_info(&plex, msg.index);
1029 get_volume_info(&vol, plex.volno);
1030 for (plexno = 0; plexno < vol.plexes; plexno++) {
1031 if (vol.plex[plexno] == msg.index) /* found our subdisk */
1034 sprintf(newname, "%s.p%d", vol.name, plexno);
1035 sprintf(oldname, "%s", plex.name);
1036 vinum_rename_2(oldname, newname); /* this may recurse */
1039 default: /* can't get here */
1042 checkupdates(); /* make sure we're updating */
1045 /* Detach a subdisk from a plex, or a plex from a volume.
1046 * detach subdisk plex [rename]
1047 * detach plex volume [rename]
1050 vinum_detach(int argc, char *argv[], char *argv0[])
1052 struct vinum_ioctl_msg msg;
1053 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
1058 "Usage: \tdetach <subdisk> [rename]\n"
1059 "\tdetach <plex> [rename]\n");
1062 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1063 perror("Can't get vinum config");
1066 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */
1067 msg.force = force; /* did we specify the use of force? */
1068 msg.rename = 0; /* don't specify new name */
1069 msg.recurse = recurse; /* but recurse if we have to */
1071 /* XXX are we going to keep this?
1072 * Don't document it yet, since the
1073 * kernel side of things doesn't
1076 if (!strcmp(argv[1], "rename"))
1077 msg.rename = 1; /* do renaming */
1079 fprintf(stderr, "Unknown attribute: %s\n", argv[1]);
1083 if ((msg.type != sd_object)
1084 && (msg.type != plex_object)) {
1085 fprintf(stderr, "Can only detach subdisks and plexes\n");
1088 ioctl(superdev, VINUM_DETACH, &msg);
1089 if (reply->error != 0)
1091 "Can't detach %s: %s (%d)\n",
1093 reply->msg[0] ? reply->msg : strerror(reply->error),
1095 checkupdates(); /* make sure we're updating */
1099 dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen)
1101 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
1103 if (strlen(name) > maxlen) {
1104 fprintf(stderr, "%s is too long\n", name);
1107 strcpy(msg->newname, name);
1108 ioctl(superdev, VINUM_RENAME, msg);
1109 if (reply->error != 0)
1111 "Can't rename %s to %s: %s (%d)\n",
1114 reply->msg[0] ? reply->msg : strerror(reply->error),
1118 /* Rename an object:
1119 * rename <object> "newname"
1122 vinum_rename_2(char *oldname, char *newname)
1124 struct vinum_rename_msg msg;
1128 msg.index = find_object(oldname, &msg.type); /* find the object to rename */
1129 msg.recurse = recurse;
1131 /* Ugh. Determine how long the name may be */
1134 dorename(&msg, oldname, newname, MAXDRIVENAME);
1138 dorename(&msg, oldname, newname, MAXSDNAME);
1143 dorename(&msg, oldname, newname, MAXPLEXNAME);
1147 get_plex_info(&plex, plexno); /* find out who we are */
1148 msg.type = sd_object;
1149 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1150 char sdname[MAXPLEXNAME + 8];
1152 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1153 sprintf(sdname, "%s.s%d", newname, sdno);
1154 msg.index = sd.sdno; /* number of the subdisk */
1155 dorename(&msg, sd.name, sdname, MAXSDNAME);
1162 dorename(&msg, oldname, newname, MAXVOLNAME);
1167 get_volume_info(&vol, volno); /* find out who we are */
1168 for (plexno = 0; plexno < vol.plexes; plexno++) {
1169 char plexname[MAXVOLNAME + 8];
1171 msg.type = plex_object;
1172 sprintf(plexname, "%s.p%d", newname, plexno);
1173 msg.index = vol.plex[plexno]; /* number of the plex */
1174 dorename(&msg, plex.name, plexname, MAXPLEXNAME);
1175 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */
1176 msg.type = sd_object;
1177 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1178 char sdname[MAXPLEXNAME + 8];
1180 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1181 sprintf(sdname, "%s.s%d", plexname, sdno);
1182 msg.index = sd.sdno; /* number of the subdisk */
1183 dorename(&msg, sd.name, sdname, MAXSDNAME);
1190 fprintf(stderr, "%s is not a Vinum object\n", oldname);
1196 vinum_rename(int argc, char *argv[], char *argv0[])
1199 fprintf(stderr, "Usage: \trename <object> <new name>\n");
1202 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1203 perror("Can't get vinum config");
1206 vinum_rename_2(argv[0], argv[1]);
1207 checkupdates(); /* make sure we're updating */
1213 * mv <dest> <src> ...
1216 vinum_mv(int argc, char *argv[], char *argv0[])
1218 int i; /* loop index */
1221 enum objecttype srct;
1222 enum objecttype destt;
1224 struct _ioctl_reply reply;
1225 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply;
1228 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n");
1231 /* Get current config */
1232 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1233 perror("Cannot get vinum config\n");
1236 /* Get our destination */
1237 destobj = find_object(argv[0], &destt);
1238 if (destobj == -1) {
1239 fprintf(stderr, "Can't find %s\n", argv[0]);
1242 /* Verify that the target is a drive */
1243 if (destt != drive_object) {
1244 fprintf(stderr, "%s is not a drive\n", argv[0]);
1247 for (i = 1; i < argc; i++) { /* for all the sources */
1248 srcobj = find_object(argv[i], &srct);
1250 fprintf(stderr, "Can't find %s\n", argv[i]);
1253 msg->index = destobj;
1254 switch (srct) { /* Handle the source object */
1255 case drive_object: /* Move all subdisks on the drive to dst. */
1256 get_drive_info(&drive, srcobj); /* get info on drive */
1257 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) {
1258 get_sd_info(&sd, sdno);
1259 if (sd.driveno == srcobj) {
1260 msg->index = destobj;
1261 msg->otherobject = sd.sdno;
1262 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1264 "Can't move %s (part of %s) to %s: %s (%d)\n",
1268 strerror(reply.error),
1275 msg->otherobject = srcobj;
1276 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1278 "Can't move %s to %s: %s (%d)\n",
1281 strerror(reply.error),
1286 get_plex_info(&plex, srcobj);
1287 for (sdno = 0; sdno < plex.subdisks; ++sdno) {
1288 get_plex_sd_info(&sd, plex.plexno, sdno);
1289 msg->index = destobj;
1290 msg->otherobject = sd.sdno;
1291 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1293 "Can't move %s (part of %s) to %s: %s (%d)\n",
1297 strerror(reply.error),
1303 case invalid_object:
1305 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]);
1310 "Can't move %s to %s: %s (%d)\n",
1313 strerror(reply.error),
1316 checkupdates(); /* make sure we're updating */
1320 * Replace objects. Not implemented, may never be.
1323 vinum_replace(int argc, char *argv[], char *argv0[])
1325 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n");
1328 /* Primitive help function */
1330 vinum_help(int argc, char *argv[], char *argv0[])
1335 "attach plex volume [rename]\n"
1336 "attach subdisk plex [offset] [rename]\n"
1337 " Attach a plex to a volume, or a subdisk to a plex.\n"
1338 "checkparity plex [-f] [-v]\n"
1339 " Check the parity blocks of a RAID-4 or RAID-5 plex.\n"
1340 "concat [-f] [-n name] [-v] drives\n"
1341 " Create a concatenated volume from the specified drives.\n"
1342 "create [-f] description-file\n"
1343 " Create a volume as described in description-file.\n"
1344 "debug Cause the volume manager to enter the kernel debugger.\n"
1346 " Set debugging flags.\n"
1347 "detach [-f] [plex | subdisk]\n"
1348 " Detach a plex or subdisk from the volume or plex to which it is\n"
1350 "dumpconfig [drive ...]\n"
1351 " List the configuration information stored on the specified\n"
1352 " drives, or all drives in the system if no drive names are speci-\n"
1355 " List information about volume manager state.\n"
1356 "init [-S size] [-w] plex | subdisk\n"
1357 " Initialize the contents of a subdisk or all the subdisks of a\n"
1358 " plex to all zeros.\n"
1360 " Create a volume label.\n"
1361 "l | list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1362 " List information about specified objects.\n"
1363 "ld [-r] [-s] [-v] [-V] [volume]\n"
1364 " List information about drives.\n"
1365 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1366 " List information about subdisks.\n"
1367 "lp [-r] [-s] [-v] [-V] [plex]\n"
1368 " List information about plexes.\n"
1369 "lv [-r] [-s] [-v] [-V] [volume]\n"
1370 " List information about volumes.\n"
1372 " Remake the device nodes in /dev/vinum.\n"
1373 "mirror [-f] [-n name] [-s] [-v] drives\n"
1374 " Create a mirrored volume from the specified drives.\n"
1375 "move | mv -f drive object ...\n"
1376 " Move the object(s) to the specified drive.\n"
1377 "printconfig [file]\n"
1378 " Write a copy of the current configuration to file.\n"
1379 "quit Exit the vinum program when running in interactive mode. Nor-\n"
1380 " mally this would be done by entering the EOF character.\n"
1382 " Read the vinum configuration from the specified disks.\n"
1383 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1384 " Change the name of the specified object.\n"
1385 "rebuildparity plex [-f] [-v] [-V]\n"
1386 " Rebuild the parity blocks of a RAID-4 or RAID-5 plex.\n"
1388 " Reset the complete vinum configuration.\n"
1389 "resetstats [-r] [volume | plex | subdisk]\n"
1390 " Reset statistics counters for the specified objects, or for all\n"
1391 " objects if none are specified.\n"
1392 "rm [-f] [-r] volume | plex | subdisk\n"
1393 " Remove an object.\n"
1395 " Save vinum configuration to disk after configuration failures.\n"
1396 "setdaemon [value]\n"
1397 " Set daemon configuration.\n"
1398 "setstate state [volume | plex | subdisk | drive]\n"
1399 " Set state without influencing other objects, for diagnostic pur-\n"
1401 "start Read configuration from all vinum drives.\n"
1402 "start [-i interval] [-S size] [-w] volume | plex | subdisk\n"
1403 " Allow the system to access the objects.\n"
1404 "stop [-f] [volume | plex | subdisk]\n"
1405 " Terminate access to the objects, or stop vinum if no parameters\n"
1407 "stripe [-f] [-n name] [-v] drives\n"
1408 " Create a striped volume from the specified drives.\n"
1413 /* Set daemon options.
1414 * XXX quick and dirty: use a bitmap, which requires
1415 * knowing which bit does what. FIXME */
1417 vinum_setdaemon(int argc, char *argv[], char *argv0[])
1423 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1424 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1426 printf("Options mask: %d\n", options);
1430 options = atoi(argv[0]);
1431 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0)
1432 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno);
1436 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n");
1438 checkupdates(); /* make sure we're updating */
1441 /* Save config info */
1443 vinum_saveconfig(int argc, char *argv[], char *argv0[])
1448 printf("Usage: saveconfig\n");
1451 ioctltype = 1; /* user saveconfig */
1452 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0)
1453 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno);
1454 checkupdates(); /* make sure we're updating */
1458 * Create a volume name for the quick and dirty
1459 * commands. It will be of the form "vinum#",
1460 * where # is a small positive number.
1465 int v; /* volume number */
1466 static char volumename[MAXVOLNAME]; /* name to create */
1467 enum objecttype type;
1469 objectname = volumename; /* point to it */
1471 sprintf(objectname, "vinum%d", v); /* create the name */
1472 if (find_object(objectname, &type) == -1) /* does it exist? */
1473 return; /* no, it's ours */
1478 * Create a drive for the quick and dirty
1479 * commands. The name will be of the form
1480 * vinumdrive#, where # is a small positive
1481 * number. Return the name of the drive.
1484 create_drive(char *devicename)
1486 int d; /* volume number */
1487 static char drivename[MAXDRIVENAME]; /* name to create */
1488 enum objecttype type;
1489 struct _ioctl_reply *reply;
1492 * We're never likely to get anything
1493 * like 10000 drives. The only reason for
1494 * this limit is to stop the thing
1495 * looping if we have a bug somewhere.
1497 for (d = 0; d < 100000; d++) { /* look for a free drive number */
1498 sprintf(drivename, "vinumdrive%d", d); /* create the name */
1499 if (find_object(drivename, &type) == -1) { /* does it exist? */
1500 char command[MAXDRIVENAME * 2];
1502 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */
1504 printf("drive %s device %s\n", drivename, devicename); /* create a create command */
1505 ioctl(superdev, VINUM_CREATE, command);
1506 reply = (struct _ioctl_reply *) &command;
1507 if (reply->error != 0) { /* error in config */
1510 "Can't create drive %s, device %s: %s\n",
1516 "Can't create drive %s, device %s: %s (%d)\n",
1519 strerror(reply->error),
1521 longjmp(command_fail, -1); /* give up */
1523 find_object(drivename, &type);
1524 return &drive; /* return the name of the drive */
1527 fprintf(stderr, "Can't generate a drive name\n");
1533 * Create a volume with a single concatenated plex from
1534 * as much space as we can get on the specified drives.
1535 * If the drives aren't Vinum drives, make them so.
1538 vinum_concat(int argc, char *argv[], char *argv0[])
1540 int o; /* object number */
1541 char buffer[BUFSIZE];
1542 struct _drive *drive; /* drive we're currently looking at */
1543 struct _ioctl_reply *reply;
1546 enum objecttype type;
1548 reply = (struct _ioctl_reply *) &buffer;
1549 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1550 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1553 if (!objectname) /* we need a name for our object */
1555 sprintf(buffer, "volume %s", objectname);
1557 printf("volume %s\n", objectname);
1558 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1559 if (reply->error != 0) { /* error in config */
1562 "Can't create volume %s: %s\n",
1567 "Can't create volume %s: %s (%d)\n",
1569 strerror(reply->error),
1571 longjmp(command_fail, -1); /* give up */
1573 sprintf(buffer, "plex name %s.p0 org concat", objectname);
1575 printf(" plex name %s.p0 org concat\n", objectname);
1576 ioctl(superdev, VINUM_CREATE, buffer);
1577 if (reply->error != 0) { /* error in config */
1580 "Can't create plex %s.p0: %s\n",
1585 "Can't create plex %s.p0: %s (%d)\n",
1587 strerror(reply->error),
1589 longjmp(command_fail, -1); /* give up */
1591 for (o = 0; o < argc; o++) {
1592 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1593 drive = create_drive(argv[o]); /* create it */
1594 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name);
1596 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name);
1597 ioctl(superdev, VINUM_CREATE, buffer);
1598 if (reply->error != 0) { /* error in config */
1601 "Can't create subdisk %s.p0.s%d: %s\n",
1607 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1610 strerror(reply->error),
1612 longjmp(command_fail, -1); /* give up */
1616 /* done, save the config */
1617 ioctltype = 0; /* saveconfig after update */
1618 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1620 perror("Can't save Vinum config");
1621 find_object(objectname, &type); /* find the index of the volume */
1622 make_vol_dev(vol.volno, 1); /* and create the devices */
1624 vflag--; /* XXX don't give too much detail */
1625 find_object(objectname, &type); /* point to the volume */
1626 vinum_lvi(vol.volno, 1); /* and print info about it */
1632 * Create a volume with a single striped plex from
1633 * as much space as we can get on the specified drives.
1634 * If the drives aren't Vinum drives, make them so.
1637 vinum_stripe(int argc, char *argv[], char *argv0[])
1639 int o; /* object number */
1640 char buffer[BUFSIZE];
1641 struct _drive *drive; /* drive we're currently looking at */
1642 struct _ioctl_reply *reply;
1645 enum objecttype type;
1647 int fe; /* freelist entry index */
1648 struct drive_freelist freelist;
1649 struct ferq { /* request to pass to ioctl */
1652 } *ferq = (struct ferq *) &freelist;
1653 u_int64_t bigchunk; /* biggest chunk in freelist */
1656 reply = (struct _ioctl_reply *) &buffer;
1659 * First, check our drives.
1662 fprintf(stderr, "You need at least two drives to create a striped plex\n");
1665 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1666 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1669 if (!objectname) /* we need a name for our object */
1671 for (o = 0; o < argc; o++) {
1672 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1673 drive = create_drive(argv[o]); /* create it */
1674 /* Now find the largest chunk available on the drive */
1675 bigchunk = 0; /* ain't found nothin' yet */
1676 for (fe = 0; fe < drive->freelist_entries; fe++) {
1677 ferq->driveno = drive->driveno;
1679 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1681 "Can't get free list element %d: %s\n",
1684 longjmp(command_fail, -1);
1686 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1688 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1691 /* Now create the volume */
1692 sprintf(buffer, "volume %s", objectname);
1694 printf("volume %s\n", objectname);
1695 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1696 if (reply->error != 0) { /* error in config */
1699 "Can't create volume %s: %s\n",
1704 "Can't create volume %s: %s (%d)\n",
1706 strerror(reply->error),
1708 longjmp(command_fail, -1); /* give up */
1710 sprintf(buffer, "plex name %s.p0 org striped 279k", objectname);
1712 printf(" plex name %s.p0 org striped 279k\n", objectname);
1713 ioctl(superdev, VINUM_CREATE, buffer);
1714 if (reply->error != 0) { /* error in config */
1717 "Can't create plex %s.p0: %s\n",
1722 "Can't create plex %s.p0: %s (%d)\n",
1724 strerror(reply->error),
1726 longjmp(command_fail, -1); /* give up */
1728 for (o = 0; o < argc; o++) {
1729 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1731 "sd name %s.p0.s%d drive %s size %lldb",
1735 (long long) maxsize);
1737 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1741 (long long) maxsize);
1742 ioctl(superdev, VINUM_CREATE, buffer);
1743 if (reply->error != 0) { /* error in config */
1746 "Can't create subdisk %s.p0.s%d: %s\n",
1752 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1755 strerror(reply->error),
1757 longjmp(command_fail, -1); /* give up */
1761 /* done, save the config */
1762 ioctltype = 0; /* saveconfig after update */
1763 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1765 perror("Can't save Vinum config");
1766 find_object(objectname, &type); /* find the index of the volume */
1767 make_vol_dev(vol.volno, 1); /* and create the devices */
1769 vflag--; /* XXX don't give too much detail */
1770 find_object(objectname, &type); /* point to the volume */
1771 vinum_lvi(vol.volno, 1); /* and print info about it */
1776 * Create a volume with a single RAID-4 plex from
1777 * as much space as we can get on the specified drives.
1778 * If the drives aren't Vinum drives, make them so.
1781 vinum_raid4(int argc, char *argv[], char *argv0[])
1783 int o; /* object number */
1784 char buffer[BUFSIZE];
1785 struct _drive *drive; /* drive we're currently looking at */
1786 struct _ioctl_reply *reply;
1789 enum objecttype type;
1791 int fe; /* freelist entry index */
1792 struct drive_freelist freelist;
1793 struct ferq { /* request to pass to ioctl */
1796 } *ferq = (struct ferq *) &freelist;
1797 u_int64_t bigchunk; /* biggest chunk in freelist */
1800 reply = (struct _ioctl_reply *) &buffer;
1803 * First, check our drives.
1806 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
1809 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1810 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1813 if (!objectname) /* we need a name for our object */
1815 for (o = 0; o < argc; o++) {
1816 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1817 drive = create_drive(argv[o]); /* create it */
1818 /* Now find the largest chunk available on the drive */
1819 bigchunk = 0; /* ain't found nothin' yet */
1820 for (fe = 0; fe < drive->freelist_entries; fe++) {
1821 ferq->driveno = drive->driveno;
1823 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1825 "Can't get free list element %d: %s\n",
1828 longjmp(command_fail, -1);
1830 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1832 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1835 /* Now create the volume */
1836 sprintf(buffer, "volume %s", objectname);
1838 printf("volume %s\n", objectname);
1839 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1840 if (reply->error != 0) { /* error in config */
1843 "Can't create volume %s: %s\n",
1848 "Can't create volume %s: %s (%d)\n",
1850 strerror(reply->error),
1852 longjmp(command_fail, -1); /* give up */
1854 sprintf(buffer, "plex name %s.p0 org raid4 279k", objectname);
1856 printf(" plex name %s.p0 org raid4 279k\n", objectname);
1857 ioctl(superdev, VINUM_CREATE, buffer);
1858 if (reply->error != 0) { /* error in config */
1861 "Can't create plex %s.p0: %s\n",
1866 "Can't create plex %s.p0: %s (%d)\n",
1868 strerror(reply->error),
1870 longjmp(command_fail, -1); /* give up */
1872 for (o = 0; o < argc; o++) {
1873 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1875 "sd name %s.p0.s%d drive %s size %lldb",
1879 (long long) maxsize);
1881 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1885 (long long) maxsize);
1886 ioctl(superdev, VINUM_CREATE, buffer);
1887 if (reply->error != 0) { /* error in config */
1890 "Can't create subdisk %s.p0.s%d: %s\n",
1896 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1899 strerror(reply->error),
1901 longjmp(command_fail, -1); /* give up */
1905 /* done, save the config */
1906 ioctltype = 0; /* saveconfig after update */
1907 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1909 perror("Can't save Vinum config");
1910 find_object(objectname, &type); /* find the index of the volume */
1911 make_vol_dev(vol.volno, 1); /* and create the devices */
1913 vflag--; /* XXX don't give too much detail */
1914 find_object(objectname, &type); /* point to the volume */
1915 vinum_lvi(vol.volno, 1); /* and print info about it */
1920 * Create a volume with a single RAID-4 plex from
1921 * as much space as we can get on the specified drives.
1922 * If the drives aren't Vinum drives, make them so.
1925 vinum_raid5(int argc, char *argv[], char *argv0[])
1927 int o; /* object number */
1928 char buffer[BUFSIZE];
1929 struct _drive *drive; /* drive we're currently looking at */
1930 struct _ioctl_reply *reply;
1933 enum objecttype type;
1935 int fe; /* freelist entry index */
1936 struct drive_freelist freelist;
1937 struct ferq { /* request to pass to ioctl */
1940 } *ferq = (struct ferq *) &freelist;
1941 u_int64_t bigchunk; /* biggest chunk in freelist */
1944 reply = (struct _ioctl_reply *) &buffer;
1947 * First, check our drives.
1950 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
1953 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1954 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1957 if (!objectname) /* we need a name for our object */
1959 for (o = 0; o < argc; o++) {
1960 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1961 drive = create_drive(argv[o]); /* create it */
1962 /* Now find the largest chunk available on the drive */
1963 bigchunk = 0; /* ain't found nothin' yet */
1964 for (fe = 0; fe < drive->freelist_entries; fe++) {
1965 ferq->driveno = drive->driveno;
1967 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1969 "Can't get free list element %d: %s\n",
1972 longjmp(command_fail, -1);
1974 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1976 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1979 /* Now create the volume */
1980 sprintf(buffer, "volume %s", objectname);
1982 printf("volume %s\n", objectname);
1983 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1984 if (reply->error != 0) { /* error in config */
1987 "Can't create volume %s: %s\n",
1992 "Can't create volume %s: %s (%d)\n",
1994 strerror(reply->error),
1996 longjmp(command_fail, -1); /* give up */
1998 sprintf(buffer, "plex name %s.p0 org raid5 279k", objectname);
2000 printf(" plex name %s.p0 org raid5 279k\n", objectname);
2001 ioctl(superdev, VINUM_CREATE, buffer);
2002 if (reply->error != 0) { /* error in config */
2005 "Can't create plex %s.p0: %s\n",
2010 "Can't create plex %s.p0: %s (%d)\n",
2012 strerror(reply->error),
2014 longjmp(command_fail, -1); /* give up */
2016 for (o = 0; o < argc; o++) {
2017 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2019 "sd name %s.p0.s%d drive %s size %lldb",
2023 (long long) maxsize);
2025 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2029 (long long) maxsize);
2030 ioctl(superdev, VINUM_CREATE, buffer);
2031 if (reply->error != 0) { /* error in config */
2034 "Can't create subdisk %s.p0.s%d: %s\n",
2040 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2043 strerror(reply->error),
2045 longjmp(command_fail, -1); /* give up */
2049 /* done, save the config */
2050 ioctltype = 0; /* saveconfig after update */
2051 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2053 perror("Can't save Vinum config");
2054 find_object(objectname, &type); /* find the index of the volume */
2055 make_vol_dev(vol.volno, 1); /* and create the devices */
2057 vflag--; /* XXX don't give too much detail */
2058 find_object(objectname, &type); /* point to the volume */
2059 vinum_lvi(vol.volno, 1); /* and print info about it */
2064 * Create a volume with a two plexes from as much space
2065 * as we can get on the specified drives. If the
2066 * drives aren't Vinum drives, make them so.
2068 * The number of drives must be even, and at least 4
2069 * for a striped plex. Specify striped plexes with the
2070 * -s flag; otherwise they will be concatenated. It's
2071 * possible that the two plexes may differ in length.
2074 vinum_mirror(int argc, char *argv[], char *argv0[])
2076 int o; /* object number */
2077 int p; /* plex number */
2078 char buffer[BUFSIZE];
2079 struct _drive *drive; /* drive we're currently looking at */
2080 struct _ioctl_reply *reply;
2083 enum objecttype type;
2084 off_t maxsize[2]; /* maximum subdisk size for striped plexes */
2085 int fe; /* freelist entry index */
2086 struct drive_freelist freelist;
2087 struct ferq { /* request to pass to ioctl */
2090 } *ferq = (struct ferq *) &freelist;
2091 u_int64_t bigchunk; /* biggest chunk in freelist */
2093 if (sflag) /* striped, */
2094 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */
2096 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */
2098 reply = (struct _ioctl_reply *) &buffer;
2101 * First, check our drives.
2104 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
2107 if (sflag && (argc < 4)) {
2108 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
2111 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
2112 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2115 if (!objectname) /* we need a name for our object */
2117 for (o = 0; o < argc; o++) {
2118 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2119 drive = create_drive(argv[o]); /* create it */
2120 if (sflag) { /* striping, */
2121 /* Find the largest chunk available on the drive */
2122 bigchunk = 0; /* ain't found nothin' yet */
2123 for (fe = 0; fe < drive->freelist_entries; fe++) {
2124 ferq->driveno = drive->driveno;
2126 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
2128 "Can't get free list element %d: %s\n",
2131 longjmp(command_fail, -1);
2133 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
2135 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */
2139 /* Now create the volume */
2140 sprintf(buffer, "volume %s setupstate", objectname);
2142 printf("volume %s setupstate\n", objectname);
2143 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
2144 if (reply->error != 0) { /* error in config */
2147 "Can't create volume %s: %s\n",
2152 "Can't create volume %s: %s (%d)\n",
2154 strerror(reply->error),
2156 longjmp(command_fail, -1); /* give up */
2158 for (p = 0; p < 2; p++) { /* create each plex */
2160 sprintf(buffer, "plex name %s.p%d org striped 279k", objectname, p);
2162 printf(" plex name %s.p%d org striped 279k\n", objectname, p);
2163 } else { /* concat */
2164 sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
2166 printf(" plex name %s.p%d org concat\n", objectname, p);
2168 ioctl(superdev, VINUM_CREATE, buffer);
2169 if (reply->error != 0) { /* error in config */
2172 "Can't create plex %s.p%d: %s\n",
2178 "Can't create plex %s.p%d: %s (%d)\n",
2181 strerror(reply->error),
2183 longjmp(command_fail, -1); /* give up */
2185 /* Now look at the subdisks */
2186 for (o = p; o < argc; o += 2) { /* every second one */
2187 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2189 "sd name %s.p%d.s%d drive %s size %lldb",
2194 (long long) maxsize[p]);
2196 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2201 (long long) maxsize[p]);
2202 ioctl(superdev, VINUM_CREATE, buffer);
2203 if (reply->error != 0) { /* error in config */
2206 "Can't create subdisk %s.p%d.s%d: %s\n",
2213 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2217 strerror(reply->error),
2219 longjmp(command_fail, -1); /* give up */
2224 /* done, save the config */
2225 ioctltype = 0; /* saveconfig after update */
2226 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2228 perror("Can't save Vinum config");
2229 find_object(objectname, &type); /* find the index of the volume */
2230 make_vol_dev(vol.volno, 1); /* and create the devices */
2232 vflag--; /* XXX don't give too much detail */
2233 sflag = 0; /* no stats, please */
2234 find_object(objectname, &type); /* point to the volume */
2235 vinum_lvi(vol.volno, 1); /* and print info about it */
2240 vinum_readpol(int argc, char *argv[], char *argv0[])
2243 struct _ioctl_reply reply;
2244 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2245 enum objecttype type;
2250 if (argc == 0) { /* start everything */
2251 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n");
2254 object = find_object(argv[1], &type); /* look for it */
2255 if (type != volume_object) {
2256 fprintf(stderr, "%s is not a volume\n", argv[1]);
2259 get_volume_info(&vol, object);
2260 if (strcmp(argv[2], "round")) { /* not 'round' */
2261 object = find_object(argv[2], &type); /* look for it */
2262 if (type != plex_object) {
2263 fprintf(stderr, "%s is not a plex\n", argv[2]);
2266 get_plex_info(&plex, object);
2267 plexno = plex.plexno;
2272 message->index = vol.volno;
2273 message->otherobject = plexno;
2274 if (ioctl(superdev, VINUM_READPOL, message) < 0)
2275 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno);
2277 vinum_lpi(plexno, recurse);
2281 * Brute force set state function. Don't look at
2282 * any dependencies, just do it.
2285 vinum_setstate(int argc, char *argv[], char *argv0[])
2288 struct _ioctl_reply reply;
2289 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2291 enum objecttype type;
2294 for (index = 1; index < argc; index++) {
2295 object = find_object(argv[index], &type); /* look for it */
2296 if (type == invalid_object)
2297 fprintf(stderr, "Can't find object: %s\n", argv[index]);
2299 int doit = 0; /* set to 1 if we pass our tests */
2302 state = DriveState(argv[0]); /* get the state */
2303 if (drive.state == state) /* already in that state */
2304 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
2310 state = SdState(argv[0]); /* get the state */
2311 if (sd.state == state) /* already in that state */
2312 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
2318 state = PlexState(argv[0]); /* get the state */
2319 if (plex.state == state) /* already in that state */
2320 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
2326 state = VolState(argv[0]); /* get the state */
2327 if (vol.state == state) /* already in that state */
2328 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
2334 state = 0; /* to keep the compiler happy */
2338 fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
2340 message->index = object; /* pass object number */
2341 message->type = type; /* and type of object */
2342 message->state = state;
2343 message->force = force; /* don't force it, use a larger hammer */
2344 ioctl(superdev, VINUM_SETSTATE_FORCE, message);
2345 if (reply.error != 0)
2347 "Can't start %s: %s (%d)\n",
2349 reply.msg[0] ? reply.msg : strerror(reply.error),
2352 vinum_li(object, type);
2359 vinum_checkparity(int argc, char *argv[], char *argv0[])
2361 Verbose = vflag; /* accept -v for verbose */
2362 if (argc == 0) /* no parameters? */
2363 fprintf(stderr, "Usage: checkparity object [object...]\n");
2365 parityops(argc, argv, checkparity);
2369 vinum_rebuildparity(int argc, char *argv[], char *argv0[])
2371 if (argc == 0) /* no parameters? */
2372 fprintf(stderr, "Usage: rebuildparity object [object...]\n");
2374 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
2378 * Common code for rebuildparity and checkparity.
2379 * We bend the meanings of some flags here:
2381 * -v: Report incorrect parity on rebuild.
2382 * -V: Show running count of position being checked.
2383 * -f: Start from beginning of the plex.
2386 parityops(int argc, char *argv[], enum parityop op)
2390 struct _ioctl_reply reply;
2391 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2393 enum objecttype type;
2397 if (op == checkparity)
2401 for (index = 0; index < argc; index++) {
2402 object = find_object(argv[index], &type); /* look for it */
2403 if (type != plex_object)
2404 fprintf(stderr, "%s is not a plex\n", argv[index]);
2406 get_plex_info(&plex, object);
2407 if (!isparity((&plex)))
2408 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
2411 message->index = object; /* pass object number */
2412 message->type = type; /* and type of object */
2413 message->op = op; /* what to do */
2415 message->offset = 0; /* start at the beginning */
2417 message->offset = plex.checkblock; /* continue where we left off */
2418 force = 0; /* don't reset after the first time */
2419 ioctl(superdev, VINUM_PARITYOP, message);
2420 get_plex_info(&plex, object);
2422 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
2424 printf("\r%s at %s (%d%%) ",
2426 roughlength(block, 1),
2427 ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
2428 if ((reply.error == EAGAIN)
2429 && (reply.msg[0])) /* got a comment back */
2430 fputs(reply.msg, stderr); /* show it */
2434 while (reply.error == EAGAIN);
2435 if (reply.error != 0) {
2437 fputs(reply.msg, stderr);
2442 strerror(reply.error));
2443 } else if (Verbose) {
2444 if (op == checkparity)
2445 fprintf(stderr, "%s has correct parity\n", argv[index]);
2447 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
2454 /* Local Variables: */
2455 /* fill-column: 50 */