summaryrefslogtreecommitdiffstats
path: root/sbin/vinum
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-11-04 12:46:46 +0000
committerphk <phk@FreeBSD.org>2004-11-04 12:46:46 +0000
commit19cb45350aa6693d3cde7f7b8b8a0bef97a8726d (patch)
tree0119d229a38f37605203af77d5c66d0f7491983c /sbin/vinum
parent1b4394c3588852abd6770a9c524cf9a9487fb603 (diff)
downloadFreeBSD-src-19cb45350aa6693d3cde7f7b8b8a0bef97a8726d.zip
FreeBSD-src-19cb45350aa6693d3cde7f7b8b8a0bef97a8726d.tar.gz
Ups! Forgot to put "sbin" on the commit line:
Remove userland vinum(8) stuff.
Diffstat (limited to 'sbin/vinum')
-rw-r--r--sbin/vinum/Makefile15
-rw-r--r--sbin/vinum/commands.c2329
-rw-r--r--sbin/vinum/list.c1502
-rw-r--r--sbin/vinum/v.c685
-rw-r--r--sbin/vinum/vext.h218
-rw-r--r--sbin/vinum/vinum.82925
6 files changed, 0 insertions, 7674 deletions
diff --git a/sbin/vinum/Makefile b/sbin/vinum/Makefile
deleted file mode 100644
index ce1bcaa..0000000
--- a/sbin/vinum/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# $FreeBSD$
-
-PROG= vinum
-SRCS= v.c list.c vinumparser.c vinumutil.c vext.h commands.c
-MAN= vinum.8
-
-CFLAGS+= -I${.CURDIR}/../../sys
-WARNS?= 0
-
-DPADD= ${LIBREADLINE} ${LIBTERMCAP} ${LIBDEVSTAT} ${LIBKVM}
-LDADD= -lreadline -ltermcap -ldevstat -lkvm
-
-.PATH: ${.CURDIR}/../../sys/dev/vinum
-
-.include <bsd.prog.mk>
diff --git a/sbin/vinum/commands.c b/sbin/vinum/commands.c
deleted file mode 100644
index c0038e4..0000000
--- a/sbin/vinum/commands.c
+++ /dev/null
@@ -1,2329 +0,0 @@
-/* commands.c: vinum interface program, main commands */
-/*-
- * Copyright (c) 1997, 1998
- * Nan Yang Computer Services Limited. All rights reserved.
- *
- * Written by Greg Lehey
- *
- * This software is distributed under the so-called ``Berkeley
- * License'':
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Nan Yang Computer
- * Services Limited.
- * 4. Neither the name of the Company nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * This software is provided ``as is'', and any express or implied
- * warranties, including, but not limited to, the implied warranties of
- * merchantability and fitness for a particular purpose are disclaimed.
- * In no event shall the company or contributors be liable for any
- * direct, indirect, incidental, special, exemplary, or consequential
- * damages (including, but not limited to, procurement of substitute
- * goods or services; loss of use, data, or profits; or business
- * interruption) however caused and on any theory of liability, whether
- * in contract, strict liability, or tort (including negligence or
- * otherwise) arising in any way out of the use of this software, even if
- * advised of the possibility of such damage.
- *
- * $Id: commands.c,v 1.52 2003/05/08 00:33:57 grog Exp $
- * $FreeBSD$
- */
-
-#include "vext.h"
-#include <devstat.h>
-
-static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen);
-
-void
-vinum_create(int argc, char *argv[], char *arg0[])
-{
- int error;
- FILE *dfd; /* file descriptor for the config file */
- char buffer[BUFSIZE]; /* read config file in here */
- char commandline[BUFSIZE]; /* issue command from here */
- struct _ioctl_reply *reply;
- int ioctltype; /* for ioctl call */
- char tempfile[PATH_MAX]; /* name of temp file for direct editing */
- char *file; /* file to read */
- FILE *tf; /* temp file */
-
- if (argc == 0) { /* no args, */
- char *editor; /* editor to start */
- int status;
-
- editor = getenv("EDITOR");
- if (editor == NULL)
- editor = _PATH_VI;
- sprintf(tempfile, "/var/tmp/" VINUMMOD ".create.%d", getpid()); /* create a temp file */
- tf = fopen(tempfile, "w"); /* open it */
- if (tf == NULL) {
- fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno));
- return;
- }
- printconfig(tf, "# "); /* and put the current config it */
- fclose(tf);
- sprintf(commandline, "%s %s", editor, tempfile); /* create an edit command */
- status = system(commandline); /* do it */
- if (status != 0) {
- fprintf(stderr, "Can't edit config: status %d\n", status);
- return;
- }
- file = tempfile;
- } else if (argc == 1)
- file = argv[0];
- else {
- fprintf(stderr, "Expecting 1 parameter, not %d\n", argc);
- return;
- }
- reply = (struct _ioctl_reply *) &buffer;
- dfd = fopen(file, "r");
- if (dfd == NULL) { /* no go */
- fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
- return;
- }
- if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
- printf("Can't configure: %s (%d)\n", strerror(errno), errno);
- return;
- }
- file_line = 0; /* start with line 1 */
- /* Parse the configuration, and add it to the global configuration */
- for (;;) { /* love this style(9) */
- char *configline;
-
- configline = fgets(buffer, BUFSIZE, dfd);
- if (History)
- fprintf(History, "%s", buffer);
-
- if (configline == NULL) {
- if (ferror(dfd))
- perror("Can't read config file");
- break;
- }
- file_line++; /* count the lines */
- if (vflag)
- printf("%4d: %s", file_line, buffer);
- strcpy(commandline, buffer); /* make a copy */
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (!vflag) /* print this line anyway */
- printf("%4d: %s", file_line, commandline);
- fprintf(stdout, "** %d %s: %s\n",
- file_line,
- reply->msg,
- strerror(reply->error));
-
- /*
- * XXX at the moment, we reset the config
- * lock on error, so try to get it again.
- * If we fail, don't cry again.
- */
- if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */
- return;
- }
- }
- fclose(dfd); /* done with the config file */
- ioctltype = 0; /* saveconfig after update */
- error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
- if (error != 0)
- perror("Can't save Vinum config");
- listconfig();
- checkupdates(); /* make sure we're updating */
-}
-
-/* Read vinum config from a disk */
-void
-vinum_read(int argc, char *argv[], char *arg0[])
-{
- char buffer[BUFSIZE]; /* read config file in here */
- struct _ioctl_reply *reply;
- int i;
-
- reply = (struct _ioctl_reply *) &buffer;
- buffer[0] = '\0'; /* make sure we don't pass anything */
- if (argc > 0) { /* args specified, */
- for (i = 0; i < argc; i++) { /* each drive name */
- strlcat(buffer, argv[i], sizeof(buffer));
- strlcat(buffer, " ", sizeof(buffer));
- }
- }
- ioctl(superdev, VINUM_READCONFIG, &buffer);
- if (reply->error != 0) /* error in config */
- fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error));
- checkupdates(); /* make sure we're updating */
-}
-
-void
-vinum_debug(int argc, char *argv[], char *arg0[])
-{
- struct debuginfo info;
-
- if (vinum_conf.flags & VF_HASDEBUG) {
- if (argc > 0) {
- info.param = atoi(argv[0]);
- info.changeit = 1;
- } else {
- info.changeit = 0;
- sleep(2); /* give a chance to leave the window */
- }
- ioctl(superdev, VINUM_DEBUG, (caddr_t) & info);
- } else /* no debug in kernel module */
- fprintf(stderr, "Kernel module does not have debug support\n");
-}
-
-void
-vinum_modify(int argc, char *argv[], char *arg0[])
-{
- fprintf(stderr, "Modify command is currently not implemented\n");
- checkupdates(); /* make sure we're updating */
-}
-
-void
-vinum_set(int argc, char *argv[], char *arg0[])
-{
- fprintf(stderr, "set is not implemented yet\n");
-}
-
-void
-vinum_rm(int argc, char *argv[], char *arg0[])
-{
- int object;
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
-
- if (argc == 0) /* start everything */
- fprintf(stderr, "usage: rm object [object...]\n");
- else { /* start specified objects */
- int index;
- enum objecttype type;
-
- for (index = 0; index < argc; index++) {
- object = find_object(argv[index], &type); /* look for it */
- if (type == invalid_object)
- fprintf(stderr, "Can't find object: %s\n", argv[index]);
- else {
- message->index = object; /* pass object number */
- message->type = type; /* and type of object */
- message->force = force; /* do we want to force the operation? */
- message->recurse = recurse; /* do we want to remove subordinates? */
- ioctl(superdev, VINUM_REMOVE, message);
- if (reply.error != 0) {
- fprintf(stderr,
- "Can't remove %s: %s (%d)\n",
- argv[index],
- reply.msg[0] ? reply.msg : strerror(reply.error),
- reply.error);
- } else if (vflag)
- fprintf(stderr, "%s removed\n", argv[index]);
- }
- }
- checkupdates(); /* make sure we're updating */
- /* Arguably we should be cleverer about this. */
- }
-}
-
-void
-vinum_resetconfig(int argc, char *argv[], char *arg0[])
-{
- char reply[32];
- int error;
-
- if (isatty(STDIN_FILENO)) {
- printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
- " All data will be lost. If you really want to do this, enter the text\n\n"
- " NO FUTURE\n"
- " Enter text -> ");
- fgets(reply, sizeof(reply), stdin);
- if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */
- printf("\n No change\n");
- else {
- error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */
- if (error) {
- if (errno == EBUSY)
- fprintf(stderr, "Can't reset configuration: objects are in use\n");
- else
- perror("Can't find vinum config");
- } else {
- printf("\b Vinum configuration obliterated\n");
- start_daemon(); /* then restart the daemon */
- }
- }
- checkupdates(); /* make sure we're updating */
- } else
- fprintf(stderr, "Please enter this command from a terminal\n");
-}
-
-/* Initialize subdisks */
-void
-vinum_init(int argc, char *argv[], char *arg0[])
-{
- if (argc > 0) { /* initialize plexes */
- int objindex;
- int objno;
- enum objecttype type; /* type returned */
-
- if (History)
- fflush(History); /* don't let all the kids do it. */
- for (objindex = 0; objindex < argc; objindex++) {
- objno = find_object(argv[objindex], &type); /* find the object */
- if (objno < 0)
- printf("Can't find %s\n", argv[objindex]);
- else {
- switch (type) {
- case volume_object:
- initvol(objno);
- break;
-
- case plex_object:
- initplex(objno, argv[objindex]);
- break;
-
- case sd_object:
- initsd(objno, dowait);
- break;
-
- default:
- printf("Can't initialize %s: wrong object type\n", argv[objindex]);
- break;
- }
- }
- }
- }
- checkupdates(); /* make sure we're updating */
-}
-
-void
-initvol(int volno)
-{
- printf("Initializing volumes is not implemented yet\n");
-}
-
-void
-initplex(int plexno, char *name)
-{
- int sdno;
- int plexfh = 0; /* file handle for plex */
- pid_t pid;
- char filename[MAXPATHLEN]; /* create a file name here */
-
- /* Variables for use by children */
- int failed = 0; /* set if a child dies badly */
-
- sprintf(filename, VINUM_DIR "/plex/%s", name);
- if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */
- /*
- * We don't actually write anything to the
- * plex. We open it to ensure that nobody
- * else tries to open it while we initialize
- * its subdisks.
- */
- fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno));
- return;
- }
- if (dowait == 0) {
- pid = fork(); /* into the background with you */
- if (pid != 0) { /* I'm the parent, or we failed */
- if (pid < 0) /* failure */
- printf("Couldn't fork: %s", strerror(errno));
- close(plexfh); /* we don't need this any more */
- return;
- }
- }
- /*
- * If we get here, we're either the first-level
- * child (if we're not waiting) or we're going
- * to wait.
- */
- for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */
- get_plex_sd_info(&sd, plexno, sdno);
- initsd(sd.sdno, 0);
- }
- /* Now wait for them to complete */
- while (1) {
- int status;
- pid = wait(&status);
- if (((int) pid == -1)
- && (errno == ECHILD)) /* all gone */
- break;
- if (WEXITSTATUS(status) != 0) { /* oh, oh */
- printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status));
- failed++;
- }
- }
- if (failed == 0) {
- syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name);
- } else
- syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died",
- plex.name,
- failed);
- if (dowait == 0) /* we're the waiting child, */
- exit(0); /* we've done our dash */
-}
-
-/* Initialize a subdisk. */
-void
-initsd(int sdno, int dowait)
-{
- pid_t pid;
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
- char filename[MAXPATHLEN]; /* create a file name here */
-
- /* Variables for use by children */
- int sdfh; /* and for subdisk */
- int initsize; /* actual size to write */
- int64_t sdsize; /* size of subdisk */
-
- if (dowait == 0) {
- pid = fork(); /* into the background with you */
- if (pid > 0) /* I'm the parent */
- return;
- else if (pid < 0) { /* failure */
- printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno));
- return;
- }
- }
- if (SSize != 0) { /* specified a size for init */
- if (SSize < 512)
- SSize <<= DEV_BSHIFT;
- initsize = min(SSize, MAXPLEXINITSIZE);
- } else
- initsize = PLEXINITSIZE;
- openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
- get_sd_info(&sd, sdno);
- sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */
- sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
- setproctitle("initializing %s", filename); /* show what we're doing */
- syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename);
- if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */
- syslog(LOG_ERR | LOG_KERN,
- "can't open subdisk %s: %s",
- filename,
- strerror(errno));
- exit(1);
- }
- /* Set the subdisk in initializing state */
- message->index = sd.sdno; /* pass object number */
- message->type = sd_object; /* and type of object */
- message->state = object_initializing;
- message->verify = vflag; /* verify what we write? */
- message->force = 1; /* insist */
- ioctl(superdev, VINUM_SETSTATE, message);
- if ((SSize > 0) /* specified a size for init */
- &&(SSize < 512))
- SSize <<= DEV_BSHIFT;
- if (reply.error) {
- fprintf(stderr,
- "Can't initialize %s: %s (%d)\n",
- filename,
- strerror(reply.error),
- reply.error);
- exit(1);
- } else {
- do {
- if (interval) /* pause between copies */
- usleep(interval * 1000);
- message->index = sd.sdno; /* pass object number */
- message->type = sd_object; /* and type of object */
- message->state = object_up;
- message->verify = vflag; /* verify what we write? */
- message->blocksize = SSize;
- ioctl(superdev, VINUM_SETSTATE, message);
- }
- while (reply.error == EAGAIN); /* until we're done */
- if (reply.error) {
- fprintf(stderr,
- "Can't initialize %s: %s (%d)\n",
- filename,
- strerror(reply.error),
- reply.error);
- get_sd_info(&sd, sdno);
- if (sd.state != sd_up)
- /* Set the subdisk down */
- message->index = sd.sdno; /* pass object number */
- message->type = sd_object; /* and type of object */
- message->state = object_down;
- message->verify = vflag; /* verify what we write? */
- message->force = 1; /* insist */
- ioctl(superdev, VINUM_SETSTATE, message);
- }
- }
- printf("subdisk %s initialized\n", filename);
- if (!dowait)
- exit(0);
-}
-
-void
-vinum_start(int argc, char *argv[], char *arg0[])
-{
- int object;
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
-
- if (argc == 0) /* start everything */
- /* XXX how should we do this right? */
- vinum_read(0, NULL, NULL); /* that's what vinum_read does now */
- else { /* start specified objects */
- int index;
- enum objecttype type;
-
- for (index = 0; index < argc; index++) {
- object = find_object(argv[index], &type); /* look for it */
- if (type == invalid_object)
- fprintf(stderr, "Can't find object: %s\n", argv[index]);
- else {
- int doit = 0; /* set to 1 if we pass our tests */
- switch (type) {
- case drive_object:
- if (drive.state == drive_up) /* already up */
- fprintf(stderr, "%s is already up\n", drive.label.name);
- else
- doit = 1;
- break;
-
- case sd_object:
- if (sd.state == sd_up) /* already up */
- fprintf(stderr, "%s is already up\n", sd.name);
- else
- doit = 1;
- break;
-
- case plex_object:
- if (plex.state == plex_up) /* already up */
- fprintf(stderr, "%s is already up\n", plex.name);
- else {
- int sdno;
-
- /*
- * First, see if we can bring it up
- * just by asking. This might happen
- * if somebody has used setupstate on
- * the subdisks. If we don't do this,
- * we'll return success, but the plex
- * won't have changed state. Note
- * that we don't check for errors
- * here.
- */
- message->index = plex.plexno; /* pass object number */
- message->type = plex_object; /* it's a plex */
- message->state = object_up;
- message->force = 0; /* don't force it */
- ioctl(superdev, VINUM_SETSTATE, message);
- for (sdno = 0; sdno < plex.subdisks; sdno++) {
- get_plex_sd_info(&sd, object, sdno);
- if ((sd.state >= sd_empty)
- && (sd.state <= sd_reviving)) { /* candidate for start */
- message->index = sd.sdno; /* pass object number */
- message->type = sd_object; /* it's a subdisk */
- message->state = object_up;
- message->force = force; /* don't force it, use a larger hammer */
-
- /*
- * We don't do any checking here.
- * The kernel module has a better
- * understanding of these things,
- * let it do it.
- */
- if (SSize != 0) { /* specified a size for init */
- if (SSize < 512)
- SSize <<= DEV_BSHIFT;
- message->blocksize = SSize;
- } else
- message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
- ioctl(superdev, VINUM_SETSTATE, message);
- if (reply.error != 0) {
- if (reply.error == EAGAIN) /* we're reviving */
- continue_revive(sd.sdno);
- else
- fprintf(stderr,
- "Can't start %s: %s (%d)\n",
- sd.name,
- reply.msg[0] ? reply.msg : strerror(reply.error),
- reply.error);
- }
- if (Verbose)
- vinum_lsi(sd.sdno, 0);
- }
- }
- }
- break;
-
- case volume_object:
- if (vol.state == volume_up) /* already up */
- fprintf(stderr, "%s is already up\n", vol.name);
- else
- doit = 1;
- break;
- }
-
- if (doit) {
- message->index = object; /* pass object number */
- message->type = type; /* and type of object */
- message->state = object_up;
- message->force = force; /* don't force it, use a larger hammer */
-
- /*
- * We don't do any checking here.
- * The kernel module has a better
- * understanding of these things,
- * let it do it.
- */
- if (SSize != 0) { /* specified a size for init or revive */
- if (SSize < 512)
- SSize <<= DEV_BSHIFT;
- message->blocksize = SSize;
- } else
- message->blocksize = 0;
- ioctl(superdev, VINUM_SETSTATE, message);
- if (reply.error != 0) {
- if ((reply.error == EAGAIN) /* we're reviving */
- &&(type == sd_object))
- continue_revive(object);
- else
- fprintf(stderr,
- "Can't start %s: %s (%d)\n",
- argv[index],
- reply.msg[0] ? reply.msg : strerror(reply.error),
- reply.error);
- }
- if (Verbose)
- vinum_li(object, type);
- }
- }
- }
- }
- checkupdates(); /* make sure we're updating */
-}
-
-void
-vinum_stop(int argc, char *argv[], char *arg0[])
-{
- int object;
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
-
- if (checkupdates() && (!force)) /* not updating? */
- return;
- message->force = force; /* should we force the transition? */
- if (argc == 0) { /* stop vinum */
- int fileid = 0; /* ID of Vinum kld */
-
- close(superdev); /* we can't stop if we have vinum open */
- sleep(1); /* wait for the daemon to let go */
- fileid = kldfind(VINUMMOD);
- if ((fileid < 0) /* no go */
- ||(kldunload(fileid) < 0))
- perror("Can't unload " VINUMMOD);
- else {
- fprintf(stderr, VINUMMOD " unloaded\n");
- exit(0);
- }
-
- /* If we got here, the stop failed. Reopen the superdevice. */
- superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */
- if (superdev < 0) {
- perror("Can't reopen Vinum superdevice");
- exit(1);
- }
- } else { /* stop specified objects */
- int i;
- enum objecttype type;
-
- for (i = 0; i < argc; i++) {
- object = find_object(argv[i], &type); /* look for it */
- if (type == invalid_object)
- fprintf(stderr, "Can't find object: %s\n", argv[i]);
- else {
- message->index = object; /* pass object number */
- message->type = type; /* and type of object */
- message->state = object_down;
- ioctl(superdev, VINUM_SETSTATE, message);
- if (reply.error != 0)
- fprintf(stderr,
- "Can't stop %s: %s (%d)\n",
- argv[i],
- reply.msg[0] ? reply.msg : strerror(reply.error),
- reply.error);
- if (Verbose)
- vinum_li(object, type);
- }
- }
- }
-}
-
-void
-reset_volume_stats(int volno, int recurse)
-{
- struct vinum_ioctl_msg msg;
- struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
-
- msg.index = volno;
- msg.type = volume_object;
- /* XXX get these numbers right if we ever
- * actually return errors */
- if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
- fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
- longjmp(command_fail, -1);
- } else if (recurse) {
- struct _volume vol;
- int plexno;
-
- get_volume_info(&vol, volno);
- for (plexno = 0; plexno < vol.plexes; plexno++)
- reset_plex_stats(vol.plex[plexno], recurse);
- }
-}
-
-void
-reset_plex_stats(int plexno, int recurse)
-{
- struct vinum_ioctl_msg msg;
- struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
-
- msg.index = plexno;
- msg.type = plex_object;
- /* XXX get these numbers right if we ever
- * actually return errors */
- if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
- fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
- longjmp(command_fail, -1);
- } else if (recurse) {
- struct _plex plex;
- struct _sd sd;
- int sdno;
-
- get_plex_info(&plex, plexno);
- for (sdno = 0; sdno < plex.subdisks; sdno++) {
- get_plex_sd_info(&sd, plex.plexno, sdno);
- reset_sd_stats(sd.sdno, recurse);
- }
- }
-}
-
-void
-reset_sd_stats(int sdno, int recurse)
-{
- struct vinum_ioctl_msg msg;
- struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
-
- msg.index = sdno;
- msg.type = sd_object;
- /* XXX get these numbers right if we ever
- * actually return errors */
- if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
- fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
- longjmp(command_fail, -1);
- } else if (recurse) {
- get_sd_info(&sd, sdno); /* get the info */
- reset_drive_stats(sd.driveno); /* and clear the drive */
- }
-}
-
-void
-reset_drive_stats(int driveno)
-{
- struct vinum_ioctl_msg msg;
- struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
-
- msg.index = driveno;
- msg.type = drive_object;
- /* XXX get these numbers right if we ever
- * actually return errors */
- if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
- fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
- longjmp(command_fail, -1);
- }
-}
-
-void
-vinum_resetstats(int argc, char *argv[], char *argv0[])
-{
- int i;
- int objno;
- enum objecttype type;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- if (argc == 0) {
- for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
- reset_volume_stats(objno, 1); /* clear everything recursively */
- } else {
- for (i = 0; i < argc; i++) {
- objno = find_object(argv[i], &type);
- if (objno >= 0) { /* not invalid */
- switch (type) {
- case drive_object:
- reset_drive_stats(objno);
- break;
-
- case sd_object:
- reset_sd_stats(objno, recurse);
- break;
-
- case plex_object:
- reset_plex_stats(objno, recurse);
- break;
-
- case volume_object:
- reset_volume_stats(objno, recurse);
- break;
-
- case invalid_object: /* can't get this */
- break;
- }
- }
- }
- }
-}
-
-/* Attach a subdisk to a plex, or a plex to a volume.
- * attach subdisk plex [offset] [rename]
- * attach plex volume [rename]
- */
-void
-vinum_attach(int argc, char *argv[], char *argv0[])
-{
- int i;
- enum objecttype supertype;
- struct vinum_ioctl_msg msg;
- struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
- const char *objname = argv[0];
- const char *supername = argv[1];
- int sdno = -1;
- int plexno = -1;
- char oldname[MAXNAME + 8];
- char newname[MAXNAME + 8];
- int rename = 0; /* set if we want to rename the object */
-
- if ((argc < 2)
- || (argc > 4)) {
- fprintf(stderr,
- "usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
- "\tattach <plex> <volume> [rename]\n");
- return;
- }
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- msg.index = find_object(objname, &msg.type); /* find the object to attach */
- msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */
- msg.force = force; /* did we specify the use of force? */
- msg.recurse = recurse;
- msg.offset = -1; /* and no offset */
-
- for (i = 2; i < argc; i++) {
- if (!strcmp(argv[i], "rename")) {
- rename = 1;
- msg.rename = 1; /* do renaming */
- } else if (!isdigit(argv[i][0])) { /* not an offset */
- fprintf(stderr, "Unknown attribute: %s\n", supername);
- return;
- } else
- msg.offset = sizespec(argv[i]);
- }
-
- switch (msg.type) {
- case sd_object:
- find_object(argv[1], &supertype);
- if (supertype != plex_object) { /* huh? */
- fprintf(stderr, "%s can only be attached to a plex\n", objname);
- return;
- }
- if ((plex.organization != plex_concat) /* not a cat plex, */
- &&(!force)) {
- fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
- return;
- }
- sdno = msg.index; /* note the subdisk number for later */
- break;
-
- case plex_object:
- find_object(argv[1], &supertype);
- if (supertype != volume_object) { /* huh? */
- fprintf(stderr, "%s can only be attached to a volume\n", objname);
- return;
- }
- break;
-
- case volume_object:
- case drive_object:
- fprintf(stderr, "Can only attach subdisks and plexes\n");
- return;
-
- default:
- fprintf(stderr, "%s is not a Vinum object\n", objname);
- return;
- }
-
- ioctl(superdev, VINUM_ATTACH, &msg);
- if (reply->error != 0) {
- if (reply->error == EAGAIN) /* reviving */
- continue_revive(sdno); /* continue the revive */
- else
- fprintf(stderr,
- "Can't attach %s to %s: %s (%d)\n",
- objname,
- supername,
- reply->msg[0] ? reply->msg : strerror(reply->error),
- reply->error);
- }
- if (rename) {
- struct sd;
- struct _plex;
- struct _volume;
-
- /* we've overwritten msg with the
- * ioctl reply, start again */
- msg.index = find_object(objname, &msg.type); /* find the object to rename */
- switch (msg.type) {
- case sd_object:
- get_sd_info(&sd, msg.index);
- get_plex_info(&plex, sd.plexno);
- for (sdno = 0; sdno < plex.subdisks; sdno++) {
- if (plex.sdnos[sdno] == msg.index) /* found our subdisk */
- break;
- }
- sprintf(newname, "%s.s%d", plex.name, sdno);
- sprintf(oldname, "%s", sd.name);
- vinum_rename_2(oldname, newname);
- break;
-
- case plex_object:
- get_plex_info(&plex, msg.index);
- get_volume_info(&vol, plex.volno);
- for (plexno = 0; plexno < vol.plexes; plexno++) {
- if (vol.plex[plexno] == msg.index) /* found our subdisk */
- break;
- }
- sprintf(newname, "%s.p%d", vol.name, plexno);
- sprintf(oldname, "%s", plex.name);
- vinum_rename_2(oldname, newname); /* this may recurse */
- break;
- }
- }
- checkupdates(); /* make sure we're updating */
-}
-
-/* Detach a subdisk from a plex, or a plex from a volume.
- * detach subdisk plex [rename]
- * detach plex volume [rename]
- */
-void
-vinum_detach(int argc, char *argv[], char *argv0[])
-{
- struct vinum_ioctl_msg msg;
- struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
-
- if ((argc < 1)
- || (argc > 2)) {
- fprintf(stderr,
- "usage: \tdetach <subdisk> [rename]\n"
- "\tdetach <plex> [rename]\n");
- return;
- }
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- msg.index = find_object(argv[0], &msg.type); /* find the object to detach */
- msg.force = force; /* did we specify the use of force? */
- msg.rename = 0; /* don't specify new name */
- msg.recurse = recurse; /* but recurse if we have to */
-
- /* XXX are we going to keep this?
- * Don't document it yet, since the
- * kernel side of things doesn't
- * implement it */
- if (argc == 2) {
- if (!strcmp(argv[1], "rename"))
- msg.rename = 1; /* do renaming */
- else {
- fprintf(stderr, "Unknown attribute: %s\n", argv[1]);
- return;
- }
- }
- if ((msg.type != sd_object)
- && (msg.type != plex_object)) {
- fprintf(stderr, "Can only detach subdisks and plexes\n");
- return;
- }
- ioctl(superdev, VINUM_DETACH, &msg);
- if (reply->error != 0)
- fprintf(stderr,
- "Can't detach %s: %s (%d)\n",
- argv[0],
- reply->msg[0] ? reply->msg : strerror(reply->error),
- reply->error);
- checkupdates(); /* make sure we're updating */
-}
-
-static void
-dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen)
-{
- struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
-
- if (strlen(name) > maxlen) {
- fprintf(stderr, "%s is too long\n", name);
- return;
- }
- strcpy(msg->newname, name);
- ioctl(superdev, VINUM_RENAME, msg);
- if (reply->error != 0)
- fprintf(stderr,
- "Can't rename %s to %s: %s (%d)\n",
- oldname,
- name,
- reply->msg[0] ? reply->msg : strerror(reply->error),
- reply->error);
-}
-
-/* Rename an object:
- * rename <object> "newname"
- */
-void
-vinum_rename_2(char *oldname, char *newname)
-{
- struct vinum_rename_msg msg;
- int volno;
- int plexno;
-
- msg.index = find_object(oldname, &msg.type); /* find the object to rename */
- msg.recurse = recurse;
-
- /* Ugh. Determine how long the name may be */
- switch (msg.type) {
- case drive_object:
- dorename(&msg, oldname, newname, MAXDRIVENAME);
- break;
-
- case sd_object:
- dorename(&msg, oldname, newname, MAXSDNAME);
- break;
-
- case plex_object:
- plexno = msg.index;
- dorename(&msg, oldname, newname, MAXPLEXNAME);
- if (recurse) {
- int sdno;
-
- get_plex_info(&plex, plexno); /* find out who we are */
- msg.type = sd_object;
- for (sdno = 0; sdno < plex.subdisks; sdno++) {
- char sdname[MAXPLEXNAME + 8];
-
- get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
- sprintf(sdname, "%s.s%d", newname, sdno);
- msg.index = sd.sdno; /* number of the subdisk */
- dorename(&msg, sd.name, sdname, MAXSDNAME);
- }
- }
- break;
-
- case volume_object:
- volno = msg.index;
- dorename(&msg, oldname, newname, MAXVOLNAME);
- if (recurse) {
- int sdno;
- int plexno;
-
- get_volume_info(&vol, volno); /* find out who we are */
- for (plexno = 0; plexno < vol.plexes; plexno++) {
- char plexname[MAXVOLNAME + 8];
-
- msg.type = plex_object;
- sprintf(plexname, "%s.p%d", newname, plexno);
- msg.index = vol.plex[plexno]; /* number of the plex */
- dorename(&msg, plex.name, plexname, MAXPLEXNAME);
- get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */
- msg.type = sd_object;
- for (sdno = 0; sdno < plex.subdisks; sdno++) {
- char sdname[MAXPLEXNAME + 8];
-
- get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
- sprintf(sdname, "%s.s%d", plexname, sdno);
- msg.index = sd.sdno; /* number of the subdisk */
- dorename(&msg, sd.name, sdname, MAXSDNAME);
- }
- }
- }
- break;
-
- default:
- fprintf(stderr, "%s is not a Vinum object\n", oldname);
- return;
- }
-}
-
-void
-vinum_rename(int argc, char *argv[], char *argv0[])
-{
- if (argc != 2) {
- fprintf(stderr, "usage: \trename <object> <new name>\n");
- return;
- }
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- vinum_rename_2(argv[0], argv[1]);
- checkupdates(); /* make sure we're updating */
-}
-
-/*
- * Move objects:
- *
- * mv <dest> <src> ...
- */
-void
-vinum_mv(int argc, char *argv[], char *argv0[])
-{
- int i; /* loop index */
- int srcobj;
- int destobj;
- enum objecttype srct;
- enum objecttype destt;
- int sdno;
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply;
-
- if (argc < 2) {
- fprintf(stderr, "usage: \tmove <dest> <src> ...\n");
- return;
- }
- /* Get current config */
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Cannot get vinum config\n");
- return;
- }
- /* Get our destination */
- destobj = find_object(argv[0], &destt);
- if (destobj == -1) {
- fprintf(stderr, "Can't find %s\n", argv[0]);
- return;
- }
- /* Verify that the target is a drive */
- if (destt != drive_object) {
- fprintf(stderr, "%s is not a drive\n", argv[0]);
- return;
- }
- for (i = 1; i < argc; i++) { /* for all the sources */
- srcobj = find_object(argv[i], &srct);
- if (srcobj == -1) {
- fprintf(stderr, "Can't find %s\n", argv[i]);
- continue;
- }
- msg->index = destobj;
- switch (srct) { /* Handle the source object */
- case drive_object: /* Move all subdisks on the drive to dst. */
- get_drive_info(&drive, srcobj); /* get info on drive */
- for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) {
- get_sd_info(&sd, sdno);
- if (sd.driveno == srcobj) {
- msg->index = destobj;
- msg->otherobject = sd.sdno;
- if (ioctl(superdev, VINUM_MOVE, msg) < 0)
- fprintf(stderr,
- "Can't move %s (part of %s) to %s: %s (%d)\n",
- sd.name,
- drive.label.name,
- argv[0],
- strerror(reply.error),
- reply.error);
- }
- }
- break;
-
- case sd_object:
- msg->otherobject = srcobj;
- if (ioctl(superdev, VINUM_MOVE, msg) < 0)
- fprintf(stderr,
- "Can't move %s to %s: %s (%d)\n",
- sd.name,
- argv[0],
- strerror(reply.error),
- reply.error);
- break;
-
- case plex_object:
- get_plex_info(&plex, srcobj);
- for (sdno = 0; sdno < plex.subdisks; ++sdno) {
- get_plex_sd_info(&sd, plex.plexno, sdno);
- msg->index = destobj;
- msg->otherobject = sd.sdno;
- if (ioctl(superdev, VINUM_MOVE, msg) < 0)
- fprintf(stderr,
- "Can't move %s (part of %s) to %s: %s (%d)\n",
- sd.name,
- plex.name,
- argv[0],
- strerror(reply.error),
- reply.error);
- }
- break;
-
- case volume_object:
- case invalid_object:
- default:
- fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]);
- break;
- }
- if (reply.error)
- fprintf(stderr,
- "Can't move %s to %s: %s (%d)\n",
- argv[i],
- argv[0],
- strerror(reply.error),
- reply.error);
- }
- checkupdates(); /* make sure we're updating */
-}
-
-/*
- * Replace objects. Not implemented, may never be.
- */
-void
-vinum_replace(int argc, char *argv[], char *argv0[])
-{
- fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n");
-}
-
-/* Primitive help function */
-void
-vinum_help(int argc, char *argv[], char *argv0[])
-{
- char commands[] =
- {
- "COMMANDS\n"
- "attach plex volume [rename]\n"
- "attach subdisk plex [offset] [rename]\n"
- " Attach a plex to a volume, or a subdisk to a plex.\n"
- "checkparity plex [-f] [-v]\n"
- " Check the parity blocks of a RAID-4 or RAID-5 plex.\n"
- "concat [-f] [-n name] [-v] drives\n"
- " Create a concatenated volume from the specified drives.\n"
- "create [-f] description-file\n"
- " Create a volume as described in description-file.\n"
- "debug Cause the volume manager to enter the kernel debugger.\n"
- "debug flags\n"
- " Set debugging flags.\n"
- "detach [-f] [plex | subdisk]\n"
- " Detach a plex or subdisk from the volume or plex to which it is\n"
- " attached.\n"
- "dumpconfig [drive ...]\n"
- " List the configuration information stored on the specified\n"
- " drives, or all drives in the system if no drive names are speci-\n"
- " fied.\n"
- "info [-v] [-V]\n"
- " List information about volume manager state.\n"
- "init [-S size] [-w] plex | subdisk\n"
- " Initialize the contents of a subdisk or all the subdisks of a\n"
- " plex to all zeros.\n"
- "label volume\n"
- " Create a volume label.\n"
- "l | list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
- " List information about specified objects.\n"
- "ld [-r] [-s] [-v] [-V] [drive]\n"
- " List information about drives.\n"
- "ls [-r] [-s] [-v] [-V] [subdisk]\n"
- " List information about subdisks.\n"
- "lp [-r] [-s] [-v] [-V] [plex]\n"
- " List information about plexes.\n"
- "lv [-r] [-s] [-v] [-V] [volume]\n"
- " List information about volumes.\n"
- "mirror [-f] [-n name] [-s] [-v] drives\n"
- " Create a mirrored volume from the specified drives.\n"
- "move | mv -f drive object ...\n"
- " Move the object(s) to the specified drive.\n"
- "printconfig [file]\n"
- " Write a copy of the current configuration to file.\n"
- "quit Exit the vinum program when running in interactive mode. Nor-\n"
- " mally this would be done by entering the EOF character.\n"
- "read disk ...\n"
- " Read the vinum configuration from the specified disks.\n"
- "rename [-r] [drive | subdisk | plex | volume] newname\n"
- " Change the name of the specified object.\n"
- "rebuildparity plex [-f] [-v] [-V]\n"
- " Rebuild the parity blocks of a RAID-4 or RAID-5 plex.\n"
- "resetconfig\n"
- " Reset the complete vinum configuration.\n"
- "resetstats [-r] [volume | plex | subdisk]\n"
- " Reset statistics counters for the specified objects, or for all\n"
- " objects if none are specified.\n"
- "rm [-f] [-r] volume | plex | subdisk\n"
- " Remove an object.\n"
- "saveconfig\n"
- " Save vinum configuration to disk after configuration failures.\n"
- "setdaemon [value]\n"
- " Set daemon configuration.\n"
- "setstate state [volume | plex | subdisk | drive]\n"
- " Set state without influencing other objects, for diagnostic pur-\n"
- " poses only.\n"
- "start Read configuration from all vinum drives.\n"
- "start [-i interval] [-S size] [-w] volume | plex | subdisk\n"
- " Allow the system to access the objects.\n"
- "stop [-f] [volume | plex | subdisk]\n"
- " Terminate access to the objects, or stop vinum if no parameters\n"
- " are specified.\n"
- "stripe [-f] [-n name] [-v] drives\n"
- " Create a striped volume from the specified drives.\n"
- };
- puts(commands);
-}
-
-/* Set daemon options.
- * XXX quick and dirty: use a bitmap, which requires
- * knowing which bit does what. FIXME */
-void
-vinum_setdaemon(int argc, char *argv[], char *argv0[])
-{
- int options;
-
- switch (argc) {
- case 0:
- if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
- fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
- else
- printf("Options mask: %d\n", options);
- break;
-
- case 1:
- options = atoi(argv[0]);
- if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0)
- fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno);
- break;
-
- default:
- fprintf(stderr, "usage: \tsetdaemon [<bitmask>]\n");
- }
- checkupdates(); /* make sure we're updating */
-}
-
-/* Save config info */
-void
-vinum_saveconfig(int argc, char *argv[], char *argv0[])
-{
- int ioctltype;
-
- if (argc != 0) {
- printf("usage: saveconfig\n");
- return;
- }
- ioctltype = 1; /* user saveconfig */
- if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0)
- fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno);
- checkupdates(); /* make sure we're updating */
-}
-
-/*
- * Create a volume name for the quick and dirty
- * commands. It will be of the form "vinum#",
- * where # is a small positive number.
- */
-void
-genvolname()
-{
- int v; /* volume number */
- static char volumename[MAXVOLNAME]; /* name to create */
- enum objecttype type;
-
- objectname = volumename; /* point to it */
- for (v = 0;; v++) {
- sprintf(objectname, "vinum%d", v); /* create the name */
- if (find_object(objectname, &type) == -1) /* does it exist? */
- return; /* no, it's ours */
- }
-}
-
-/*
- * Create a drive for the quick and dirty
- * commands. The name will be of the form
- * vinumdrive#, where # is a small positive
- * number. Return the name of the drive.
- */
-struct _drive *
-create_drive(char *devicename)
-{
- int d; /* volume number */
- static char drivename[MAXDRIVENAME]; /* name to create */
- enum objecttype type;
- struct _ioctl_reply *reply;
-
- /*
- * We're never likely to get anything
- * like 10000 drives. The only reason for
- * this limit is to stop the thing
- * looping if we have a bug somewhere.
- */
- for (d = 0; d < 100000; d++) { /* look for a free drive number */
- sprintf(drivename, "vinumdrive%d", d); /* create the name */
- if (find_object(drivename, &type) == -1) { /* does it exist? */
- char command[MAXDRIVENAME * 2];
-
- sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */
- if (vflag)
- printf("drive %s device %s\n", drivename, devicename); /* create a create command */
- ioctl(superdev, VINUM_CREATE, command);
- reply = (struct _ioctl_reply *) &command;
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create drive %s, device %s: %s\n",
- drivename,
- devicename,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create drive %s, device %s: %s (%d)\n",
- drivename,
- devicename,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- find_object(drivename, &type);
- return &drive; /* return the name of the drive */
- }
- }
- fprintf(stderr, "Can't generate a drive name\n");
- /* NOTREACHED */
- return NULL;
-}
-
-/*
- * Create a volume with a single concatenated plex from
- * as much space as we can get on the specified drives.
- * If the drives aren't Vinum drives, make them so.
- */
-void
-vinum_concat(int argc, char *argv[], char *argv0[])
-{
- int o; /* object number */
- char buffer[BUFSIZE];
- struct _drive *drive; /* drive we're currently looking at */
- struct _ioctl_reply *reply;
- int ioctltype;
- int error;
- enum objecttype type;
-
- reply = (struct _ioctl_reply *) &buffer;
- if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
- printf("Can't configure: %s (%d)\n", strerror(errno), errno);
- return;
- }
- if (!objectname) /* we need a name for our object */
- genvolname();
- sprintf(buffer, "volume %s", objectname);
- if (vflag)
- printf("volume %s\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create volume %s: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create volume %s: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- sprintf(buffer, "plex name %s.p0 org concat", objectname);
- if (vflag)
- printf(" plex name %s.p0 org concat\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create plex %s.p0: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create plex %s.p0: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- for (o = 0; o < argc; o++) {
- if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
- drive = create_drive(argv[o]); /* create it */
- sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name);
- if (vflag)
- printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create subdisk %s.p0.s%d: %s\n",
- objectname,
- o,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create subdisk %s.p0.s%d: %s (%d)\n",
- objectname,
- o,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- }
-
- /* done, save the config */
- ioctltype = 0; /* saveconfig after update */
- error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
- if (error != 0)
- perror("Can't save Vinum config");
- find_object(objectname, &type); /* find the index of the volume */
- if (vflag) {
- vflag--; /* XXX don't give too much detail */
- find_object(objectname, &type); /* point to the volume */
- vinum_lvi(vol.volno, 1); /* and print info about it */
- }
-}
-
-
-/*
- * Create a volume with a single striped plex from
- * as much space as we can get on the specified drives.
- * If the drives aren't Vinum drives, make them so.
- */
-void
-vinum_stripe(int argc, char *argv[], char *argv0[])
-{
- int o; /* object number */
- char buffer[BUFSIZE];
- struct _drive *drive; /* drive we're currently looking at */
- struct _ioctl_reply *reply;
- int ioctltype;
- int error;
- enum objecttype type;
- off_t maxsize;
- int fe; /* freelist entry index */
- struct drive_freelist freelist;
- struct ferq { /* request to pass to ioctl */
- int driveno;
- int fe;
- } *ferq = (struct ferq *) &freelist;
- u_int64_t bigchunk; /* biggest chunk in freelist */
-
- maxsize = QUAD_MAX;
- reply = (struct _ioctl_reply *) &buffer;
-
- /*
- * First, check our drives.
- */
- if (argc < 2) {
- fprintf(stderr, "You need at least two drives to create a striped plex\n");
- return;
- }
- if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
- printf("Can't configure: %s (%d)\n", strerror(errno), errno);
- return;
- }
- if (!objectname) /* we need a name for our object */
- genvolname();
- for (o = 0; o < argc; o++) {
- if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
- drive = create_drive(argv[o]); /* create it */
- /* Now find the largest chunk available on the drive */
- bigchunk = 0; /* ain't found nothin' yet */
- for (fe = 0; fe < drive->freelist_entries; fe++) {
- ferq->driveno = drive->driveno;
- ferq->fe = fe;
- if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
- fprintf(stderr,
- "Can't get free list element %d: %s\n",
- fe,
- strerror(errno));
- longjmp(command_fail, -1);
- }
- bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
- }
- maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
- }
-
- /* Now create the volume */
- sprintf(buffer, "volume %s", objectname);
- if (vflag)
- printf("volume %s\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create volume %s: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create volume %s: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- sprintf(buffer, "plex name %s.p0 org striped 279k", objectname);
- if (vflag)
- printf(" plex name %s.p0 org striped 279k\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create plex %s.p0: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create plex %s.p0: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- for (o = 0; o < argc; o++) {
- drive = find_drive_by_devname(argv[o]); /* we know it exists... */
- sprintf(buffer,
- "sd name %s.p0.s%d drive %s size %lldb",
- objectname,
- o,
- drive->label.name,
- (long long) maxsize);
- if (vflag)
- printf(" sd name %s.p0.s%d drive %s size %lldb\n",
- objectname,
- o,
- drive->label.name,
- (long long) maxsize);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create subdisk %s.p0.s%d: %s\n",
- objectname,
- o,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create subdisk %s.p0.s%d: %s (%d)\n",
- objectname,
- o,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- }
-
- /* done, save the config */
- ioctltype = 0; /* saveconfig after update */
- error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
- if (error != 0)
- perror("Can't save Vinum config");
- find_object(objectname, &type); /* find the index of the volume */
- if (vflag) {
- vflag--; /* XXX don't give too much detail */
- find_object(objectname, &type); /* point to the volume */
- vinum_lvi(vol.volno, 1); /* and print info about it */
- }
-}
-
-/*
- * Create a volume with a single RAID-4 plex from
- * as much space as we can get on the specified drives.
- * If the drives aren't Vinum drives, make them so.
- */
-void
-vinum_raid4(int argc, char *argv[], char *argv0[])
-{
- int o; /* object number */
- char buffer[BUFSIZE];
- struct _drive *drive; /* drive we're currently looking at */
- struct _ioctl_reply *reply;
- int ioctltype;
- int error;
- enum objecttype type;
- off_t maxsize;
- int fe; /* freelist entry index */
- struct drive_freelist freelist;
- struct ferq { /* request to pass to ioctl */
- int driveno;
- int fe;
- } *ferq = (struct ferq *) &freelist;
- u_int64_t bigchunk; /* biggest chunk in freelist */
-
- maxsize = QUAD_MAX;
- reply = (struct _ioctl_reply *) &buffer;
-
- /*
- * First, check our drives.
- */
- if (argc < 3) {
- fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
- return;
- }
- if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
- printf("Can't configure: %s (%d)\n", strerror(errno), errno);
- return;
- }
- if (!objectname) /* we need a name for our object */
- genvolname();
- for (o = 0; o < argc; o++) {
- if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
- drive = create_drive(argv[o]); /* create it */
- /* Now find the largest chunk available on the drive */
- bigchunk = 0; /* ain't found nothin' yet */
- for (fe = 0; fe < drive->freelist_entries; fe++) {
- ferq->driveno = drive->driveno;
- ferq->fe = fe;
- if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
- fprintf(stderr,
- "Can't get free list element %d: %s\n",
- fe,
- strerror(errno));
- longjmp(command_fail, -1);
- }
- bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
- }
- maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
- }
-
- /* Now create the volume */
- sprintf(buffer, "volume %s", objectname);
- if (vflag)
- printf("volume %s\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create volume %s: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create volume %s: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- sprintf(buffer, "plex name %s.p0 org raid4 279k", objectname);
- if (vflag)
- printf(" plex name %s.p0 org raid4 279k\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create plex %s.p0: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create plex %s.p0: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- for (o = 0; o < argc; o++) {
- drive = find_drive_by_devname(argv[o]); /* we know it exists... */
- sprintf(buffer,
- "sd name %s.p0.s%d drive %s size %lldb",
- objectname,
- o,
- drive->label.name,
- (long long) maxsize);
- if (vflag)
- printf(" sd name %s.p0.s%d drive %s size %lldb\n",
- objectname,
- o,
- drive->label.name,
- (long long) maxsize);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create subdisk %s.p0.s%d: %s\n",
- objectname,
- o,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create subdisk %s.p0.s%d: %s (%d)\n",
- objectname,
- o,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- }
-
- /* done, save the config */
- ioctltype = 0; /* saveconfig after update */
- error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
- if (error != 0)
- perror("Can't save Vinum config");
- find_object(objectname, &type); /* find the index of the volume */
- if (vflag) {
- vflag--; /* XXX don't give too much detail */
- find_object(objectname, &type); /* point to the volume */
- vinum_lvi(vol.volno, 1); /* and print info about it */
- }
-}
-
-/*
- * Create a volume with a single RAID-4 plex from
- * as much space as we can get on the specified drives.
- * If the drives aren't Vinum drives, make them so.
- */
-void
-vinum_raid5(int argc, char *argv[], char *argv0[])
-{
- int o; /* object number */
- char buffer[BUFSIZE];
- struct _drive *drive; /* drive we're currently looking at */
- struct _ioctl_reply *reply;
- int ioctltype;
- int error;
- enum objecttype type;
- off_t maxsize;
- int fe; /* freelist entry index */
- struct drive_freelist freelist;
- struct ferq { /* request to pass to ioctl */
- int driveno;
- int fe;
- } *ferq = (struct ferq *) &freelist;
- u_int64_t bigchunk; /* biggest chunk in freelist */
-
- maxsize = QUAD_MAX;
- reply = (struct _ioctl_reply *) &buffer;
-
- /*
- * First, check our drives.
- */
- if (argc < 3) {
- fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
- return;
- }
- if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
- printf("Can't configure: %s (%d)\n", strerror(errno), errno);
- return;
- }
- if (!objectname) /* we need a name for our object */
- genvolname();
- for (o = 0; o < argc; o++) {
- if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
- drive = create_drive(argv[o]); /* create it */
- /* Now find the largest chunk available on the drive */
- bigchunk = 0; /* ain't found nothin' yet */
- for (fe = 0; fe < drive->freelist_entries; fe++) {
- ferq->driveno = drive->driveno;
- ferq->fe = fe;
- if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
- fprintf(stderr,
- "Can't get free list element %d: %s\n",
- fe,
- strerror(errno));
- longjmp(command_fail, -1);
- }
- bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
- }
- maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
- }
-
- /* Now create the volume */
- sprintf(buffer, "volume %s", objectname);
- if (vflag)
- printf("volume %s\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create volume %s: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create volume %s: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- sprintf(buffer, "plex name %s.p0 org raid5 279k", objectname);
- if (vflag)
- printf(" plex name %s.p0 org raid5 279k\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create plex %s.p0: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create plex %s.p0: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- for (o = 0; o < argc; o++) {
- drive = find_drive_by_devname(argv[o]); /* we know it exists... */
- sprintf(buffer,
- "sd name %s.p0.s%d drive %s size %lldb",
- objectname,
- o,
- drive->label.name,
- (long long) maxsize);
- if (vflag)
- printf(" sd name %s.p0.s%d drive %s size %lldb\n",
- objectname,
- o,
- drive->label.name,
- (long long) maxsize);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create subdisk %s.p0.s%d: %s\n",
- objectname,
- o,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create subdisk %s.p0.s%d: %s (%d)\n",
- objectname,
- o,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- }
-
- /* done, save the config */
- ioctltype = 0; /* saveconfig after update */
- error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
- if (error != 0)
- perror("Can't save Vinum config");
- find_object(objectname, &type); /* find the index of the volume */
- if (vflag) {
- vflag--; /* XXX don't give too much detail */
- find_object(objectname, &type); /* point to the volume */
- vinum_lvi(vol.volno, 1); /* and print info about it */
- }
-}
-
-/*
- * Create a volume with a two plexes from as much space
- * as we can get on the specified drives. If the
- * drives aren't Vinum drives, make them so.
- *
- * The number of drives must be even, and at least 4
- * for a striped plex. Specify striped plexes with the
- * -s flag; otherwise they will be concatenated. It's
- * possible that the two plexes may differ in length.
- */
-void
-vinum_mirror(int argc, char *argv[], char *argv0[])
-{
- int o; /* object number */
- int p; /* plex number */
- char buffer[BUFSIZE];
- struct _drive *drive; /* drive we're currently looking at */
- struct _ioctl_reply *reply;
- int ioctltype;
- int error;
- enum objecttype type;
- off_t maxsize[2]; /* maximum subdisk size for striped plexes */
- int fe; /* freelist entry index */
- struct drive_freelist freelist;
- struct ferq { /* request to pass to ioctl */
- int driveno;
- int fe;
- } *ferq = (struct ferq *) &freelist;
- u_int64_t bigchunk; /* biggest chunk in freelist */
-
- if (sflag) /* striped, */
- maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */
- else
- maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */
-
- reply = (struct _ioctl_reply *) &buffer;
-
- /*
- * First, check our drives.
- */
- if ((argc < 2)
- || (argc & 1)) {
- fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
- return;
- }
- if (sflag && (argc < 4)) {
- fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
- return;
- }
- if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
- printf("Can't configure: %s (%d)\n", strerror(errno), errno);
- return;
- }
- if (!objectname) /* we need a name for our object */
- genvolname();
- for (o = 0; o < argc; o++) {
- if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
- drive = create_drive(argv[o]); /* create it */
- if (sflag) { /* striping, */
- /* Find the largest chunk available on the drive */
- bigchunk = 0; /* ain't found nothin' yet */
- for (fe = 0; fe < drive->freelist_entries; fe++) {
- ferq->driveno = drive->driveno;
- ferq->fe = fe;
- if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
- fprintf(stderr,
- "Can't get free list element %d: %s\n",
- fe,
- strerror(errno));
- longjmp(command_fail, -1);
- }
- bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
- }
- maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */
- }
- }
-
- /* Now create the volume */
- sprintf(buffer, "volume %s setupstate", objectname);
- if (vflag)
- printf("volume %s setupstate\n", objectname);
- ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create volume %s: %s\n",
- objectname,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create volume %s: %s (%d)\n",
- objectname,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- for (p = 0; p < 2; p++) { /* create each plex */
- if (sflag) {
- sprintf(buffer, "plex name %s.p%d org striped 279k", objectname, p);
- if (vflag)
- printf(" plex name %s.p%d org striped 279k\n", objectname, p);
- } else { /* concat */
- sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
- if (vflag)
- printf(" plex name %s.p%d org concat\n", objectname, p);
- }
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create plex %s.p%d: %s\n",
- objectname,
- p,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create plex %s.p%d: %s (%d)\n",
- objectname,
- p,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- /* Now look at the subdisks */
- for (o = p; o < argc; o += 2) { /* every second one */
- drive = find_drive_by_devname(argv[o]); /* we know it exists... */
- sprintf(buffer,
- "sd name %s.p%d.s%d drive %s size %lldb",
- objectname,
- p,
- o >> 1,
- drive->label.name,
- (long long) maxsize[p]);
- if (vflag)
- printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
- objectname,
- p,
- o >> 1,
- drive->label.name,
- (long long) maxsize[p]);
- ioctl(superdev, VINUM_CREATE, buffer);
- if (reply->error != 0) { /* error in config */
- if (reply->msg[0])
- fprintf(stderr,
- "Can't create subdisk %s.p%d.s%d: %s\n",
- objectname,
- p,
- o >> 1,
- reply->msg);
- else
- fprintf(stderr,
- "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
- objectname,
- p,
- o >> 1,
- strerror(reply->error),
- reply->error);
- longjmp(command_fail, -1); /* give up */
- }
- }
- }
-
- /* done, save the config */
- ioctltype = 0; /* saveconfig after update */
- error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
- if (error != 0)
- perror("Can't save Vinum config");
- find_object(objectname, &type); /* find the index of the volume */
- if (vflag) {
- vflag--; /* XXX don't give too much detail */
- sflag = 0; /* no stats, please */
- find_object(objectname, &type); /* point to the volume */
- vinum_lvi(vol.volno, 1); /* and print info about it */
- }
-}
-
-void
-vinum_readpol(int argc, char *argv[], char *argv0[])
-{
- int object;
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
- enum objecttype type;
- struct _plex plex;
- struct _volume vol;
- int plexno;
-
- if (argc != 2) {
- fprintf(stderr, "usage: readpol <volume> <plex> | round\n");
- return;
- }
- object = find_object(argv[0], &type); /* look for it */
- if (type != volume_object) {
- fprintf(stderr, "%s is not a volume\n", argv[0]);
- return;
- }
- get_volume_info(&vol, object);
- if (strcmp(argv[1], "round")) { /* not 'round' */
- object = find_object(argv[1], &type); /* look for it */
- if (type != plex_object) {
- fprintf(stderr, "%s is not a plex\n", argv[1]);
- return;
- }
- get_plex_info(&plex, object);
- plexno = plex.plexno;
- } else /* round */
- plexno = -1;
-
- /* Set the value */
- message->index = vol.volno;
- message->otherobject = plexno;
- ioctl(superdev, VINUM_READPOL, message);
- if (reply.error)
- fprintf(stderr,
- "Can't set read policy: %s (%d)\n",
- reply.msg[0] ? reply.msg : strerror(reply.error),
- reply.error);
- if (vflag)
- vinum_lpi(plexno, recurse);
-}
-
-/*
- * Brute force set state function. Don't look at
- * any dependencies, just do it.
- */
-void
-vinum_setstate(int argc, char *argv[], char *argv0[])
-{
- int object;
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
- int index;
- enum objecttype type;
- int state;
-
- for (index = 1; index < argc; index++) {
- object = find_object(argv[index], &type); /* look for it */
- if (type == invalid_object)
- fprintf(stderr, "Can't find object: %s\n", argv[index]);
- else {
- int doit = 0; /* set to 1 if we pass our tests */
- switch (type) {
- case drive_object:
- state = DriveState(argv[0]); /* get the state */
- if (drive.state == state) /* already in that state */
- fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
- else
- doit = 1;
- break;
-
- case sd_object:
- state = SdState(argv[0]); /* get the state */
- if (sd.state == state) /* already in that state */
- fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
- else
- doit = 1;
- break;
-
- case plex_object:
- state = PlexState(argv[0]); /* get the state */
- if (plex.state == state) /* already in that state */
- fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
- else
- doit = 1;
- break;
-
- case volume_object:
- state = VolState(argv[0]); /* get the state */
- if (vol.state == state) /* already in that state */
- fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
- else
- doit = 1;
- break;
-
- default:
- state = 0; /* to keep the compiler happy */
- }
-
- if (state == -1)
- fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
- else if (doit) {
- message->index = object; /* pass object number */
- message->type = type; /* and type of object */
- message->state = state;
- message->force = force; /* don't force it, use a larger hammer */
- ioctl(superdev, VINUM_SETSTATE_FORCE, message);
- if (reply.error != 0)
- fprintf(stderr,
- "Can't start %s: %s (%d)\n",
- argv[index],
- reply.msg[0] ? reply.msg : strerror(reply.error),
- reply.error);
- if (Verbose)
- vinum_li(object, type);
- }
- }
- }
-}
-
-void
-vinum_checkparity(int argc, char *argv[], char *argv0[])
-{
- Verbose = vflag; /* accept -v for verbose */
- if (argc == 0) /* no parameters? */
- fprintf(stderr, "usage: checkparity object [object...]\n");
- else
- parityops(argc, argv, checkparity);
-}
-
-void
-vinum_rebuildparity(int argc, char *argv[], char *argv0[])
-{
- if (argc == 0) /* no parameters? */
- fprintf(stderr, "usage: rebuildparity object [object...]\n");
- else
- parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
-}
-
-/*
- * Common code for rebuildparity and checkparity.
- * We bend the meanings of some flags here:
- *
- * -v: Report incorrect parity on rebuild.
- * -V: Show running count of position being checked.
- * -f: Start from beginning of the plex.
- */
-void
-parityops(int argc, char *argv[], enum parityop op)
-{
- int object;
- struct _plex plex;
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
- int index;
- enum objecttype type;
- char *msg;
- off_t block;
-
- if (op == checkparity)
- msg = "Checking";
- else
- msg = "Rebuilding";
- for (index = 0; index < argc; index++) {
- object = find_object(argv[index], &type); /* look for it */
- if (type != plex_object)
- fprintf(stderr, "%s is not a plex\n", argv[index]);
- else {
- get_plex_info(&plex, object);
- if (!isparity((&plex)))
- fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
- else {
- do {
- message->index = object; /* pass object number */
- message->type = type; /* and type of object */
- message->op = op; /* what to do */
- if (force)
- message->offset = 0; /* start at the beginning */
- else
- message->offset = plex.checkblock; /* continue where we left off */
- force = 0; /* don't reset after the first time */
- ioctl(superdev, VINUM_PARITYOP, message);
- get_plex_info(&plex, object);
- if (Verbose) {
- block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
- if (block != 0)
- printf("\r%s at %s (%d%%) ",
- msg,
- roughlength(block, 1),
- ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
- if ((reply.error == EAGAIN)
- && (reply.msg[0])) /* got a comment back */
- fputs(reply.msg, stderr); /* show it */
- fflush(stdout);
- }
- }
- while (reply.error == EAGAIN);
- if (reply.error != 0) {
- if (reply.msg[0])
- fputs(reply.msg, stderr);
- else
- fprintf(stderr,
- "%s failed: %s\n",
- msg,
- strerror(reply.error));
- } else if (Verbose) {
- if (op == checkparity)
- fprintf(stderr, "%s has correct parity\n", argv[index]);
- else
- fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
- }
- }
- }
- }
-}
-
-/* Local Variables: */
-/* fill-column: 50 */
-/* End: */
diff --git a/sbin/vinum/list.c b/sbin/vinum/list.c
deleted file mode 100644
index ee5602a..0000000
--- a/sbin/vinum/list.c
+++ /dev/null
@@ -1,1502 +0,0 @@
-/* list.c: vinum interface program, list routines
- */
-/*-
- * Copyright (c) 1997, 1998
- * Nan Yang Computer Services Limited. All rights reserved.
- *
- * Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
- *
- * Written by Greg Lehey
- *
- * This software is distributed under the so-called ``Berkeley
- * License'':
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Nan Yang Computer
- * Services Limited.
- * 4. Neither the name of the Company nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * This software is provided ``as is'', and any express or implied
- * warranties, including, but not limited to, the implied warranties of
- * merchantability and fitness for a particular purpose are disclaimed.
- * In no event shall the company or contributors be liable for any
- * direct, indirect, incidental, special, exemplary, or consequential
- * damages (including, but not limited to, procurement of substitute
- * goods or services; loss of use, data, or profits; or business
- * interruption) however caused and on any theory of liability, whether
- * in contract, strict liability, or tort (including negligence or
- * otherwise) arising in any way out of the use of this software, even if
- * advised of the possibility of such damage.
- *
- * $Id: list.c,v 1.32 2003/04/28 06:19:06 grog Exp $
- * $FreeBSD$
- */
-
-#include "vext.h"
-#include <sys/utsname.h>
-#include <dev/vinum/request.h>
-#include <devstat.h>
-
-/*
- * When a subdisk is reviving or initializing, we
- * check to see whether it is still progressing
- * and print a warning if not. We check every 50
- * ms, up to a maximum of 5 seconds. This is the
- * counter value.
- */
-#define STALLCOUNT 100
-
-/*
- * Take a size in sectors and return a pointer to
- * a string which represents the size best. If lj
- * is != 0, return left justified, otherwise in a
- * fixed 10 character field suitable for columnar
- * printing.
- *
- * Note this uses a static string: it's only
- * intended to be used immediately for printing.
- */
-char *
-roughlength(int64_t bytes, int lj)
-{
- static char description[16];
-
- if (bytes > (int64_t) MEGABYTE * 10000) /* gigabytes */
- sprintf(description, lj ? "%lld GB" : "%10d GB", bytes / GIGABYTE);
- else if (bytes > KILOBYTE * 10000) /* megabytes */
- sprintf(description, lj ? "%lld MB" : "%10d MB", bytes / MEGABYTE);
- else if (bytes > 10000) /* kilobytes */
- sprintf(description, lj ? "%lld kB" : "%10d kB", bytes / KILOBYTE);
- else /* bytes */
- sprintf(description, lj ? "%lld B" : "%10d B", bytes);
- return description;
-}
-
-void
-vinum_list(int argc, char *argv[], char *argv0[])
-{
- int object;
- int i;
- enum objecttype type;
-
- if (sflag & (!vflag)) /* just summary stats, */
- printf("Object\t\t Reads\t\tBytes\tAverage\tRecover\t Writes"
- "\t\tBytes\tAverage\t Mblock Mstripe\n\n");
- if (argc == 0)
- listconfig(); /* list everything */
- else {
- for (i = 0; i < argc; i++) {
- object = find_object(argv[i], &type); /* look for it */
- if (vinum_li(object, type))
- fprintf(stderr, "Can't find object: %s\n", argv[i]);
- }
- }
-}
-
-/* List an object */
-int
-vinum_li(int object, enum objecttype type)
-{
- switch (type) {
- case drive_object:
- vinum_ldi(object, recurse);
- break;
-
- case sd_object:
- vinum_lsi(object, recurse);
- break;
-
- case plex_object:
- vinum_lpi(object, recurse);
- break;
-
- case volume_object:
- vinum_lvi(object, recurse);
- break;
-
- default:
- return -1;
- }
- return 0;
-}
-
-void
-vinum_ldi(int driveno, int recurse)
-{
- time_t t; /* because Bruce says so */
- int sdno; /* for recursion */
-
- get_drive_info(&drive, driveno);
- if (drive.state != drive_unallocated) {
- if (vflag) {
- printf("Drive %s:\tDevice %s\n",
- drive.label.name,
- drive.devicename);
- t = drive.label.date_of_birth.tv_sec;
- printf("\t\tCreated on %s at %s",
- drive.label.sysname,
- ctime(&t));
- t = drive.label.last_update.tv_sec;
- printf("\t\tConfig last updated %s", /* care: \n at end */
- ctime(&t));
- printf("\t\tSize: %16lld bytes (%lld MB)\n\t\tUsed: %16lld bytes (%lld MB)\n"
- "\t\tAvailable: %11qd bytes (%d MB)\n",
- (long long) drive.label.drive_size, /* bytes used */
- (long long) (drive.label.drive_size / MEGABYTE),
- (long long) (drive.label.drive_size - drive.sectors_available
- * DEV_BSIZE),
- (long long) (drive.label.drive_size - drive.sectors_available
- * DEV_BSIZE) / MEGABYTE,
- (long long) drive.sectors_available * DEV_BSIZE,
- (int) (drive.sectors_available * DEV_BSIZE / MEGABYTE));
- printf("\t\tState: %s\n", drive_state(drive.state));
- if (drive.lasterror != 0)
- printf("\t\tLast error: %s\n", strerror(drive.lasterror));
- else
- printf("\t\tLast error: none\n");
- printf("\t\tActive requests:\t%d\n\t\tMaximum active:\t\t%d\n",
- drive.active,
- drive.maxactive);
- if (Verbose) { /* print the free list */
- int fe; /* freelist entry */
- struct drive_freelist freelist;
- struct ferq { /* request to pass to ioctl */
- int driveno;
- int fe;
- } *ferq = (struct ferq *) &freelist;
-
- printf("\t\tFree list contains %d entries:\n\t\t Offset\t Size\n",
- drive.freelist_entries);
- for (fe = 0; fe < drive.freelist_entries; fe++) {
- ferq->driveno = drive.driveno;
- ferq->fe = fe;
- if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
- fprintf(stderr,
- "Can't get free list element %d: %s\n",
- fe,
- strerror(errno));
- longjmp(command_fail, -1);
- }
- printf("\t\t%9lld\t%9lld\n",
- (long long) freelist.offset,
- (long long) freelist.sectors);
- }
- }
- } else if (!sflag) {
- printf("D %-21s State: %s\t%s\tA: %lld/%lld MB",
- drive.label.name,
- drive_state(drive.state),
- drive.devicename,
- (long long) drive.sectors_available * DEV_BSIZE / MEGABYTE,
- (long long) (drive.label.drive_size / MEGABYTE));
- if (drive.label.drive_size != 0)
- printf(" (%d%%)",
- (int) ((drive.sectors_available * 100 * DEV_BSIZE)
- / (drive.label.drive_size - (DATASTART * DEV_BSIZE))));
- }
- if (sflag) {
- if (vflag || Verbose) {
- printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n",
- (long long) drive.reads,
- (long long) drive.bytes_read,
- roughlength(drive.bytes_read, 1));
- if (drive.reads != 0)
- printf("\t\tAverage read:\t%16lld bytes\n",
- (long long) drive.bytes_read / drive.reads);
- printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n",
- (long long) drive.writes,
- (long long) drive.bytes_written,
- roughlength(drive.bytes_written, 1));
- if (drive.writes != 0)
- printf("\t\tAverage write:\t%16lld bytes\n",
- (long long) (drive.bytes_written / drive.writes));
- } else { /* non-verbose stats */
- printf("%-15s\t%7lld\t%15lld\t",
- drive.label.name,
- (long long) drive.reads,
- (long long) drive.bytes_read);
- if (drive.reads != 0)
- printf("%7lld\t\t",
- (long long) (drive.bytes_read / drive.reads));
- else
- printf("\t\t");
- printf("%7lld\t%15lld\t",
- (long long) drive.writes,
- (long long) drive.bytes_written);
- if (drive.writes != 0)
- printf("%7lld",
- (long long) (drive.bytes_written / drive.writes));
- }
- }
- if (recurse) {
- printf("\n");
- for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) {
- get_sd_info(&sd, sdno);
- if ((sd.state != sd_unallocated)
- && (sd.driveno == drive.driveno))
- vinum_lsi(sd.sdno, 0);
- }
- }
- printf("\n");
- }
-}
-
-void
-vinum_ld(int argc, char *argv[], char *argv0[])
-{
- int i;
- int driveno;
- enum objecttype type;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- if (argc == 0) {
- for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++)
- vinum_ldi(driveno, recurse);
- } else {
- for (i = 0; i < argc; i++) {
- driveno = find_object(argv[i], &type);
- if (type == drive_object)
- vinum_ldi(driveno, recurse);
- else
- fprintf(stderr, "%s is not a drive\n", argv[i]);
- }
- }
-}
-
-void
-vinum_lvi(int volno, int recurse)
-{
- get_volume_info(&vol, volno);
- if (vol.state != volume_unallocated) {
- if (vflag) {
- printf("Volume %s:\tSize: %lld bytes (%lld MB)\n"
- "\t\tState: %s\n\t\tFlags: %s%s%s\n",
- vol.name,
- ((long long) vol.size) * DEV_BSIZE,
- ((long long) vol.size) * DEV_BSIZE / MEGABYTE,
- volume_state(vol.state),
- vol.flags & VF_OPEN ? "open " : "",
- (vol.flags & VF_WRITETHROUGH ? "writethrough " : ""),
- (vol.flags & VF_RAW ? "raw" : ""));
- printf("\t\t%d plexes\n\t\tRead policy: ", vol.plexes);
- if (vol.preferred_plex < 0) /* round robin */
- printf("round robin\n");
- else {
- get_plex_info(&plex, vol.plex[vol.preferred_plex]);
- printf("plex %d (%s)\n", vol.preferred_plex, plex.name);
- }
- } else if (!sflag) /* brief */
- printf("V %-21s State: %s\tPlexes: %7d\tSize: %s\n",
- vol.name,
- volume_state(vol.state),
- vol.plexes,
- roughlength(vol.size << DEV_BSHIFT, 0));
- if (sflag) {
- if (vflag || Verbose) {
- printf("\t\tReads: \t%16lld\n\t\tRecovered:\t%16lld\n\t\tBytes read:\t%16lld (%s)\n",
- (long long) vol.reads,
- (long long) vol.recovered_reads,
- (long long) vol.bytes_read,
- roughlength(vol.bytes_read, 1));
- if (vol.reads != 0)
- printf("\t\tAverage read:\t%16lld bytes\n",
- (long long) (vol.bytes_read / vol.reads));
- printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n",
- (long long) vol.writes,
- (long long) vol.bytes_written,
- roughlength(vol.bytes_written, 1));
- if (vol.writes != 0)
- printf("\t\tAverage write:\t%16lld bytes\n",
- (long long) (vol.bytes_written / vol.writes));
- printf("\t\tActive requests:\t%8d\n", vol.active);
- } else { /* brief stats listing */
- printf("%-15s\t%7lld\t%15lld\t",
- vol.name,
- (long long) vol.reads,
- (long long) vol.bytes_read);
- if (vol.reads != 0)
- printf("%7lld\t",
- (long long) (vol.bytes_read / vol.reads));
- else
- printf("\t");
- printf("%7lld\t", (long long) vol.recovered_reads);
- printf("%7lld\t%15lld\t",
- (long long) vol.writes,
- vol.bytes_written);
- if (vol.writes != 0)
- printf("%7lld\n",
- (long long) (vol.bytes_written / vol.writes));
- else
- printf("\n");
- }
- }
- if (vol.plexes > 0) {
- int plexno;
- if (Verbose) { /* brief list */
- for (plexno = 0; plexno < vol.plexes; plexno++) {
- get_plex_info(&plex, vol.plex[plexno]);
- /* Just a brief summary here */
- printf("\t\tPlex %2d:\t%s\t(%s), %s\n",
- plexno,
- plex.name,
- plex_org(plex.organization),
- roughlength(plex.length << DEV_BSHIFT, 0));
- }
- }
- if (recurse) {
- for (plexno = 0; plexno < vol.plexes; plexno++)
- vinum_lpi(vol.plex[plexno], 0); /* first show the plexes */
- for (plexno = 0; plexno < vol.plexes; plexno++) { /* then the subdisks */
- get_plex_info(&plex, vol.plex[plexno]);
- if (plex.subdisks > 0) {
- int sdno;
-
- for (sdno = 0; sdno < plex.subdisks; sdno++) {
- get_plex_sd_info(&sd, vol.plex[plexno], sdno);
- vinum_lsi(sd.sdno, 0);
- }
- }
- }
- printf("\n");
- }
- }
- }
-}
-
-void
-vinum_lv(int argc, char *argv[], char *argv0[])
-{
- int i;
- int volno;
- enum objecttype type;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- if (argc == 0)
- for (volno = 0; volno < vinum_conf.volumes_allocated; volno++)
- vinum_lvi(volno, recurse);
- else {
- for (i = 0; i < argc; i++) {
- volno = find_object(argv[i], &type);
- if (type == volume_object)
- vinum_lvi(volno, recurse);
- else
- fprintf(stderr, "%s is not a volume\n", argv[i]);
- }
- }
-}
-
-void
-vinum_lpi(int plexno, int recurse)
-{
- get_plex_info(&plex, plexno);
- if (plex.state != plex_unallocated) {
- if (vflag) {
- printf("Plex %s:\tSize:\t%9lld bytes (%lld MB)\n\t\tSubdisks: %8d\n",
- plex.name,
- (long long) plex.length * DEV_BSIZE,
- (long long) plex.length * DEV_BSIZE / MEGABYTE,
- plex.subdisks);
- printf("\t\tState: %s\n\t\tOrganization: %s",
- plex_state(plex.state),
- plex_org(plex.organization));
- if (isstriped((&plex)))
- printf("\tStripe size: %s\n", roughlength(plex.stripesize * DEV_BSIZE, 1));
- else
- printf("\n");
- if ((isparity((&plex)))
- && (plex.checkblock != 0))
- printf("\t\tCheck block pointer:\t\t%s (%d%%)\n",
- roughlength((plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1), 0),
- (int) (((u_int64_t) (plex.checkblock * 100)) * (plex.subdisks - 1) / plex.length));
- if (plex.volno >= 0) {
- get_volume_info(&vol, plex.volno);
- printf("\t\tPart of volume %s\n", vol.name);
- }
- } else if (!sflag) { /* non-verbose list */
- char *org = ""; /* organization */
-
- switch (plex.organization) {
- case plex_disorg: /* disorganized */
- org = "??";
- break;
- case plex_concat: /* concatenated plex */
- org = "C";
- break;
- case plex_striped: /* striped plex */
- org = "S";
- break;
- case plex_raid4: /* RAID4 plex */
- org = "R4";
- break;
- case plex_raid5: /* RAID5 plex */
- org = "R5";
- break;
- }
- printf("P %-18s %2s State: %s\tSubdisks: %5d\tSize: %s",
- plex.name,
- org,
- plex_state(plex.state),
- plex.subdisks,
- roughlength(plex.length << DEV_BSHIFT, 0));
- }
- if (sflag) {
- if (vflag || Verbose) {
- printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n",
- (long long) plex.reads,
- (long long) plex.bytes_read,
- roughlength(plex.bytes_read, 1));
- if (plex.reads != 0)
- printf("\t\tAverage read:\t%16lld bytes\n",
- (long long) (plex.bytes_read / plex.reads));
- printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n",
- (long long) plex.writes,
- (long long) plex.bytes_written,
- roughlength(plex.bytes_written, 1));
- if (plex.writes != 0)
- printf("\t\tAverage write:\t%16lld bytes\n",
- (long long) (plex.bytes_written / plex.writes));
- if (((plex.reads + plex.writes) > 0)
- && isstriped((&plex)))
- printf("\t\tMultiblock:\t%16lld (%d%%)\n"
- "\t\tMultistripe:\t%16lld (%d%%)\n",
- (long long) plex.multiblock,
- (int) (plex.multiblock * 100 / (plex.reads + plex.writes)),
- (long long) plex.multistripe,
- (int) (plex.multistripe * 100 / (plex.reads + plex.writes)));
- if (plex.recovered_reads)
- printf("\t\tRecovered reads:%16lld\n",
- (long long) plex.recovered_reads);
- if (plex.degraded_writes)
- printf("\t\tDegraded writes:%16lld\n",
- (long long) plex.degraded_writes);
- if (plex.parityless_writes)
- printf("\t\tParityless writes:%14lld\n",
- (long long) plex.parityless_writes);
- } else {
- printf("%-15s\t%7lld\t%15lld\t",
- plex.name,
- (long long) plex.reads,
- (long long) plex.bytes_read);
- if (plex.reads != 0)
- printf("%7lld\t",
- (long long) (plex.bytes_read / plex.reads));
- else
- printf("\t");
- printf("%7lld\t", (long long) plex.recovered_reads);
- printf("%7lld\t%15lld\t",
- (long long) plex.writes,
- (long long) plex.bytes_written);
- if (plex.writes != 0)
- printf("%7lld\t",
- (long long) (plex.bytes_written / plex.writes));
- else
- printf("\t");
- printf("%7lld\t%7lld\n",
- (long long) plex.multiblock,
- (long long) plex.multistripe);
- }
- }
- if (plex.subdisks > 0) {
- int sdno;
-
- if (Verbose) {
- printf("\n");
- for (sdno = 0; sdno < plex.subdisks; sdno++) {
- get_plex_sd_info(&sd, plexno, sdno);
- printf("\t\tSubdisk %d:\t%s\n\t\t state: %s\tsize %11lld (%lld MB)\n",
- sdno,
- sd.name,
- sd_state(sd.state),
- (long long) sd.sectors * DEV_BSIZE,
- (long long) sd.sectors * DEV_BSIZE / MEGABYTE);
- if (plex.organization == plex_concat)
- printf("\t\t\toffset %9ld (0x%lx)\n",
- (long) sd.plexoffset,
- (long) sd.plexoffset);
- }
- }
- if (recurse) {
- printf("\n");
- for (sdno = 0; sdno < plex.subdisks; sdno++) {
- get_plex_sd_info(&sd, plexno, sdno);
- vinum_lsi(sd.sdno, 0);
- }
- }
- }
- printf("\n");
- }
-}
-
-void
-vinum_lp(int argc, char *argv[], char *argv0[])
-{
- int i;
- int plexno;
- enum objecttype type;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- if (argc == 0) {
- for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++)
- vinum_lpi(plexno, recurse);
- } else {
- for (i = 0; i < argc; i++) {
- plexno = find_object(argv[i], &type);
- if (type == plex_object)
- vinum_lpi(plexno, recurse);
- else
- fprintf(stderr, "%s is not a plex\n", argv[i]);
- }
- }
-}
-
-void
-vinum_lsi(int sdno, int recurse)
-{
- long long revived; /* keep an eye on revive progress */
- int times;
-
- get_sd_info(&sd, sdno);
- if (sd.state != sd_unallocated) {
- get_drive_info(&drive, sd.driveno);
-
- if (vflag) {
- printf("Subdisk %s:\n\t\tSize: %16lld bytes (%lld MB)\n\t\tState: %s\n",
- sd.name,
- (long long) sd.sectors * DEV_BSIZE,
- (long long) sd.sectors / (MEGABYTE / DEV_BSIZE),
- sd_state(sd.state));
- if (sd.flags & VF_RETRYERRORS)
- printf("\t\tretryerrors\n");
- if (sd.plexno >= 0) {
- get_plex_info(&plex, sd.plexno);
- printf("\t\tPlex %s", plex.name);
- printf(" at offset %lld (%s)\n",
- (long long) sd.plexoffset * DEV_BSIZE,
- roughlength((long long) sd.plexoffset * DEV_BSIZE, 1));
- }
- if (sd.state == sd_reviving) {
- if (sd.reviver == 0)
- printf("\t\t*** Start subdisk with 'start' command ***\n");
- else {
- printf("\t\tReviver PID:\t%d\n", sd.reviver);
- if (kill(sd.reviver, 0) == -1) {
- if (errno == ESRCH) /* no process */
- printf("\t\t*** Revive process has died ***\n");
- /* Don't report a problem that "can't happen" */
- } else {
- revived = sd.revived; /* note how far we were */
-
- /*
- * Wait for up to a second until we
- * see some progress with the revive.
- * Do it like this so we don't have
- * annoying delays in the listing.
- */
- for (times = 0; times < STALLCOUNT; times++) {
- get_sd_info(&sd, sdno);
- if (sd.revived != revived) /* progress? */
- break;
- usleep(50000);
- }
- if (times == STALLCOUNT)
- printf("\t\t*** Revive has stalled ***\n");
- }
- }
- printf("\t\tRevive pointer:\t\t%s (%d%%)\n",
- roughlength(sd.revived << DEV_BSHIFT, 0),
- (int) (((u_int64_t) (sd.revived * 100)) / sd.sectors));
- printf("\t\tRevive blocksize:\t%s\n"
- "\t\tRevive interval:\t%10d seconds\n",
- roughlength(sd.revive_blocksize, 0),
- sd.revive_interval);
- }
- if (sd.state == sd_initializing) {
- printf("\t\tInitialize pointer:\t%s (%d%%)\n",
- roughlength(sd.initialized << DEV_BSHIFT, 0),
- (int) (((u_int64_t) (sd.initialized * 100)) / sd.sectors));
- printf("\t\tInitialize blocksize:\t%s\n"
- "\t\tInitialize interval:\t%10d seconds\n",
- roughlength(sd.init_blocksize, 0),
- sd.init_interval);
- }
- if (sd.driveoffset < 0)
- printf("\t\tDrive %s (%s), no offset\n",
- drive.label.name,
- drive.devicename);
- else if (drive.devicename[0] != '\0') /* has a name */
- printf("\t\tDrive %s (%s) at offset %lld (%s)\n",
- drive.label.name,
- drive.devicename,
- (long long) (sd.driveoffset * DEV_BSIZE),
- roughlength(sd.driveoffset * DEV_BSIZE, 1));
- else
- printf("\t\tDrive %s (*missing*) at offset %lld (%s)\n",
- drive.label.name,
- (long long) (sd.driveoffset * DEV_BSIZE),
- roughlength(sd.driveoffset * DEV_BSIZE, 1));
- } else if (!sflag) { /* brief listing, no stats */
- if (sd.state == sd_reviving)
- printf("S %-21s State: R %d%%\t",
- sd.name,
- (int) (((u_int64_t) (sd.revived * 100)) / sd.sectors));
- else if (sd.state == sd_initializing)
- printf("S %-21s State: I %d%%\t",
- sd.name,
- (int) (((u_int64_t) (sd.initialized * 100)) / sd.sectors));
- else
- printf("S %-21s State: %s\t",
- sd.name,
- sd_state(sd.state));
- printf("D: %-12s Size: %s\n",
- drive.label.name,
- roughlength(sd.sectors << DEV_BSHIFT, 0));
- if (sd.state == sd_reviving) {
- if (sd.reviver == 0)
- printf("\t\t\t*** Start %s with 'start' command ***\n",
- sd.name);
- else if (kill(sd.reviver, 0) == -1) {
- if (errno == ESRCH) /* no process */
- printf("\t\t\t*** Revive process for %s has died ***\n",
- sd.name);
- /* Don't report a problem that "can't happen" */
- } else {
- revived = sd.revived; /* note how far we were */
-
- /*
- * Wait for up to a second until we
- * see some progress with the revive.
- * Do it like this so we don't have
- * annoying delays in the listing.
- */
- for (times = 0; times < STALLCOUNT; times++) {
- get_sd_info(&sd, sdno);
- if (sd.revived != revived) /* progress? */
- break;
- usleep(50000);
- }
- if (times == STALLCOUNT)
- printf("\t\t\t*** Revive of %s has stalled ***\n",
- sd.name);
- }
- }
- }
- if (sflag) {
- if (vflag || Verbose) {
- printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n",
- (long long) sd.reads,
- (long long) sd.bytes_read,
- roughlength(sd.bytes_read, 1));
- if (sd.reads != 0)
- printf("\t\tAverage read:\t%16lld bytes\n",
- (long long) (sd.bytes_read / sd.reads));
- printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n",
- (long long) sd.writes,
- (long long) sd.bytes_written,
- roughlength(sd.bytes_written, 1));
- if (sd.writes != 0)
- printf("\t\tAverage write:\t%16lld bytes\n",
- (long long) (sd.bytes_written / sd.writes));
- } else {
- printf("%-15s\t%7lld\t%15lld\t",
- sd.name,
- (long long) sd.reads,
- (long long) sd.bytes_read);
- if (sd.reads != 0)
- printf("%7lld\t\t",
- (long long) (sd.bytes_read / sd.reads));
- else
- printf("\t\t");
- printf("%7lld\t%15lld\t",
- (long long) sd.writes,
- (long long) sd.bytes_written);
- if (sd.writes != 0)
- printf("%7lld\n",
- (long long) (sd.bytes_written / sd.writes));
- else
- printf("\n");
- }
- }
- if (recurse)
- vinum_ldi(sd.driveno, 0);
- if (vflag)
- printf("\n"); /* make it more readable */
- }
-}
-
-void
-vinum_ls(int argc, char *argv[], char *argv0[])
-{
- int i;
- int sdno;
-
- /* Structures to read kernel data into */
- struct __vinum_conf vinum_conf;
- enum objecttype type;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- if (argc == 0) {
- for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++)
- vinum_lsi(sdno, recurse);
- } else { /* specific subdisks */
- for (i = 0; i < argc; i++) {
- sdno = find_object(argv[i], &type);
- if (type == sd_object)
- vinum_lsi(sdno, recurse);
- else
- fprintf(stderr, "%s is not a subdisk\n", argv[i]);
- }
- }
-}
-
-
-/* List the complete configuration.
-
- * XXX Change this to specific lists */
-void
-listconfig()
-{
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- printf("%d drives:\n", vinum_conf.drives_used);
- if (vinum_conf.drives_used > 0) {
- vinum_ld(0, NULL, NULL);
- printf("\n");
- }
- printf("%d volumes:\n", vinum_conf.volumes_used);
- if (vinum_conf.volumes_used > 0) {
- vinum_lv(0, NULL, NULL);
- printf("\n");
- }
- printf("%d plexes:\n", vinum_conf.plexes_used);
- if (vinum_conf.plexes_used > 0) {
- vinum_lp(0, NULL, NULL);
- printf("\n");
- }
- printf("%d subdisks:\n", vinum_conf.subdisks_used);
- if (vinum_conf.subdisks_used > 0)
- vinum_ls(0, NULL, NULL);
-}
-
-/* Convert a timeval to Tue Oct 13 13:54:14.0434324
- * Return pointer to text */
-char *
-timetext(struct timeval *time)
-{
- static char text[30];
- time_t t; /* to keep Bruce happy */
-
- t = time->tv_sec;
- strcpy(text, ctime(&t)); /* to the second */
- sprintf(&text[19], ".%06ld", time->tv_usec); /* and the microseconds */
- return &text[11];
-}
-
-/* Return the difference in microseconds between two timevals. */
-inline struct timeval
-timediff(struct timeval then, struct timeval now)
-{
- struct timeval diff;
-
- diff.tv_sec = now.tv_sec - then.tv_sec;
- diff.tv_usec = now.tv_usec - then.tv_usec;
- if (diff.tv_usec < 0) {
- diff.tv_usec += 1000000;
- diff.tv_sec--;
- }
- return diff;
-}
-
-void
-vinum_info(int argc, char *argv[], char *argv0[])
-{
- struct meminfo meminfo;
- struct mc malloced;
- int i;
- struct rqinfo rq;
- struct timeval lasttime; /* time of previous request */
- struct timeval diff; /* difference from now */
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- if ((vinum_conf.flags & VF_HASDEBUG) == 0)
- fprintf(stderr, "Kernel module does not have debug support\n");
- else {
- printf("Flags: 0x%x\n", vinum_conf.flags);
- if (ioctl(superdev, VINUM_MEMINFO, &meminfo) < 0) {
- perror("Can't get information");
- return;
- }
- printf("Total of %d blocks malloced, total memory: %d\n"
- "Maximum allocs: %8d, malloc table at 0x%08lx\n",
- meminfo.mallocs,
- meminfo.total_malloced,
- meminfo.highwater,
- (unsigned long) meminfo.malloced);
-
- printf("%d requests active, maximum %d active\n",
- vinum_conf.active,
- vinum_conf.maxactive);
- if (vflag && (!Verbose))
- for (i = 0; i < meminfo.mallocs; i++) {
- malloced.seq = i;
- if (ioctl(superdev, VINUM_MALLOCINFO, &malloced) < 0) {
- perror("Can't get information");
- return;
- }
- if (!(i & 63))
- printf("Block\tSequence\t size\t address\t line\t\tfile\n\n");
- printf("%6d\t%6d\t\t%6d\t0x%08lx\t%6d\t\t%s\n",
- i,
- malloced.seq,
- malloced.size,
- (unsigned long) malloced.address,
- malloced.line,
- (char *) &malloced.file);
- }
- if (Verbose) {
- if (Verbose > 1) {
- lasttime.tv_sec = 0;
- lasttime.tv_usec = 0;
- printf("\n Time\t\t Event\t Buf\tDev\t Offset\t"
- "Bytes\tSD\tSDoff\tDoffset\tGoffset\n\n");
- } else
- printf("\nTime\t\t Event\t Buf\tDev\t Offset\tBytes\tSD"
- "\tSDoff\tDoffset\tGoffset\n\n");
- for (i = RQINFO_SIZE - 1; i >= 0; i--) { /* go through the request list in order */
- *((int *) &rq) = i;
- if (ioctl(superdev, VINUM_RQINFO, &rq) < 0) {
- perror("Can't get information");
- return;
- }
- if (rq.type != loginfo_unused) {
- switch (Verbose) {
- case 2:
- if ((lasttime.tv_usec != 0) || (lasttime.tv_sec != 0)) {
- diff = timediff(lasttime, rq.timestamp);
- if (diff.tv_sec != 0)
- printf("\n+ %d.%06d sec:\n ", diff.tv_sec, diff.tv_usec);
- else
- printf("+%6d µs ", diff.tv_usec);
- } else
- printf(" ");
- break;
-
- case 3:
- if ((lasttime.tv_usec != 0) || (lasttime.tv_sec != 0))
- diff = timediff(lasttime, rq.timestamp);
- if (diff.tv_sec != 0)
- printf("\n+ %d.%06d sec:\n ", diff.tv_sec, diff.tv_usec);
- else if (rq.type == loginfo_iodone) {
- diff = timediff(rq.info.rqe.launchtime, rq.timestamp);
- printf("+%6d µs ",
- diff.tv_usec);
- } else
- printf(" ");
- break;
-
- default:
- break;
- }
-
- /* Compress devminor into something printable. */
- rq.devminor = (rq.devminor & 0xff)
- | ((rq.devminor & 0xfff0000) >> 8);
- switch (rq.type) {
- case loginfo_user_bp: /* this is the bp when strategy is called */
- printf("%s %dVS %s %p\t%2d.%-6d 0x%9llx\t%d\n",
- timetext(&rq.timestamp),
- rq.type,
- rq.info.b.b_iocmd == BIO_READ ? "Read " : "Write",
- rq.bp,
- rq.devmajor,
- rq.devminor,
- rq.info.b.b_blkno,
- rq.info.b.b_bcount);
- break;
-
- case loginfo_sdiol: /* subdisk I/O launch */
- case loginfo_user_bpl: /* and this is the bp at launch time */
- printf("%s %dLR %s %p\t%2d.%-6d 0x%9llx\t%ld\n",
- timetext(&rq.timestamp),
- rq.type,
- rq.info.b.b_iocmd == BIO_READ ? "Read " : "Write",
- rq.bp,
- rq.devmajor,
- rq.devminor,
- rq.info.b.b_blkno,
- rq.info.b.b_bcount);
- break;
-
- case loginfo_rqe: /* user RQE */
- /*
- * We have two timestamps
- * in this request, and
- * they might not agree by
- * one or two µs. Make
- * them agree by force.
- */
- rq.timestamp = rq.info.rqe.launchtime;
- printf("%s 3RQ %s %p\t%2d.%-6d 0x%9llx\t%ld\t%d\t%6x\t%6x\t%x\n",
- timetext(&rq.timestamp),
- rq.info.rqe.b.b_iocmd == BIO_READ ? "Read " : "Write",
- rq.bp,
- rq.devmajor,
- rq.devminor,
- rq.info.rqe.b.b_blkno,
- rq.info.rqe.b.b_bcount,
- rq.info.rqe.sdno,
- rq.info.rqe.sdoffset,
- rq.info.rqe.dataoffset,
- rq.info.rqe.groupoffset);
- break;
-
- case loginfo_iodone: /* iodone called */
- printf("%s 4DN %s %p\t%2d.%-6d 0x%9llx\t%ld\t%d\t%6x\t%6x\t%x\n",
- timetext(&rq.timestamp),
- rq.info.rqe.b.b_iocmd == BIO_READ ? "Read " : "Write",
- rq.bp,
- rq.devmajor,
- rq.devminor,
- rq.info.rqe.b.b_blkno,
- rq.info.rqe.b.b_bcount,
- rq.info.rqe.sdno,
- rq.info.rqe.sdoffset,
- rq.info.rqe.dataoffset,
- rq.info.rqe.groupoffset);
- break;
-
- case loginfo_raid5_data: /* RAID-5 write data block */
- printf("%s 5RD %s %p\t%2d.%-6d 0x%9llx\t%ld\t%d\t%6x\t%6x\t%x\n",
- timetext(&rq.timestamp),
- rq.info.rqe.b.b_iocmd == BIO_READ ? "Read " : "Write",
- rq.bp,
- rq.devmajor,
- rq.devminor,
- rq.info.rqe.b.b_blkno,
- rq.info.rqe.b.b_bcount,
- rq.info.rqe.sdno,
- rq.info.rqe.sdoffset,
- rq.info.rqe.dataoffset,
- rq.info.rqe.groupoffset);
- break;
-
- case loginfo_raid5_parity: /* RAID-5 write parity block */
- printf("%s 6RP %s %p\t%2d.%-6d 0x%9llx\t%ld\t%d\t%6x\t%6x\t%x\n",
- timetext(&rq.timestamp),
- rq.info.rqe.b.b_iocmd == BIO_READ ? "Read " : "Write",
- rq.bp,
- rq.devmajor,
- rq.devminor,
- rq.info.rqe.b.b_blkno,
- rq.info.rqe.b.b_bcount,
- rq.info.rqe.sdno,
- rq.info.rqe.sdoffset,
- rq.info.rqe.dataoffset,
- rq.info.rqe.groupoffset);
- break;
-
- case loginfo_sdio: /* subdisk I/O */
- printf("%s %dVS %s %p\t\t 0x%9llx\t%ld\t%d\n",
- timetext(&rq.timestamp),
- rq.type,
- rq.info.b.b_iocmd == BIO_READ ? "Read " : "Write",
- rq.bp,
- rq.info.b.b_blkno,
- rq.info.b.b_bcount,
- rq.devminor);
- break;
-
- case loginfo_sdiodone: /* subdisk I/O done */
- printf("%s %dSD %s %p\t\t 0x%9llx\t%ld\t%d\n",
- timetext(&rq.timestamp),
- rq.type,
- rq.info.b.b_iocmd == BIO_READ ? "Read " : "Write",
- rq.bp,
- rq.info.b.b_blkno,
- rq.info.b.b_bcount,
- rq.devminor);
- break;
-
- case loginfo_lockwait:
- printf("%s Lockwait %p\t 0x%x\n",
- timetext(&rq.timestamp),
- rq.bp,
- rq.info.lockinfo.stripe);
- break;
-
- case loginfo_lock:
- printf("%s Lock %p\t 0x%x\n",
- timetext(&rq.timestamp),
- rq.bp,
- rq.info.lockinfo.stripe);
- break;
-
- case loginfo_unlock:
- printf("%s Unlock\t %p\t 0x%x\n",
- timetext(&rq.timestamp),
- rq.bp,
- rq.info.lockinfo.stripe);
- break;
- default:
- printf("*** invalid log type: %d ***\n", rq.type);
- }
- if (Verbose > 1)
- lasttime = rq.timestamp;
- }
- }
- }
- }
-}
-
-/*
- * Print config file to a file. This is a userland version
- * of kernel format_config
- */
-void
-vinum_printconfig(int argc, char *argv[], char *argv0[])
-{
- FILE *of;
-
- if (argc > 1) {
- fprintf(stderr, "usage: \tprintconfig [<outfile>]\n");
- return;
- } else if (argc == 1)
- of = fopen(argv[0], "w");
- else
- of = stdout;
- if (of == NULL) {
- fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno));
- return;
- }
- printconfig(of, "");
- if (argc == 1)
- fclose(of);
-}
-
-/*
- * The guts of printconfig. This is called from
- * vinum_printconfig and from vinum_create when
- * called without an argument, in order to give
- * the user something to edit.
- */
-void
-printconfig(FILE * of, char *comment)
-{
- struct utsname uname_s;
- time_t now;
- int i;
- struct _volume vol;
- struct _plex plex;
- struct _sd sd;
- struct _drive drive;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- uname(&uname_s); /* get our system name */
- time(&now); /* and the current time */
- fprintf(of,
- "# Vinum configuration of %s, saved at %s",
- uname_s.nodename,
- ctime(&now)); /* say who did it */
-
- if (comment[0] != 0) /* abuse this for commented version */
- fprintf(of, "# Current configuration:\n");
- for (i = 0; i < vinum_conf.drives_allocated; i++) {
- get_drive_info(&drive, i);
- if (drive.state != drive_unallocated) {
- fprintf(of,
- "%sdrive %s device %s\n",
- comment,
- drive.label.name,
- drive.devicename);
- }
- }
-
- for (i = 0; i < vinum_conf.volumes_allocated; i++) {
- get_volume_info(&vol, i);
- if (vol.state != volume_unallocated) {
- if (vol.preferred_plex >= 0) { /* preferences, */
- get_plex_info(&plex, vol.plex[vol.preferred_plex]);
- fprintf(of,
- "%svolume %s readpol prefer %s\n",
- comment,
- vol.name,
- plex.name);
- } else /* default round-robin */
- fprintf(of, "%svolume %s\n", comment, vol.name);
- }
- }
-
- /* Then the plex configuration */
- for (i = 0; i < vinum_conf.plexes_allocated; i++) {
- get_plex_info(&plex, i);
- if (plex.state != plex_unallocated) {
- fprintf(of, "%splex name %s org %s ",
- comment,
- plex.name,
- plex_org(plex.organization));
- if (isstriped((&plex)))
- fprintf(of, "%ds ", (int) plex.stripesize);
- if (plex.volno >= 0) { /* we have a volume */
- get_volume_info(&vol, plex.volno);
- fprintf(of, "vol %s ", vol.name);
- if ((vol.preferred_plex >= 0) /* has a preferred plex */
- &&vol.plex[vol.preferred_plex] == i) /* and it's us */
- fprintf(of, "preferred ");
- } else
- fprintf(of, "detached ");
- fprintf(of, "\n");
- }
- }
-
- /* And finally the subdisk configuration */
- for (i = 0; i < vinum_conf.subdisks_allocated; i++) {
- get_sd_info(&sd, i);
- if (sd.state != sd_unallocated) {
- get_drive_info(&drive, sd.driveno);
- if (sd.plexno >= 0) {
- get_plex_info(&plex, sd.plexno);
- fprintf(of,
- "%ssd name %s drive %s plex %s len %llds driveoffset %llds plexoffset %llds\n",
- comment,
- sd.name,
- drive.label.name,
- plex.name,
- (long long) sd.sectors,
- (long long) sd.driveoffset,
- (long long) sd.plexoffset);
- } else
- fprintf(of,
- "%ssd name %s drive %s detached len %llds driveoffset %llds\n",
- comment,
- sd.name,
- drive.label.name,
- (long long) sd.sectors,
- (long long) sd.driveoffset);
- }
- }
-}
-
-void
-list_defective_objects()
-{
- int o; /* object */
- int heading_needed = 1;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return;
- }
- for (o = 0; o < vinum_conf.drives_allocated; o++) {
- get_drive_info(&drive, o);
- if ((drive.state != drive_unallocated) /* drive exists */
- &&(drive.state != drive_up)) { /* but it's not up */
- if (heading_needed) {
- printf("Warning: defective objects\n\n");
- heading_needed = 0;
- }
- vinum_ldi(o, 0); /* print info */
- }
- }
-
- for (o = 0; o < vinum_conf.volumes_allocated; o++) {
- get_volume_info(&vol, o);
- if ((vol.state != volume_unallocated) /* volume exists */
- &&(vol.state != volume_up)) { /* but it's not up */
- if (heading_needed) {
- printf("Warning: defective objects\n\n");
- heading_needed = 0;
- }
- vinum_lvi(o, 0); /* print info */
- }
- }
-
- for (o = 0; o < vinum_conf.plexes_allocated; o++) {
- get_plex_info(&plex, o);
- if ((plex.state != plex_unallocated) /* plex exists */
- &&(plex.state != plex_up)) { /* but it's not up */
- if (heading_needed) {
- printf("Warning: defective objects\n\n");
- heading_needed = 0;
- }
- vinum_lpi(o, 0); /* print info */
- }
- }
-
- for (o = 0; o < vinum_conf.subdisks_allocated; o++) {
- get_sd_info(&sd, o);
- if ((sd.state != sd_unallocated) /* sd exists */
- &&(sd.state != sd_up)) { /* but it's not up */
- if (heading_needed) {
- printf("Warning: defective objects\n\n");
- heading_needed = 0;
- }
- vinum_lsi(o, 0); /* print info */
- }
- }
-}
-
-/* Dump config from specified disk drives */
-void
-vinum_dumpconfig(int argc, char *argv[], char *argv0[])
-{
- int i;
-
- if (argc == 0) { /* dump everything */
- int devs = devstat_getnumdevs(NULL);
- struct statinfo statinfo;
- char *namelist;
- char *enamelist; /* end of name list */
- int i;
- char **token; /* list of tokens */
- int tokens; /* and their number */
-
- bzero(&statinfo, sizeof(struct statinfo));
- statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
- namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
- token = malloc((devs + 1) * sizeof(char *));
- if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
- fprintf(stderr, "Can't allocate memory for drive list\n");
- return;
- }
- bzero(statinfo.dinfo, sizeof(struct devinfo));
-
- tokens = 0; /* no tokens yet */
- if (devstat_getdevs(NULL, &statinfo) < 0) { /* find out what devices we have */
- perror("Can't get device list");
- return;
- }
- namelist[0] = '\0'; /* start with empty namelist */
- enamelist = namelist; /* point to the end of the list */
-
- for (i = 0; i < devs; i++) {
- struct devstat *stat = &statinfo.dinfo->devices[i];
-
- if (((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
- &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
- &&((stat->device_name[0] != '\0'))) { /* and it has a name */
- sprintf(enamelist, "/dev/%s%d", stat->device_name, stat->unit_number);
- token[tokens] = enamelist; /* point to it */
- tokens++; /* one more token */
- enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
- }
- }
- free(statinfo.dinfo); /* don't need the list any more */
- for (i = 0; i < tokens; i++)
- dumpconfig(token[i]);
- free(namelist);
- free(token);
- } else { /* list specified drives */
- for (i = 0; i < argc; i++)
- dumpconfig(argv[i]);
- }
-}
-
-#define DEVLEN 5
-void
-dumpconfig(char *part)
-{
- char partname[MAXPATHLEN];
- char *partid;
- char partition; /* UNIX partition */
- int slice;
- int founddrive; /* flag when we find a vinum drive */
- struct disklabel label; /* label of this drive */
- int driveno; /* fd of drive */
- int found;
- u_int64_t drivelength;
-
- if (memcmp(part, "/dev/", DEVLEN) == 0) /* starts with /dev */
- memcpy(partname, part, MAXPATHLEN);
- else { /* prepend */
- strcpy(partname, "/dev/");
- strncat(&partname[DEVLEN], part, MAXPATHLEN - DEVLEN);
- }
- partid = &partname[strlen(partname)];
- founddrive = 0; /* no vinum drive found yet on this spindle */
- /* first try the partition table */
- for (slice = 1; slice < 5; slice++) {
- sprintf(partid, "s%dc", slice); /* c partition */
- driveno = open(partname, O_RDONLY);
- if (driveno < 0) {
- if (errno != ENOENT)
- fprintf(stderr, "Can't open %s: %s (%d)\n", partname, strerror(errno), errno);
- continue;
- }
- if (ioctl(driveno, DIOCGDINFO, &label) < 0) {
- if ((errno != EINVAL) || vflag)
- fprintf(stderr, "Can't get label from %s: %s (%d)\n", partname, strerror(errno), errno);
- continue;
- }
- for (partition = 'a'; partition < 'i'; partition++) {
- if ((partition != 'c') /* it's not the c partition */
- &&((label.d_partitions[partition - 'a'].p_fstype == FS_VINUM) /* and it's a Vinum partition */
- ||Verbose)) { /* or we're just plain curious */
- sprintf(partid, "s%d%c", slice, partition);
- found = check_drive(partname); /* try to open it */
- founddrive |= found; /* and note if we were successful at all */
- if (label.d_partitions[partition - 'a'].p_fstype == FS_VINUM) { /* it's a Vinum partition */
- drivelength = ((u_int64_t) label.d_partitions[partition - 'a'].p_size) * DEV_BSIZE;
- printf("Drive %s: %s (%lld bytes)\n",
- partname,
- roughlength(drivelength, 1),
- drivelength);
- if ((!found) && vflag) /* we're talkative */
- printf("*** no configuration found ***\n");
- }
- }
- }
- }
- if (founddrive == 0) { /* didn't find anything, */
- sprintf(partid, "c"); /* c partition */
- driveno = open(partname, O_RDONLY);
- if (driveno < 0) {
- if (errno != ENOENT)
- fprintf(stderr, "Can't open %s: %s (%d)\n", partname, strerror(errno), errno);
- return;
- }
- if (ioctl(driveno, DIOCGDINFO, &label) < 0) {
- fprintf(stderr, "Can't get label from %s: %s (%d)\n", partname, strerror(errno), errno);
- return;
- }
- for (partition = 'a'; partition < 'i'; partition++) { /* try the compatibility partition */
- if ((partition != 'c') /* it's not the c partition */
- &&((label.d_partitions[partition - 'a'].p_fstype == FS_VINUM) /* and it's a Vinum partition */
- ||Verbose)) { /* or we're just plain curious */
- sprintf(partid, "%c", partition);
- found = check_drive(partname); /* try to open it */
- founddrive |= found; /* and note if we were successful at all */
- if (label.d_partitions[partition - 'a'].p_fstype == FS_VINUM) { /* it's a Vinum partition */
- drivelength = ((u_int64_t) label.d_partitions[partition - 'a'].p_size) * DEV_BSIZE;
- printf("Drive %s: %s (%lld bytes)\n",
- partname,
- roughlength(drivelength, 1),
- drivelength);
- if ((!found) && vflag) /* we're talkative */
- printf("*** no configuration found ***\n");
- }
- }
- }
- }
-}
-
-/*
- * Check a drive for a Vinum header. If found,
- * print configuration information from the drive.
- *
- * Return 1 if Vinum config found.
- */
-int
-check_drive(char *devicename)
-{
- int fd;
- char vinumlabel[DEV_BSIZE]; /* one sector for label */
- struct vinum_hdr *hdr = (struct vinum_hdr *) vinumlabel; /* with this structure */
- char *config_text; /* read the config info from disk into here */
- time_t t;
-
- fd = open(devicename, O_RDONLY);
- if (fd >= 0) {
- if (lseek(fd, VINUM_LABEL_OFFSET, SEEK_SET) < 0) {
- fprintf(stderr,
- "Can't seek label for %s: %s (%d)\n",
- devicename,
- strerror(errno),
- errno);
- close(fd);
- return 0;
- }
- if (read(fd, vinumlabel, DEV_BSIZE) != DEV_BSIZE) {
- if (errno != EINVAL)
- fprintf(stderr,
- "Can't read label from %s: %s (%d)\n",
- devicename,
- strerror(errno),
- errno);
- close(fd);
- return 0;
- }
- if ((hdr->magic == VINUM_MAGIC)
- || (vflag && (hdr->magic == VINUM_NOMAGIC))) {
- printf("Drive %s:\tDevice %s\n",
- hdr->label.name,
- devicename);
- if (hdr->magic == VINUM_NOMAGIC)
- printf("*** Drive has been obliterated ***\n");
- t = hdr->label.date_of_birth.tv_sec;
- printf("\t\tCreated on %s at %s",
- hdr->label.sysname,
- ctime(&t));
- t = hdr->label.last_update.tv_sec;
- printf("\t\tConfig last updated %s", /* care: \n at end */
- ctime(&t));
- printf("\t\tSize: %16lld bytes (%lld MB)\n",
- (long long) hdr->label.drive_size, /* bytes used */
- (long long) (hdr->label.drive_size / MEGABYTE));
- config_text = (char *) malloc(MAXCONFIG);
- if (config_text == NULL)
- fprintf(stderr, "Can't allocate memory\n");
- else {
- if (read(fd, config_text, MAXCONFIG) != MAXCONFIG)
- fprintf(stderr,
- "Can't read config from %s: %s (%d)\n",
- devicename,
- strerror(errno),
- errno);
- else
- puts(config_text);
- free(config_text);
- }
- }
- close(fd);
- return 1;
- }
- return 0;
-}
-
-int
-checkupdates()
-{
- int options;
-
- if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
- fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
- if (options & daemon_noupdate) {
- fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n");
- return 1;
- } else
- return 0;
-}
-
-/* Local Variables: */
-/* fill-column: 50 */
-/* End: */
diff --git a/sbin/vinum/v.c b/sbin/vinum/v.c
deleted file mode 100644
index e00f734..0000000
--- a/sbin/vinum/v.c
+++ /dev/null
@@ -1,685 +0,0 @@
-/* vinum.c: vinum interface program */
-/*-
- * Copyright (c) 1997, 1998
- * Nan Yang Computer Services Limited. All rights reserved.
- *
- * Written by Greg Lehey
- *
- * This software is distributed under the so-called ``Berkeley
- * License'':
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Nan Yang Computer
- * Services Limited.
- * 4. Neither the name of the Company nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * This software is provided ``as is'', and any express or implied
- * warranties, including, but not limited to, the implied warranties of
- * merchantability and fitness for a particular purpose are disclaimed.
- * In no event shall the company or contributors be liable for any
- * direct, indirect, incidental, special, exemplary, or consequential
- * damages (including, but not limited to, procurement of substitute
- * goods or services; loss of use, data, or profits; or business
- * interruption) however caused and on any theory of liability, whether
- * in contract, strict liability, or tort (including negligence or
- * otherwise) arising in any way out of the use of this software, even if
- * advised of the possibility of such damage.
- *
- * $Id: v.c,v 1.38 2003/05/01 01:39:42 grog Exp $
- * $FreeBSD$
- */
-
-#include "vext.h"
-
-FILE *cf; /* config file handle */
-FILE *History; /* history file */
-char *historyfile; /* and its name */
-
-char *dateformat; /* format in which to store date */
-
-char buffer[BUFSIZE]; /* buffer to read in to */
-
-int line = 0; /* stdin line number for error messages */
-int file_line = 0; /* and line in input file (yes, this is tacky) */
-int inerror; /* set to 1 to exit after end of config file */
-
-/* flags */
-
-int debug = 0; /* debug flag, usage varies */
-int force = 0; /* set to 1 to force some dangerous ops */
-int interval = 0; /* interval in ms between init/revive */
-int vflag = 0; /* set verbose operation or verify */
-int Verbose = 0; /* set very verbose operation */
-int recurse = 0; /* set recursion */
-int sflag = 0; /* show statistics */
-int SSize = 0; /* sector size for revive */
-int dowait = 0; /* wait for completion */
-char *objectname; /* name to be passed for -n flag */
-
-/*
- * Structures to read kernel data into. These are shortened versions
- * of the kernel data structures, without the bits and pieces we
- * shouldn't be using.
- */
-struct __vinum_conf vinum_conf; /* configuration information */
-struct _volume vol;
-struct _plex plex;
-struct _sd sd;
-struct _drive drive;
-
-jmp_buf command_fail; /* return on a failed command */
-int superdev; /* vinum super device */
-gid_t gid_operator; /* group operator for chown */
-#define GROUP_OPERATOR "operator"
-#define UID_ROOT 0 /* no need to lookup... */
-
-void start_daemon(void);
-
-#define ofs(x) ((void *) (& ((struct confdata *) 0)->x)) /* offset of x in struct confdata */
-
-char *token[MAXARGS]; /* pointers to individual tokens */
-int tokens; /* number of tokens */
-
-int
-main(int argc, char *argv[], char *envp[])
-{
- struct stat histstat;
- struct group *g;
-
- if (modfind(VINUMMOD) < 0) {
- /* need to load the vinum module */
- if (kldload(VINUMMOD) < 0 || modfind(VINUMMOD) < 0) {
- perror(VINUMMOD ": Kernel module not available");
- return 1;
- }
- }
- dateformat = getenv("VINUM_DATEFORMAT");
- if (dateformat == NULL)
- dateformat = "%e %b %Y %H:%M:%S";
- historyfile = getenv("VINUM_HISTORY");
- if (historyfile == NULL)
- historyfile = DEFAULT_HISTORYFILE;
- if (stat(historyfile, &histstat) == 0) { /* history file exists */
- if ((histstat.st_mode & S_IFMT) != S_IFREG) {
- fprintf(stderr,
- "Vinum history file %s must be a regular file\n",
- historyfile);
- exit(1);
- }
- } else if ((errno != ENOENT) /* not "not there", */
- &&(errno != EROFS)) { /* and not read-only file system */
- fprintf(stderr,
- "Can't open %s: %s (%d)\n",
- historyfile,
- strerror(errno),
- errno);
- exit(1);
- }
- History = fopen(historyfile, "a+");
- if (History != NULL) {
- timestamp();
- fprintf(History, "*** " VINUMMOD " started ***\n");
- fflush(History); /* before we start the daemon */
- }
- superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* open vinum superdevice */
- if (superdev < 0) { /* no go */
- perror("Can't open " VINUM_SUPERDEV_NAME);
- return 1;
- }
- /*
- * Check that we match the kernel version. There are a number of
- * possibilities here:
- *
- * 0: The versions are OK.
- * 1: The kernel module could be a pre-version 1 module, which
- * doesn't include this check. In that case, vinum_conf will be too
- * short, and so we'll get an EINVAL back when trying to get it. In
- * this case we'll fake a 0 in the version.
- * 2: The module versions are different. Print appropriate messages
- * and die.
- */
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- if (errno == EINVAL) /* wrong length, */
- vinum_conf.version = 0; /* must be the old version */
- else {
- perror("Can't get vinum config");
- return 1;
- }
- }
- if (vinum_conf.version != VINUMVERSION) {
- fprintf(stderr,
- "Version mismatch. The kernel module is version %d of Vinum,\n"
- "but this program is designed for version %d\n",
- vinum_conf.version,
- VINUMVERSION);
- if (vinum_conf.version < VINUMVERSION)
- fprintf(stderr, "Please upgrade your kernel module.\n");
- else
- fprintf(stderr, "Please upgrade vinum(8).\n");
- return 1;
- }
- /* Check if the dæmon is running. If not, start it in the
- * background */
- start_daemon();
- if ((g = getgrnam(GROUP_OPERATOR)) != NULL)
- gid_operator = g->gr_gid;
- endgrent();
-
- if (argc > 1) { /* we have a command on the line */
- if (setjmp(command_fail) != 0) /* long jumped out */
- return -1;
- parseline(argc - 1, &argv[1]); /* do it */
- } else {
- /*
- * Catch a possible race condition which could cause us to
- * longjmp() into nowhere if we receive a SIGINT in the next few
- * lines.
- */
- if (setjmp(command_fail)) /* come back here on catastrophic failure */
- return 1;
- setsigs(); /* set signal handler */
- for (;;) { /* ugh */
- char *c;
- int childstatus; /* from wait4 */
-
- if (setjmp(command_fail) == 2) /* come back here on catastrophic failure */
- fprintf(stderr, "*** interrupted ***\n"); /* interrupted */
-
- while (wait4(-1, &childstatus, WNOHANG, NULL) > 0); /* wait for all dead children */
- c = readline(VINUMMOD " -> "); /* get an input */
- if (c == NULL) { /* EOF or error */
- if (ferror(stdin)) {
- fprintf(stderr, "Can't read input: %s (%d)\n", strerror(errno), errno);
- return 1;
- } else { /* EOF */
- printf("\n");
- return 0;
- }
- } else if (*c) { /* got something there */
- add_history(c); /* save it in the history */
- strcpy(buffer, c); /* put it where we can munge it */
- free(c);
- line++; /* count the lines */
- tokens = tokenize(buffer, token, MAXARGS);
- /* got something potentially worth parsing */
- if (tokens)
- parseline(tokens, token); /* and do what he says */
- }
- if (History)
- fflush(History);
- }
- }
- return 0; /* normal completion */
-}
-
-/* stop the hard way */
-void
-vinum_quit(int argc, char *argv[], char *argv0[])
-{
- exit(0);
-}
-
-/* Set action on receiving a SIGINT */
-void
-setsigs()
-{
- struct sigaction act;
-
- act.sa_handler = catchsig;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT, &act, NULL);
-}
-
-void
-catchsig(int ignore)
-{
- longjmp(command_fail, 2);
-}
-
-#define FUNKEY(x) { kw_##x, &vinum_##x } /* create pair "kw_foo", vinum_foo */
-#define vinum_move vinum_mv /* synonym for 'mv' */
-
-struct funkey {
- enum keyword kw;
- void (*fun) (int argc, char *argv[], char *arg0[]);
-} funkeys[] = {
-
- FUNKEY(create),
- FUNKEY(read),
- FUNKEY(debug),
- FUNKEY(modify),
- FUNKEY(list),
- FUNKEY(ld),
- FUNKEY(ls),
- FUNKEY(lp),
- FUNKEY(lv),
- FUNKEY(info),
- FUNKEY(set),
- FUNKEY(init),
- FUNKEY(resetconfig),
- FUNKEY(rm),
- FUNKEY(mv),
- FUNKEY(move),
- FUNKEY(attach),
- FUNKEY(detach),
- FUNKEY(rename),
- FUNKEY(replace),
- FUNKEY(printconfig),
- FUNKEY(saveconfig),
- FUNKEY(start),
- FUNKEY(stop),
- FUNKEY(makedev),
- FUNKEY(help),
- FUNKEY(quit),
- FUNKEY(concat),
- FUNKEY(stripe),
- FUNKEY(raid4),
- FUNKEY(raid5),
- FUNKEY(mirror),
- FUNKEY(setdaemon),
- FUNKEY(readpol),
- FUNKEY(resetstats),
- FUNKEY(setstate),
- FUNKEY(checkparity),
- FUNKEY(rebuildparity),
- FUNKEY(dumpconfig)
-};
-
-/* Take args arguments at argv and attempt to perform the operation specified */
-void
-parseline(int args, char *argv[])
-{
- int i;
- int j;
- enum keyword command; /* command to execute */
-
- if (History != NULL) { /* save the command to history file */
- timestamp();
- for (i = 0; i < args; i++) /* all args */
- fprintf(History, "%s ", argv[i]);
- fputs("\n", History);
- }
- if ((args == 0) /* empty line */
- ||(*argv[0] == '#')) /* or a comment, */
- return;
- if (args == MAXARGS) { /* too many arguments, */
- fprintf(stderr, "Too many arguments to %s, this can't be right\n", argv[0]);
- return;
- }
- command = get_keyword(argv[0], &keyword_set);
- dowait = 0; /* initialize flags */
- force = 0; /* initialize flags */
- vflag = 0; /* initialize flags */
- Verbose = 0; /* initialize flags */
- recurse = 0; /* initialize flags */
- sflag = 0; /* initialize flags */
- objectname = NULL; /* no name yet */
-
- /*
- * first handle generic options
- * We don't use getopt(3) because
- * getopt doesn't allow merging flags
- * (for example, -fr).
- */
- for (i = 1; (i < args) && (argv[i][0] == '-'); i++) { /* while we have flags */
- for (j = 1; j < strlen(argv[i]); j++)
- switch (argv[i][j]) {
- case 'd': /* -d: debug */
- debug = 1;
- break;
-
- case 'f': /* -f: force */
- force = 1;
- break;
-
- case 'i': /* interval */
- interval = 0;
- if (argv[i][j + 1] != '\0') /* operand follows, */
- interval = atoi(&argv[i][j + 1]); /* use it */
- else if (args > (i + 1)) /* another following, */
- interval = atoi(argv[++i]); /* use it */
- if (interval == 0) /* nothing valid, */
- fprintf(stderr, "-i: no interval specified\n");
- break;
-
- case 'n': /* -n: get name */
- if (i == args - 1) { /* last arg */
- fprintf(stderr, "-n requires a name parameter\n");
- return;
- }
- objectname = argv[++i]; /* pick it up */
- j = strlen(argv[i]); /* skip the next parm */
- break;
-
- case 'r': /* -r: recurse */
- recurse = 1;
- break;
-
- case 's': /* -s: show statistics */
- sflag = 1;
- break;
-
- case 'S':
- SSize = 0;
- if (argv[i][j + 1] != '\0') /* operand follows, */
- SSize = atoi(&argv[i][j + 1]); /* use it */
- else if (args > (i + 1)) /* another following, */
- SSize = atoi(argv[++i]); /* use it */
- if (SSize == 0) /* nothing valid, */
- fprintf(stderr, "-S: no size specified\n");
- break;
-
- case 'v': /* -v: verbose */
- vflag++;
- break;
-
- case 'V': /* -V: Very verbose */
- vflag++;
- Verbose++;
- break;
-
- case 'w': /* -w: wait for completion */
- dowait = 1;
- break;
-
- default:
- fprintf(stderr, "Invalid flag: %s\n", argv[i]);
- }
- }
-
- /* Pass what we have left to the command to handle it */
- for (j = 0; j < (sizeof(funkeys) / sizeof(struct funkey)); j++) {
- if (funkeys[j].kw == command) { /* found the command */
- funkeys[j].fun(args - i, &argv[i], &argv[0]);
- return;
- }
- }
- fprintf(stderr, "Unknown command: %s\n", argv[0]);
-}
-
-void
-get_drive_info(struct _drive *drive, int index)
-{
- *(int *) drive = index; /* put in drive to hand to driver */
- if (ioctl(superdev, VINUM_DRIVECONFIG, drive) < 0) {
- fprintf(stderr,
- "Can't get config for drive %d: %s\n",
- index,
- strerror(errno));
- longjmp(command_fail, -1);
- }
-}
-
-void
-get_sd_info(struct _sd *sd, int index)
-{
- *(int *) sd = index; /* put in sd to hand to driver */
- if (ioctl(superdev, VINUM_SDCONFIG, sd) < 0) {
- fprintf(stderr,
- "Can't get config for subdisk %d: %s\n",
- index,
- strerror(errno));
- longjmp(command_fail, -1);
- }
-}
-
-/* Get the contents of the sd entry for subdisk <sdno>
- * of the specified plex. */
-void
-get_plex_sd_info(struct _sd *sd, int plexno, int sdno)
-{
- ((int *) sd)[0] = plexno;
- ((int *) sd)[1] = sdno; /* pass parameters */
- if (ioctl(superdev, VINUM_PLEXSDCONFIG, sd) < 0) {
- fprintf(stderr,
- "Can't get config for subdisk %d (part of plex %d): %s\n",
- sdno,
- plexno,
- strerror(errno));
- longjmp(command_fail, -1);
- }
-}
-
-void
-get_plex_info(struct _plex *plex, int index)
-{
- *(int *) plex = index; /* put in plex to hand to driver */
- if (ioctl(superdev, VINUM_PLEXCONFIG, plex) < 0) {
- fprintf(stderr,
- "Can't get config for plex %d: %s\n",
- index,
- strerror(errno));
- longjmp(command_fail, -1);
- }
-}
-
-void
-get_volume_info(struct _volume *volume, int index)
-{
- *(int *) volume = index; /* put in volume to hand to driver */
- if (ioctl(superdev, VINUM_VOLCONFIG, volume) < 0) {
- fprintf(stderr,
- "Can't get config for volume %d: %s\n",
- index,
- strerror(errno));
- longjmp(command_fail, -1);
- }
-}
-
-struct _drive *
-find_drive_by_devname(char *name)
-{
- int driveno;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- return NULL;
- }
- for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
- get_drive_info(&drive, driveno);
- if ((drive.state != drive_unallocated) /* real drive */
- &&(!strcmp(drive.devicename, name))) /* and the name's right, */
- return &drive; /* found it */
- }
- return NULL; /* no drive of that name */
-}
-
-/* command line interface for the 'makedev' command */
-void
-vinum_makedev(int argc, char *argv[], char *arg0[])
-{
- fprintf(stderr, "makedev is not needed for a DEVFS-based system\n");
-}
-
-/*
- * Find the object "name". Return object type at type,
- * and the index as the return value.
- * If not found, return -1 and invalid_object.
- */
-int
-find_object(const char *name, enum objecttype *type)
-{
- int object;
-
- if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
- perror("Can't get vinum config");
- *type = invalid_object;
- return -1;
- }
- /* Search the drive table */
- for (object = 0; object < vinum_conf.drives_allocated; object++) {
- get_drive_info(&drive, object);
- if (strcmp(name, drive.label.name) == 0) {
- *type = drive_object;
- return object;
- }
- }
-
- /* Search the subdisk table */
- for (object = 0; object < vinum_conf.subdisks_allocated; object++) {
- get_sd_info(&sd, object);
- if (strcmp(name, sd.name) == 0) {
- *type = sd_object;
- return object;
- }
- }
-
- /* Search the plex table */
- for (object = 0; object < vinum_conf.plexes_allocated; object++) {
- get_plex_info(&plex, object);
- if (strcmp(name, plex.name) == 0) {
- *type = plex_object;
- return object;
- }
- }
-
- /* Search the volume table */
- for (object = 0; object < vinum_conf.volumes_allocated; object++) {
- get_volume_info(&vol, object);
- if (strcmp(name, vol.name) == 0) {
- *type = volume_object;
- return object;
- }
- }
-
- /* Didn't find the name: invalid */
- *type = invalid_object;
- return -1;
-}
-
-/* Continue reviving a subdisk in the background */
-void
-continue_revive(int sdno)
-{
- struct _sd sd;
- pid_t pid;
- get_sd_info(&sd, sdno);
-
- if (dowait == 0)
- pid = fork(); /* do this in the background */
- else
- pid = 0;
- if (pid == 0) { /* we're the child */
- struct _ioctl_reply reply;
- struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
-
- openlog(VINUMMOD, LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
- syslog(LOG_INFO | LOG_KERN, "reviving %s", sd.name);
- setproctitle("reviving %s", sd.name);
-
- for (reply.error = EAGAIN; reply.error == EAGAIN;) { /* revive the subdisk */
- if (interval)
- usleep(interval * 1000); /* pause between each copy */
- message->index = sdno; /* pass sd number */
- message->type = sd_object; /* and type of object */
- message->state = object_up;
- if (SSize != 0) { /* specified a size for init */
- if (SSize < 512)
- SSize <<= DEV_BSHIFT;
- message->blocksize = SSize;
- } else
- message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
- ioctl(superdev, VINUM_SETSTATE, message);
- }
- if (reply.error) {
- syslog(LOG_ERR | LOG_KERN,
- "can't revive %s: %s",
- sd.name,
- reply.msg[0] ? reply.msg : strerror(reply.error));
- if (dowait == 0)
- exit(1);
- } else {
- get_sd_info(&sd, sdno); /* update the info */
- syslog(LOG_INFO | LOG_KERN, "%s is %s", sd.name, sd_state(sd.state));
- if (dowait == 0)
- exit(0);
- }
- } else if (pid < 0) /* couldn't fork? */
- fprintf(stderr, "Can't continue reviving %s: %s\n", sd.name, strerror(errno));
- else /* parent */
- printf("Reviving %s in the background\n", sd.name);
-}
-
-/*
- * Check if the daemon is running,
- * start it if it isn't. The check itself
- * could take a while, so we do it as a separate
- * process, which will become the daemon if one isn't
- * running already
- */
-void
-start_daemon(void)
-{
- int pid;
- int status;
- int error;
-
- pid = (int) fork();
-
- if (pid == 0) { /* We're the child, do the work */
- /*
- * We have a problem when stopping the subsystem:
- * The only way to know that we're idle is when
- * all open superdevs close. But we want the
- * daemon to clean up for us, and since we can't
- * count the opens, we need to have the main device
- * closed when we stop. We solve this conundrum
- * by getting the daemon to open a separate device.
- */
- close(superdev); /* this is the wrong device */
- superdev = open(VINUM_DAEMON_DEV_NAME, O_RDWR); /* open deamon superdevice */
- if (superdev < 0) {
- perror("Can't open " VINUM_DAEMON_DEV_NAME);
- exit(1);
- }
- error = daemon(0, 0); /* this will fork again, but who's counting? */
- if (error != 0) {
- fprintf(stderr, "Can't start daemon: %s (%d)\n", strerror(errno), errno);
- exit(1);
- }
- setproctitle(VINUMMOD " daemon"); /* show what we're doing */
- status = ioctl(superdev, VINUM_FINDDAEMON, NULL);
- if (status != 0) { /* no daemon, */
- ioctl(superdev, VINUM_DAEMON, &vflag); /* we should hang here */
- syslog(LOG_ERR | LOG_KERN, "%s", strerror(errno));
- exit(1);
- }
- exit(0); /* when told to die */
- } else if (pid < 0) /* couldn't fork */
- printf("Can't fork to check daemon\n");
-}
-
-void
-timestamp()
-{
- struct timeval now;
- struct tm *date;
- char datetext[MAXDATETEXT];
- time_t sec;
-
- if (History != NULL) {
- if (gettimeofday(&now, NULL) != 0) {
- fprintf(stderr, "Can't get time: %s\n", strerror(errno));
- return;
- }
- sec = now.tv_sec;
- date = localtime(&sec);
- strftime(datetext, MAXDATETEXT, dateformat, date),
- fprintf(History,
- "%s.%06ld ",
- datetext,
- now.tv_usec);
- }
-}
diff --git a/sbin/vinum/vext.h b/sbin/vinum/vext.h
deleted file mode 100644
index 63f668f..0000000
--- a/sbin/vinum/vext.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/*-
- * Copyright (c) 1997, 1998
- * Nan Yang Computer Services Limited. All rights reserved.
- *
- * This software is distributed under the so-called ``Berkeley
- * License'':
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Nan Yang Computer
- * Services Limited.
- * 4. Neither the name of the Company nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * This software is provided ``as is'', and any express or implied
- * warranties, including, but not limited to, the implied warranties of
- * merchantability and fitness for a particular purpose are disclaimed.
- * In no event shall the company or contributors be liable for any
- * direct, indirect, incidental, special, exemplary, or consequential
- * damages (including, but not limited to, procurement of substitute
- * goods or services; loss of use, data, or profits; or business
- * interruption) however caused and on any theory of liability, whether
- * in contract, strict liability, or tort (including negligence or
- * otherwise) arising in any way out of the use of this software, even if
- * advised of the possibility of such damage.
- */
-
-/*
- * $Id: vext.h,v 1.22 2003/04/28 06:19:06 grog Exp $
- * $FreeBSD$
- */
-
-#define MAXARGS 64 /* maximum number of args on a line */
-#define PLEXINITSIZE 65536 /* init in this size chunks */
-#define MAXPLEXINITSIZE 65536 /* max chunk size to use for init */
-#define MAXDATETEXT 128 /* date text in history (far too much) */
-#define VINUMDEBUG /* for including kernel headers */
-
-enum {
- KILOBYTE = 1024,
- MEGABYTE = 1048576,
- GIGABYTE = 1073741824
-};
-
-#define VINUMMOD "vinum"
-
-#define DEFAULT_HISTORYFILE "/var/log/vinum_history" /* default name for history stuff */
-
-#include <ctype.h>
-#include <errno.h>
-#include <sys/param.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <grp.h>
-#include <netdb.h>
-#include <paths.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/linker.h>
-#include <sys/module.h>
-#include <sys/resource.h>
-#include <readline/history.h>
-#include <readline/readline.h>
-#include <sys/sysctl.h>
-
-#include <sys/time.h>
-#include <sys/bio.h>
-#include <sys/buf.h>
-#include <sys/malloc.h>
-#include <sys/uio.h>
-#include <sys/namei.h>
-#include <sys/stat.h>
-#include <sys/disklabel.h>
-#include <sys/syslog.h>
-#include <sys/fcntl.h>
-#include <sys/queue.h>
-#include <stdarg.h>
-#include <vm/vm.h>
-#include <dev/vinum/vinumvar.h>
-#include <dev/vinum/vinumio.h>
-#include <dev/vinum/vinumkw.h>
-#include <dev/vinum/vinumutil.h>
-#include <machine/cpu.h>
-
-/* Prototype declarations */
-void parseline(int c, char *args[]); /* parse a line with c parameters at args */
-void checkentry(int index);
-int haveargs(int); /* check arg, error message if not valid */
-void setsigs(void);
-void catchsig(int ignore);
-void vinum_create(int argc, char *argv[], char *arg0[]);
-void vinum_read(int argc, char *argv[], char *arg0[]);
-void vinum_modify(int argc, char *argv[], char *arg0[]);
-void vinum_volume(int argc, char *argv[], char *arg0[]);
-void vinum_plex(int argc, char *argv[], char *arg0[]);
-void vinum_sd(int argc, char *argv[], char *arg0[]);
-void vinum_drive(int argc, char *argv[], char *arg0[]);
-void vinum_list(int argc, char *argv[], char *arg0[]);
-void vinum_info(int argc, char *argv[], char *arg0[]);
-void vinum_set(int argc, char *argv[], char *arg0[]);
-void vinum_rm(int argc, char *argv[], char *arg0[]);
-void vinum_mv(int argc, char *argv[], char *arg0[]);
-void vinum_init(int argc, char *argv[], char *arg0[]);
-void listconfig(void);
-void resetstats(struct vinum_ioctl_msg *msg);
-void initvol(int volno);
-void initplex(int plexno, char *name);
-void initsd(int sdno, int dowait);
-void vinum_resetconfig(int argc, char *argv[], char *arg0[]);
-void vinum_start(int argc, char *argv[], char *arg0[]);
-void continue_revive(int plexno);
-void vinum_stop(int argc, char *argv[], char *arg0[]);
-void vinum_makedev(int argc, char *argv[], char *arg0[]);
-void vinum_help(int argc, char *argv[], char *arg0[]);
-void vinum_quit(int argc, char *argv[], char *arg0[]);
-void vinum_setdaemon(int argc, char *argv[], char *arg0[]);
-void vinum_replace(int argc, char *argv[], char *arg0[]);
-void vinum_readpol(int argc, char *argv[], char *arg0[]);
-void reset_volume_stats(int volno, int recurse);
-void reset_plex_stats(int plexno, int recurse);
-void reset_sd_stats(int sdno, int recurse);
-void reset_drive_stats(int driveno);
-void vinum_resetstats(int argc, char *argv[], char *arg0[]);
-void vinum_attach(int argc, char *argv[], char *argv0[]);
-void vinum_detach(int argc, char *argv[], char *argv0[]);
-void vinum_rename(int argc, char *argv[], char *argv0[]);
-void vinum_rename_2(char *, char *);
-void vinum_replace(int argc, char *argv[], char *argv0[]);
-void vinum_printconfig(int argc, char *argv[], char *argv0[]);
-void printconfig(FILE * of, char *comment);
-void vinum_saveconfig(int argc, char *argv[], char *argv0[]);
-int checkupdates(void);
-void genvolname(void);
-struct _drive *create_drive(char *devicename);
-void vinum_concat(int argc, char *argv[], char *argv0[]);
-void vinum_stripe(int argc, char *argv[], char *argv0[]);
-void vinum_raid4(int argc, char *argv[], char *argv0[]);
-void vinum_raid5(int argc, char *argv[], char *argv0[]);
-void vinum_mirror(int argc, char *argv[], char *argv0[]);
-void vinum_label(int argc, char *argv[], char *arg0[]);
-void vinum_ld(int argc, char *argv[], char *arg0[]);
-void vinum_ls(int argc, char *argv[], char *arg0[]);
-void vinum_lp(int argc, char *argv[], char *arg0[]);
-void vinum_lv(int argc, char *argv[], char *arg0[]);
-void vinum_setstate(int argc, char *argv[], char *argv0[]);
-void vinum_checkparity(int argc, char *argv[], char *argv0[]);
-void vinum_rebuildparity(int argc, char *argv[], char *argv0[]);
-void parityops(int argc, char *argv[], enum parityop op);
-void start_daemon(void);
-void vinum_debug(int argc, char *argv[], char *arg0[]);
-void list_defective_objects(void);
-void vinum_dumpconfig(int argc, char *argv[], char *argv0[]);
-void dumpconfig(char *part);
-int check_drive(char *devicename);
-void get_drive_info(struct _drive *drive, int index);
-void get_sd_info(struct _sd *sd, int index);
-void get_plex_sd_info(struct _sd *sd, int plexno, int sdno);
-void get_plex_info(struct _plex *plex, int index);
-void get_volume_info(struct _volume *volume, int index);
-struct _drive *find_drive_by_devname(char *name);
-int find_object(const char *name, enum objecttype *type);
-char *lltoa(int64_t l, char *s);
-void vinum_ldi(int, int);
-void vinum_lvi(int, int);
-void vinum_lpi(int, int);
-void vinum_lsi(int, int);
-int vinum_li(int object, enum objecttype type);
-char *roughlength(int64_t bytes, int);
-u_int64_t sizespec(char *spec);
-char *sd_state(enum sdstate);
-void timestamp(void);
-
-extern int force; /* set to 1 to force some dangerous ops */
-extern int interval; /* interval in ms between init/revive */
-extern int vflag; /* set verbose operation or verify */
-extern int Verbose; /* very verbose operation */
-extern int recurse; /* set recursion */
-extern int sflag; /* show statistics */
-extern int SSize; /* sector size for revive */
-extern int dowait; /* wait for children to exit */
-extern char *objectname; /* name for some functions */
-
-extern FILE *History; /* history file */
-
-/* Structures to read kernel data into */
-extern struct __vinum_conf vinum_conf; /* configuration information */
-
-extern struct _volume vol;
-extern struct _plex plex;
-extern struct _sd sd;
-extern struct _drive drive;
-
-extern jmp_buf command_fail; /* return on a failed command */
-extern int superdev; /* vinum super device */
-
-extern int line; /* stdin line number for error messages */
-extern int file_line; /* and line in input file (yes, this is tacky) */
-
-extern char buffer[]; /* buffer to read in to */
-
-#define min(a, b) a < b? a: b
diff --git a/sbin/vinum/vinum.8 b/sbin/vinum/vinum.8
deleted file mode 100644
index f71ac23..0000000
--- a/sbin/vinum/vinum.8
+++ /dev/null
@@ -1,2925 +0,0 @@
-.\" Hey, Emacs, edit this file in -*- nroff-fill -*- mode
-.\"-
-.\" Copyright (c) 1997, 1998
-.\" Nan Yang Computer Services Limited. All rights reserved.
-.\"
-.\" This software is distributed under the so-called ``Berkeley
-.\" License'':
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by Nan Yang Computer
-.\" Services Limited.
-.\" 4. Neither the name of the Company nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" This software is provided ``as is'', and any express or implied
-.\" warranties, including, but not limited to, the implied warranties of
-.\" merchantability and fitness for a particular purpose are disclaimed.
-.\" In no event shall the company or contributors be liable for any
-.\" direct, indirect, incidental, special, exemplary, or consequential
-.\" damages (including, but not limited to, procurement of substitute
-.\" goods or services; loss of use, data, or profits; or business
-.\" interruption) however caused and on any theory of liability, whether
-.\" in contract, strict liability, or tort (including negligence or
-.\" otherwise) arising in any way out of the use of this software, even if
-.\" advised of the possibility of such damage.
-.\"
-.\" $Id: vinum.8,v 1.15 2001/05/14 01:10:37 grog Exp grog $
-.\" $FreeBSD$
-.\"
-.Dd May 5, 2003
-.Dt VINUM 8
-.Os
-.Sh NAME
-.Nm vinum
-.Nd Logical Volume Manager control program
-.Sh SYNOPSIS
-.Nm
-.Op Ar command
-.Op Fl options
-.Sh COMMANDS
-.Bl -tag -width indent
-.It Ic attach Ar plex volume Op Cm rename
-.It Xo
-.Ic attach Ar subdisk plex
-.Op Ar offset
-.Op Cm rename
-.Xc
-Attach a plex to a volume, or a subdisk to a plex.
-.It Xo
-.Ic checkparity
-.Op Fl f
-.Op Fl v
-.Ar plex
-.Xc
-Check the parity blocks of a RAID-4 or RAID-5 plex.
-.It Xo
-.Ic concat
-.Op Fl f
-.Op Fl n Ar name
-.Op Fl v
-.Ar drives
-.Xc
-Create a concatenated volume from the specified drives.
-.It Xo
-.Ic create
-.Op Fl f
-.Ar description-file
-.Xc
-Create a volume as described in
-.Ar description-file .
-.It Ic debug
-Cause the volume manager to enter the kernel debugger.
-.It Ic debug Ar flags
-Set debugging flags.
-.It Xo
-.Ic detach
-.Op Fl f
-.Op Ar plex | subdisk
-.Xc
-Detach a plex or subdisk from the volume or plex to which it is attached.
-.It Ic dumpconfig Op Ar drive ...
-List the configuration information stored on the specified drives, or all drives
-in the system if no drive names are specified.
-.It Xo
-.Ic info
-.Op Fl v
-.Op Fl V
-.Xc
-List information about volume manager state.
-.It Xo
-.Ic init
-.Op Fl S Ar size
-.Op Fl w
-.Ar plex | subdisk
-.Xc
-.\" XXX
-Initialize the contents of a subdisk or all the subdisks of a plex to all zeros.
-.It Ic label Ar volume
-Create a volume label.
-.It Xo
-.Ic l | list
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar volume | plex | subdisk
-.Xc
-List information about specified objects.
-.It Xo
-.Ic ld
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar drive
-.Xc
-List information about drives.
-.It Xo
-.Ic ls
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar subdisk
-.Xc
-List information about subdisks.
-.It Xo
-.Ic lp
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar plex
-.Xc
-List information about plexes.
-.It Xo
-.Ic lv
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar volume
-.Xc
-List information about volumes.
-.It Xo
-.Ic mirror
-.Op Fl f
-.Op Fl n Ar name
-.Op Fl s
-.Op Fl v
-.Ar drives
-.Xc
-Create a mirrored volume from the specified drives.
-.It Xo
-.Ic move | mv
-.Fl f
-.Ar drive object ...
-.Xc
-Move the object(s) to the specified drive.
-.It Ic printconfig Op Ar file
-Write a copy of the current configuration to
-.Ar file .
-.It Ic quit
-Exit the
-.Nm
-utility when running in interactive mode.
-Normally this would be done by
-entering the
-.Dv EOF
-character.
-.It Ic read Ar disk ...
-Read the
-.Nm
-configuration from the specified disks.
-.It Xo
-.Ic rename Op Fl r
-.Op Ar drive | subdisk | plex | volume
-.Ar newname
-.Xc
-Change the name of the specified object.
-.\" XXX
-.\".It Ic replace Ar drive newdrive
-.\"Move all the subdisks from the specified drive onto the new drive.
-.It Xo
-.Ic rebuildparity
-.Op Fl f
-.Op Fl v
-.Op Fl V
-.Ar plex
-.Xc
-Rebuild the parity blocks of a RAID-4 or RAID-5 plex.
-.It Ic resetconfig
-Reset the complete
-.Nm
-configuration.
-.It Xo
-.Ic resetstats
-.Op Fl r
-.Op Ar volume | plex | subdisk
-.Xc
-Reset statistics counters for the specified objects, or for all objects if none
-are specified.
-.It Xo
-.Ic rm
-.Op Fl f
-.Op Fl r
-.Ar volume | plex | subdisk
-.Xc
-Remove an object.
-.It Ic saveconfig
-Save
-.Nm
-configuration to disk after configuration failures.
-.\" XXX
-.\".It Xo
-.\".Ic set
-.\".Op Fl f
-.\".Ar state
-.\".Ar volume | plex | subdisk | disk
-.\".Xc
-.\"Set the state of the object to
-.\".Ar state .
-.It Ic setdaemon Op Ar value
-Set daemon configuration.
-.It Xo
-.Ic setstate
-.Ar state
-.Op Ar volume | plex | subdisk | drive
-.Xc
-Set state without influencing other objects, for diagnostic purposes only.
-.It Ic start
-Read configuration from all vinum drives.
-.It Xo
-.Ic start
-.Op Fl i Ar interval
-.Op Fl S Ar size
-.Op Fl w
-.Ar volume | plex | subdisk
-.Xc
-Allow the system to access the objects.
-.It Xo
-.Ic stop
-.Op Fl f
-.Op Ar volume | plex | subdisk
-.Xc
-Terminate access to the objects, or stop
-.Nm
-if no parameters are specified.
-.It Xo
-.Ic stripe
-.Op Fl f
-.Op Fl n Ar name
-.Op Fl v
-.Ar drives
-.Xc
-Create a striped volume from the specified drives.
-.El
-.Sh DESCRIPTION
-The
-.Nm
-utility communicates with the kernel component of the Vinum
-logical volume manager.
-It is designed either for interactive use, when started without command line
-arguments, or to execute a single command if the command is supplied on the
-command line.
-In interactive mode,
-.Nm
-maintains a command line history.
-.Sh OPTIONS
-.Nm
-commands may optionally be followed by an option.
-Any of the following options
-may be specified with any command, but in some cases the options are ignored.
-For example, the
-.Ic stop
-command ignores the
-.Fl v
-and
-.Fl V
-options.
-.Bl -tag -width indent
-.It Fl f
-The
-.Fl f
-.Pq Dq force
-option overrides safety checks.
-Use with extreme care.
-This option is for
-emergency use only.
-For example, the command
-.Pp
-.Dl rm -f myvolume
-.Pp
-removes
-.Ar myvolume
-even if it is open.
-Any subsequent access to the volume will almost certainly
-cause a panic.
-.It Fl i Ar millisecs
-When performing the
-.Ic init
-and
-.Ic start
-commands, wait
-.Ar millisecs
-milliseconds between copying each block.
-This lowers the load on the system.
-.It Fl n Ar name
-Use the
-.Fl n
-option to specify a volume name to the simplified configuration commands
-.Ic concat , mirror
-and
-.Ic stripe .
-.It Fl r
-The
-.Fl r
-.Pq Dq recursive
-option is used by the list commands to display information not
-only about the specified objects, but also about subordinate objects.
-For
-example, in conjunction with the
-.Ic lv
-command, the
-.Fl r
-option will also show information about the plexes and subdisks belonging to the
-volume.
-.It Fl s
-The
-.Fl s
-.Pq Dq statistics
-option is used by the list commands to display statistical information.
-The
-.Ic mirror
-command also uses this option to specify that it should create striped plexes.
-.It Fl S Ar size
-The
-.Fl S
-option specifies the transfer size for the
-.Ic init
-and
-.Ic start
-commands.
-.It Fl v
-The
-.Fl v
-.Pq Dq verbose
-option can be used to request more detailed information.
-.It Fl V
-The
-.Fl V
-.Pq Dq Very verbose
-option can be used to request more detailed information than the
-.Fl v
-option provides.
-.It Fl w
-The
-.Fl w
-.Pq Dq wait
-option tells
-.Nm
-to wait for completion of commands which normally run in the background, such as
-.Ic init .
-.El
-.Sh COMMANDS IN DETAIL
-.Nm
-commands perform the following functions:
-.Pp
-.Bl -tag -width indent -compact
-.It Ic attach Ar plex volume Op Cm rename
-.It Xo
-.Ic attach Ar subdisk plex
-.Op Ar offset
-.Op Cm rename
-.Xc
-.Nm Ic attach
-inserts the specified plex or subdisk in a volume or plex.
-In the case of a
-subdisk, an offset in the plex may be specified.
-If it is not, the subdisk will
-be attached at the first possible location.
-After attaching a plex to a
-non-empty volume,
-.Nm
-reintegrates the plex.
-.Pp
-If the keyword
-.Cm rename
-is specified,
-.Nm
-renames the object (and in the case of a plex, any subordinate subdisks) to fit
-in with the default
-.Nm
-naming convention.
-To rename the object to any other name, use the
-.Ic rename
-command.
-.Pp
-A number of considerations apply to attaching subdisks:
-.Bl -bullet
-.It
-Subdisks can normally only be attached to concatenated plexes.
-.It
-If a striped or RAID-5 plex is missing a subdisk (for example after drive
-failure), it should be replaced by a subdisk of the same size only.
-.It
-In order to add further subdisks to a striped or RAID-5 plex, use the
-.Fl f
-(force) option.
-This will corrupt the data in the plex.
-.\"No other attachment of
-.\"subdisks is currently allowed for striped and RAID-5 plexes.
-.It
-For concatenated plexes, the
-.Ar offset
-parameter specifies the offset in blocks from the beginning of the plex.
-For
-striped and RAID-5 plexes, it specifies the offset of the first block of the
-subdisk: in other words, the offset is the numerical position of the subdisk
-multiplied by the stripe size.
-For example, in a plex with stripe size 271k,
-the first subdisk will have offset 0, the second offset 271k, the third 542k,
-etc.
-This calculation ignores parity blocks in RAID-5 plexes.
-.El
-.Pp
-.It Xo
-.Ic checkparity
-.Op Fl f
-.Op Fl v
-.Ar plex
-.Xc
-Check the parity blocks on the specified RAID-4 or RAID-5 plex.
-This operation
-maintains a pointer in the plex, so it can be stopped and later restarted from
-the same position if desired.
-In addition, this pointer is used by the
-.Ic rebuildparity
-command, so rebuilding the parity blocks need only start at the location where
-the first parity problem has been detected.
-.Pp
-If the
-.Fl f
-flag is specified,
-.Ic checkparity
-starts checking at the beginning of the plex.
-If the
-.Fl v
-flag is specified,
-.Ic checkparity
-prints a running progress report.
-.Pp
-.It Xo
-.Ic concat
-.Op Fl f
-.Op Fl n Ar name
-.Op Fl v
-.Ar drives
-.Xc
-The
-.Ic concat
-command provides a simplified alternative to the
-.Ic create
-command for creating volumes with a single concatenated plex.
-The largest
-contiguous space available on each drive is used to create the subdisks for the
-plexes.
-.Pp
-Normally, the
-.Ic concat
-command creates an arbitrary name for the volume and its components.
-The name
-is composed of the text
-.Dq Li vinum
-and a small integer, for example
-.Dq Li vinum3 .
-You can override this with the
-.Fl n Ar name
-option, which assigns the name specified to the volume.
-The plexes and subdisks
-are named after the volume in the default manner.
-.Pp
-There is no choice of name for the drives.
-If the drives have already been
-initialized as
-.Nm
-drives, the name remains.
-Otherwise the drives are given names starting with
-the text
-.Dq Li vinumdrive
-and a small integer, for example
-.Dq Li vinumdrive7 .
-As with the
-.Ic create
-command, the
-.Fl f
-option can be used to specify that a previous name should be overwritten.
-The
-.Fl v
-is used to specify verbose output.
-.Pp
-See the section
-.Sx SIMPLIFIED CONFIGURATION
-below for some examples of this
-command.
-.Pp
-.It Xo
-.Ic create
-.Op Fl f
-.Ar description-file
-.Xc
-.Nm Ic create
-is used to create any object.
-In view of the relatively complicated
-relationship and the potential dangers involved in creating a
-.Nm
-object, there is no interactive interface to this function.
-If you do not
-specify a file name,
-.Nm
-starts an editor on a temporary file.
-If the environment variable
-.Ev EDITOR
-is set,
-.Nm
-starts this editor.
-If not, it defaults to
-.Nm vi .
-See the section
-.Sx CONFIGURATION FILE
-below for more information on the format of
-this file.
-.Pp
-Note that the
-.Nm Ic create
-function is additive: if you run it multiple times, you will create multiple
-copies of all unnamed objects.
-.Pp
-Normally the
-.Ic create
-command will not change the names of existing
-.Nm
-drives, in order to avoid accidentally erasing them.
-The correct way to dispose
-of no longer wanted
-.Nm
-drives is to reset the configuration with the
-.Ic resetconfig
-command.
-In some cases, however, it may be necessary to create new data on
-.Nm
-drives which can no longer be started.
-In this case, use the
-.Ic create Fl f
-command.
-.Pp
-.It Ic debug
-.Nm Ic debug ,
-without any arguments, is used to enter the remote kernel debugger.
-It is only
-activated if
-.Nm
-is built with the
-.Dv VINUMDEBUG
-option.
-This option will stop the execution of the operating system until the
-kernel debugger is exited.
-If remote debugging is set and there is no remote
-connection for a kernel debugger, it will be necessary to reset the system and
-reboot in order to leave the debugger.
-.Pp
-.It Ic debug Ar flags
-Set a bit mask of internal debugging flags.
-These will change without warning
-as the product matures; to be certain, read the header file
-.In sys/dev/vinumvar.h .
-The bit mask is composed of the following values:
-.Bl -tag -width indent
-.It Dv DEBUG_ADDRESSES Pq No 1
-Show buffer information during requests
-.\".It Dv DEBUG_NUMOUTPUT Pq No 2
-.\"Show the value of
-.\".Va vp->v_numoutput .
-.It Dv DEBUG_RESID Pq No 4
-Go into debugger in
-.Fn complete_rqe .
-.It Dv DEBUG_LASTREQS Pq No 8
-Keep a circular buffer of last requests.
-.It Dv DEBUG_REVIVECONFLICT Pq No 16
-Print info about revive conflicts.
-.It Dv DEBUG_EOFINFO Pq No 32
-Print information about internal state when returning an
-.Dv EOF
-on a striped plex.
-.It Dv DEBUG_MEMFREE Pq No 64
-Maintain a circular list of the last memory areas freed by the memory allocator.
-.It Dv DEBUG_REMOTEGDB Pq No 256
-Go into remote
-.Nm gdb
-when the
-.Ic debug
-command is issued.
-.It Dv DEBUG_WARNINGS Pq No 512
-Print some warnings about minor problems in the implementation.
-.El
-.Pp
-.It Ic detach Oo Fl f Oc Ar plex
-.It Ic detach Oo Fl f Oc Ar subdisk
-.Nm Ic detach
-removes the specified plex or subdisk from the volume or plex to which it is
-attached.
-If removing the object would impair the data integrity of the volume,
-the operation will fail unless the
-.Fl f
-option is specified.
-If the object is named after the object above it (for
-example, subdisk
-.Li vol1.p7.s0
-attached to plex
-.Li vol1.p7 ) ,
-the name will be changed
-by prepending the text
-.Dq Li ex-
-(for example,
-.Li ex-vol1.p7.s0 ) .
-If necessary, the name will be truncated in the
-process.
-.Pp
-.Ic detach
-does not reduce the number of subdisks in a striped or RAID-5 plex.
-Instead,
-the subdisk is marked absent, and can later be replaced with the
-.Ic attach
-command.
-.Pp
-.It Ic dumpconfig Op Ar drive ...
-.Pp
-.Nm Ic dumpconfig
-shows the configuration information stored on the specified drives.
-If no drive
-names are specified,
-.Ic dumpconfig
-searches all drives on the system for Vinum partitions and dumps the
-information.
-If configuration updates are disabled, it is possible that this
-information is not the same as the information returned by the
-.Ic list
-command.
-This command is used primarily for maintenance and debugging.
-.Pp
-.It Ic info
-.Nm Ic info
-displays information about
-.Nm
-memory usage.
-This is intended primarily for debugging.
-With the
-.Fl v
-option, it will give detailed information about the memory areas in use.
-.Pp
-With the
-.Fl V
-option,
-.Ic info
-displays information about the last up to 64 I/O requests handled by the
-.Nm
-driver.
-This information is only collected if debug flag 8 is set.
-The format
-looks like:
-.Bd -literal
-vinum -> info -V
-Flags: 0x200 1 opens
-Total of 38 blocks malloced, total memory: 16460
-Maximum allocs: 56, malloc table at 0xf0f72dbc
-
-Time Event Buf Dev Offset Bytes SD SDoff Doffset Goffset
-
-14:40:00.637758 1VS Write 0xf2361f40 91.3 0x10 16384
-14:40:00.639280 2LR Write 0xf2361f40 91.3 0x10 16384
-14:40:00.639294 3RQ Read 0xf2361f40 4.39 0x104109 8192 19 0 0 0
-14:40:00.639455 3RQ Read 0xf2361f40 4.23 0xd2109 8192 17 0 0 0
-14:40:00.639529 3RQ Read 0xf2361f40 4.15 0x6e109 8192 16 0 0 0
-14:40:00.652978 4DN Read 0xf2361f40 4.39 0x104109 8192 19 0 0 0
-14:40:00.667040 4DN Read 0xf2361f40 4.15 0x6e109 8192 16 0 0 0
-14:40:00.668556 4DN Read 0xf2361f40 4.23 0xd2109 8192 17 0 0 0
-14:40:00.669777 6RP Write 0xf2361f40 4.39 0x104109 8192 19 0 0 0
-14:40:00.685547 4DN Write 0xf2361f40 4.39 0x104109 8192 19 0 0 0
-11:11:14.975184 Lock 0xc2374210 2 0x1f8001
-11:11:15.018400 7VS Write 0xc2374210 0x7c0 32768 10
-11:11:15.018456 8LR Write 0xc2374210 13.39 0xcc0c9 32768
-11:11:15.046229 Unlock 0xc2374210 2 0x1f8001
-.Ed
-.Pp
-The
-.Ar Buf
-field always contains the address of the user buffer header.
-This can be used
-to identify the requests associated with a user request, though this is not 100%
-reliable: theoretically two requests in sequence could use the same buffer
-header, though this is not common.
-The beginning of a request can be identified
-by the event
-.Ar 1VS
-or
-.Ar 7VS .
-The first example above shows the requests involved in a user request.
-The
-second is a subdisk I/O request with locking.
-.Pp
-The
-.Ar Event
-field contains information related to the sequence of events in the request
-chain.
-The digit
-.Ar 1
-to
-.Ar 6
-indicates the approximate sequence of events, and the two-letter abbreviation is
-a mnemonic for the location:
-.Bl -tag -width Lockwait
-.It 1VS
-(vinumstrategy) shows information about the user request on entry to
-.Fn vinumstrategy .
-The device number is the
-.Nm
-device, and offset and length are the user parameters.
-This is always the
-beginning of a request sequence.
-.It 2LR
-(launch_requests) shows the user request just prior to launching the low-level
-.Nm
-requests in the function
-.Fn launch_requests .
-The parameters should be the same as in the
-.Ar 1VS
-information.
-.El
-.Pp
-In the following requests,
-.Ar Dev
-is the device number of the associated disk partition,
-.Ar Offset
-is the offset from the beginning of the partition,
-.Ar SD
-is the subdisk index in
-.Va vinum_conf ,
-.Ar SDoff
-is the offset from the beginning of the subdisk,
-.Ar Doffset
-is the offset of the associated data request, and
-.Ar Goffset
-is the offset of the associated group request, where applicable.
-.Bl -tag -width Lockwait
-.It 3RQ
-(request) shows one of possibly several low-level
-.Nm
-requests which are launched to satisfy the high-level request.
-This information
-is also logged in
-.Fn launch_requests .
-.It 4DN
-(done) is called from
-.Fn complete_rqe ,
-showing the completion of a request.
-This completion should match a request
-launched either at stage
-.Ar 4DN
-from
-.Fn launch_requests ,
-or from
-.Fn complete_raid5_write
-at stage
-.Ar 5RD
-or
-.Ar 6RP .
-.It 5RD
-(RAID-5 data) is called from
-.Fn complete_raid5_write
-and represents the data written to a RAID-5 data stripe after calculating
-parity.
-.It 6RP
-(RAID-5 parity) is called from
-.Fn complete_raid5_write
-and represents the data written to a RAID-5 parity stripe after calculating
-parity.
-.It 7VS
-shows a subdisk I/O request.
-These requests are usually internal to
-.Nm
-for operations like initialization or rebuilding plexes.
-.It 8LR
-shows the low-level operation generated for a subdisk I/O request.
-.It Lockwait
-specifies that the process is waiting for a range lock.
-The parameters are the
-buffer header associated with the request, the plex number and the block number.
-For internal reasons the block number is one higher than the address of the
-beginning of the stripe.
-.It Lock
-specifies that a range lock has been obtained.
-The parameters are the same as
-for the range lock.
-.It Unlock
-specifies that a range lock has been released.
-The parameters are the same as
-for the range lock.
-.El
-.\" XXX
-.Pp
-.It Xo
-.Ic init
-.Op Fl S Ar size
-.Op Fl w
-.Ar plex | subdisk
-.Xc
-.Nm Ic init
-initializes a subdisk by writing zeroes to it.
-You can initialize all subdisks
-in a plex by specifying the plex name.
-This is the only way to ensure
-consistent data in a plex.
-You must perform this initialization before using a
-RAID-5 plex.
-It is also recommended for other new plexes.
-.Nm
-initializes all subdisks of a plex in parallel.
-Since this operation can take a
-long time, it is normally performed in the background.
-If you want to wait for
-completion of the command, use the
-.Fl w
-(wait) option.
-.Pp
-Specify the
-.Fl S
-option if you want to write blocks of a different size from the default value of
-16 kB.
-.Nm
-prints a console message when the initialization is complete.
-.Pp
-.It Ic label Ar volume
-The
-.Ic label
-command writes a
-.Em ufs
-style volume label on a volume.
-It is a simple alternative to an appropriate
-call to
-.Ic disklabel .
-This is needed because some
-.Em ufs
-commands still read the disk to find the label instead of using the correct
-.Xr ioctl 2
-call to access it.
-.Nm
-maintains a volume label separately from the volume data, so this command is not
-needed for
-.Xr newfs 8 .
-This command is deprecated.
-.Pp
-.It Xo
-.Ic list
-.Op Fl r
-.Op Fl V
-.Op Ar volume | plex | subdisk
-.Xc
-.It Xo
-.Ic l
-.Op Fl r
-.Op Fl V
-.Op Ar volume | plex | subdisk
-.Xc
-.It Xo
-.Ic ld
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar drive
-.Xc
-.It Xo
-.Ic ls
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar subdisk
-.Xc
-.It Xo
-.Ic lp
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar plex
-.Xc
-.It Xo
-.Ic lv
-.Op Fl r
-.Op Fl s
-.Op Fl v
-.Op Fl V
-.Op Ar volume
-.Xc
-.Ic list
-is used to show information about the specified object.
-If the argument is
-omitted, information is shown about all objects known to
-.Nm .
-The
-.Ic l
-command is a synonym for
-.Ic list .
-.Pp
-The
-.Fl r
-option relates to volumes and plexes: if specified, it recursively lists
-information for the subdisks and (for a volume) plexes subordinate to the
-objects.
-The commands
-.Ic lv , lp , ls
-and
-.Ic ld
-list only volumes, plexes, subdisks and drives respectively.
-This is
-particularly useful when used without parameters.
-.Pp
-The
-.Fl s
-option causes
-.Nm
-to output device statistics, the
-.Fl v
-(verbose) option causes some additional information to be output, and the
-.Fl V
-causes considerable additional information to be output.
-.Pp
-.It Xo
-.Ic mirror
-.Op Fl f
-.Op Fl n Ar name
-.Op Fl s
-.Op Fl v
-.Ar drives
-.Xc
-The
-.Ic mirror
-command provides a simplified alternative to the
-.Ic create
-command for creating mirrored volumes.
-Without any options, it creates a RAID-1
-(mirrored) volume with two concatenated plexes.
-The largest contiguous space
-available on each drive is used to create the subdisks for the plexes.
-The
-first plex is built from the odd-numbered drives in the list, and the second
-plex is built from the even-numbered drives.
-If the drives are of different
-sizes, the plexes will be of different sizes.
-.Pp
-If the
-.Fl s
-option is provided,
-.Ic mirror
-builds striped plexes with a stripe size of 279 kB.
-The size of the subdisks in
-each plex is the size of the smallest contiguous storage available on any of the
-drives which form the plex.
-Again, the plexes may differ in size.
-.Pp
-Normally, the
-.Ic mirror
-command creates an arbitrary name for the volume and its components.
-The name
-is composed of the text
-.Dq Li vinum
-and a small integer, for example
-.Dq Li vinum3 .
-You can override this with the
-.Fl n Ar name
-option, which assigns the name specified to the volume.
-The plexes and subdisks
-are named after the volume in the default manner.
-.Pp
-There is no choice of name for the drives.
-If the drives have already been
-initialized as
-.Nm
-drives, the name remains.
-Otherwise the drives are given names starting with
-the text
-.Dq Li vinumdrive
-and a small integer, for example
-.Dq Li vinumdrive7 .
-As with the
-.Ic create
-command, the
-.Fl f
-option can be used to specify that a previous name should be overwritten.
-The
-.Fl v
-is used to specify verbose output.
-.Pp
-See the section
-.Sx SIMPLIFIED CONFIGURATION
-below for some examples of this
-command.
-.Pp
-.It Ic mv Fl f Ar drive object ...
-.It Ic move Fl f Ar drive object ...
-Move all the subdisks from the specified objects onto the new drive.
-The
-objects may be subdisks, drives or plexes.
-When drives or plexes are specified,
-all subdisks associated with the object are moved.
-.Pp
-The
-.Fl f
-option is required for this function, since it currently does not preserve the
-data in the subdisk.
-This functionality will be added at a later date.
-In this
-form, however, it is suited to recovering a failed disk drive.
-.Pp
-.It Ic printconfig Op Ar file
-Write a copy of the current configuration to
-.Ar file
-in a format that can be used to recreate the
-.Nm
-configuration.
-Unlike the configuration saved on disk, it includes definitions
-of the drives.
-If you omit
-.Ar file ,
-.Nm
-writes the list to
-.Dv stdout .
-.Pp
-.It Ic quit
-Exit the
-.Nm
-utility when running in interactive mode.
-Normally this would be done by
-entering the
-.Dv EOF
-character.
-.Pp
-.It Ic read Ar disk ...
-The
-.Ic read
-command scans the specified disks for
-.Nm
-partitions containing previously created configuration information.
-It reads
-the configuration in order from the most recently updated to least recently
-updated configuration.
-The
-.Nm
-utility
-maintains an up-to-date copy of all configuration information on each disk
-partition.
-You must specify all of the slices in a configuration as the
-parameter to this command.
-.Pp
-The
-.Ic read
-command is intended to selectively load a
-.Nm
-configuration on a system which has other
-.Nm
-partitions.
-If you want to start all partitions on the system, it is easier to
-use the
-.Ic start
-command.
-.Pp
-If
-.Nm
-encounters any errors during this command, it will turn off automatic
-configuration update to avoid corrupting the copies on disk.
-This will also
-happen if the configuration on disk indicates a configuration error (for
-example, subdisks which do not have a valid space specification).
-You can turn
-the updates on again with the
-.Ic setdaemon
-and
-.Ic saveconfig
-commands.
-Reset bit 2 (numerical value 4) of the daemon options mask to
-re-enable configuration saves.
-.Pp
-.It Xo
-.Ic rebuildparity
-.Op Fl f
-.Op Fl v
-.Op Fl V
-.Ar plex
-.Xc
-Rebuild the parity blocks on the specified RAID-4 or RAID-5 plex.
-This
-operation maintains a pointer in the plex, so it can be stopped and later
-restarted from the same position if desired.
-In addition, this pointer is used
-by the
-.Ic checkparity
-command, so rebuilding the parity blocks need only start at the location where
-the first parity problem has been detected.
-.Pp
-If the
-.Fl f
-flag is specified,
-.Ic rebuildparity
-starts rebuilding at the beginning of the plex.
-If the
-.Fl v
-flag is specified,
-.Ic rebuildparity
-first checks the existing parity blocks prints information about those found to
-be incorrect before rebuilding.
-If the
-.Fl V
-flag is specified,
-.Ic rebuildparity
-prints a running progress report.
-.Pp
-.It Xo
-.Ic rename
-.Op Fl r
-.Op Ar drive | subdisk | plex | volume
-.Ar newname
-.Xc
-Change the name of the specified object.
-If the
-.Fl r
-option is specified, subordinate objects will be named by the default rules:
-plex names will be formed by appending
-.Li .p Ns Ar number
-to the volume name, and
-subdisk names will be formed by appending
-.Li .s Ns Ar number
-to the plex name.
-.\".Pp
-.\".It Xo
-.\".Ic replace
-.\".Ar drive newdrive
-.\"Move all the subdisks from the specified drive onto the new drive.
-.\"This will
-.\"attempt to recover those subdisks that can be recovered, and create the others
-.\"from scratch.
-.\"If the new drive lacks the space for this operation, as many
-.\"subdisks as possible will be fitted onto the drive, and the rest will be left on
-.\"the original drive.
-.Pp
-.It Ic resetconfig
-The
-.Ic resetconfig
-command completely obliterates the
-.Nm
-configuration on a system.
-Use this command only when you want to completely
-delete the configuration.
-.Nm
-will ask for confirmation; you must type in the words
-.Li "NO FUTURE"
-exactly as shown:
-.Bd -unfilled -offset indent
-.No # Nm Ic resetconfig
-
-WARNING! This command will completely wipe out your vinum
-configuration. All data will be lost. If you really want
-to do this, enter the text
-
-NO FUTURE
-.No "Enter text ->" Sy "NO FUTURE"
-Vinum configuration obliterated
-.Ed
-.Pp
-As the message suggests, this is a last-ditch command.
-Don't use it unless you
-have an existing configuration which you never want to see again.
-.Pp
-.It Xo
-.Ic resetstats
-.Op Fl r
-.Op Ar volume | plex | subdisk
-.Xc
-.Nm
-maintains a number of statistical counters for each object.
-See the header file
-.In sys/dev/vinumvar.h
-for more information.
-.\" XXX put it in here when it's finalized
-Use the
-.Ic resetstats
-command to reset these counters.
-In conjunction with the
-.Fl r
-option,
-.Nm
-also resets the counters of subordinate objects.
-.Pp
-.It Xo
-.Ic rm
-.Op Fl f
-.Op Fl r
-.Ar volume | plex | subdisk
-.Xc
-.Ic rm
-removes an object from the
-.Nm
-configuration.
-Once an object has been removed, there is no way to recover it.
-Normally
-.Nm
-performs a large amount of consistency checking before removing an object.
-The
-.Fl f
-option tells
-.Nm
-to omit this checking and remove the object anyway.
-Use this option with great
-care: it can result in total loss of data on a volume.
-.Pp
-Normally,
-.Nm
-refuses to remove a volume or plex if it has subordinate plexes or subdisks
-respectively.
-You can tell
-.Nm
-to remove the object anyway by using the
-.Fl f
-option, or you can cause
-.Nm
-to remove the subordinate objects as well by using the
-.Fl r
-(recursive) option.
-If you remove a volume with the
-.Fl r
-option, it will remove both the plexes and the subdisks which belong to the
-plexes.
-.Pp
-.It Ic saveconfig
-Save the current configuration to disk.
-Normally this is not necessary, since
-.Nm
-automatically saves any change in configuration.
-If an error occurs on startup,
-updates will be disabled.
-When you reenable them with the
-.Ic setdaemon
-command,
-.Nm
-does not automatically save the configuration to disk.
-Use this command to save
-the configuration.
-.\".Pp
-.\".It Xo
-.\".Ic set
-.\".Op Fl f
-.\".Ar state
-.\".Ar volume | plex | subdisk | disk
-.\".Xc
-.\".Ic set
-.\"sets the state of the specified object to one of the valid states (see
-.\".Sx OBJECT STATES
-.\"below).
-.\"Normally
-.\".Nm
-.\"performs a large amount of consistency checking before making the change.
-.\"The
-.\".Fl f
-.\"option tells
-.\".Nm
-.\"to omit this checking and perform the change anyway.
-.\"Use this option with great
-.\"care: it can result in total loss of data on a volume.
-.Pp
-.It Ic setdaemon Op Ar value
-.Ic setdaemon
-sets a variable bitmask for the
-.Nm
-daemon.
-This command is temporary and will be replaced.
-Currently, the bit mask
-may contain the bits 1 (log every action to syslog) and 4 (don't update
-configuration).
-Option bit 4 can be useful for error recovery.
-.Pp
-.It Xo
-.Ic setstate Ar state
-.Op Ar volume | plex | subdisk | drive
-.Xc
-.Ic setstate
-sets the state of the specified objects to the specified state.
-This bypasses
-the usual consistency mechanism of
-.Nm
-and should be used only for recovery purposes.
-It is possible to crash the
-system by incorrect use of this command.
-.Pp
-.It Xo
-.Ic start
-.Op Fl i Ar interval
-.Op Fl S Ar size
-.Op Fl w
-.Op Ar plex | subdisk
-.Xc
-.Ic start
-starts (brings into to the
-.Em up
-state) one or more
-.Nm
-objects.
-.Pp
-If no object names are specified,
-.Nm
-scans the disks known to the system for
-.Nm
-drives and then reads in the configuration as described under the
-.Ic read
-commands.
-The
-.Nm
-drive contains a header with all information about the data stored on the drive,
-including the names of the other drives which are required in order to represent
-plexes and volumes.
-.Pp
-If
-.Nm
-encounters any errors during this command, it will turn off automatic
-configuration update to avoid corrupting the copies on disk.
-This will also
-happen if the configuration on disk indicates a configuration error (for
-example, subdisks which do not have a valid space specification).
-You can turn
-the updates on again with the
-.Ic setdaemon
-and
-.Ic saveconfig
-command.
-Reset bit 4 of the daemon options mask to re-enable configuration
-saves.
-.Pp
-If object names are specified,
-.Nm
-starts them.
-Normally this operation is only of use with subdisks.
-The action
-depends on the current state of the object:
-.Bl -bullet
-.It
-If the object is already in the
-.Em up
-state,
-.Nm
-does nothing.
-.It
-If the object is a subdisk in the
-.Em down
-or
-.Em reborn
-states,
-.Nm
-changes it to the
-.Em up
-state.
-.It
-If the object is a subdisk in the
-.Em empty
-state, the change depends on the subdisk.
-If it is part of a plex which is part
-of a volume which contains other plexes,
-.Nm
-places the subdisk in the
-.Em reviving
-state and attempts to copy the data from the volume.
-When the operation
-completes, the subdisk is set into the
-.Em up
-state.
-If it is part of a plex which is part of a volume which contains no
-other plexes, or if it is not part of a plex,
-.Nm
-brings it into the
-.Em up
-state immediately.
-.It
-If the object is a subdisk in the
-.Em reviving
-state,
-.Nm
-continues the revive
-operation offline.
-When the operation completes, the subdisk is set into the
-.Em up
-state.
-.El
-.Pp
-When a subdisk comes into the
-.Em up
-state,
-.Nm
-automatically checks the state of any plex and volume to which it may belong and
-changes their state where appropriate.
-.Pp
-If the object is a plex,
-.Ic start
-checks the state of the subordinate subdisks (and plexes in the case of a
-volume) and starts any subdisks which can be started.
-.Pp
-To start a plex in a multi-plex volume, the data must be copied from another
-plex in the volume.
-Since this frequently takes a long time, it is normally
-done in the background.
-If you want to wait for this operation to complete (for
-example, if you are performing this operation in a script), use the
-.Fl w
-option.
-.Pp
-Copying data doesn't just take a long time, it can also place a significant load
-on the system.
-You can specify the transfer size in bytes or sectors with the
-.Fl S
-option, and an interval (in milliseconds) to wait between copying each block with
-the
-.Fl i
-option.
-Both of these options lessen the load on the system.
-.Pp
-.It Xo
-.Ic stop
-.Op Fl f
-.Op Ar volume | plex | subdisk
-.Xc
-If no parameters are specified,
-.Ic stop
-removes the
-.Nm
-kld and stops
-.Xr vinum 4 .
-This can only be done if no objects are active.
-In particular, the
-.Fl f
-option does not override this requirement.
-Normally, the
-.Ic stop
-command writes the current configuration back to the drives before terminating.
-This will not be possible if configuration updates are disabled, so
-.Nm
-will not stop if configuration updates are disabled.
-You can override this by
-specifying the
-.Fl f
-option.
-.Pp
-The
-.Ic stop
-command can only work if
-.Nm
-has been loaded as a kld, since it is not possible to unload a statically
-configured driver.
-.Nm Ic stop
-will fail if
-.Nm
-is statically configured.
-.Pp
-If object names are specified,
-.Ic stop
-disables access to the objects.
-If the objects have subordinate objects, the
-subordinate objects must either already be inactive (stopped or in error), or
-the
-.Fl r
-and
-.Fl f
-options must be specified.
-This command does not remove the objects from the
-configuration.
-They can be accessed again after a
-.Ic start
-command.
-.Pp
-By default,
-.Nm
-does not stop active objects.
-For example, you cannot stop a plex which is
-attached to an active volume, and you cannot stop a volume which is open.
-The
-.Fl f
-option tells
-.Nm
-to omit this checking and remove the object anyway.
-Use this option with great
-care and understanding: used incorrectly, it can result in serious data
-corruption.
-.Pp
-.It Xo
-.Ic stripe
-.Op Fl f
-.Op Fl n Ar name
-.Op Fl v
-.Ar drives
-.Xc
-The
-.Ic stripe
-command provides a simplified alternative to the
-.Ic create
-command for creating volumes with a single striped plex.
-The size of the
-subdisks is the size of the largest contiguous space available on all the
-specified drives.
-The stripe size is fixed at 279 kB.
-.Pp
-Normally, the
-.Ic stripe
-command creates an arbitrary name for the volume and its components.
-The name
-is composed of the text
-.Dq Li vinum
-and a small integer, for example
-.Dq Li vinum3 .
-You can override this with the
-.Fl n Ar name
-option, which assigns the name specified to the volume.
-The plexes and subdisks
-are named after the volume in the default manner.
-.Pp
-There is no choice of name for the drives.
-If the drives have already been
-initialized as
-.Nm
-drives, the name remains.
-Otherwise the drives are given names starting with
-the text
-.Dq Li vinumdrive
-and a small integer, for example
-.Dq Li vinumdrive7 .
-As with the
-.Ic create
-command, the
-.Fl f
-option can be used to specify that a previous name should be overwritten.
-The
-.Fl v
-is used to specify verbose output.
-.Pp
-See the section
-.Sx SIMPLIFIED CONFIGURATION
-below for some examples of this
-command.
-.El
-.Sh SIMPLIFIED CONFIGURATION
-This section describes a simplified interface to
-.Nm
-configuration using the
-.Ic concat ,
-.Ic mirror
-and
-.Ic stripe
-commands.
-These commands create convenient configurations for some more normal
-situations, but they are not as flexible as the
-.Ic create
-command.
-.Pp
-See above for the description of the commands.
-Here are some examples, all
-performed with the same collection of disks.
-Note that the first drive,
-.Pa /dev/da1h ,
-is smaller than the others.
-This has an effect on the sizes chosen for each
-kind of subdisk.
-.Pp
-The following examples all use the
-.Fl v
-option to show the commands passed to the system, and also to list the structure
-of the volume.
-Without the
-.Fl v
-option, these commands produce no output.
-.Ss Volume with a single concatenated plex
-Use a volume with a single concatenated plex for the largest possible storage
-without resilience to drive failures:
-.Bd -literal
-vinum -> concat -v /dev/da1h /dev/da2h /dev/da3h /dev/da4h
-volume vinum0
- plex name vinum0.p0 org concat
-drive vinumdrive0 device /dev/da1h
- sd name vinum0.p0.s0 drive vinumdrive0 size 0
-drive vinumdrive1 device /dev/da2h
- sd name vinum0.p0.s1 drive vinumdrive1 size 0
-drive vinumdrive2 device /dev/da3h
- sd name vinum0.p0.s2 drive vinumdrive2 size 0
-drive vinumdrive3 device /dev/da4h
- sd name vinum0.p0.s3 drive vinumdrive3 size 0
-V vinum0 State: up Plexes: 1 Size: 2134 MB
-P vinum0.p0 C State: up Subdisks: 4 Size: 2134 MB
-S vinum0.p0.s0 State: up D: vinumdrive0 Size: 414 MB
-S vinum0.p0.s1 State: up D: vinumdrive1 Size: 573 MB
-S vinum0.p0.s2 State: up D: vinumdrive2 Size: 573 MB
-S vinum0.p0.s3 State: up D: vinumdrive3 Size: 573 MB
-.Ed
-.Pp
-In this case, the complete space on all four disks was used, giving a volume
-2134 MB in size.
-.Ss Volume with a single striped plex
-A volume with a single striped plex may give better performance than a
-concatenated plex, but restrictions on striped plexes can mean that the volume
-is smaller.
-It will also not be resilient to a drive failure:
-.Bd -literal
-vinum -> stripe -v /dev/da1h /dev/da2h /dev/da3h /dev/da4h
-drive vinumdrive0 device /dev/da1h
-drive vinumdrive1 device /dev/da2h
-drive vinumdrive2 device /dev/da3h
-drive vinumdrive3 device /dev/da4h
-volume vinum0
- plex name vinum0.p0 org striped 279k
- sd name vinum0.p0.s0 drive vinumdrive0 size 849825b
- sd name vinum0.p0.s1 drive vinumdrive1 size 849825b
- sd name vinum0.p0.s2 drive vinumdrive2 size 849825b
- sd name vinum0.p0.s3 drive vinumdrive3 size 849825b
-V vinum0 State: up Plexes: 1 Size: 1659 MB
-P vinum0.p0 S State: up Subdisks: 4 Size: 1659 MB
-S vinum0.p0.s0 State: up D: vinumdrive0 Size: 414 MB
-S vinum0.p0.s1 State: up D: vinumdrive1 Size: 414 MB
-S vinum0.p0.s2 State: up D: vinumdrive2 Size: 414 MB
-S vinum0.p0.s3 State: up D: vinumdrive3 Size: 414 MB
-.Ed
-.Pp
-In this case, the size of the subdisks has been limited to the smallest
-available disk, so the resulting volume is only 1659 MB in size.
-.Ss Mirrored volume with two concatenated plexes
-For more reliability, use a mirrored, concatenated volume:
-.Bd -literal
-vinum -> mirror -v -n mirror /dev/da1h /dev/da2h /dev/da3h /dev/da4h
-drive vinumdrive0 device /dev/da1h
-drive vinumdrive1 device /dev/da2h
-drive vinumdrive2 device /dev/da3h
-drive vinumdrive3 device /dev/da4h
-volume mirror setupstate
- plex name mirror.p0 org concat
- sd name mirror.p0.s0 drive vinumdrive0 size 0b
- sd name mirror.p0.s1 drive vinumdrive2 size 0b
- plex name mirror.p1 org concat
- sd name mirror.p1.s0 drive vinumdrive1 size 0b
- sd name mirror.p1.s1 drive vinumdrive3 size 0b
-V mirror State: up Plexes: 2 Size: 1146 MB
-P mirror.p0 C State: up Subdisks: 2 Size: 988 MB
-P mirror.p1 C State: up Subdisks: 2 Size: 1146 MB
-S vinum0.p0.s0 State: up D: vinumdrive0 Size: 414 MB
-S vinum0.p0.s2 State: up D: vinumdrive2 Size: 414 MB
-S vinum0.p0.s1 State: up D: vinumdrive1 Size: 414 MB
-S vinum0.p0.s3 State: up D: vinumdrive3 Size: 414 MB
-.Ed
-.Pp
-This example specifies the name of the volume,
-.Ar mirror .
-Since one drive is smaller than the others, the two plexes are of different
-size, and the last 158 MB of the volume is non-resilient.
-To ensure complete
-reliability in such a situation, use the
-.Ic create
-command to create a volume with 988 MB.
-.Ss Mirrored volume with two striped plexes
-Alternatively, use the
-.Fl s
-option to create a mirrored volume with two striped plexes:
-.Bd -literal
-vinum -> mirror -v -n raid10 -s /dev/da1h /dev/da2h /dev/da3h /dev/da4h
-drive vinumdrive0 device /dev/da1h
-drive vinumdrive1 device /dev/da2h
-drive vinumdrive2 device /dev/da3h
-drive vinumdrive3 device /dev/da4h
-volume raid10 setupstate
- plex name raid10.p0 org striped 279k
- sd name raid10.p0.s0 drive vinumdrive0 size 849825b
- sd name raid10.p0.s1 drive vinumdrive2 size 849825b
- plex name raid10.p1 org striped 279k
- sd name raid10.p1.s0 drive vinumdrive1 size 1173665b
- sd name raid10.p1.s1 drive vinumdrive3 size 1173665b
-V raid10 State: up Plexes: 2 Size: 1146 MB
-P raid10.p0 S State: up Subdisks: 2 Size: 829 MB
-P raid10.p1 S State: up Subdisks: 2 Size: 1146 MB
-S raid10.p0.s0 State: up PO: 0 B Size: 414 MB
-S raid10.p0.s1 State: up PO: 279 kB Size: 414 MB
-S raid10.p1.s0 State: up PO: 0 B Size: 573 MB
-S raid10.p1.s1 State: up PO: 279 kB Size: 573 MB
-.Ed
-.Pp
-In this case, the usable part of the volume is even smaller, since the first
-plex has shrunken to match the smallest drive.
-.Sh CONFIGURATION FILE
-The
-.Nm
-utility requires that all parameters to the
-.Ic create
-commands must be in a configuration file.
-Entries in the configuration file
-define volumes, plexes and subdisks, and may be in free format, except that each
-entry must be on a single line.
-.Ss Scale factors
-Some configuration file parameters specify a size (lengths, stripe sizes).
-These values can be specified as bytes, or one of the following scale factors
-may be appended:
-.Bl -tag -width indent
-.It s
-specifies that the value is a number of sectors of 512 bytes.
-.It k
-specifies that the value is a number of kilobytes (1024 bytes).
-.It m
-specifies that the value is a number of megabytes (1048576 bytes).
-.It g
-specifies that the value is a number of gigabytes (1073741824 bytes).
-.It b
-is used for compatibility with
-.Tn VERITAS .
-It stands for blocks of 512 bytes.
-This abbreviation is confusing, since the word
-.Dq block
-is used in different meanings, and its use is deprecated.
-Use the keyword 's'
-instead.
-.El
-.Pp
-For example, the value 16777216 bytes can also be written as
-.Em 16m ,
-.Em 16384k
-or
-.Em 32768s .
-.Pp
-The configuration file can contain the following entries:
-.Bl -tag -width 4n
-.It Ic drive Ar name devicename Op Ar options
-Define a drive.
-The options are:
-.Bl -tag -width 18n
-.It Cm device Ar devicename
-Specify the device on which the drive resides.
-.Ar devicename
-must be the name of a disk partition, for example
-.Pa /dev/da1e
-or
-.Pa /dev/ad3s2h ,
-and it must be of type
-.Em vinum .
-Do not use the
-.Dq Li c
-partition, which is reserved for the complete disk.
-.It Cm hotspare
-Define the drive to be a
-.Dq hot spare
-drive, which is maintained to automatically replace a failed drive.
-The
-.Nm
-utility
-does not allow this drive to be used for any other purpose.
-In particular, it
-is not possible to create subdisks on it.
-This functionality has not been
-completely implemented.
-.El
-.It Ic volume Ar name Op Ar options
-Define a volume with name
-.Ar name .
-Options are:
-.Bl -tag -width 18n
-.It Cm plex Ar plexname
-Add the specified plex to the volume.
-If
-.Ar plexname
-is specified as
-.Cm * ,
-.Nm
-will look for the definition of the plex as the next possible entry in the
-configuration file after the definition of the volume.
-.It Cm readpol Ar policy
-Define a
-.Em read policy
-for the volume.
-.Ar policy
-may be either
-.Cm round
-or
-.Cm prefer Ar plexname .
-The
-.Nm
-utility satisfies a read request from only one of the plexes.
-A
-.Cm round
-read policy specifies that each read should be performed from a different plex
-in
-.Em round-robin
-fashion.
-A
-.Cm prefer
-read policy reads from the specified plex every time.
-.It Cm setupstate
-When creating a multi-plex volume, assume that the contents of all the plexes
-are consistent.
-This is normally not the case, so by default
-.Nm
-sets all plexes except the first one to the
-.Em faulty
-state.
-Use the
-.Ic start
-command to first bring them to a consistent state.
-In the case of striped and
-concatenated plexes, however, it does not normally cause problems to leave them
-inconsistent: when using a volume for a file system or a swap partition, the
-previous contents of the disks are not of interest, so they may be ignored.
-If you want to take this risk, use the
-.Cm setupstate
-keyword.
-It will only apply to the plexes defined immediately after the volume
-in the configuration file.
-If you add plexes to a volume at a later time, you
-must integrate them manually with the
-.Ic start
-command.
-.Pp
-Note that you
-.Em must
-use the
-.Ic init
-command with RAID-5 plexes: otherwise extreme data corruption will result if one
-subdisk fails.
-.El
-.It Ic plex Op Ar options
-Define a plex.
-Unlike a volume, you do not need to specify a name for a plex.
-The options may be:
-.Bl -tag -width 18n
-.It Cm name Ar plexname
-Specify the name of the plex.
-Note that you must use the keyword
-.Cm name
-when naming a plex or subdisk.
-.It Cm org Ar organization Op Ar stripesize
-Specify the organization of the plex.
-.Ar organization
-can be one of
-.Cm concat , striped
-or
-.Cm raid5 .
-For
-.Cm striped
-and
-.Cm raid5
-plexes, the parameter
-.Ar stripesize
-must be specified, while for
-.Cm concat
-it must be omitted.
-For type
-.Cm striped ,
-it specifies the width of each stripe.
-For type
-.Cm raid5 ,
-it specifies the size of a group.
-A group is a portion of a plex which
-stores the parity bits all in the same subdisk.
-It must be a factor of the plex size (in
-other words, the result of dividing the plex size by the stripe size must be an
-integer), and it must be a multiple of a disk sector (512 bytes).
-.Pp
-For optimum performance, stripes should be at least 128 kB in size: anything
-smaller will result in a significant increase in I/O activity due to mapping of
-individual requests over multiple disks.
-The performance improvement due to the
-increased number of concurrent transfers caused by this mapping will not make up
-for the performance drop due to the increase in latency.
-A good guideline for
-stripe size is between 256 kB and 512 kB.
-Avoid powers of 2, however: they tend
-to cause all superblocks to be placed on the first subdisk.
-The simplified
-commands use a stripe size of 279 kB, which shows a reasonable distribution of
-superblocks.
-.Pp
-A striped plex must have at least two subdisks (otherwise it is a concatenated
-plex), and each must be the same size.
-A RAID-5 plex must have at least three
-subdisks, and each must be the same size.
-In practice, a RAID-5 plex should
-have at least 5 subdisks.
-.It Cm volume Ar volname
-Add the plex to the specified volume.
-If no
-.Cm volume
-keyword is specified, the plex will be added to the last volume mentioned in the
-configuration file.
-.It Cm sd Ar sdname offset
-Add the specified subdisk to the plex at offset
-.Ar offset .
-.El
-.It Ic subdisk Op Ar options
-Define a subdisk.
-Options may be:
-.Bl -hang -width 18n
-.It Cm name Ar name
-Specify the name of a subdisk.
-It is not necessary to specify a name for a
-subdisk\(emsee
-.Sx OBJECT NAMING
-above.
-Note that you must specify the keyword
-.Cm name
-if you wish to name a subdisk.
-.It Cm plexoffset Ar offset
-Specify the starting offset of the subdisk in the plex.
-If not specified,
-.Nm
-allocates the space immediately after the previous subdisk, if any, or otherwise
-at the beginning of the plex.
-.It Cm driveoffset Ar offset
-Specify the starting offset of the subdisk in the drive.
-If not specified,
-.Nm
-allocates the first contiguous
-.Ar length
-bytes of free space on the drive.
-.It Cm length Ar length
-Specify the length of the subdisk.
-This keyword must be specified.
-There is no
-default, but the value 0 may be specified to mean
-.Dq "use the largest available contiguous free area on the drive" .
-If the drive is empty, this means that the entire drive will be used for the
-subdisk.
-.Cm length
-may be shortened to
-.Cm len .
-.It Cm plex Ar plex
-Specify the plex to which the subdisk belongs.
-By default, the subdisk belongs
-to the last plex specified.
-.It Cm drive Ar drive
-Specify the drive on which the subdisk resides.
-By default, the subdisk resides
-on the last drive specified.
-.It Cm retryerrors
-Specify that the subdisk should not be taken down if an unrecoverable error
-occurs.
-Normally
-.Nm
-responds to an unrecoverable error by making the entire subdisk inaccessible.
-.El
-.El
-.Sh EXAMPLE CONFIGURATION FILE
-.Bd -literal
-# Sample vinum configuration file
-#
-# Our drives
-drive drive1 device /dev/da1h
-drive drive2 device /dev/da2h
-drive drive3 device /dev/da3h
-drive drive4 device /dev/da4h
-drive drive5 device /dev/da5h
-drive drive6 device /dev/da6h
-# A volume with one striped plex
-volume tinyvol
- plex org striped 279k
- sd length 64m drive drive2
- sd length 64m drive drive4
-volume stripe
- plex org striped 279k
- sd length 512m drive drive2
- sd length 512m drive drive4
-# Two plexes
-volume concat
- plex org concat
- sd length 100m drive drive2
- sd length 50m drive drive4
- plex org concat
- sd length 150m drive drive4
-# A volume with one striped plex and one concatenated plex
-volume strcon
- plex org striped 279k
- sd length 100m drive drive2
- sd length 100m drive drive4
- plex org concat
- sd length 150m drive drive2
- sd length 50m drive drive4
-# a volume with a RAID-5 and a striped plex
-# note that the RAID-5 volume is longer by
-# the length of one subdisk
-volume vol5
- plex org striped 491k
- sd length 1000m drive drive2
- sd length 1000m drive drive4
- plex org raid5 273k
- sd length 500m drive drive1
- sd length 500m drive drive2
- sd length 500m drive drive3
- sd length 500m drive drive4
- sd length 500m drive drive5
-.Ed
-.Sh DRIVE LAYOUT CONSIDERATIONS
-.Nm
-drives are currently
-.Bx
-disk partitions.
-They must be of type
-.Em vinum
-in order to avoid overwriting data used for other purposes.
-Use
-.Nm disklabel Fl e
-to edit a partition type definition.
-The following display shows a typical
-partition layout as shown by
-.Xr disklabel 8 :
-.Bd -literal
-8 partitions:
-# size offset fstype [fsize bsize bps/cpg]
- a: 81920 344064 4.2BSD 0 0 0 # (Cyl. 240*- 297*)
- b: 262144 81920 swap # (Cyl. 57*- 240*)
- c: 4226725 0 unused 0 0 # (Cyl. 0 - 2955*)
- e: 81920 0 4.2BSD 0 0 0 # (Cyl. 0 - 57*)
- f: 1900000 425984 4.2BSD 0 0 0 # (Cyl. 297*- 1626*)
- g: 1900741 2325984 vinum 0 0 0 # (Cyl. 1626*- 2955*)
-.Ed
-.Pp
-In this example, partition
-.Dq Li g
-may be used as a
-.Nm
-partition.
-Partitions
-.Dq Li a ,
-.Dq Li e
-and
-.Dq Li f
-may be used as
-.Em UFS
-file systems or
-.Em ccd
-partitions.
-Partition
-.Dq Li b
-is a swap partition, and partition
-.Dq Li c
-represents the whole disk and should not be used for any other purpose.
-.Pp
-The
-.Nm
-utility
-uses the first 265 sectors on each partition for configuration information, so
-the maximum size of a subdisk is 265 sectors smaller than the drive.
-.Sh LOG FILE
-The
-.Nm
-utility maintains a log file, by default
-.Pa /var/log/vinum_history ,
-in which it keeps track of the commands issued to
-.Nm .
-You can override the name of this file by setting the environment variable
-.Ev VINUM_HISTORY
-to the name of the file.
-.Pp
-Each message in the log file is preceded by a date.
-The default format is
-.Qq Li %e %b %Y %H:%M:%S .
-See
-.Xr strftime 3
-for further details of the format string.
-It can be overridden by the
-environment variable
-.Ev VINUM_DATEFORMAT .
-.Sh HOW TO SET UP VINUM
-This section gives practical advice about how to implement a
-.Nm
-system.
-.Ss Where to put the data
-The first choice you need to make is where to put the data.
-You need dedicated
-disk partitions for
-.Nm .
-They should be partitions, not devices, and they should not be partition
-.Dq Li c .
-For example, good names are
-.Pa /dev/da0e
-or
-.Pa /dev/ad3s4a .
-Bad names are
-.Pa /dev/da0
-and
-.Pa /dev/da0s1 ,
-both of which represent a device, not a partition, and
-.Pa /dev/ad1c ,
-which represents a complete disk and should be of type
-.Em unused .
-See the example under
-.Sx DRIVE LAYOUT CONSIDERATIONS
-above.
-.Ss Designing volumes
-The way you set up
-.Nm
-volumes depends on your intentions.
-There are a number of possibilities:
-.Bl -enum
-.It
-You may want to join up a number of small disks to make a reasonable sized file
-system.
-For example, if you had five small drives and wanted to use all the
-space for a single volume, you might write a configuration file like:
-.Bd -literal -offset indent
-drive d1 device /dev/da2e
-drive d2 device /dev/da3e
-drive d3 device /dev/da4e
-drive d4 device /dev/da5e
-drive d5 device /dev/da6e
-volume bigger
- plex org concat
- sd length 0 drive d1
- sd length 0 drive d2
- sd length 0 drive d3
- sd length 0 drive d4
- sd length 0 drive d5
-.Ed
-.Pp
-In this case, you specify the length of the subdisks as 0, which means
-.Dq "use the largest area of free space that you can find on the drive" .
-If the subdisk is the only subdisk on the drive, it will use all available
-space.
-.It
-You want to set up
-.Nm
-to obtain additional resilience against disk failures.
-You have the choice of
-RAID-1, also called
-.Dq mirroring ,
-or RAID-5, also called
-.Dq parity .
-.Pp
-To set up mirroring, create multiple plexes in a volume.
-For example, to create
-a mirrored volume of 2 GB, you might create the following configuration file:
-.Bd -literal -offset indent
-drive d1 device /dev/da2e
-drive d2 device /dev/da3e
-volume mirror
- plex org concat
- sd length 2g drive d1
- plex org concat
- sd length 2g drive d2
-.Ed
-.Pp
-When creating mirrored drives, it is important to ensure that the data from each
-plex is on a different physical disk so that
-.Nm
-can access the complete address space of the volume even if a drive fails.
-Note that each plex requires as much data as the complete volume: in this
-example, the volume has a size of 2 GB, but each plex (and each subdisk)
-requires 2 GB, so the total disk storage requirement is 4 GB.
-.Pp
-To set up RAID-5, create a single plex of type
-.Cm raid5 .
-For example, to create an equivalent resilient volume of 2 GB, you might use the
-following configuration file:
-.Bd -literal -offset indent
-drive d1 device /dev/da2e
-drive d2 device /dev/da3e
-drive d3 device /dev/da4e
-drive d4 device /dev/da5e
-drive d5 device /dev/da6e
-volume raid
- plex org raid5 433k
- sd length 512m drive d1
- sd length 512m drive d2
- sd length 512m drive d3
- sd length 512m drive d4
- sd length 512m drive d5
-.Ed
-.Pp
-RAID-5 plexes require at least three subdisks, one of which is used for storing
-parity information and is lost for data storage.
-The more disks you use, the
-greater the proportion of the disk storage can be used for data storage.
-In
-this example, the total storage usage is 2.5 GB, compared to 4 GB for a mirrored
-configuration.
-If you were to use the minimum of only three disks, you would
-require 3 GB to store the information, for example:
-.Bd -literal -offset indent
-drive d1 device /dev/da2e
-drive d2 device /dev/da3e
-drive d3 device /dev/da4e
-volume raid
- plex org raid5 433k
- sd length 1g drive d1
- sd length 1g drive d2
- sd length 1g drive d3
-.Ed
-.Pp
-As with creating mirrored drives, it is important to ensure that the data from
-each subdisk is on a different physical disk so that
-.Nm
-can access the complete address space of the volume even if a drive fails.
-.It
-You want to set up
-.Nm
-to allow more concurrent access to a file system.
-In many cases, access to a
-file system is limited by the speed of the disk.
-By spreading the volume across
-multiple disks, you can increase the throughput in multi-access environments.
-This technique shows little or no performance improvement in single-access
-environments.
-The
-.Nm
-utility uses a technique called
-.Dq striping ,
-or sometimes RAID-0, to increase this concurrency of access.
-The name RAID-0 is
-misleading: striping does not provide any redundancy or additional reliability.
-In fact, it decreases the reliability, since the failure of a single disk will
-render the volume useless, and the more disks you have, the more likely it is
-that one of them will fail.
-.Pp
-To implement striping, use a
-.Cm striped
-plex:
-.Bd -literal -offset indent
-drive d1 device /dev/da2e
-drive d2 device /dev/da3e
-drive d3 device /dev/da4e
-drive d4 device /dev/da5e
-volume raid
- plex org striped 433k
- sd length 512m drive d1
- sd length 512m drive d2
- sd length 512m drive d3
- sd length 512m drive d4
-.Ed
-.Pp
-A striped plex must have at least two subdisks, but the increase in performance
-is greater if you have a larger number of disks.
-.It
-You may want to have the best of both worlds and have both resilience and
-performance.
-This is sometimes called RAID-10 (a combination of RAID-1 and
-RAID-0), though again this name is misleading.
-With
-.Nm
-you can do this with the following configuration file:
-.Bd -literal -offset indent
-drive d1 device /dev/da2e
-drive d2 device /dev/da3e
-drive d3 device /dev/da4e
-drive d4 device /dev/da5e
-volume raid setupstate
- plex org striped 433k
- sd length 512m drive d1
- sd length 512m drive d2
- sd length 512m drive d3
- sd length 512m drive d4
- plex org striped 433k
- sd length 512m drive d4
- sd length 512m drive d3
- sd length 512m drive d2
- sd length 512m drive d1
-.Ed
-.Pp
-Here the plexes are striped, increasing performance, and there are two of them,
-increasing reliability.
-Note that this example shows the subdisks of the second
-plex in reverse order from the first plex.
-This is for performance reasons and
-will be discussed below.
-In addition, the volume specification includes the
-keyword
-.Cm setupstate ,
-which ensures that all plexes are
-.Em up
-after creation.
-.El
-.Ss Creating the volumes
-Once you have created your configuration files, start
-.Nm
-and create the volumes.
-In this example, the configuration is in the file
-.Pa configfile :
-.Bd -literal -offset 2n
-# vinum create -v configfile
- 1: drive d1 device /dev/da2e
- 2: drive d2 device /dev/da3e
- 3: volume mirror
- 4: plex org concat
- 5: sd length 2g drive d1
- 6: plex org concat
- 7: sd length 2g drive d2
-Configuration summary
-
-Drives: 2 (4 configured)
-Volumes: 1 (4 configured)
-Plexes: 2 (8 configured)
-Subdisks: 2 (16 configured)
-
-Drive d1: Device /dev/da2e
- Created on vinum.lemis.com at Tue Mar 23 12:30:31 1999
- Config last updated Tue Mar 23 14:30:32 1999
- Size: 60105216000 bytes (57320 MB)
- Used: 2147619328 bytes (2048 MB)
- Available: 57957596672 bytes (55272 MB)
- State: up
- Last error: none
-Drive d2: Device /dev/da3e
- Created on vinum.lemis.com at Tue Mar 23 12:30:32 1999
- Config last updated Tue Mar 23 14:30:33 1999
- Size: 60105216000 bytes (57320 MB)
- Used: 2147619328 bytes (2048 MB)
- Available: 57957596672 bytes (55272 MB)
- State: up
- Last error: none
-
-Volume mirror: Size: 2147483648 bytes (2048 MB)
- State: up
- Flags:
- 2 plexes
- Read policy: round robin
-
-Plex mirror.p0: Size: 2147483648 bytes (2048 MB)
- Subdisks: 1
- State: up
- Organization: concat
- Part of volume mirror
-Plex mirror.p1: Size: 2147483648 bytes (2048 MB)
- Subdisks: 1
- State: up
- Organization: concat
- Part of volume mirror
-
-Subdisk mirror.p0.s0:
- Size: 2147483648 bytes (2048 MB)
- State: up
- Plex mirror.p0 at offset 0
-
-Subdisk mirror.p1.s0:
- Size: 2147483648 bytes (2048 MB)
- State: up
- Plex mirror.p1 at offset 0
-.Ed
-.Pp
-The
-.Fl v
-option tells
-.Nm
-to list the file as it configures.
-Subsequently it lists the current
-configuration in the same format as the
-.Ic list Fl v
-command.
-.Ss Creating more volumes
-Once you have created the
-.Nm
-volumes,
-.Nm
-keeps track of them in its internal configuration files.
-You do not need to
-create them again.
-In particular, if you run the
-.Ic create
-command again, you will create additional objects:
-.Bd -literal
-# vinum create sampleconfig
-Configuration summary
-
-Drives: 2 (4 configured)
-Volumes: 1 (4 configured)
-Plexes: 4 (8 configured)
-Subdisks: 4 (16 configured)
-
-D d1 State: up Device /dev/da2e Avail: 53224/57320 MB (92%)
-D d2 State: up Device /dev/da3e Avail: 53224/57320 MB (92%)
-
-V mirror State: up Plexes: 4 Size: 2048 MB
-
-P mirror.p0 C State: up Subdisks: 1 Size: 2048 MB
-P mirror.p1 C State: up Subdisks: 1 Size: 2048 MB
-P mirror.p2 C State: up Subdisks: 1 Size: 2048 MB
-P mirror.p3 C State: up Subdisks: 1 Size: 2048 MB
-
-S mirror.p0.s0 State: up PO: 0 B Size: 2048 MB
-S mirror.p1.s0 State: up PO: 0 B Size: 2048 MB
-S mirror.p2.s0 State: up PO: 0 B Size: 2048 MB
-S mirror.p3.s0 State: up PO: 0 B Size: 2048 MB
-.Ed
-.Pp
-As this example (this time with the
-.Fl f
-option) shows, re-running the
-.Ic create
-has created four new plexes, each with a new subdisk.
-If you want to add other
-volumes, create new configuration files for them.
-They do not need to reference
-the drives that
-.Nm
-already knows about.
-For example, to create a volume
-.Pa raid
-on the four drives
-.Pa /dev/da1e , /dev/da2e , /dev/da3e
-and
-.Pa /dev/da4e ,
-you only need to mention the other two:
-.Bd -literal -offset indent
-drive d3 device /dev/da1e
-drive d4 device /dev/da4e
-volume raid
- plex org raid5 433k
- sd size 2g drive d1
- sd size 2g drive d2
- sd size 2g drive d3
- sd size 2g drive d4
-.Ed
-.Pp
-With this configuration file, we get:
-.Bd -literal
-# vinum create newconfig
-Configuration summary
-
-Drives: 4 (4 configured)
-Volumes: 2 (4 configured)
-Plexes: 5 (8 configured)
-Subdisks: 8 (16 configured)
-
-D d1 State: up Device /dev/da2e Avail: 51176/57320 MB (89%)
-D d2 State: up Device /dev/da3e Avail: 53220/57320 MB (89%)
-D d3 State: up Device /dev/da1e Avail: 53224/57320 MB (92%)
-D d4 State: up Device /dev/da4e Avail: 53224/57320 MB (92%)
-
-V mirror State: down Plexes: 4 Size: 2048 MB
-V raid State: down Plexes: 1 Size: 6144 MB
-
-P mirror.p0 C State: init Subdisks: 1 Size: 2048 MB
-P mirror.p1 C State: init Subdisks: 1 Size: 2048 MB
-P mirror.p2 C State: init Subdisks: 1 Size: 2048 MB
-P mirror.p3 C State: init Subdisks: 1 Size: 2048 MB
-P raid.p0 R5 State: init Subdisks: 4 Size: 6144 MB
-
-S mirror.p0.s0 State: up PO: 0 B Size: 2048 MB
-S mirror.p1.s0 State: up PO: 0 B Size: 2048 MB
-S mirror.p2.s0 State: up PO: 0 B Size: 2048 MB
-S mirror.p3.s0 State: up PO: 0 B Size: 2048 MB
-S raid.p0.s0 State: empty PO: 0 B Size: 2048 MB
-S raid.p0.s1 State: empty PO: 433 kB Size: 2048 MB
-S raid.p0.s2 State: empty PO: 866 kB Size: 2048 MB
-S raid.p0.s3 State: empty PO: 1299 kB Size: 2048 MB
-.Ed
-.Pp
-Note the size of the RAID-5 plex: it is only 6 GB, although together its
-components use 8 GB of disk space.
-This is because the equivalent of one
-subdisk is used for storing parity data.
-.Ss Restarting Vinum
-On rebooting the system, start
-.Nm
-with the
-.Ic start
-command:
-.Pp
-.Dl "# vinum start"
-.Pp
-This will start all the
-.Nm
-drives in the system.
-If for some reason you wish to start only some of them,
-use the
-.Ic read
-command.
-.Ss Performance considerations
-A number of misconceptions exist about how to set up a RAID array for best
-performance.
-In particular, most systems use far too small a stripe size.
-The
-following discussion applies to all RAID systems, not just to
-.Nm .
-.Pp
-The
-.Fx
-block I/O system issues requests of between .5kB and 128 kB; a
-typical mix is somewhere round 8 kB.
-You can't stop any striping system from
-breaking a request into two physical requests, and if you make the stripe small
-enough, it can be broken into several.
-This will result in a significant drop
-in performance: the decrease in transfer time per disk is offset by the order of
-magnitude greater increase in latency.
-.Pp
-With modern disk sizes and the
-.Fx
-I/O system, you can expect to have a
-reasonably small number of fragmented requests with a stripe size between 256 kB
-and 512 kB; with correct RAID implementations there is no obvious reason not to
-increase the size to 2 or 4 MB on a large disk.
-.Pp
-When choosing a stripe size, consider that most current UFS file systems have
-cylinder groups 32 MB in size.
-If you have a stripe size and number of disks
-both of which are a power of two, it is probable that all superblocks and inodes
-will be placed on the same subdisk, which will impact performance significantly.
-Choose an odd number instead, for example 479 kB.
-.Pp
-The easiest way to consider the impact of any transfer in a multi-access system
-is to look at it from the point of view of the potential bottleneck, the disk
-subsystem: how much total disk time does the transfer use?
-Since just about
-everything is cached, the time relationship between the request and its
-completion is not so important: the important parameter is the total time that
-the request keeps the disks active, the time when the disks are not available to
-perform other transfers.
-As a result, it doesn't really matter if the transfers
-are happening at the same time or different times.
-In practical terms, the time
-we're looking at is the sum of the total latency (positioning time and
-rotational latency, or the time it takes for the data to arrive under the disk
-heads) and the total transfer time.
-For a given transfer to disks of the same
-speed, the transfer time depends only on the total size of the transfer.
-.Pp
-Consider a typical news article or web page of 24 kB, which will probably be
-read in a single I/O.
-Take disks with a transfer rate of 6 MB/s and an average
-positioning time of 8 ms, and a file system with 4 kB blocks.
-Since it's 24 kB,
-we don't have to worry about fragments, so the file will start on a 4 kB
-boundary.
-The number of transfers required depends on where the block starts:
-it's (S + F - 1) / S, where S is the stripe size in file system blocks, and F is
-the file size in file system blocks.
-.Bl -enum
-.It
-Stripe size of 4 kB.
-You'll have 6 transfers.
-Total subsystem load: 48 ms
-latency, 2 ms transfer, 50 ms total.
-.It
-Stripe size of 8 kB.
-On average, you'll have 3.5 transfers.
-Total subsystem
-load: 28 ms latency, 2 ms transfer, 30 ms total.
-.It
-Stripe size of 16 kB.
-On average, you'll have 2.25 transfers.
-Total subsystem
-load: 18 ms latency, 2 ms transfer, 20 ms total.
-.It
-Stripe size of 256 kB.
-On average, you'll have 1.08 transfers.
-Total subsystem
-load: 8.6 ms latency, 2 ms transfer, 10.6 ms total.
-.It
-Stripe size of 4 MB.
-On average, you'll have 1.0009 transfers.
-Total subsystem
-load: 8.01 ms latency, 2 ms transfer, 10.01 ms total.
-.El
-.Pp
-It appears that some hardware RAID systems have problems with large stripes:
-they appear to always transfer a complete stripe to or from disk, so that a
-large stripe size will have an adverse effect on performance.
-The
-.Nm
-utility
-does not suffer from this problem: it optimizes all disk transfers and does not
-transfer unneeded data.
-.Pp
-Note that no well-known benchmark program tests true multi-access conditions
-(more than 100 concurrent users), so it is difficult to demonstrate the validity
-of these statements.
-.Pp
-Given these considerations, the following factors affect the performance of a
-.Nm
-volume:
-.Bl -bullet
-.It
-Striping improves performance for multiple access only, since it increases the
-chance of individual requests being on different drives.
-.It
-Concatenating UFS file systems across multiple drives can also improve
-performance for multiple file access, since UFS divides a file system into
-cylinder groups and attempts to keep files in a single cylinder group.
-In
-general, it is not as effective as striping.
-.It
-Mirroring can improve multi-access performance for reads, since by default
-.Nm
-issues consecutive reads to consecutive plexes.
-.It
-Mirroring decreases performance for all writes, whether multi-access or single
-access, since the data must be written to both plexes.
-This explains the
-subdisk layout in the example of a mirroring configuration above: if the
-corresponding subdisk in each plex is on a different physical disk, the write
-commands can be issued in parallel, whereas if they are on the same physical
-disk, they will be performed sequentially.
-.It
-RAID-5 reads have essentially the same considerations as striped reads, unless
-the striped plex is part of a mirrored volume, in which case the performance of
-the mirrored volume will be better.
-.It
-RAID-5 writes are approximately 25% of the speed of striped writes: to perform
-the write,
-.Nm
-must first read the data block and the corresponding parity block, perform some
-calculations and write back the parity block and the data block, four times as
-many transfers as for writing a striped plex.
-On the other hand, this is offset
-by the cost of mirroring, so writes to a volume with a single RAID-5 plex are
-approximately half the speed of writes to a correctly configured volume with two
-striped plexes.
-.It
-When the
-.Nm
-configuration changes (for example, adding or removing objects, or the change of
-state of one of the objects),
-.Nm
-writes up to 128 kB of updated configuration to each drive.
-The larger the
-number of drives, the longer this takes.
-.El
-.Ss Creating file systems on Vinum volumes
-You do not need to run
-.Xr disklabel 8
-before creating a file system on a
-.Nm
-volume.
-Just run
-.Xr newfs 8 .
-Use the
-.Fl v
-option to state that the device is not divided into partitions.
-For example, to
-create a file system on volume
-.Pa mirror ,
-enter the following command:
-.Pp
-.Dl "# newfs -v /dev/vinum/mirror"
-.Pp
-A number of other considerations apply to
-.Nm
-configuration:
-.Bl -bullet
-.It
-There is no advantage in creating multiple drives on a single disk.
-Each drive
-uses 131.5 kB of data for label and configuration information, and performance
-will suffer when the configuration changes.
-Use appropriately sized subdisks instead.
-.It
-It is possible to increase the size of a concatenated
-.Nm
-plex, but currently the size of striped and RAID-5 plexes cannot be increased.
-Currently the size of an existing UFS file system also cannot be increased, but
-it is planned to make both plexes and file systems extensible.
-.El
-.Sh STATE MANAGEMENT
-Vinum objects have the concept of
-.Em state .
-See
-.Xr vinum 4
-for more details.
-They are only completely accessible if their state is
-.Em up .
-To change an object state to
-.Em up ,
-use the
-.Ic start
-command.
-To change an object state to
-.Em down ,
-use the
-.Ic stop
-command.
-Normally other states are created automatically by the relationship
-between objects.
-For example, if you add a plex to a volume, the subdisks of
-the plex will be set in the
-.Em empty
-state, indicating that, though the hardware is accessible, the data on the
-subdisk is invalid.
-As a result of this state, the plex will be set in the
-.Em faulty
-state.
-.Ss The `reviving' state
-In many cases, when you start a subdisk the system must copy data to the
-subdisk.
-Depending on the size of the subdisk, this can take a long time.
-During this time, the subdisk is set in the
-.Em reviving
-state.
-On successful completion of the copy operation, it is automatically set
-to the
-.Em up
-state.
-It is possible for the process performing the revive to be stopped and
-restarted.
-The system keeps track of how far the subdisk has been revived, and
-when the
-.Ic start
-command is reissued, the copying continues from this point.
-.Pp
-In order to maintain the consistency of a volume while one or more of its plexes
-is being revived,
-.Nm
-writes to subdisks which have been revived up to the point of the write.
-It may
-also read from the plex if the area being read has already been revived.
-.Sh GOTCHAS
-The following points are not bugs, and they have good reasons for existing, but
-they have shown to cause confusion.
-Each is discussed in the appropriate
-section above.
-.Bl -enum
-.It
-.Nm
-drives are
-.Ux
-disk partitions and must have the partition type
-.Em vinum .
-This is different from ccd, which expects partitions of type
-.Em 4.2BSD .
-This behaviour of
-.Nm ccd
-is an invitation to shoot yourself in the foot: with
-.Nm ccd
-you can easily overwrite a file system.
-The
-.Nm
-utility will not permit this.
-.Pp
-For similar reasons, the
-.Nm Ic start
-command will not accept a drive on partition
-.Dq Li c .
-Partition
-.Dq Li c
-is used by the system to represent the whole disk, and must be of type
-.Em unused .
-Clearly there is a conflict here, which
-.Nm
-resolves by not using the
-.Dq Li c
-partition.
-.It
-When you create a volume with multiple plexes,
-.Nm
-does not automatically initialize the plexes.
-This means that the contents are
-not known, but they are certainly not consistent.
-As a result, by default
-.Nm
-sets the state of all newly-created plexes except the first to
-.Em faulty .
-In order to synchronize them with the first plex, you must
-.Ic start
-them, which causes
-.Nm
-to copy the data from a plex which is in the
-.Em up
-state.
-Depending on the size of the subdisks involved, this can take a long
-time.
-.Pp
-In practice, people aren't too interested in what was in the plex when it was
-created, and other volume managers cheat by setting them
-.Em up
-anyway.
-The
-.Nm
-utility provides two ways to ensure that newly created plexes are
-.Em up :
-.Bl -bullet
-.It
-Create the plexes and then synchronize them with
-.Nm Ic start .
-.It
-Create the volume (not the plex) with the keyword
-.Cm setupstate ,
-which tells
-.Nm
-to ignore any possible inconsistency and set the plexes to be
-.Em up .
-.El
-.It
-Some of the commands currently supported by
-.Nm
-are not really needed.
-For reasons which I don't understand, however, I find
-that users frequently try the
-.Ic label
-and
-.Ic resetconfig
-commands, though especially
-.Ic resetconfig
-outputs all sort of dire warnings.
-Don't use these commands unless you have a
-good reason to do so.
-.It
-Some state transitions are not very intuitive.
-In fact, it's not clear whether
-this is a bug or a feature.
-If you find that you can't start an object in some
-strange state, such as a
-.Em reborn
-subdisk, try first to get it into
-.Em stopped
-state, with the
-.Ic stop
-or
-.Ic stop Fl f
-commands.
-If that works, you should then be able to start it.
-If you find
-that this is the only way to get out of a position where easier methods fail,
-please report the situation.
-.It
-If you build the kernel module with the
-.Fl D Ns Dv VINUMDEBUG
-option, you must also build
-.Nm
-with the
-.Fl D Ns Dv VINUMDEBUG
-option, since the size of some data objects used by both components depends on
-this option.
-If you don't do so, commands will fail with a corresponding error
-message.
-.It
-The
-.Nm Ic read
-command has a particularly emetic syntax.
-Once it was the only way to start
-.Nm ,
-but now the preferred method is with
-.Nm Ic start .
-.Nm Ic read
-should be used for maintenance purposes only.
-Note that its syntax has changed,
-and the arguments must be disk slices, such as
-.Pa /dev/da0 ,
-not partitions such as
-.Pa /dev/da0e .
-.El
-.Sh FILES
-.Bl -tag -width /dev/vinum/control -compact
-.It Pa /dev/vinum
-directory with device nodes for
-.Nm
-objects
-.It Pa /dev/vinum/control
-control device for
-.Nm
-.It Pa /dev/vinum/plex
-directory containing device nodes for
-.Nm
-plexes
-.It Pa /dev/vinum/sd
-directory containing device nodes for
-.Nm
-subdisks
-.El
-.Sh ENVIRONMENT
-.Bl -tag -width VINUM_DATEFORMAT
-.It Ev VINUM_HISTORY
-The name of the log file, by default
-.Pa /var/log/vinum_history .
-.It Ev VINUM_DATEFORMAT
-The format of dates in the log file, by default
-.Qq Li %e %b %Y %H:%M:%S .
-.It Ev EDITOR
-The name of the editor to use for editing configuration files, by default
-.Nm vi .
-.El
-.Sh SEE ALSO
-.Xr strftime 3 ,
-.Xr vinum 4 ,
-.Xr disklabel 8 ,
-.Xr newfs 8
-.Pp
-.Pa http://www.vinumvm.org/vinum/ ,
-.Pa http://www.vinumvm.org/vinum/how-to-debug.html .
-.Sh AUTHORS
-.An Greg Lehey Aq grog@lemis.com
-.Sh HISTORY
-The
-.Nm
-utility first appeared in
-.Fx 3.0 .
-The RAID-5 component of
-.Nm
-was developed for Cybernet Inc.\&
-.Pq Pa www.cybernet.com
-for its NetMAX product.
-.Sh BUGS
-.Xr vinum 4
-does not use the
-.Xr geom 4
-subsystem so
-.Xr vinum 4
-volumes cannot be used with GEOM based facilities like
-.Xr gbde 8 .
-.Pp
-.Xr vinum 4
-is unable to function on devices with a block size other than
-.Dv DEV_BSIZE
-(512), so cannot be used on swap-backed
-.Xr md 4
-devices.
OpenPOWER on IntegriCloud