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 $
41 * $DragonFly: src/sbin/vinum/commands.c,v 1.2 2003/06/17 04:27:34 dillon Exp $
56 #include <sys/ioctl.h>
57 #include <dev/vinum/vinumhdr.h>
58 #include <dev/vinum/request.h>
60 #include <sys/types.h>
61 #include <sys/linker.h>
62 #include <sys/module.h>
64 #include <readline/history.h>
65 #include <readline/readline.h>
68 static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen);
71 vinum_create(int argc, char *argv[], char *arg0[])
74 FILE *dfd; /* file descriptor for the config file */
75 char buffer[BUFSIZE]; /* read config file in here */
76 char commandline[BUFSIZE]; /* issue command from here */
77 struct _ioctl_reply *reply;
78 int ioctltype; /* for ioctl call */
79 char tempfile[PATH_MAX]; /* name of temp file for direct editing */
80 char *file; /* file to read */
81 FILE *tf; /* temp file */
83 if (argc == 0) { /* no args, */
84 char *editor; /* editor to start */
87 editor = getenv("EDITOR");
89 editor = "/usr/bin/vi";
90 sprintf(tempfile, "/var/tmp/" VINUMMOD ".create.%d", getpid()); /* create a temp file */
91 tf = fopen(tempfile, "w"); /* open it */
93 fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno));
96 printconfig(tf, "# "); /* and put the current config it */
98 sprintf(commandline, "%s %s", editor, tempfile); /* create an edit command */
99 status = system(commandline); /* do it */
101 fprintf(stderr, "Can't edit config: status %d\n", status);
105 } else if (argc == 1)
108 fprintf(stderr, "Expecting 1 parameter, not %d\n", argc);
111 reply = (struct _ioctl_reply *) &buffer;
112 dfd = fopen(file, "r");
113 if (dfd == NULL) { /* no go */
114 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
117 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
118 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
121 file_line = 0; /* start with line 1 */
122 /* Parse the configuration, and add it to the global configuration */
123 for (;;) { /* love this style(9) */
126 configline = fgets(buffer, BUFSIZE, dfd);
128 fprintf(history, "%s", buffer);
130 if (configline == NULL) {
132 perror("Can't read config file");
135 file_line++; /* count the lines */
137 printf("%4d: %s", file_line, buffer);
138 strcpy(commandline, buffer); /* make a copy */
139 ioctl(superdev, VINUM_CREATE, buffer);
140 if (reply->error != 0) { /* error in config */
141 if (!vflag) /* print this line anyway */
142 printf("%4d: %s", file_line, commandline);
143 fprintf(stdout, "** %d %s: %s\n",
146 strerror(reply->error));
149 * XXX at the moment, we reset the config
150 * lock on error, so try to get it again.
151 * If we fail, don't cry again.
153 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */
157 fclose(dfd); /* done with the config file */
158 ioctltype = 0; /* saveconfig after update */
159 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
161 perror("Can't save Vinum config");
164 checkupdates(); /* make sure we're updating */
167 /* Read vinum config from a disk */
169 vinum_read(int argc, char *argv[], char *arg0[])
172 char buffer[BUFSIZE]; /* read config file in here */
173 struct _ioctl_reply *reply;
176 reply = (struct _ioctl_reply *) &buffer;
177 if (argc < 1) { /* wrong arg count */
178 fprintf(stderr, "Usage: read drive [drive ...]\n");
181 strcpy(buffer, "read ");
182 for (i = 0; i < argc; i++) { /* each drive name */
183 strcat(buffer, argv[i]);
187 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
188 fprintf(stderr, "Can't configure: %s (%d)\n", strerror(errno), errno);
191 ioctl(superdev, VINUM_CREATE, &buffer);
192 if (reply->error != 0) { /* error in config */
193 fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error));
194 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
196 perror("Can't save Vinum config");
198 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
200 perror("Can't save Vinum config");
203 checkupdates(); /* make sure we're updating */
208 vinum_debug(int argc, char *argv[], char *arg0[])
210 struct debuginfo info;
213 info.param = atoi(argv[0]);
217 sleep(2); /* give a chance to leave the window */
219 ioctl(superdev, VINUM_DEBUG, (caddr_t) & info);
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 if (! isatty (STDIN_FILENO)) {
280 fprintf (stderr, "Please enter this command from a tty device\n");
283 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
284 " All data will be lost. If you really want to do this, enter the text\n\n"
287 fgets(reply, sizeof(reply), stdin);
288 if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */
289 printf("\n No change\n");
291 error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */
294 fprintf(stderr, "Can't reset configuration: objects are in use\n");
296 perror("Can't find vinum config");
298 make_devices(); /* recreate the /dev/vinum hierarchy */
299 printf("\b Vinum configuration obliterated\n");
300 start_daemon(); /* then restart the daemon */
303 checkupdates(); /* make sure we're updating */
306 /* Initialize subdisks */
308 vinum_init(int argc, char *argv[], char *arg0[])
310 if (argc > 0) { /* initialize plexes */
313 enum objecttype type; /* type returned */
316 fflush(history); /* don't let all the kids do it. */
317 for (objindex = 0; objindex < argc; objindex++) {
318 objno = find_object(argv[objindex], &type); /* find the object */
320 printf("Can't find %s\n", argv[objindex]);
328 initplex(objno, argv[objindex]);
332 initsd(objno, dowait);
336 printf("Can't initialize %s: wrong object type\n", argv[objindex]);
342 checkupdates(); /* make sure we're updating */
348 printf("Initializing volumes is not implemented yet\n");
352 initplex(int plexno, char *name)
355 int plexfh = NULL; /* file handle for plex */
357 char filename[MAXPATHLEN]; /* create a file name here */
359 /* Variables for use by children */
360 int failed = 0; /* set if a child dies badly */
362 sprintf(filename, VINUM_DIR "/plex/%s", name);
363 if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */
365 * We don't actually write anything to the
366 * plex. We open it to ensure that nobody
367 * else tries to open it while we initialize
370 fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno));
374 pid = fork(); /* into the background with you */
375 if (pid != 0) { /* I'm the parent, or we failed */
376 if (pid < 0) /* failure */
377 printf("Couldn't fork: %s", strerror(errno));
378 close(plexfh); /* we don't need this any more */
383 * If we get here, we're either the first-level
384 * child (if we're not waiting) or we're going
387 for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */
388 get_plex_sd_info(&sd, plexno, sdno);
391 /* Now wait for them to complete */
395 if (((int) pid == -1)
396 && (errno == ECHILD)) /* all gone */
398 if (WEXITSTATUS(status) != 0) { /* oh, oh */
399 printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status));
405 message->index = plexno; /* pass object number */
406 message->type = plex_object; /* and type of object */
407 message->state = object_up;
408 message->force = 1; /* insist */
409 ioctl(superdev, VINUM_SETSTATE, message);
411 syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name);
413 syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died",
416 if (dowait == 0) /* we're the waiting child, */
417 exit(0); /* we've done our dash */
420 /* Initialize a subdisk. */
422 initsd(int sdno, int dowait)
425 struct _ioctl_reply reply;
426 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
427 char filename[MAXPATHLEN]; /* create a file name here */
429 /* Variables for use by children */
430 int sdfh; /* and for subdisk */
431 int initsize; /* actual size to write */
432 int64_t sdsize; /* size of subdisk */
435 pid = fork(); /* into the background with you */
436 if (pid > 0) /* I'm the parent */
438 else if (pid < 0) { /* failure */
439 printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno));
443 if (SSize != 0) { /* specified a size for init */
445 SSize <<= DEV_BSHIFT;
446 initsize = min(SSize, MAXPLEXINITSIZE);
448 initsize = PLEXINITSIZE;
449 openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
450 get_sd_info(&sd, sdno);
451 sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */
452 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
453 setproctitle("initializing %s", filename); /* show what we're doing */
454 syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename);
455 if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */
456 syslog(LOG_ERR | LOG_KERN,
457 "can't open subdisk %s: %s",
462 /* Set the subdisk in initializing state */
463 message->index = sd.sdno; /* pass object number */
464 message->type = sd_object; /* and type of object */
465 message->state = object_initializing;
466 message->verify = vflag; /* verify what we write? */
467 message->force = 1; /* insist */
468 ioctl(superdev, VINUM_SETSTATE, message);
469 if ((SSize > 0) /* specified a size for init */
471 SSize <<= DEV_BSHIFT;
474 "Can't initialize %s: %s (%d)\n",
476 strerror(reply.error),
481 if (interval) /* pause between copies */
482 usleep(interval * 1000);
483 message->index = sd.sdno; /* pass object number */
484 message->type = sd_object; /* and type of object */
485 message->state = object_up;
486 message->verify = vflag; /* verify what we write? */
487 message->blocksize = SSize;
488 ioctl(superdev, VINUM_SETSTATE, message);
490 while (reply.error == EAGAIN); /* until we're done */
493 "Can't initialize %s: %s (%d)\n",
495 strerror(reply.error),
497 get_sd_info(&sd, sdno);
498 if (sd.state != sd_up)
499 /* Set the subdisk down */
500 message->index = sd.sdno; /* pass object number */
501 message->type = sd_object; /* and type of object */
502 message->state = object_down;
503 message->verify = vflag; /* verify what we write? */
504 message->force = 1; /* insist */
505 ioctl(superdev, VINUM_SETSTATE, message);
508 printf("subdisk %s initialized\n", filename);
514 vinum_start(int argc, char *argv[], char *arg0[])
517 struct _ioctl_reply reply;
518 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
520 if (argc == 0) { /* start everything */
521 int devs = getnumdevs();
522 struct statinfo statinfo;
524 char *enamelist; /* end of name list */
526 char **token; /* list of tokens */
527 int tokens; /* and their number */
529 bzero(&statinfo, sizeof(struct statinfo));
530 statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
531 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
532 token = malloc((devs + 1) * sizeof(char *));
533 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
534 fprintf(stderr, "Can't allocate memory for drive list\n");
537 bzero(statinfo.dinfo, sizeof(struct devinfo));
539 tokens = 0; /* no tokens yet */
540 if (getdevs(&statinfo) < 0) { /* find out what devices we have */
541 perror("Can't get device list");
544 namelist[0] = '\0'; /* start with empty namelist */
545 enamelist = namelist; /* point to the end of the list */
547 for (i = 0; i < devs; i++) {
548 struct devstat *stat = &statinfo.dinfo->devices[i];
550 if ((((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
551 || ((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) /* storage array */
552 &&((stat->device_type & DEVSTAT_TYPE_IF_MASK) != DEVSTAT_TYPE_IF_OTHER) /* and not md */
553 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
554 &&((stat->device_name[0] != '\0'))) { /* and it has a name */
555 sprintf(enamelist, "%s%s%d", _PATH_DEV, stat->device_name, stat->unit_number);
556 token[tokens] = enamelist; /* point to it */
557 tokens++; /* one more token */
558 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
561 free(statinfo.dinfo); /* don't need the list any more */
562 vinum_read(tokens, token, &token[0]); /* start the system */
565 list_defective_objects(); /* and list anything that's down */
566 } else { /* start specified objects */
568 enum objecttype type;
570 for (index = 0; index < argc; index++) {
571 object = find_object(argv[index], &type); /* look for it */
572 if (type == invalid_object)
573 fprintf(stderr, "Can't find object: %s\n", argv[index]);
575 int doit = 0; /* set to 1 if we pass our tests */
578 if (drive.state == drive_up) /* already up */
579 fprintf(stderr, "%s is already up\n", drive.label.name);
585 if (sd.state == sd_up) /* already up */
586 fprintf(stderr, "%s is already up\n", sd.name);
592 if (plex.state == plex_up) /* already up */
593 fprintf(stderr, "%s is already up\n", plex.name);
598 * First, see if we can bring it up
599 * just by asking. This might happen
600 * if somebody has used setupstate on
601 * the subdisks. If we don't do this,
602 * we'll return success, but the plex
603 * won't have changed state. Note
604 * that we don't check for errors
607 message->index = plex.plexno; /* pass object number */
608 message->type = plex_object; /* it's a plex */
609 message->state = object_up;
610 message->force = 0; /* don't force it */
611 ioctl(superdev, VINUM_SETSTATE, message);
612 for (sdno = 0; sdno < plex.subdisks; sdno++) {
613 get_plex_sd_info(&sd, object, sdno);
614 if ((sd.state >= sd_empty)
615 && (sd.state <= sd_reviving)) { /* candidate for start */
616 message->index = sd.sdno; /* pass object number */
617 message->type = sd_object; /* it's a subdisk */
618 message->state = object_up;
619 message->force = force; /* don't force it, use a larger hammer */
622 * We don't do any checking here.
623 * The kernel module has a better
624 * understanding of these things,
627 if (SSize != 0) { /* specified a size for init */
629 SSize <<= DEV_BSHIFT;
630 message->blocksize = SSize;
632 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
633 ioctl(superdev, VINUM_SETSTATE, message);
634 if (reply.error != 0) {
635 if (reply.error == EAGAIN) /* we're reviving */
636 continue_revive(sd.sdno);
639 "Can't start %s: %s (%d)\n",
641 reply.msg[0] ? reply.msg : strerror(reply.error),
645 vinum_lsi(sd.sdno, 0);
652 if (vol.state == volume_up) /* already up */
653 fprintf(stderr, "%s is already up\n", vol.name);
662 message->index = object; /* pass object number */
663 message->type = type; /* and type of object */
664 message->state = object_up;
665 message->force = force; /* don't force it, use a larger hammer */
668 * We don't do any checking here.
669 * The kernel module has a better
670 * understanding of these things,
673 if (SSize != 0) { /* specified a size for init or revive */
675 SSize <<= DEV_BSHIFT;
676 message->blocksize = SSize;
678 message->blocksize = 0;
679 ioctl(superdev, VINUM_SETSTATE, message);
680 if (reply.error != 0) {
681 if ((reply.error == EAGAIN) /* we're reviving */
682 &&(type == sd_object))
683 continue_revive(object);
686 "Can't start %s: %s (%d)\n",
688 reply.msg[0] ? reply.msg : strerror(reply.error),
692 vinum_li(object, type);
697 checkupdates(); /* make sure we're updating */
701 vinum_stop(int argc, char *argv[], char *arg0[])
704 struct _ioctl_reply reply;
705 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
707 if (checkupdates() && (!force)) /* not updating? */
709 message->force = force; /* should we force the transition? */
710 if (argc == 0) { /* stop vinum */
711 int fileid = 0; /* ID of Vinum kld */
713 close(superdev); /* we can't stop if we have vinum open */
714 sleep(1); /* wait for the daemon to let go */
715 fileid = kldfind(VINUMMOD);
716 if ((fileid < 0) /* no go */
717 ||(kldunload(fileid) < 0))
718 perror("Can't unload " VINUMMOD);
720 fprintf(stderr, VINUMMOD " unloaded\n");
724 /* If we got here, the stop failed. Reopen the superdevice. */
725 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */
727 perror("Can't reopen Vinum superdevice");
730 } else { /* stop specified objects */
732 enum objecttype type;
734 for (i = 0; i < argc; i++) {
735 object = find_object(argv[i], &type); /* look for it */
736 if (type == invalid_object)
737 fprintf(stderr, "Can't find object: %s\n", argv[i]);
739 message->index = object; /* pass object number */
740 message->type = type; /* and type of object */
741 message->state = object_down;
742 ioctl(superdev, VINUM_SETSTATE, message);
743 if (reply.error != 0)
745 "Can't stop %s: %s (%d)\n",
747 reply.msg[0] ? reply.msg : strerror(reply.error),
750 vinum_li(object, type);
757 vinum_label(int argc, char *argv[], char *arg0[])
760 struct _ioctl_reply reply;
761 int *message = (int *) &reply;
763 if (argc == 0) /* start everything */
764 fprintf(stderr, "label: please specify one or more volume names\n");
765 else { /* start specified objects */
767 enum objecttype type;
769 for (i = 0; i < argc; i++) {
770 object = find_object(argv[i], &type); /* look for it */
771 if (type == invalid_object)
772 fprintf(stderr, "Can't find object: %s\n", argv[i]);
773 else if (type != volume_object) /* it exists, but it isn't a volume */
774 fprintf(stderr, "%s is not a volume\n", argv[i]);
776 message[0] = object; /* pass object number */
777 ioctl(superdev, VINUM_LABEL, message);
778 if (reply.error != 0)
780 "Can't label %s: %s (%d)\n",
782 reply.msg[0] ? reply.msg : strerror(reply.error),
785 vinum_li(object, type);
789 checkupdates(); /* not updating? */
793 reset_volume_stats(int volno, int recurse)
795 struct vinum_ioctl_msg msg;
796 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
799 msg.type = volume_object;
800 /* XXX get these numbers right if we ever
801 * actually return errors */
802 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
803 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
804 longjmp(command_fail, -1);
805 } else if (recurse) {
809 get_volume_info(&vol, volno);
810 for (plexno = 0; plexno < vol.plexes; plexno++)
811 reset_plex_stats(vol.plex[plexno], recurse);
816 reset_plex_stats(int plexno, int recurse)
818 struct vinum_ioctl_msg msg;
819 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
822 msg.type = plex_object;
823 /* XXX get these numbers right if we ever
824 * actually return errors */
825 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
826 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
827 longjmp(command_fail, -1);
828 } else if (recurse) {
833 get_plex_info(&plex, plexno);
834 for (sdno = 0; sdno < plex.subdisks; sdno++) {
835 get_plex_sd_info(&sd, plex.plexno, sdno);
836 reset_sd_stats(sd.sdno, recurse);
842 reset_sd_stats(int sdno, int recurse)
844 struct vinum_ioctl_msg msg;
845 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
848 msg.type = sd_object;
849 /* XXX get these numbers right if we ever
850 * actually return errors */
851 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
852 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
853 longjmp(command_fail, -1);
854 } else if (recurse) {
855 get_sd_info(&sd, sdno); /* get the info */
856 reset_drive_stats(sd.driveno); /* and clear the drive */
861 reset_drive_stats(int driveno)
863 struct vinum_ioctl_msg msg;
864 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
867 msg.type = drive_object;
868 /* XXX get these numbers right if we ever
869 * actually return errors */
870 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
871 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
872 longjmp(command_fail, -1);
877 vinum_resetstats(int argc, char *argv[], char *argv0[])
881 enum objecttype type;
883 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
884 perror("Can't get vinum config");
888 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
889 reset_volume_stats(objno, 1); /* clear everything recursively */
891 for (i = 0; i < argc; i++) {
892 objno = find_object(argv[i], &type);
893 if (objno >= 0) { /* not invalid */
896 reset_drive_stats(objno);
900 reset_sd_stats(objno, recurse);
904 reset_plex_stats(objno, recurse);
908 reset_volume_stats(objno, recurse);
911 case invalid_object: /* can't get this */
919 /* Attach a subdisk to a plex, or a plex to a volume.
920 * attach subdisk plex [offset] [rename]
921 * attach plex volume [rename]
924 vinum_attach(int argc, char *argv[], char *argv0[])
927 enum objecttype supertype;
928 struct vinum_ioctl_msg msg;
929 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
930 const char *objname = argv[0];
931 const char *supername = argv[1];
934 char oldname[MAXNAME + 8];
935 char newname[MAXNAME + 8];
936 int rename = 0; /* set if we want to rename the object */
941 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
942 "\tattach <plex> <volume> [rename]\n");
945 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
946 perror("Can't get vinum config");
949 msg.index = find_object(objname, &msg.type); /* find the object to attach */
950 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */
951 msg.force = force; /* did we specify the use of force? */
952 msg.recurse = recurse;
953 msg.offset = -1; /* and no offset */
955 for (i = 2; i < argc; i++) {
956 if (!strcmp(argv[i], "rename")) {
958 msg.rename = 1; /* do renaming */
959 } else if (!isdigit(argv[i][0])) { /* not an offset */
960 fprintf(stderr, "Unknown attribute: %s\n", supername);
963 msg.offset = sizespec(argv[i]);
968 find_object(argv[1], &supertype);
969 if (supertype != plex_object) { /* huh? */
970 fprintf(stderr, "%s can only be attached to a plex\n", objname);
973 if ((plex.organization != plex_concat) /* not a cat plex, */
975 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
978 sdno = msg.index; /* note the subdisk number for later */
982 find_object(argv[1], &supertype);
983 if (supertype != volume_object) { /* huh? */
984 fprintf(stderr, "%s can only be attached to a volume\n", objname);
991 fprintf(stderr, "Can only attach subdisks and plexes\n");
995 fprintf(stderr, "%s is not a Vinum object\n", objname);
999 ioctl(superdev, VINUM_ATTACH, &msg);
1000 if (reply->error != 0) {
1001 if (reply->error == EAGAIN) /* reviving */
1002 continue_revive(sdno); /* continue the revive */
1005 "Can't attach %s to %s: %s (%d)\n",
1008 reply->msg[0] ? reply->msg : strerror(reply->error),
1016 /* we've overwritten msg with the
1017 * ioctl reply, start again */
1018 msg.index = find_object(objname, &msg.type); /* find the object to rename */
1021 get_sd_info(&sd, msg.index);
1022 get_plex_info(&plex, sd.plexno);
1023 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1024 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */
1027 sprintf(newname, "%s.s%d", plex.name, sdno);
1028 sprintf(oldname, "%s", sd.name);
1029 vinum_rename_2(oldname, newname);
1033 get_plex_info(&plex, msg.index);
1034 get_volume_info(&vol, plex.volno);
1035 for (plexno = 0; plexno < vol.plexes; plexno++) {
1036 if (vol.plex[plexno] == msg.index) /* found our subdisk */
1039 sprintf(newname, "%s.p%d", vol.name, plexno);
1040 sprintf(oldname, "%s", plex.name);
1041 vinum_rename_2(oldname, newname); /* this may recurse */
1044 default: /* can't get here */
1047 checkupdates(); /* make sure we're updating */
1050 /* Detach a subdisk from a plex, or a plex from a volume.
1051 * detach subdisk plex [rename]
1052 * detach plex volume [rename]
1055 vinum_detach(int argc, char *argv[], char *argv0[])
1057 struct vinum_ioctl_msg msg;
1058 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
1063 "Usage: \tdetach <subdisk> [rename]\n"
1064 "\tdetach <plex> [rename]\n");
1067 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1068 perror("Can't get vinum config");
1071 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */
1072 msg.force = force; /* did we specify the use of force? */
1073 msg.rename = 0; /* don't specify new name */
1074 msg.recurse = recurse; /* but recurse if we have to */
1076 /* XXX are we going to keep this?
1077 * Don't document it yet, since the
1078 * kernel side of things doesn't
1081 if (!strcmp(argv[1], "rename"))
1082 msg.rename = 1; /* do renaming */
1084 fprintf(stderr, "Unknown attribute: %s\n", argv[1]);
1088 if ((msg.type != sd_object)
1089 && (msg.type != plex_object)) {
1090 fprintf(stderr, "Can only detach subdisks and plexes\n");
1093 ioctl(superdev, VINUM_DETACH, &msg);
1094 if (reply->error != 0)
1096 "Can't detach %s: %s (%d)\n",
1098 reply->msg[0] ? reply->msg : strerror(reply->error),
1100 checkupdates(); /* make sure we're updating */
1104 dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen)
1106 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
1108 if (strlen(name) > maxlen) {
1109 fprintf(stderr, "%s is too long\n", name);
1112 strcpy(msg->newname, name);
1113 ioctl(superdev, VINUM_RENAME, msg);
1114 if (reply->error != 0)
1116 "Can't rename %s to %s: %s (%d)\n",
1119 reply->msg[0] ? reply->msg : strerror(reply->error),
1123 /* Rename an object:
1124 * rename <object> "newname"
1127 vinum_rename_2(char *oldname, char *newname)
1129 struct vinum_rename_msg msg;
1133 msg.index = find_object(oldname, &msg.type); /* find the object to rename */
1134 msg.recurse = recurse;
1136 /* Ugh. Determine how long the name may be */
1139 dorename(&msg, oldname, newname, MAXDRIVENAME);
1143 dorename(&msg, oldname, newname, MAXSDNAME);
1148 dorename(&msg, oldname, newname, MAXPLEXNAME);
1152 get_plex_info(&plex, plexno); /* find out who we are */
1153 msg.type = sd_object;
1154 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1155 char sdname[MAXPLEXNAME + 8];
1157 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1158 sprintf(sdname, "%s.s%d", newname, sdno);
1159 msg.index = sd.sdno; /* number of the subdisk */
1160 dorename(&msg, sd.name, sdname, MAXSDNAME);
1167 dorename(&msg, oldname, newname, MAXVOLNAME);
1172 get_volume_info(&vol, volno); /* find out who we are */
1173 for (plexno = 0; plexno < vol.plexes; plexno++) {
1174 char plexname[MAXVOLNAME + 8];
1176 msg.type = plex_object;
1177 sprintf(plexname, "%s.p%d", newname, plexno);
1178 msg.index = vol.plex[plexno]; /* number of the plex */
1179 dorename(&msg, plex.name, plexname, MAXPLEXNAME);
1180 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */
1181 msg.type = sd_object;
1182 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1183 char sdname[MAXPLEXNAME + 8];
1185 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1186 sprintf(sdname, "%s.s%d", plexname, sdno);
1187 msg.index = sd.sdno; /* number of the subdisk */
1188 dorename(&msg, sd.name, sdname, MAXSDNAME);
1195 fprintf(stderr, "%s is not a Vinum object\n", oldname);
1201 vinum_rename(int argc, char *argv[], char *argv0[])
1204 fprintf(stderr, "Usage: \trename <object> <new name>\n");
1207 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1208 perror("Can't get vinum config");
1211 vinum_rename_2(argv[0], argv[1]);
1212 checkupdates(); /* make sure we're updating */
1218 * mv <dest> <src> ...
1221 vinum_mv(int argc, char *argv[], char *argv0[])
1223 int i; /* loop index */
1226 enum objecttype srct;
1227 enum objecttype destt;
1229 struct _ioctl_reply reply;
1230 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply;
1233 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n");
1236 /* Get current config */
1237 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1238 perror("Cannot get vinum config\n");
1241 /* Get our destination */
1242 destobj = find_object(argv[0], &destt);
1243 if (destobj == -1) {
1244 fprintf(stderr, "Can't find %s\n", argv[0]);
1247 /* Verify that the target is a drive */
1248 if (destt != drive_object) {
1249 fprintf(stderr, "%s is not a drive\n", argv[0]);
1252 for (i = 1; i < argc; i++) { /* for all the sources */
1253 srcobj = find_object(argv[i], &srct);
1255 fprintf(stderr, "Can't find %s\n", argv[i]);
1258 msg->index = destobj;
1259 switch (srct) { /* Handle the source object */
1260 case drive_object: /* Move all subdisks on the drive to dst. */
1261 get_drive_info(&drive, srcobj); /* get info on drive */
1262 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) {
1263 get_sd_info(&sd, sdno);
1264 if (sd.driveno == srcobj) {
1265 msg->index = destobj;
1266 msg->otherobject = sd.sdno;
1267 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1269 "Can't move %s (part of %s) to %s: %s (%d)\n",
1273 strerror(reply.error),
1280 msg->otherobject = srcobj;
1281 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1283 "Can't move %s to %s: %s (%d)\n",
1286 strerror(reply.error),
1291 get_plex_info(&plex, srcobj);
1292 for (sdno = 0; sdno < plex.subdisks; ++sdno) {
1293 get_plex_sd_info(&sd, plex.plexno, sdno);
1294 msg->index = destobj;
1295 msg->otherobject = sd.sdno;
1296 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1298 "Can't move %s (part of %s) to %s: %s (%d)\n",
1302 strerror(reply.error),
1308 case invalid_object:
1310 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]);
1315 "Can't move %s to %s: %s (%d)\n",
1318 strerror(reply.error),
1321 checkupdates(); /* make sure we're updating */
1325 * Replace objects. Not implemented, may never be.
1328 vinum_replace(int argc, char *argv[], char *argv0[])
1330 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n");
1333 /* Primitive help function */
1335 vinum_help(int argc, char *argv[], char *argv0[])
1340 "create [-f description-file]\n"
1341 " Create a volume as described in description-file\n"
1342 "attach plex volume [rename]\n"
1343 "attach subdisk plex [offset] [rename]\n"
1344 " Attach a plex to a volume, or a subdisk to a plex.\n"
1346 " Cause the volume manager to enter the kernel debugger.\n"
1348 " Set debugging flags.\n"
1349 "detach [plex | subdisk]\n"
1350 " Detach a plex or subdisk from the volume or plex to which it is\n"
1353 " List information about volume manager state.\n"
1354 "init [-v] [-w] plex\n"
1355 " Initialize a plex by writing zeroes to all its subdisks.\n"
1357 " Create a volume label\n"
1358 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1359 " List information about specified objects\n"
1360 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1361 " List information about specified objects (alternative to\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"
1371 "printconfig [file]\n"
1372 " Write a copy of the current configuration to file.\n"
1374 " Remake the device nodes in " _PATH_DEV "vinum.\n"
1375 "move drive [subdisk | plex | drive]\n"
1376 " Move the subdisks of the specified object(s) to drive.\n"
1378 " Exit the vinum program when running in interactive mode. Nor-\n"
1379 " mally this would be done by entering the EOF character.\n"
1380 "read disk [disk...]\n"
1381 " Read the vinum configuration from the specified disks.\n"
1382 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1383 " Change the name of the specified object.\n"
1385 " Reset the complete vinum configuration.\n"
1386 "resetstats [-r] [volume | plex | subdisk]\n"
1387 " Reset statistisc counters for the specified objects, or for all\n"
1388 " objects if none are specified.\n"
1389 "rm [-f] [-r] volume | plex | subdisk\n"
1390 " Remove an object\n"
1392 " Save vinum configuration to disk.\n"
1393 "setdaemon [value]\n"
1394 " Set daemon configuration.\n"
1396 " Read configuration from all vinum drives.\n"
1397 "start [volume | plex | subdisk]\n"
1398 " Allow the system to access the objects\n"
1399 "stop [-f] [volume | plex | subdisk]\n"
1400 " Terminate access to the objects, or stop vinum if no parameters\n"
1406 /* Set daemon options.
1407 * XXX quick and dirty: use a bitmap, which requires
1408 * knowing which bit does what. FIXME */
1410 vinum_setdaemon(int argc, char *argv[], char *argv0[])
1416 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1417 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1419 printf("Options mask: %d\n", options);
1423 options = atoi(argv[0]);
1424 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0)
1425 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno);
1429 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n");
1431 checkupdates(); /* make sure we're updating */
1439 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1440 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1441 if (options & daemon_noupdate) {
1442 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n");
1448 /* Save config info */
1450 vinum_saveconfig(int argc, char *argv[], char *argv0[])
1455 printf("Usage: saveconfig\n");
1458 ioctltype = 1; /* user saveconfig */
1459 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0)
1460 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno);
1461 checkupdates(); /* make sure we're updating */
1465 * Create a volume name for the quick and dirty
1466 * commands. It will be of the form "vinum#",
1467 * where # is a small positive number.
1472 int v; /* volume number */
1473 static char volumename[MAXVOLNAME]; /* name to create */
1474 enum objecttype type;
1476 objectname = volumename; /* point to it */
1478 sprintf(objectname, "vinum%d", v); /* create the name */
1479 if (find_object(objectname, &type) == -1) /* does it exist? */
1480 return; /* no, it's ours */
1485 * Create a drive for the quick and dirty
1486 * commands. The name will be of the form
1487 * vinumdrive#, where # is a small positive
1488 * number. Return the name of the drive.
1491 create_drive(char *devicename)
1493 int d; /* volume number */
1494 static char drivename[MAXDRIVENAME]; /* name to create */
1495 enum objecttype type;
1496 struct _ioctl_reply *reply;
1499 * We're never likely to get anything
1500 * like 10000 drives. The only reason for
1501 * this limit is to stop the thing
1502 * looping if we have a bug somewhere.
1504 for (d = 0; d < 100000; d++) { /* look for a free drive number */
1505 sprintf(drivename, "vinumdrive%d", d); /* create the name */
1506 if (find_object(drivename, &type) == -1) { /* does it exist? */
1507 char command[MAXDRIVENAME * 2];
1509 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */
1511 printf("drive %s device %s\n", drivename, devicename); /* create a create command */
1512 ioctl(superdev, VINUM_CREATE, command);
1513 reply = (struct _ioctl_reply *) &command;
1514 if (reply->error != 0) { /* error in config */
1517 "Can't create drive %s, device %s: %s\n",
1523 "Can't create drive %s, device %s: %s (%d)\n",
1526 strerror(reply->error),
1528 longjmp(command_fail, -1); /* give up */
1530 find_object(drivename, &type);
1531 return &drive; /* return the name of the drive */
1534 fprintf(stderr, "Can't generate a drive name\n");
1540 * Create a volume with a single concatenated plex from
1541 * as much space as we can get on the specified drives.
1542 * If the drives aren't Vinum drives, make them so.
1545 vinum_concat(int argc, char *argv[], char *argv0[])
1547 int o; /* object number */
1548 char buffer[BUFSIZE];
1549 struct drive *drive; /* drive we're currently looking at */
1550 struct _ioctl_reply *reply;
1553 enum objecttype type;
1555 reply = (struct _ioctl_reply *) &buffer;
1556 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1557 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1560 if (!objectname) /* we need a name for our object */
1562 sprintf(buffer, "volume %s", objectname);
1564 printf("volume %s\n", objectname);
1565 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1566 if (reply->error != 0) { /* error in config */
1569 "Can't create volume %s: %s\n",
1574 "Can't create volume %s: %s (%d)\n",
1576 strerror(reply->error),
1578 longjmp(command_fail, -1); /* give up */
1580 sprintf(buffer, "plex name %s.p0 org concat", objectname);
1582 printf(" plex name %s.p0 org concat\n", objectname);
1583 ioctl(superdev, VINUM_CREATE, buffer);
1584 if (reply->error != 0) { /* error in config */
1587 "Can't create plex %s.p0: %s\n",
1592 "Can't create plex %s.p0: %s (%d)\n",
1594 strerror(reply->error),
1596 longjmp(command_fail, -1); /* give up */
1598 for (o = 0; o < argc; o++) {
1599 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1600 drive = create_drive(argv[o]); /* create it */
1601 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name);
1603 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name);
1604 ioctl(superdev, VINUM_CREATE, buffer);
1605 if (reply->error != 0) { /* error in config */
1608 "Can't create subdisk %s.p0.s%d: %s\n",
1614 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1617 strerror(reply->error),
1619 longjmp(command_fail, -1); /* give up */
1623 /* done, save the config */
1624 ioctltype = 0; /* saveconfig after update */
1625 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1627 perror("Can't save Vinum config");
1628 find_object(objectname, &type); /* find the index of the volume */
1629 make_vol_dev(vol.volno, 1); /* and create the devices */
1631 vflag--; /* XXX don't give too much detail */
1632 find_object(objectname, &type); /* point to the volume */
1633 vinum_lvi(vol.volno, 1); /* and print info about it */
1639 * Create a volume with a single striped plex from
1640 * as much space as we can get on the specified drives.
1641 * If the drives aren't Vinum drives, make them so.
1644 vinum_stripe(int argc, char *argv[], char *argv0[])
1646 int o; /* object number */
1647 char buffer[BUFSIZE];
1648 struct drive *drive; /* drive we're currently looking at */
1649 struct _ioctl_reply *reply;
1652 enum objecttype type;
1654 int fe; /* freelist entry index */
1655 struct drive_freelist freelist;
1656 struct ferq { /* request to pass to ioctl */
1659 } *ferq = (struct ferq *) &freelist;
1660 u_int64_t bigchunk; /* biggest chunk in freelist */
1663 reply = (struct _ioctl_reply *) &buffer;
1666 * First, check our drives.
1669 fprintf(stderr, "You need at least two drives to create a striped plex\n");
1672 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1673 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1676 if (!objectname) /* we need a name for our object */
1678 for (o = 0; o < argc; o++) {
1679 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1680 drive = create_drive(argv[o]); /* create it */
1681 /* Now find the largest chunk available on the drive */
1682 bigchunk = 0; /* ain't found nothin' yet */
1683 for (fe = 0; fe < drive->freelist_entries; fe++) {
1684 ferq->driveno = drive->driveno;
1686 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1688 "Can't get free list element %d: %s\n",
1691 longjmp(command_fail, -1);
1693 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1695 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1698 /* Now create the volume */
1699 sprintf(buffer, "volume %s", objectname);
1701 printf("volume %s\n", objectname);
1702 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1703 if (reply->error != 0) { /* error in config */
1706 "Can't create volume %s: %s\n",
1711 "Can't create volume %s: %s (%d)\n",
1713 strerror(reply->error),
1715 longjmp(command_fail, -1); /* give up */
1717 sprintf(buffer, "plex name %s.p0 org striped 256k", objectname);
1719 printf(" plex name %s.p0 org striped 256k\n", objectname);
1720 ioctl(superdev, VINUM_CREATE, buffer);
1721 if (reply->error != 0) { /* error in config */
1724 "Can't create plex %s.p0: %s\n",
1729 "Can't create plex %s.p0: %s (%d)\n",
1731 strerror(reply->error),
1733 longjmp(command_fail, -1); /* give up */
1735 for (o = 0; o < argc; o++) {
1736 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1738 "sd name %s.p0.s%d drive %s size %lldb",
1742 (long long) maxsize);
1744 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1748 (long long) maxsize);
1749 ioctl(superdev, VINUM_CREATE, buffer);
1750 if (reply->error != 0) { /* error in config */
1753 "Can't create subdisk %s.p0.s%d: %s\n",
1759 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1762 strerror(reply->error),
1764 longjmp(command_fail, -1); /* give up */
1768 /* done, save the config */
1769 ioctltype = 0; /* saveconfig after update */
1770 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1772 perror("Can't save Vinum config");
1773 find_object(objectname, &type); /* find the index of the volume */
1774 make_vol_dev(vol.volno, 1); /* and create the devices */
1776 vflag--; /* XXX don't give too much detail */
1777 find_object(objectname, &type); /* point to the volume */
1778 vinum_lvi(vol.volno, 1); /* and print info about it */
1783 * Create a volume with a single RAID-4 plex from
1784 * as much space as we can get on the specified drives.
1785 * If the drives aren't Vinum drives, make them so.
1788 vinum_raid4(int argc, char *argv[], char *argv0[])
1790 int o; /* object number */
1791 char buffer[BUFSIZE];
1792 struct drive *drive; /* drive we're currently looking at */
1793 struct _ioctl_reply *reply;
1796 enum objecttype type;
1798 int fe; /* freelist entry index */
1799 struct drive_freelist freelist;
1800 struct ferq { /* request to pass to ioctl */
1803 } *ferq = (struct ferq *) &freelist;
1804 u_int64_t bigchunk; /* biggest chunk in freelist */
1807 reply = (struct _ioctl_reply *) &buffer;
1810 * First, check our drives.
1813 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
1816 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1817 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1820 if (!objectname) /* we need a name for our object */
1822 for (o = 0; o < argc; o++) {
1823 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1824 drive = create_drive(argv[o]); /* create it */
1825 /* Now find the largest chunk available on the drive */
1826 bigchunk = 0; /* ain't found nothin' yet */
1827 for (fe = 0; fe < drive->freelist_entries; fe++) {
1828 ferq->driveno = drive->driveno;
1830 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1832 "Can't get free list element %d: %s\n",
1835 longjmp(command_fail, -1);
1837 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1839 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1842 /* Now create the volume */
1843 sprintf(buffer, "volume %s", objectname);
1845 printf("volume %s\n", objectname);
1846 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1847 if (reply->error != 0) { /* error in config */
1850 "Can't create volume %s: %s\n",
1855 "Can't create volume %s: %s (%d)\n",
1857 strerror(reply->error),
1859 longjmp(command_fail, -1); /* give up */
1861 sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname);
1863 printf(" plex name %s.p0 org raid4 256k\n", objectname);
1864 ioctl(superdev, VINUM_CREATE, buffer);
1865 if (reply->error != 0) { /* error in config */
1868 "Can't create plex %s.p0: %s\n",
1873 "Can't create plex %s.p0: %s (%d)\n",
1875 strerror(reply->error),
1877 longjmp(command_fail, -1); /* give up */
1879 for (o = 0; o < argc; o++) {
1880 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1882 "sd name %s.p0.s%d drive %s size %lldb",
1886 (long long) maxsize);
1888 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1892 (long long) maxsize);
1893 ioctl(superdev, VINUM_CREATE, buffer);
1894 if (reply->error != 0) { /* error in config */
1897 "Can't create subdisk %s.p0.s%d: %s\n",
1903 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1906 strerror(reply->error),
1908 longjmp(command_fail, -1); /* give up */
1912 /* done, save the config */
1913 ioctltype = 0; /* saveconfig after update */
1914 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1916 perror("Can't save Vinum config");
1917 find_object(objectname, &type); /* find the index of the volume */
1918 make_vol_dev(vol.volno, 1); /* and create the devices */
1920 vflag--; /* XXX don't give too much detail */
1921 find_object(objectname, &type); /* point to the volume */
1922 vinum_lvi(vol.volno, 1); /* and print info about it */
1927 * Create a volume with a single RAID-4 plex from
1928 * as much space as we can get on the specified drives.
1929 * If the drives aren't Vinum drives, make them so.
1932 vinum_raid5(int argc, char *argv[], char *argv0[])
1934 int o; /* object number */
1935 char buffer[BUFSIZE];
1936 struct drive *drive; /* drive we're currently looking at */
1937 struct _ioctl_reply *reply;
1940 enum objecttype type;
1942 int fe; /* freelist entry index */
1943 struct drive_freelist freelist;
1944 struct ferq { /* request to pass to ioctl */
1947 } *ferq = (struct ferq *) &freelist;
1948 u_int64_t bigchunk; /* biggest chunk in freelist */
1951 reply = (struct _ioctl_reply *) &buffer;
1954 * First, check our drives.
1957 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
1960 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1961 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1964 if (!objectname) /* we need a name for our object */
1966 for (o = 0; o < argc; o++) {
1967 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1968 drive = create_drive(argv[o]); /* create it */
1969 /* Now find the largest chunk available on the drive */
1970 bigchunk = 0; /* ain't found nothin' yet */
1971 for (fe = 0; fe < drive->freelist_entries; fe++) {
1972 ferq->driveno = drive->driveno;
1974 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1976 "Can't get free list element %d: %s\n",
1979 longjmp(command_fail, -1);
1981 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1983 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1986 /* Now create the volume */
1987 sprintf(buffer, "volume %s", objectname);
1989 printf("volume %s\n", objectname);
1990 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1991 if (reply->error != 0) { /* error in config */
1994 "Can't create volume %s: %s\n",
1999 "Can't create volume %s: %s (%d)\n",
2001 strerror(reply->error),
2003 longjmp(command_fail, -1); /* give up */
2005 sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname);
2007 printf(" plex name %s.p0 org raid5 256k\n", objectname);
2008 ioctl(superdev, VINUM_CREATE, buffer);
2009 if (reply->error != 0) { /* error in config */
2012 "Can't create plex %s.p0: %s\n",
2017 "Can't create plex %s.p0: %s (%d)\n",
2019 strerror(reply->error),
2021 longjmp(command_fail, -1); /* give up */
2023 for (o = 0; o < argc; o++) {
2024 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2026 "sd name %s.p0.s%d drive %s size %lldb",
2030 (long long) maxsize);
2032 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2036 (long long) maxsize);
2037 ioctl(superdev, VINUM_CREATE, buffer);
2038 if (reply->error != 0) { /* error in config */
2041 "Can't create subdisk %s.p0.s%d: %s\n",
2047 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2050 strerror(reply->error),
2052 longjmp(command_fail, -1); /* give up */
2056 /* done, save the config */
2057 ioctltype = 0; /* saveconfig after update */
2058 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2060 perror("Can't save Vinum config");
2061 find_object(objectname, &type); /* find the index of the volume */
2062 make_vol_dev(vol.volno, 1); /* and create the devices */
2064 vflag--; /* XXX don't give too much detail */
2065 find_object(objectname, &type); /* point to the volume */
2066 vinum_lvi(vol.volno, 1); /* and print info about it */
2071 * Create a volume with a two plexes from as much space
2072 * as we can get on the specified drives. If the
2073 * drives aren't Vinum drives, make them so.
2075 * The number of drives must be even, and at least 4
2076 * for a striped plex. Specify striped plexes with the
2077 * -s flag; otherwise they will be concatenated. It's
2078 * possible that the two plexes may differ in length.
2081 vinum_mirror(int argc, char *argv[], char *argv0[])
2083 int o; /* object number */
2084 int p; /* plex number */
2085 char buffer[BUFSIZE];
2086 struct drive *drive; /* drive we're currently looking at */
2087 struct _ioctl_reply *reply;
2090 enum objecttype type;
2091 off_t maxsize[2]; /* maximum subdisk size for striped plexes */
2092 int fe; /* freelist entry index */
2093 struct drive_freelist freelist;
2094 struct ferq { /* request to pass to ioctl */
2097 } *ferq = (struct ferq *) &freelist;
2098 u_int64_t bigchunk; /* biggest chunk in freelist */
2100 if (sflag) /* striped, */
2101 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */
2103 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */
2105 reply = (struct _ioctl_reply *) &buffer;
2108 * First, check our drives.
2111 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
2114 if (sflag && (argc < 4)) {
2115 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
2118 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
2119 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2122 if (!objectname) /* we need a name for our object */
2124 for (o = 0; o < argc; o++) {
2125 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2126 drive = create_drive(argv[o]); /* create it */
2127 if (sflag) { /* striping, */
2128 /* Find the largest chunk available on the drive */
2129 bigchunk = 0; /* ain't found nothin' yet */
2130 for (fe = 0; fe < drive->freelist_entries; fe++) {
2131 ferq->driveno = drive->driveno;
2133 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
2135 "Can't get free list element %d: %s\n",
2138 longjmp(command_fail, -1);
2140 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
2142 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */
2146 /* Now create the volume */
2147 sprintf(buffer, "volume %s setupstate", objectname);
2149 printf("volume %s setupstate\n", objectname);
2150 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
2151 if (reply->error != 0) { /* error in config */
2154 "Can't create volume %s: %s\n",
2159 "Can't create volume %s: %s (%d)\n",
2161 strerror(reply->error),
2163 longjmp(command_fail, -1); /* give up */
2165 for (p = 0; p < 2; p++) { /* create each plex */
2167 sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p);
2169 printf(" plex name %s.p%d org striped 256k\n", objectname, p);
2170 } else { /* concat */
2171 sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
2173 printf(" plex name %s.p%d org concat\n", objectname, p);
2175 ioctl(superdev, VINUM_CREATE, buffer);
2176 if (reply->error != 0) { /* error in config */
2179 "Can't create plex %s.p%d: %s\n",
2185 "Can't create plex %s.p%d: %s (%d)\n",
2188 strerror(reply->error),
2190 longjmp(command_fail, -1); /* give up */
2192 /* Now look at the subdisks */
2193 for (o = p; o < argc; o += 2) { /* every second one */
2194 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2196 "sd name %s.p%d.s%d drive %s size %lldb",
2201 (long long) maxsize[p]);
2203 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2208 (long long) maxsize[p]);
2209 ioctl(superdev, VINUM_CREATE, buffer);
2210 if (reply->error != 0) { /* error in config */
2213 "Can't create subdisk %s.p%d.s%d: %s\n",
2220 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2224 strerror(reply->error),
2226 longjmp(command_fail, -1); /* give up */
2231 /* done, save the config */
2232 ioctltype = 0; /* saveconfig after update */
2233 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2235 perror("Can't save Vinum config");
2236 find_object(objectname, &type); /* find the index of the volume */
2237 make_vol_dev(vol.volno, 1); /* and create the devices */
2239 vflag--; /* XXX don't give too much detail */
2240 sflag = 0; /* no stats, please */
2241 find_object(objectname, &type); /* point to the volume */
2242 vinum_lvi(vol.volno, 1); /* and print info about it */
2247 vinum_readpol(int argc, char *argv[], char *argv0[])
2250 struct _ioctl_reply reply;
2251 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2252 enum objecttype type;
2257 if (argc == 0) { /* start everything */
2258 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n");
2261 object = find_object(argv[1], &type); /* look for it */
2262 if (type != volume_object) {
2263 fprintf(stderr, "%s is not a volume\n", argv[1]);
2266 get_volume_info(&vol, object);
2267 if (strcmp(argv[2], "round")) { /* not 'round' */
2268 object = find_object(argv[2], &type); /* look for it */
2269 if (type != plex_object) {
2270 fprintf(stderr, "%s is not a plex\n", argv[2]);
2273 get_plex_info(&plex, object);
2274 plexno = plex.plexno;
2279 message->index = vol.volno;
2280 message->otherobject = plexno;
2281 if (ioctl(superdev, VINUM_READPOL, message) < 0)
2282 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno);
2284 vinum_lpi(plexno, recurse);
2288 * Brute force set state function. Don't look at
2289 * any dependencies, just do it.
2292 vinum_setstate(int argc, char *argv[], char *argv0[])
2295 struct _ioctl_reply reply;
2296 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2298 enum objecttype type;
2301 for (index = 1; index < argc; index++) {
2302 object = find_object(argv[index], &type); /* look for it */
2303 if (type == invalid_object)
2304 fprintf(stderr, "Can't find object: %s\n", argv[index]);
2306 int doit = 0; /* set to 1 if we pass our tests */
2309 state = DriveState(argv[0]); /* get the state */
2310 if (drive.state == state) /* already in that state */
2311 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
2317 state = SdState(argv[0]); /* get the state */
2318 if (sd.state == state) /* already in that state */
2319 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
2325 state = PlexState(argv[0]); /* get the state */
2326 if (plex.state == state) /* already in that state */
2327 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
2333 state = VolState(argv[0]); /* get the state */
2334 if (vol.state == state) /* already in that state */
2335 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
2341 state = 0; /* to keep the compiler happy */
2345 fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
2347 message->index = object; /* pass object number */
2348 message->type = type; /* and type of object */
2349 message->state = state;
2350 message->force = force; /* don't force it, use a larger hammer */
2351 ioctl(superdev, VINUM_SETSTATE_FORCE, message);
2352 if (reply.error != 0)
2354 "Can't start %s: %s (%d)\n",
2356 reply.msg[0] ? reply.msg : strerror(reply.error),
2359 vinum_li(object, type);
2366 vinum_checkparity(int argc, char *argv[], char *argv0[])
2368 Verbose = vflag; /* accept -v for verbose */
2369 if (argc == 0) /* no parameters? */
2370 fprintf(stderr, "Usage: checkparity object [object...]\n");
2372 parityops(argc, argv, checkparity);
2376 vinum_rebuildparity(int argc, char *argv[], char *argv0[])
2378 if (argc == 0) /* no parameters? */
2379 fprintf(stderr, "Usage: rebuildparity object [object...]\n");
2381 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
2385 * Common code for rebuildparity and checkparity.
2386 * We bend the meanings of some flags here:
2388 * -v: Report incorrect parity on rebuild.
2389 * -V: Show running count of position being checked.
2390 * -f: Start from beginning of the plex.
2393 parityops(int argc, char *argv[], enum parityop op)
2397 struct _ioctl_reply reply;
2398 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2400 enum objecttype type;
2404 if (op == checkparity)
2408 for (index = 0; index < argc; index++) {
2409 object = find_object(argv[index], &type); /* look for it */
2410 if (type != plex_object)
2411 fprintf(stderr, "%s is not a plex\n", argv[index]);
2413 get_plex_info(&plex, object);
2414 if (!isparity((&plex)))
2415 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
2418 message->index = object; /* pass object number */
2419 message->type = type; /* and type of object */
2420 message->op = op; /* what to do */
2422 message->offset = 0; /* start at the beginning */
2424 message->offset = plex.checkblock; /* continue where we left off */
2425 force = 0; /* don't reset after the first time */
2426 ioctl(superdev, VINUM_PARITYOP, message);
2427 get_plex_info(&plex, object);
2429 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
2431 printf("\r%s at %s (%d%%) ",
2433 roughlength(block, 1),
2434 ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
2435 if ((reply.error == EAGAIN)
2436 && (reply.msg[0])) /* got a comment back */
2437 fputs(reply.msg, stderr); /* show it */
2441 while (reply.error == EAGAIN);
2442 if (reply.error != 0) {
2444 fputs(reply.msg, stderr);
2449 strerror(reply.error));
2450 } else if (Verbose) {
2451 if (op == checkparity)
2452 fprintf(stderr, "%s has correct parity\n", argv[index]);
2454 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
2461 /* Local Variables: */
2462 /* fill-column: 50 */