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.14 2000/11/14 20:01:23 grog Exp grog $
40 * $FreeBSD: src/sbin/vinum/commands.c,v 1.31.2.6 2003/06/06 05:13:29 grog Exp $
55 #include <sys/ioctl.h>
56 #include <dev/vinum/vinumhdr.h>
57 #include <dev/vinum/request.h>
59 #include <sys/types.h>
60 #include <sys/linker.h>
61 #include <sys/module.h>
63 #include <readline/history.h>
64 #include <readline/readline.h>
67 static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen);
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 fprintf(history, "%s", buffer);
129 if (configline == NULL) {
131 perror("Can't read config file");
134 file_line++; /* count the lines */
136 printf("%4d: %s", file_line, buffer);
137 strcpy(commandline, buffer); /* make a copy */
138 ioctl(superdev, VINUM_CREATE, buffer);
139 if (reply->error != 0) { /* error in config */
140 if (!vflag) /* print this line anyway */
141 printf("%4d: %s", file_line, commandline);
142 fprintf(stdout, "** %d %s: %s\n",
145 strerror(reply->error));
148 * XXX at the moment, we reset the config
149 * lock on error, so try to get it again.
150 * If we fail, don't cry again.
152 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */
156 fclose(dfd); /* done with the config file */
157 ioctltype = 0; /* saveconfig after update */
158 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
160 perror("Can't save Vinum config");
163 checkupdates(); /* make sure we're updating */
166 /* Read vinum config from a disk */
168 vinum_read(int argc, char *argv[], char *arg0[])
171 char buffer[BUFSIZE]; /* read config file in here */
172 struct _ioctl_reply *reply;
175 reply = (struct _ioctl_reply *) &buffer;
176 if (argc < 1) { /* wrong arg count */
177 fprintf(stderr, "Usage: read drive [drive ...]\n");
180 strcpy(buffer, "read ");
181 for (i = 0; i < argc; i++) { /* each drive name */
182 strcat(buffer, argv[i]);
186 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
187 fprintf(stderr, "Can't configure: %s (%d)\n", strerror(errno), errno);
190 ioctl(superdev, VINUM_CREATE, &buffer);
191 if (reply->error != 0) { /* error in config */
192 fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error));
193 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
195 perror("Can't save Vinum config");
197 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
199 perror("Can't save Vinum config");
202 checkupdates(); /* make sure we're updating */
207 vinum_debug(int argc, char *argv[], char *arg0[])
209 struct debuginfo info;
212 info.param = atoi(argv[0]);
216 sleep(2); /* give a chance to leave the window */
218 ioctl(superdev, VINUM_DEBUG, (caddr_t) & info);
223 vinum_modify(int argc, char *argv[], char *arg0[])
225 fprintf(stderr, "Modify command is currently not implemented\n");
226 checkupdates(); /* make sure we're updating */
230 vinum_set(int argc, char *argv[], char *arg0[])
232 fprintf(stderr, "set is not implemented yet\n");
236 vinum_rm(int argc, char *argv[], char *arg0[])
239 struct _ioctl_reply reply;
240 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
242 if (argc == 0) /* start everything */
243 fprintf(stderr, "Usage: rm object [object...]\n");
244 else { /* start specified objects */
246 enum objecttype type;
248 for (index = 0; index < argc; index++) {
249 object = find_object(argv[index], &type); /* look for it */
250 if (type == invalid_object)
251 fprintf(stderr, "Can't find object: %s\n", argv[index]);
253 message->index = object; /* pass object number */
254 message->type = type; /* and type of object */
255 message->force = force; /* do we want to force the operation? */
256 message->recurse = recurse; /* do we want to remove subordinates? */
257 ioctl(superdev, VINUM_REMOVE, message);
258 if (reply.error != 0) {
260 "Can't remove %s: %s (%d)\n",
262 reply.msg[0] ? reply.msg : strerror(reply.error),
265 fprintf(stderr, "%s removed\n", argv[index]);
268 checkupdates(); /* make sure we're updating */
273 vinum_resetconfig(int argc, char *argv[], char *arg0[])
278 if (! isatty (STDIN_FILENO)) {
279 fprintf (stderr, "Please enter this command from a tty device\n");
282 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
283 " All data will be lost. If you really want to do this, enter the text\n\n"
286 fgets(reply, sizeof(reply), stdin);
287 if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */
288 printf("\n No change\n");
290 error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */
293 fprintf(stderr, "Can't reset configuration: objects are in use\n");
295 perror("Can't find vinum config");
297 make_devices(); /* recreate the /dev/vinum hierarchy */
298 printf("\b Vinum configuration obliterated\n");
299 start_daemon(); /* then restart the daemon */
302 checkupdates(); /* make sure we're updating */
305 /* Initialize subdisks */
307 vinum_init(int argc, char *argv[], char *arg0[])
309 if (argc > 0) { /* initialize plexes */
312 enum objecttype type; /* type returned */
315 fflush(history); /* don't let all the kids do it. */
316 for (objindex = 0; objindex < argc; objindex++) {
317 objno = find_object(argv[objindex], &type); /* find the object */
319 printf("Can't find %s\n", argv[objindex]);
327 initplex(objno, argv[objindex]);
331 initsd(objno, dowait);
335 printf("Can't initialize %s: wrong object type\n", argv[objindex]);
341 checkupdates(); /* make sure we're updating */
347 printf("Initializing volumes is not implemented yet\n");
351 initplex(int plexno, char *name)
354 int plexfh = NULL; /* file handle for plex */
356 char filename[MAXPATHLEN]; /* create a file name here */
358 /* Variables for use by children */
359 int failed = 0; /* set if a child dies badly */
361 sprintf(filename, VINUM_DIR "/plex/%s", name);
362 if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */
364 * We don't actually write anything to the
365 * plex. We open it to ensure that nobody
366 * else tries to open it while we initialize
369 fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno));
373 pid = fork(); /* into the background with you */
374 if (pid != 0) { /* I'm the parent, or we failed */
375 if (pid < 0) /* failure */
376 printf("Couldn't fork: %s", strerror(errno));
377 close(plexfh); /* we don't need this any more */
382 * If we get here, we're either the first-level
383 * child (if we're not waiting) or we're going
386 for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */
387 get_plex_sd_info(&sd, plexno, sdno);
390 /* Now wait for them to complete */
394 if (((int) pid == -1)
395 && (errno == ECHILD)) /* all gone */
397 if (WEXITSTATUS(status) != 0) { /* oh, oh */
398 printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status));
404 message->index = plexno; /* pass object number */
405 message->type = plex_object; /* and type of object */
406 message->state = object_up;
407 message->force = 1; /* insist */
408 ioctl(superdev, VINUM_SETSTATE, message);
410 syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name);
412 syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died",
415 if (dowait == 0) /* we're the waiting child, */
416 exit(0); /* we've done our dash */
419 /* Initialize a subdisk. */
421 initsd(int sdno, int dowait)
424 struct _ioctl_reply reply;
425 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
426 char filename[MAXPATHLEN]; /* create a file name here */
428 /* Variables for use by children */
429 int sdfh; /* and for subdisk */
430 int initsize; /* actual size to write */
431 int64_t sdsize; /* size of subdisk */
434 pid = fork(); /* into the background with you */
435 if (pid > 0) /* I'm the parent */
437 else if (pid < 0) { /* failure */
438 printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno));
442 if (SSize != 0) { /* specified a size for init */
444 SSize <<= DEV_BSHIFT;
445 initsize = min(SSize, MAXPLEXINITSIZE);
447 initsize = PLEXINITSIZE;
448 openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
449 get_sd_info(&sd, sdno);
450 sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */
451 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
452 setproctitle("initializing %s", filename); /* show what we're doing */
453 syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename);
454 if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */
455 syslog(LOG_ERR | LOG_KERN,
456 "can't open subdisk %s: %s",
461 /* Set the subdisk in initializing state */
462 message->index = sd.sdno; /* pass object number */
463 message->type = sd_object; /* and type of object */
464 message->state = object_initializing;
465 message->verify = vflag; /* verify what we write? */
466 message->force = 1; /* insist */
467 ioctl(superdev, VINUM_SETSTATE, message);
468 if ((SSize > 0) /* specified a size for init */
470 SSize <<= DEV_BSHIFT;
473 "Can't initialize %s: %s (%d)\n",
475 strerror(reply.error),
480 if (interval) /* pause between copies */
481 usleep(interval * 1000);
482 message->index = sd.sdno; /* pass object number */
483 message->type = sd_object; /* and type of object */
484 message->state = object_up;
485 message->verify = vflag; /* verify what we write? */
486 message->blocksize = SSize;
487 ioctl(superdev, VINUM_SETSTATE, message);
489 while (reply.error == EAGAIN); /* until we're done */
492 "Can't initialize %s: %s (%d)\n",
494 strerror(reply.error),
496 get_sd_info(&sd, sdno);
497 if (sd.state != sd_up)
498 /* Set the subdisk down */
499 message->index = sd.sdno; /* pass object number */
500 message->type = sd_object; /* and type of object */
501 message->state = object_down;
502 message->verify = vflag; /* verify what we write? */
503 message->force = 1; /* insist */
504 ioctl(superdev, VINUM_SETSTATE, message);
507 printf("subdisk %s initialized\n", filename);
513 vinum_start(int argc, char *argv[], char *arg0[])
516 struct _ioctl_reply reply;
517 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
519 if (argc == 0) { /* start everything */
520 int devs = getnumdevs();
521 struct statinfo statinfo;
523 char *enamelist; /* end of name list */
525 char **token; /* list of tokens */
526 int tokens; /* and their number */
528 bzero(&statinfo, sizeof(struct statinfo));
529 statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
530 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
531 token = malloc((devs + 1) * sizeof(char *));
532 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
533 fprintf(stderr, "Can't allocate memory for drive list\n");
536 bzero(statinfo.dinfo, sizeof(struct devinfo));
538 tokens = 0; /* no tokens yet */
539 if (getdevs(&statinfo) < 0) { /* find out what devices we have */
540 perror("Can't get device list");
543 namelist[0] = '\0'; /* start with empty namelist */
544 enamelist = namelist; /* point to the end of the list */
546 for (i = 0; i < devs; i++) {
547 struct devstat *stat = &statinfo.dinfo->devices[i];
549 if ((((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
550 || ((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) /* storage array */
551 &&((stat->device_type & DEVSTAT_TYPE_IF_MASK) != DEVSTAT_TYPE_IF_OTHER) /* and not md */
552 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
553 &&((stat->device_name[0] != '\0'))) { /* and it has a name */
554 sprintf(enamelist, "%s%s%d", _PATH_DEV, stat->device_name, stat->unit_number);
555 token[tokens] = enamelist; /* point to it */
556 tokens++; /* one more token */
557 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
560 free(statinfo.dinfo); /* don't need the list any more */
561 vinum_read(tokens, token, &token[0]); /* start the system */
564 list_defective_objects(); /* and list anything that's down */
565 } else { /* start specified objects */
567 enum objecttype type;
569 for (index = 0; index < argc; index++) {
570 object = find_object(argv[index], &type); /* look for it */
571 if (type == invalid_object)
572 fprintf(stderr, "Can't find object: %s\n", argv[index]);
574 int doit = 0; /* set to 1 if we pass our tests */
577 if (drive.state == drive_up) /* already up */
578 fprintf(stderr, "%s is already up\n", drive.label.name);
584 if (sd.state == sd_up) /* already up */
585 fprintf(stderr, "%s is already up\n", sd.name);
591 if (plex.state == plex_up) /* already up */
592 fprintf(stderr, "%s is already up\n", plex.name);
597 * First, see if we can bring it up
598 * just by asking. This might happen
599 * if somebody has used setupstate on
600 * the subdisks. If we don't do this,
601 * we'll return success, but the plex
602 * won't have changed state. Note
603 * that we don't check for errors
606 message->index = plex.plexno; /* pass object number */
607 message->type = plex_object; /* it's a plex */
608 message->state = object_up;
609 message->force = 0; /* don't force it */
610 ioctl(superdev, VINUM_SETSTATE, message);
611 for (sdno = 0; sdno < plex.subdisks; sdno++) {
612 get_plex_sd_info(&sd, object, sdno);
613 if ((sd.state >= sd_empty)
614 && (sd.state <= sd_reviving)) { /* candidate for start */
615 message->index = sd.sdno; /* pass object number */
616 message->type = sd_object; /* it's a subdisk */
617 message->state = object_up;
618 message->force = force; /* don't force it, use a larger hammer */
621 * We don't do any checking here.
622 * The kernel module has a better
623 * understanding of these things,
626 if (SSize != 0) { /* specified a size for init */
628 SSize <<= DEV_BSHIFT;
629 message->blocksize = SSize;
631 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
632 ioctl(superdev, VINUM_SETSTATE, message);
633 if (reply.error != 0) {
634 if (reply.error == EAGAIN) /* we're reviving */
635 continue_revive(sd.sdno);
638 "Can't start %s: %s (%d)\n",
640 reply.msg[0] ? reply.msg : strerror(reply.error),
644 vinum_lsi(sd.sdno, 0);
651 if (vol.state == volume_up) /* already up */
652 fprintf(stderr, "%s is already up\n", vol.name);
661 message->index = object; /* pass object number */
662 message->type = type; /* and type of object */
663 message->state = object_up;
664 message->force = force; /* don't force it, use a larger hammer */
667 * We don't do any checking here.
668 * The kernel module has a better
669 * understanding of these things,
672 if (SSize != 0) { /* specified a size for init or revive */
674 SSize <<= DEV_BSHIFT;
675 message->blocksize = SSize;
677 message->blocksize = 0;
678 ioctl(superdev, VINUM_SETSTATE, message);
679 if (reply.error != 0) {
680 if ((reply.error == EAGAIN) /* we're reviving */
681 &&(type == sd_object))
682 continue_revive(object);
685 "Can't start %s: %s (%d)\n",
687 reply.msg[0] ? reply.msg : strerror(reply.error),
691 vinum_li(object, type);
696 checkupdates(); /* make sure we're updating */
700 vinum_stop(int argc, char *argv[], char *arg0[])
703 struct _ioctl_reply reply;
704 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
706 if (checkupdates() && (!force)) /* not updating? */
708 message->force = force; /* should we force the transition? */
709 if (argc == 0) { /* stop vinum */
710 int fileid = 0; /* ID of Vinum kld */
712 close(superdev); /* we can't stop if we have vinum open */
713 sleep(1); /* wait for the daemon to let go */
714 fileid = kldfind(VINUMMOD);
715 if ((fileid < 0) /* no go */
716 ||(kldunload(fileid) < 0))
717 perror("Can't unload " VINUMMOD);
719 fprintf(stderr, VINUMMOD " unloaded\n");
723 /* If we got here, the stop failed. Reopen the superdevice. */
724 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */
726 perror("Can't reopen Vinum superdevice");
729 } else { /* stop specified objects */
731 enum objecttype type;
733 for (i = 0; i < argc; i++) {
734 object = find_object(argv[i], &type); /* look for it */
735 if (type == invalid_object)
736 fprintf(stderr, "Can't find object: %s\n", argv[i]);
738 message->index = object; /* pass object number */
739 message->type = type; /* and type of object */
740 message->state = object_down;
741 ioctl(superdev, VINUM_SETSTATE, message);
742 if (reply.error != 0)
744 "Can't stop %s: %s (%d)\n",
746 reply.msg[0] ? reply.msg : strerror(reply.error),
749 vinum_li(object, type);
756 vinum_label(int argc, char *argv[], char *arg0[])
759 struct _ioctl_reply reply;
760 int *message = (int *) &reply;
762 if (argc == 0) /* start everything */
763 fprintf(stderr, "label: please specify one or more volume names\n");
764 else { /* start specified objects */
766 enum objecttype type;
768 for (i = 0; i < argc; i++) {
769 object = find_object(argv[i], &type); /* look for it */
770 if (type == invalid_object)
771 fprintf(stderr, "Can't find object: %s\n", argv[i]);
772 else if (type != volume_object) /* it exists, but it isn't a volume */
773 fprintf(stderr, "%s is not a volume\n", argv[i]);
775 message[0] = object; /* pass object number */
776 ioctl(superdev, VINUM_LABEL, message);
777 if (reply.error != 0)
779 "Can't label %s: %s (%d)\n",
781 reply.msg[0] ? reply.msg : strerror(reply.error),
784 vinum_li(object, type);
788 checkupdates(); /* not updating? */
792 reset_volume_stats(int volno, int recurse)
794 struct vinum_ioctl_msg msg;
795 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
798 msg.type = volume_object;
799 /* XXX get these numbers right if we ever
800 * actually return errors */
801 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
802 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
803 longjmp(command_fail, -1);
804 } else if (recurse) {
808 get_volume_info(&vol, volno);
809 for (plexno = 0; plexno < vol.plexes; plexno++)
810 reset_plex_stats(vol.plex[plexno], recurse);
815 reset_plex_stats(int plexno, int recurse)
817 struct vinum_ioctl_msg msg;
818 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
821 msg.type = plex_object;
822 /* XXX get these numbers right if we ever
823 * actually return errors */
824 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
825 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
826 longjmp(command_fail, -1);
827 } else if (recurse) {
832 get_plex_info(&plex, plexno);
833 for (sdno = 0; sdno < plex.subdisks; sdno++) {
834 get_plex_sd_info(&sd, plex.plexno, sdno);
835 reset_sd_stats(sd.sdno, recurse);
841 reset_sd_stats(int sdno, int recurse)
843 struct vinum_ioctl_msg msg;
844 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
847 msg.type = sd_object;
848 /* XXX get these numbers right if we ever
849 * actually return errors */
850 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
851 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
852 longjmp(command_fail, -1);
853 } else if (recurse) {
854 get_sd_info(&sd, sdno); /* get the info */
855 reset_drive_stats(sd.driveno); /* and clear the drive */
860 reset_drive_stats(int driveno)
862 struct vinum_ioctl_msg msg;
863 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
866 msg.type = drive_object;
867 /* XXX get these numbers right if we ever
868 * actually return errors */
869 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
870 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
871 longjmp(command_fail, -1);
876 vinum_resetstats(int argc, char *argv[], char *argv0[])
880 enum objecttype type;
882 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
883 perror("Can't get vinum config");
887 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
888 reset_volume_stats(objno, 1); /* clear everything recursively */
890 for (i = 0; i < argc; i++) {
891 objno = find_object(argv[i], &type);
892 if (objno >= 0) { /* not invalid */
895 reset_drive_stats(objno);
899 reset_sd_stats(objno, recurse);
903 reset_plex_stats(objno, recurse);
907 reset_volume_stats(objno, recurse);
910 case invalid_object: /* can't get this */
918 /* Attach a subdisk to a plex, or a plex to a volume.
919 * attach subdisk plex [offset] [rename]
920 * attach plex volume [rename]
923 vinum_attach(int argc, char *argv[], char *argv0[])
926 enum objecttype supertype;
927 struct vinum_ioctl_msg msg;
928 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
929 const char *objname = argv[0];
930 const char *supername = argv[1];
933 char oldname[MAXNAME + 8];
934 char newname[MAXNAME + 8];
935 int rename = 0; /* set if we want to rename the object */
940 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
941 "\tattach <plex> <volume> [rename]\n");
944 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
945 perror("Can't get vinum config");
948 msg.index = find_object(objname, &msg.type); /* find the object to attach */
949 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */
950 msg.force = force; /* did we specify the use of force? */
951 msg.recurse = recurse;
952 msg.offset = -1; /* and no offset */
954 for (i = 2; i < argc; i++) {
955 if (!strcmp(argv[i], "rename")) {
957 msg.rename = 1; /* do renaming */
958 } else if (!isdigit(argv[i][0])) { /* not an offset */
959 fprintf(stderr, "Unknown attribute: %s\n", supername);
962 msg.offset = sizespec(argv[i]);
967 find_object(argv[1], &supertype);
968 if (supertype != plex_object) { /* huh? */
969 fprintf(stderr, "%s can only be attached to a plex\n", objname);
972 if ((plex.organization != plex_concat) /* not a cat plex, */
974 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
977 sdno = msg.index; /* note the subdisk number for later */
981 find_object(argv[1], &supertype);
982 if (supertype != volume_object) { /* huh? */
983 fprintf(stderr, "%s can only be attached to a volume\n", objname);
990 fprintf(stderr, "Can only attach subdisks and plexes\n");
994 fprintf(stderr, "%s is not a Vinum object\n", objname);
998 ioctl(superdev, VINUM_ATTACH, &msg);
999 if (reply->error != 0) {
1000 if (reply->error == EAGAIN) /* reviving */
1001 continue_revive(sdno); /* continue the revive */
1004 "Can't attach %s to %s: %s (%d)\n",
1007 reply->msg[0] ? reply->msg : strerror(reply->error),
1015 /* we've overwritten msg with the
1016 * ioctl reply, start again */
1017 msg.index = find_object(objname, &msg.type); /* find the object to rename */
1020 get_sd_info(&sd, msg.index);
1021 get_plex_info(&plex, sd.plexno);
1022 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1023 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */
1026 sprintf(newname, "%s.s%d", plex.name, sdno);
1027 sprintf(oldname, "%s", sd.name);
1028 vinum_rename_2(oldname, newname);
1032 get_plex_info(&plex, msg.index);
1033 get_volume_info(&vol, plex.volno);
1034 for (plexno = 0; plexno < vol.plexes; plexno++) {
1035 if (vol.plex[plexno] == msg.index) /* found our subdisk */
1038 sprintf(newname, "%s.p%d", vol.name, plexno);
1039 sprintf(oldname, "%s", plex.name);
1040 vinum_rename_2(oldname, newname); /* this may recurse */
1043 default: /* can't get here */
1046 checkupdates(); /* make sure we're updating */
1049 /* Detach a subdisk from a plex, or a plex from a volume.
1050 * detach subdisk plex [rename]
1051 * detach plex volume [rename]
1054 vinum_detach(int argc, char *argv[], char *argv0[])
1056 struct vinum_ioctl_msg msg;
1057 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
1062 "Usage: \tdetach <subdisk> [rename]\n"
1063 "\tdetach <plex> [rename]\n");
1066 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1067 perror("Can't get vinum config");
1070 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */
1071 msg.force = force; /* did we specify the use of force? */
1072 msg.rename = 0; /* don't specify new name */
1073 msg.recurse = recurse; /* but recurse if we have to */
1075 /* XXX are we going to keep this?
1076 * Don't document it yet, since the
1077 * kernel side of things doesn't
1080 if (!strcmp(argv[1], "rename"))
1081 msg.rename = 1; /* do renaming */
1083 fprintf(stderr, "Unknown attribute: %s\n", argv[1]);
1087 if ((msg.type != sd_object)
1088 && (msg.type != plex_object)) {
1089 fprintf(stderr, "Can only detach subdisks and plexes\n");
1092 ioctl(superdev, VINUM_DETACH, &msg);
1093 if (reply->error != 0)
1095 "Can't detach %s: %s (%d)\n",
1097 reply->msg[0] ? reply->msg : strerror(reply->error),
1099 checkupdates(); /* make sure we're updating */
1103 dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen)
1105 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
1107 if (strlen(name) > maxlen) {
1108 fprintf(stderr, "%s is too long\n", name);
1111 strcpy(msg->newname, name);
1112 ioctl(superdev, VINUM_RENAME, msg);
1113 if (reply->error != 0)
1115 "Can't rename %s to %s: %s (%d)\n",
1118 reply->msg[0] ? reply->msg : strerror(reply->error),
1122 /* Rename an object:
1123 * rename <object> "newname"
1126 vinum_rename_2(char *oldname, char *newname)
1128 struct vinum_rename_msg msg;
1132 msg.index = find_object(oldname, &msg.type); /* find the object to rename */
1133 msg.recurse = recurse;
1135 /* Ugh. Determine how long the name may be */
1138 dorename(&msg, oldname, newname, MAXDRIVENAME);
1142 dorename(&msg, oldname, newname, MAXSDNAME);
1147 dorename(&msg, oldname, newname, MAXPLEXNAME);
1151 get_plex_info(&plex, plexno); /* find out who we are */
1152 msg.type = sd_object;
1153 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1154 char sdname[MAXPLEXNAME + 8];
1156 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1157 sprintf(sdname, "%s.s%d", newname, sdno);
1158 msg.index = sd.sdno; /* number of the subdisk */
1159 dorename(&msg, sd.name, sdname, MAXSDNAME);
1166 dorename(&msg, oldname, newname, MAXVOLNAME);
1171 get_volume_info(&vol, volno); /* find out who we are */
1172 for (plexno = 0; plexno < vol.plexes; plexno++) {
1173 char plexname[MAXVOLNAME + 8];
1175 msg.type = plex_object;
1176 sprintf(plexname, "%s.p%d", newname, plexno);
1177 msg.index = vol.plex[plexno]; /* number of the plex */
1178 dorename(&msg, plex.name, plexname, MAXPLEXNAME);
1179 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */
1180 msg.type = sd_object;
1181 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1182 char sdname[MAXPLEXNAME + 8];
1184 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1185 sprintf(sdname, "%s.s%d", plexname, sdno);
1186 msg.index = sd.sdno; /* number of the subdisk */
1187 dorename(&msg, sd.name, sdname, MAXSDNAME);
1194 fprintf(stderr, "%s is not a Vinum object\n", oldname);
1200 vinum_rename(int argc, char *argv[], char *argv0[])
1203 fprintf(stderr, "Usage: \trename <object> <new name>\n");
1206 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1207 perror("Can't get vinum config");
1210 vinum_rename_2(argv[0], argv[1]);
1211 checkupdates(); /* make sure we're updating */
1217 * mv <dest> <src> ...
1220 vinum_mv(int argc, char *argv[], char *argv0[])
1222 int i; /* loop index */
1225 enum objecttype srct;
1226 enum objecttype destt;
1228 struct _ioctl_reply reply;
1229 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply;
1232 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n");
1235 /* Get current config */
1236 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1237 perror("Cannot get vinum config\n");
1240 /* Get our destination */
1241 destobj = find_object(argv[0], &destt);
1242 if (destobj == -1) {
1243 fprintf(stderr, "Can't find %s\n", argv[0]);
1246 /* Verify that the target is a drive */
1247 if (destt != drive_object) {
1248 fprintf(stderr, "%s is not a drive\n", argv[0]);
1251 for (i = 1; i < argc; i++) { /* for all the sources */
1252 srcobj = find_object(argv[i], &srct);
1254 fprintf(stderr, "Can't find %s\n", argv[i]);
1257 msg->index = destobj;
1258 switch (srct) { /* Handle the source object */
1259 case drive_object: /* Move all subdisks on the drive to dst. */
1260 get_drive_info(&drive, srcobj); /* get info on drive */
1261 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) {
1262 get_sd_info(&sd, sdno);
1263 if (sd.driveno == srcobj) {
1264 msg->index = destobj;
1265 msg->otherobject = sd.sdno;
1266 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1268 "Can't move %s (part of %s) to %s: %s (%d)\n",
1272 strerror(reply.error),
1279 msg->otherobject = srcobj;
1280 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1282 "Can't move %s to %s: %s (%d)\n",
1285 strerror(reply.error),
1290 get_plex_info(&plex, srcobj);
1291 for (sdno = 0; sdno < plex.subdisks; ++sdno) {
1292 get_plex_sd_info(&sd, plex.plexno, sdno);
1293 msg->index = destobj;
1294 msg->otherobject = sd.sdno;
1295 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1297 "Can't move %s (part of %s) to %s: %s (%d)\n",
1301 strerror(reply.error),
1307 case invalid_object:
1309 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]);
1314 "Can't move %s to %s: %s (%d)\n",
1317 strerror(reply.error),
1320 checkupdates(); /* make sure we're updating */
1324 * Replace objects. Not implemented, may never be.
1327 vinum_replace(int argc, char *argv[], char *argv0[])
1329 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n");
1332 /* Primitive help function */
1334 vinum_help(int argc, char *argv[], char *argv0[])
1339 "create [-f description-file]\n"
1340 " Create a volume as described in description-file\n"
1341 "attach plex volume [rename]\n"
1342 "attach subdisk plex [offset] [rename]\n"
1343 " Attach a plex to a volume, or a subdisk to a plex.\n"
1345 " Cause the volume manager to enter the kernel debugger.\n"
1347 " Set debugging flags.\n"
1348 "detach [plex | subdisk]\n"
1349 " Detach a plex or subdisk from the volume or plex to which it is\n"
1352 " List information about volume manager state.\n"
1353 "init [-v] [-w] plex\n"
1354 " Initialize a plex by writing zeroes to all its subdisks.\n"
1356 " Create a volume label\n"
1357 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1358 " List information about specified objects\n"
1359 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1360 " List information about specified objects (alternative to\n"
1362 "ld [-r] [-s] [-v] [-V] [volume]\n"
1363 " List information about drives\n"
1364 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1365 " List information about subdisks\n"
1366 "lp [-r] [-s] [-v] [-V] [plex]\n"
1367 " List information about plexes\n"
1368 "lv [-r] [-s] [-v] [-V] [volume]\n"
1369 " List information about volumes\n"
1370 "printconfig [file]\n"
1371 " Write a copy of the current configuration to file.\n"
1373 " Remake the device nodes in " _PATH_DEV "vinum.\n"
1374 "move drive [subdisk | plex | drive]\n"
1375 " Move the subdisks of the specified object(s) to drive.\n"
1377 " Exit the vinum program when running in interactive mode. Nor-\n"
1378 " mally this would be done by entering the EOF character.\n"
1379 "read disk [disk...]\n"
1380 " Read the vinum configuration from the specified disks.\n"
1381 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1382 " Change the name of the specified object.\n"
1384 " Reset the complete vinum configuration.\n"
1385 "resetstats [-r] [volume | plex | subdisk]\n"
1386 " Reset statistisc counters for the specified objects, or for all\n"
1387 " objects if none are specified.\n"
1388 "rm [-f] [-r] volume | plex | subdisk\n"
1389 " Remove an object\n"
1391 " Save vinum configuration to disk.\n"
1392 "setdaemon [value]\n"
1393 " Set daemon configuration.\n"
1395 " Read configuration from all vinum drives.\n"
1396 "start [volume | plex | subdisk]\n"
1397 " Allow the system to access the objects\n"
1398 "stop [-f] [volume | plex | subdisk]\n"
1399 " Terminate access to the objects, or stop vinum if no parameters\n"
1405 /* Set daemon options.
1406 * XXX quick and dirty: use a bitmap, which requires
1407 * knowing which bit does what. FIXME */
1409 vinum_setdaemon(int argc, char *argv[], char *argv0[])
1415 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1416 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1418 printf("Options mask: %d\n", options);
1422 options = atoi(argv[0]);
1423 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0)
1424 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno);
1428 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n");
1430 checkupdates(); /* make sure we're updating */
1438 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1439 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1440 if (options & daemon_noupdate) {
1441 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n");
1447 /* Save config info */
1449 vinum_saveconfig(int argc, char *argv[], char *argv0[])
1454 printf("Usage: saveconfig\n");
1457 ioctltype = 1; /* user saveconfig */
1458 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0)
1459 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno);
1460 checkupdates(); /* make sure we're updating */
1464 * Create a volume name for the quick and dirty
1465 * commands. It will be of the form "vinum#",
1466 * where # is a small positive number.
1471 int v; /* volume number */
1472 static char volumename[MAXVOLNAME]; /* name to create */
1473 enum objecttype type;
1475 objectname = volumename; /* point to it */
1477 sprintf(objectname, "vinum%d", v); /* create the name */
1478 if (find_object(objectname, &type) == -1) /* does it exist? */
1479 return; /* no, it's ours */
1484 * Create a drive for the quick and dirty
1485 * commands. The name will be of the form
1486 * vinumdrive#, where # is a small positive
1487 * number. Return the name of the drive.
1490 create_drive(char *devicename)
1492 int d; /* volume number */
1493 static char drivename[MAXDRIVENAME]; /* name to create */
1494 enum objecttype type;
1495 struct _ioctl_reply *reply;
1498 * We're never likely to get anything
1499 * like 10000 drives. The only reason for
1500 * this limit is to stop the thing
1501 * looping if we have a bug somewhere.
1503 for (d = 0; d < 100000; d++) { /* look for a free drive number */
1504 sprintf(drivename, "vinumdrive%d", d); /* create the name */
1505 if (find_object(drivename, &type) == -1) { /* does it exist? */
1506 char command[MAXDRIVENAME * 2];
1508 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */
1510 printf("drive %s device %s\n", drivename, devicename); /* create a create command */
1511 ioctl(superdev, VINUM_CREATE, command);
1512 reply = (struct _ioctl_reply *) &command;
1513 if (reply->error != 0) { /* error in config */
1516 "Can't create drive %s, device %s: %s\n",
1522 "Can't create drive %s, device %s: %s (%d)\n",
1525 strerror(reply->error),
1527 longjmp(command_fail, -1); /* give up */
1529 find_object(drivename, &type);
1530 return &drive; /* return the name of the drive */
1533 fprintf(stderr, "Can't generate a drive name\n");
1539 * Create a volume with a single concatenated plex from
1540 * as much space as we can get on the specified drives.
1541 * If the drives aren't Vinum drives, make them so.
1544 vinum_concat(int argc, char *argv[], char *argv0[])
1546 int o; /* object number */
1547 char buffer[BUFSIZE];
1548 struct drive *drive; /* drive we're currently looking at */
1549 struct _ioctl_reply *reply;
1552 enum objecttype type;
1554 reply = (struct _ioctl_reply *) &buffer;
1555 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1556 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1559 if (!objectname) /* we need a name for our object */
1561 sprintf(buffer, "volume %s", objectname);
1563 printf("volume %s\n", objectname);
1564 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1565 if (reply->error != 0) { /* error in config */
1568 "Can't create volume %s: %s\n",
1573 "Can't create volume %s: %s (%d)\n",
1575 strerror(reply->error),
1577 longjmp(command_fail, -1); /* give up */
1579 sprintf(buffer, "plex name %s.p0 org concat", objectname);
1581 printf(" plex name %s.p0 org concat\n", objectname);
1582 ioctl(superdev, VINUM_CREATE, buffer);
1583 if (reply->error != 0) { /* error in config */
1586 "Can't create plex %s.p0: %s\n",
1591 "Can't create plex %s.p0: %s (%d)\n",
1593 strerror(reply->error),
1595 longjmp(command_fail, -1); /* give up */
1597 for (o = 0; o < argc; o++) {
1598 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1599 drive = create_drive(argv[o]); /* create it */
1600 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name);
1602 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name);
1603 ioctl(superdev, VINUM_CREATE, buffer);
1604 if (reply->error != 0) { /* error in config */
1607 "Can't create subdisk %s.p0.s%d: %s\n",
1613 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1616 strerror(reply->error),
1618 longjmp(command_fail, -1); /* give up */
1622 /* done, save the config */
1623 ioctltype = 0; /* saveconfig after update */
1624 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1626 perror("Can't save Vinum config");
1627 find_object(objectname, &type); /* find the index of the volume */
1628 make_vol_dev(vol.volno, 1); /* and create the devices */
1630 vflag--; /* XXX don't give too much detail */
1631 find_object(objectname, &type); /* point to the volume */
1632 vinum_lvi(vol.volno, 1); /* and print info about it */
1638 * Create a volume with a single striped plex from
1639 * as much space as we can get on the specified drives.
1640 * If the drives aren't Vinum drives, make them so.
1643 vinum_stripe(int argc, char *argv[], char *argv0[])
1645 int o; /* object number */
1646 char buffer[BUFSIZE];
1647 struct drive *drive; /* drive we're currently looking at */
1648 struct _ioctl_reply *reply;
1651 enum objecttype type;
1653 int fe; /* freelist entry index */
1654 struct drive_freelist freelist;
1655 struct ferq { /* request to pass to ioctl */
1658 } *ferq = (struct ferq *) &freelist;
1659 u_int64_t bigchunk; /* biggest chunk in freelist */
1662 reply = (struct _ioctl_reply *) &buffer;
1665 * First, check our drives.
1668 fprintf(stderr, "You need at least two drives to create a striped plex\n");
1671 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1672 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1675 if (!objectname) /* we need a name for our object */
1677 for (o = 0; o < argc; o++) {
1678 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1679 drive = create_drive(argv[o]); /* create it */
1680 /* Now find the largest chunk available on the drive */
1681 bigchunk = 0; /* ain't found nothin' yet */
1682 for (fe = 0; fe < drive->freelist_entries; fe++) {
1683 ferq->driveno = drive->driveno;
1685 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1687 "Can't get free list element %d: %s\n",
1690 longjmp(command_fail, -1);
1692 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1694 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1697 /* Now create the volume */
1698 sprintf(buffer, "volume %s", objectname);
1700 printf("volume %s\n", objectname);
1701 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1702 if (reply->error != 0) { /* error in config */
1705 "Can't create volume %s: %s\n",
1710 "Can't create volume %s: %s (%d)\n",
1712 strerror(reply->error),
1714 longjmp(command_fail, -1); /* give up */
1716 sprintf(buffer, "plex name %s.p0 org striped 256k", objectname);
1718 printf(" plex name %s.p0 org striped 256k\n", objectname);
1719 ioctl(superdev, VINUM_CREATE, buffer);
1720 if (reply->error != 0) { /* error in config */
1723 "Can't create plex %s.p0: %s\n",
1728 "Can't create plex %s.p0: %s (%d)\n",
1730 strerror(reply->error),
1732 longjmp(command_fail, -1); /* give up */
1734 for (o = 0; o < argc; o++) {
1735 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1737 "sd name %s.p0.s%d drive %s size %lldb",
1741 (long long) maxsize);
1743 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1747 (long long) maxsize);
1748 ioctl(superdev, VINUM_CREATE, buffer);
1749 if (reply->error != 0) { /* error in config */
1752 "Can't create subdisk %s.p0.s%d: %s\n",
1758 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1761 strerror(reply->error),
1763 longjmp(command_fail, -1); /* give up */
1767 /* done, save the config */
1768 ioctltype = 0; /* saveconfig after update */
1769 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1771 perror("Can't save Vinum config");
1772 find_object(objectname, &type); /* find the index of the volume */
1773 make_vol_dev(vol.volno, 1); /* and create the devices */
1775 vflag--; /* XXX don't give too much detail */
1776 find_object(objectname, &type); /* point to the volume */
1777 vinum_lvi(vol.volno, 1); /* and print info about it */
1782 * Create a volume with a single RAID-4 plex from
1783 * as much space as we can get on the specified drives.
1784 * If the drives aren't Vinum drives, make them so.
1787 vinum_raid4(int argc, char *argv[], char *argv0[])
1789 int o; /* object number */
1790 char buffer[BUFSIZE];
1791 struct drive *drive; /* drive we're currently looking at */
1792 struct _ioctl_reply *reply;
1795 enum objecttype type;
1797 int fe; /* freelist entry index */
1798 struct drive_freelist freelist;
1799 struct ferq { /* request to pass to ioctl */
1802 } *ferq = (struct ferq *) &freelist;
1803 u_int64_t bigchunk; /* biggest chunk in freelist */
1806 reply = (struct _ioctl_reply *) &buffer;
1809 * First, check our drives.
1812 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
1815 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1816 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1819 if (!objectname) /* we need a name for our object */
1821 for (o = 0; o < argc; o++) {
1822 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1823 drive = create_drive(argv[o]); /* create it */
1824 /* Now find the largest chunk available on the drive */
1825 bigchunk = 0; /* ain't found nothin' yet */
1826 for (fe = 0; fe < drive->freelist_entries; fe++) {
1827 ferq->driveno = drive->driveno;
1829 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1831 "Can't get free list element %d: %s\n",
1834 longjmp(command_fail, -1);
1836 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1838 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1841 /* Now create the volume */
1842 sprintf(buffer, "volume %s", objectname);
1844 printf("volume %s\n", objectname);
1845 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1846 if (reply->error != 0) { /* error in config */
1849 "Can't create volume %s: %s\n",
1854 "Can't create volume %s: %s (%d)\n",
1856 strerror(reply->error),
1858 longjmp(command_fail, -1); /* give up */
1860 sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname);
1862 printf(" plex name %s.p0 org raid4 256k\n", objectname);
1863 ioctl(superdev, VINUM_CREATE, buffer);
1864 if (reply->error != 0) { /* error in config */
1867 "Can't create plex %s.p0: %s\n",
1872 "Can't create plex %s.p0: %s (%d)\n",
1874 strerror(reply->error),
1876 longjmp(command_fail, -1); /* give up */
1878 for (o = 0; o < argc; o++) {
1879 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1881 "sd name %s.p0.s%d drive %s size %lldb",
1885 (long long) maxsize);
1887 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1891 (long long) maxsize);
1892 ioctl(superdev, VINUM_CREATE, buffer);
1893 if (reply->error != 0) { /* error in config */
1896 "Can't create subdisk %s.p0.s%d: %s\n",
1902 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1905 strerror(reply->error),
1907 longjmp(command_fail, -1); /* give up */
1911 /* done, save the config */
1912 ioctltype = 0; /* saveconfig after update */
1913 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1915 perror("Can't save Vinum config");
1916 find_object(objectname, &type); /* find the index of the volume */
1917 make_vol_dev(vol.volno, 1); /* and create the devices */
1919 vflag--; /* XXX don't give too much detail */
1920 find_object(objectname, &type); /* point to the volume */
1921 vinum_lvi(vol.volno, 1); /* and print info about it */
1926 * Create a volume with a single RAID-4 plex from
1927 * as much space as we can get on the specified drives.
1928 * If the drives aren't Vinum drives, make them so.
1931 vinum_raid5(int argc, char *argv[], char *argv0[])
1933 int o; /* object number */
1934 char buffer[BUFSIZE];
1935 struct drive *drive; /* drive we're currently looking at */
1936 struct _ioctl_reply *reply;
1939 enum objecttype type;
1941 int fe; /* freelist entry index */
1942 struct drive_freelist freelist;
1943 struct ferq { /* request to pass to ioctl */
1946 } *ferq = (struct ferq *) &freelist;
1947 u_int64_t bigchunk; /* biggest chunk in freelist */
1950 reply = (struct _ioctl_reply *) &buffer;
1953 * First, check our drives.
1956 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
1959 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1960 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1963 if (!objectname) /* we need a name for our object */
1965 for (o = 0; o < argc; o++) {
1966 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1967 drive = create_drive(argv[o]); /* create it */
1968 /* Now find the largest chunk available on the drive */
1969 bigchunk = 0; /* ain't found nothin' yet */
1970 for (fe = 0; fe < drive->freelist_entries; fe++) {
1971 ferq->driveno = drive->driveno;
1973 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1975 "Can't get free list element %d: %s\n",
1978 longjmp(command_fail, -1);
1980 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1982 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1985 /* Now create the volume */
1986 sprintf(buffer, "volume %s", objectname);
1988 printf("volume %s\n", objectname);
1989 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1990 if (reply->error != 0) { /* error in config */
1993 "Can't create volume %s: %s\n",
1998 "Can't create volume %s: %s (%d)\n",
2000 strerror(reply->error),
2002 longjmp(command_fail, -1); /* give up */
2004 sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname);
2006 printf(" plex name %s.p0 org raid5 256k\n", objectname);
2007 ioctl(superdev, VINUM_CREATE, buffer);
2008 if (reply->error != 0) { /* error in config */
2011 "Can't create plex %s.p0: %s\n",
2016 "Can't create plex %s.p0: %s (%d)\n",
2018 strerror(reply->error),
2020 longjmp(command_fail, -1); /* give up */
2022 for (o = 0; o < argc; o++) {
2023 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2025 "sd name %s.p0.s%d drive %s size %lldb",
2029 (long long) maxsize);
2031 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2035 (long long) maxsize);
2036 ioctl(superdev, VINUM_CREATE, buffer);
2037 if (reply->error != 0) { /* error in config */
2040 "Can't create subdisk %s.p0.s%d: %s\n",
2046 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2049 strerror(reply->error),
2051 longjmp(command_fail, -1); /* give up */
2055 /* done, save the config */
2056 ioctltype = 0; /* saveconfig after update */
2057 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2059 perror("Can't save Vinum config");
2060 find_object(objectname, &type); /* find the index of the volume */
2061 make_vol_dev(vol.volno, 1); /* and create the devices */
2063 vflag--; /* XXX don't give too much detail */
2064 find_object(objectname, &type); /* point to the volume */
2065 vinum_lvi(vol.volno, 1); /* and print info about it */
2070 * Create a volume with a two plexes from as much space
2071 * as we can get on the specified drives. If the
2072 * drives aren't Vinum drives, make them so.
2074 * The number of drives must be even, and at least 4
2075 * for a striped plex. Specify striped plexes with the
2076 * -s flag; otherwise they will be concatenated. It's
2077 * possible that the two plexes may differ in length.
2080 vinum_mirror(int argc, char *argv[], char *argv0[])
2082 int o; /* object number */
2083 int p; /* plex number */
2084 char buffer[BUFSIZE];
2085 struct drive *drive; /* drive we're currently looking at */
2086 struct _ioctl_reply *reply;
2089 enum objecttype type;
2090 off_t maxsize[2]; /* maximum subdisk size for striped plexes */
2091 int fe; /* freelist entry index */
2092 struct drive_freelist freelist;
2093 struct ferq { /* request to pass to ioctl */
2096 } *ferq = (struct ferq *) &freelist;
2097 u_int64_t bigchunk; /* biggest chunk in freelist */
2099 if (sflag) /* striped, */
2100 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */
2102 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */
2104 reply = (struct _ioctl_reply *) &buffer;
2107 * First, check our drives.
2110 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
2113 if (sflag && (argc < 4)) {
2114 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
2117 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
2118 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2121 if (!objectname) /* we need a name for our object */
2123 for (o = 0; o < argc; o++) {
2124 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2125 drive = create_drive(argv[o]); /* create it */
2126 if (sflag) { /* striping, */
2127 /* Find the largest chunk available on the drive */
2128 bigchunk = 0; /* ain't found nothin' yet */
2129 for (fe = 0; fe < drive->freelist_entries; fe++) {
2130 ferq->driveno = drive->driveno;
2132 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
2134 "Can't get free list element %d: %s\n",
2137 longjmp(command_fail, -1);
2139 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
2141 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */
2145 /* Now create the volume */
2146 sprintf(buffer, "volume %s setupstate", objectname);
2148 printf("volume %s setupstate\n", objectname);
2149 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
2150 if (reply->error != 0) { /* error in config */
2153 "Can't create volume %s: %s\n",
2158 "Can't create volume %s: %s (%d)\n",
2160 strerror(reply->error),
2162 longjmp(command_fail, -1); /* give up */
2164 for (p = 0; p < 2; p++) { /* create each plex */
2166 sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p);
2168 printf(" plex name %s.p%d org striped 256k\n", objectname, p);
2169 } else { /* concat */
2170 sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
2172 printf(" plex name %s.p%d org concat\n", objectname, p);
2174 ioctl(superdev, VINUM_CREATE, buffer);
2175 if (reply->error != 0) { /* error in config */
2178 "Can't create plex %s.p%d: %s\n",
2184 "Can't create plex %s.p%d: %s (%d)\n",
2187 strerror(reply->error),
2189 longjmp(command_fail, -1); /* give up */
2191 /* Now look at the subdisks */
2192 for (o = p; o < argc; o += 2) { /* every second one */
2193 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2195 "sd name %s.p%d.s%d drive %s size %lldb",
2200 (long long) maxsize[p]);
2202 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2207 (long long) maxsize[p]);
2208 ioctl(superdev, VINUM_CREATE, buffer);
2209 if (reply->error != 0) { /* error in config */
2212 "Can't create subdisk %s.p%d.s%d: %s\n",
2219 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2223 strerror(reply->error),
2225 longjmp(command_fail, -1); /* give up */
2230 /* done, save the config */
2231 ioctltype = 0; /* saveconfig after update */
2232 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2234 perror("Can't save Vinum config");
2235 find_object(objectname, &type); /* find the index of the volume */
2236 make_vol_dev(vol.volno, 1); /* and create the devices */
2238 vflag--; /* XXX don't give too much detail */
2239 sflag = 0; /* no stats, please */
2240 find_object(objectname, &type); /* point to the volume */
2241 vinum_lvi(vol.volno, 1); /* and print info about it */
2246 vinum_readpol(int argc, char *argv[], char *argv0[])
2249 struct _ioctl_reply reply;
2250 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2251 enum objecttype type;
2256 if (argc == 0) { /* start everything */
2257 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n");
2260 object = find_object(argv[1], &type); /* look for it */
2261 if (type != volume_object) {
2262 fprintf(stderr, "%s is not a volume\n", argv[1]);
2265 get_volume_info(&vol, object);
2266 if (strcmp(argv[2], "round")) { /* not 'round' */
2267 object = find_object(argv[2], &type); /* look for it */
2268 if (type != plex_object) {
2269 fprintf(stderr, "%s is not a plex\n", argv[2]);
2272 get_plex_info(&plex, object);
2273 plexno = plex.plexno;
2278 message->index = vol.volno;
2279 message->otherobject = plexno;
2280 if (ioctl(superdev, VINUM_READPOL, message) < 0)
2281 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno);
2283 vinum_lpi(plexno, recurse);
2287 * Brute force set state function. Don't look at
2288 * any dependencies, just do it.
2291 vinum_setstate(int argc, char *argv[], char *argv0[])
2294 struct _ioctl_reply reply;
2295 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2297 enum objecttype type;
2300 for (index = 1; index < argc; index++) {
2301 object = find_object(argv[index], &type); /* look for it */
2302 if (type == invalid_object)
2303 fprintf(stderr, "Can't find object: %s\n", argv[index]);
2305 int doit = 0; /* set to 1 if we pass our tests */
2308 state = DriveState(argv[0]); /* get the state */
2309 if (drive.state == state) /* already in that state */
2310 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
2316 state = SdState(argv[0]); /* get the state */
2317 if (sd.state == state) /* already in that state */
2318 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
2324 state = PlexState(argv[0]); /* get the state */
2325 if (plex.state == state) /* already in that state */
2326 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
2332 state = VolState(argv[0]); /* get the state */
2333 if (vol.state == state) /* already in that state */
2334 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
2340 state = 0; /* to keep the compiler happy */
2344 fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
2346 message->index = object; /* pass object number */
2347 message->type = type; /* and type of object */
2348 message->state = state;
2349 message->force = force; /* don't force it, use a larger hammer */
2350 ioctl(superdev, VINUM_SETSTATE_FORCE, message);
2351 if (reply.error != 0)
2353 "Can't start %s: %s (%d)\n",
2355 reply.msg[0] ? reply.msg : strerror(reply.error),
2358 vinum_li(object, type);
2365 vinum_checkparity(int argc, char *argv[], char *argv0[])
2367 Verbose = vflag; /* accept -v for verbose */
2368 if (argc == 0) /* no parameters? */
2369 fprintf(stderr, "Usage: checkparity object [object...]\n");
2371 parityops(argc, argv, checkparity);
2375 vinum_rebuildparity(int argc, char *argv[], char *argv0[])
2377 if (argc == 0) /* no parameters? */
2378 fprintf(stderr, "Usage: rebuildparity object [object...]\n");
2380 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
2384 * Common code for rebuildparity and checkparity.
2385 * We bend the meanings of some flags here:
2387 * -v: Report incorrect parity on rebuild.
2388 * -V: Show running count of position being checked.
2389 * -f: Start from beginning of the plex.
2392 parityops(int argc, char *argv[], enum parityop op)
2396 struct _ioctl_reply reply;
2397 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2399 enum objecttype type;
2403 if (op == checkparity)
2407 for (index = 0; index < argc; index++) {
2408 object = find_object(argv[index], &type); /* look for it */
2409 if (type != plex_object)
2410 fprintf(stderr, "%s is not a plex\n", argv[index]);
2412 get_plex_info(&plex, object);
2413 if (!isparity((&plex)))
2414 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
2417 message->index = object; /* pass object number */
2418 message->type = type; /* and type of object */
2419 message->op = op; /* what to do */
2421 message->offset = 0; /* start at the beginning */
2423 message->offset = plex.checkblock; /* continue where we left off */
2424 force = 0; /* don't reset after the first time */
2425 ioctl(superdev, VINUM_PARITYOP, message);
2426 get_plex_info(&plex, object);
2428 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
2430 printf("\r%s at %s (%d%%) ",
2432 roughlength(block, 1),
2433 ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
2434 if ((reply.error == EAGAIN)
2435 && (reply.msg[0])) /* got a comment back */
2436 fputs(reply.msg, stderr); /* show it */
2440 while (reply.error == EAGAIN);
2441 if (reply.error != 0) {
2443 fputs(reply.msg, stderr);
2448 strerror(reply.error));
2449 } else if (Verbose) {
2450 if (op == checkparity)
2451 fprintf(stderr, "%s has correct parity\n", argv[index]);
2453 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
2460 /* Local Variables: */
2461 /* fill-column: 50 */