1 /* list.c: vinum interface program, list routines
4 * Copyright (c) 1997, 1998
5 * Nan Yang Computer Services Limited. All rights reserved.
7 * Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
9 * Written by Greg Lehey
11 * This software is distributed under the so-called ``Berkeley
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by Nan Yang Computer
26 * 4. Neither the name of the Company nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
30 * This software is provided ``as is'', and any express or implied
31 * warranties, including, but not limited to, the implied warranties of
32 * merchantability and fitness for a particular purpose are disclaimed.
33 * In no event shall the company or contributors be liable for any
34 * direct, indirect, incidental, special, exemplary, or consequential
35 * damages (including, but not limited to, procurement of substitute
36 * goods or services; loss of use, data, or profits; or business
37 * interruption) however caused and on any theory of liability, whether
38 * in contract, strict liability, or tort (including negligence or
39 * otherwise) arising in any way out of the use of this software, even if
40 * advised of the possibility of such damage.
42 * $Id: list.c,v 1.25 2000/12/20 03:38:43 grog Exp grog $
57 #include <sys/ioctl.h>
58 #include <sys/utsname.h>
60 #include <dev/vinum/request.h>
61 /* #include <dev/vinum/vinumhdr.h> */
65 * When a subdisk is reviving or initializing, we
66 * check to see whether it is still progressing
67 * and print a warning if not. We check every 50
68 * ms, up to a maximum of 5 seconds. This is the
71 #define STALLCOUNT 100
74 * Take a size in sectors and return a pointer to
75 * a string which represents the size best. If lj
76 * is != 0, return left justified, otherwise in a
77 * fixed 10 character field suitable for columnar
80 * Note this uses a static string: it's only
81 * intended to be used immediately for printing.
84 roughlength(int64_t bytes, int lj)
86 static char description[16];
88 if (bytes > (int64_t) MEGABYTE * 10000) /* gigabytes */
89 sprintf(description, lj ? "%lld GB" : "%10d GB", bytes / GIGABYTE);
90 else if (bytes > KILOBYTE * 10000) /* megabytes */
91 sprintf(description, lj ? "%lld MB" : "%10d MB", bytes / MEGABYTE);
92 else if (bytes > 10000) /* kilobytes */
93 sprintf(description, lj ? "%lld kB" : "%10d kB", bytes / KILOBYTE);
95 sprintf(description, lj ? "%lld B" : "%10d B", bytes);
100 vinum_list(int argc, char *argv[], char *argv0[])
104 enum objecttype type;
106 if (sflag & (!vflag)) /* just summary stats, */
107 printf("Object\t\t Reads\t\tBytes\tAverage\tRecover\t Writes"
108 "\t\tBytes\tAverage\t Mblock Mstripe\n\n");
110 listconfig(); /* list everything */
112 for (i = 0; i < argc; i++) {
113 object = find_object(argv[i], &type); /* look for it */
114 if (vinum_li(object, type))
115 fprintf(stderr, "Can't find object: %s\n", argv[i]);
122 vinum_li(int object, enum objecttype type)
126 vinum_ldi(object, recurse);
130 vinum_lsi(object, recurse);
134 vinum_lpi(object, recurse);
138 vinum_lvi(object, recurse);
148 vinum_ldi(int driveno, int recurse)
150 time_t t; /* because Bruce says so */
151 int sdno; /* for recursion */
153 get_drive_info(&drive, driveno);
154 if (drive.state != drive_unallocated) {
156 printf("Drive %s:\tDevice %s\n",
159 t = drive.label.date_of_birth.tv_sec;
160 printf("\t\tCreated on %s at %s",
163 t = drive.label.last_update.tv_sec;
164 printf("\t\tConfig last updated %s", /* care: \n at end */
166 printf("\t\tSize: %16lld bytes (%lld MB)\n\t\tUsed: %16lld bytes (%lld MB)\n"
167 "\t\tAvailable: %11qd bytes (%d MB)\n",
168 (long long) drive.label.drive_size, /* bytes used */
169 (long long) (drive.label.drive_size / MEGABYTE),
170 (long long) (drive.label.drive_size - drive.sectors_available
172 (long long) (drive.label.drive_size - drive.sectors_available
173 * DEV_BSIZE) / MEGABYTE,
174 (long long) drive.sectors_available * DEV_BSIZE,
175 (int) (drive.sectors_available * DEV_BSIZE / MEGABYTE));
176 printf("\t\tState: %s\n", drive_state(drive.state));
177 if (drive.lasterror != 0)
178 printf("\t\tLast error: %s\n", strerror(drive.lasterror));
180 printf("\t\tLast error: none\n");
181 printf("\t\tActive requests:\t%d\n\t\tMaximum active:\t\t%d\n",
184 if (Verbose) { /* print the free list */
185 int fe; /* freelist entry */
186 struct drive_freelist freelist;
187 struct ferq { /* request to pass to ioctl */
190 } *ferq = (struct ferq *) &freelist;
192 printf("\t\tFree list contains %d entries:\n\t\t Offset\t Size\n",
193 drive.freelist_entries);
194 for (fe = 0; fe < drive.freelist_entries; fe++) {
195 ferq->driveno = drive.driveno;
197 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
199 "Can't get free list element %d: %s\n",
202 longjmp(command_fail, -1);
204 printf("\t\t%9lld\t%9lld\n",
205 (long long) freelist.offset,
206 (long long) freelist.sectors);
210 printf("D %-21s State: %s\t%s\tA: %lld/%lld MB",
212 drive_state(drive.state),
214 (long long) drive.sectors_available * DEV_BSIZE / MEGABYTE,
215 (long long) (drive.label.drive_size / MEGABYTE));
216 if (drive.label.drive_size != 0)
218 (int) ((drive.sectors_available * 100 * DEV_BSIZE)
219 / (drive.label.drive_size - (DATASTART * DEV_BSIZE))));
222 if (vflag || Verbose) {
223 printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n",
224 (long long) drive.reads,
225 (long long) drive.bytes_read,
226 roughlength(drive.bytes_read, 1));
227 if (drive.reads != 0)
228 printf("\t\tAverage read:\t%16lld bytes\n",
229 (long long) drive.bytes_read / drive.reads);
230 printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n",
231 (long long) drive.writes,
232 (long long) drive.bytes_written,
233 roughlength(drive.bytes_written, 1));
234 if (drive.writes != 0)
235 printf("\t\tAverage write:\t%16lld bytes\n",
236 (long long) (drive.bytes_written / drive.writes));
237 } else { /* non-verbose stats */
238 printf("%-15s\t%7lld\t%15lld\t",
240 (long long) drive.reads,
241 (long long) drive.bytes_read);
242 if (drive.reads != 0)
244 (long long) (drive.bytes_read / drive.reads));
247 printf("%7lld\t%15lld\t",
248 (long long) drive.writes,
249 (long long) drive.bytes_written);
250 if (drive.writes != 0)
252 (long long) (drive.bytes_written / drive.writes));
257 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) {
258 get_sd_info(&sd, sdno);
259 if ((sd.state != sd_unallocated)
260 && (sd.driveno == drive.driveno))
261 vinum_lsi(sd.sdno, 0);
269 vinum_ld(int argc, char *argv[], char *argv0[])
273 enum objecttype type;
275 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
276 perror("Can't get vinum config");
280 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++)
281 vinum_ldi(driveno, recurse);
283 for (i = 0; i < argc; i++) {
284 driveno = find_object(argv[i], &type);
285 if (type == drive_object)
286 vinum_ldi(driveno, recurse);
288 fprintf(stderr, "%s is not a drive\n", argv[i]);
294 vinum_lvi(int volno, int recurse)
296 get_volume_info(&vol, volno);
297 if (vol.state != volume_unallocated) {
299 printf("Volume %s:\tSize: %lld bytes (%lld MB)\n"
300 "\t\tState: %s\n\t\tFlags: %s%s%s\n",
302 ((long long) vol.size) * DEV_BSIZE,
303 ((long long) vol.size) * DEV_BSIZE / MEGABYTE,
304 volume_state(vol.state),
305 vol.flags & VF_OPEN ? "open " : "",
306 (vol.flags & VF_WRITETHROUGH ? "writethrough " : ""),
307 (vol.flags & VF_RAW ? "raw" : ""));
308 printf("\t\t%d plexes\n\t\tRead policy: ", vol.plexes);
309 if (vol.preferred_plex < 0) /* round robin */
310 printf("round robin\n");
312 get_plex_info(&plex, vol.plex[vol.preferred_plex]);
313 printf("plex %d (%s)\n", vol.preferred_plex, plex.name);
315 } else if (!sflag) /* brief */
316 printf("V %-21s State: %s\tPlexes: %7d\tSize: %s\n",
318 volume_state(vol.state),
320 roughlength(vol.size << DEV_BSHIFT, 0));
322 if (vflag || Verbose) {
323 printf("\t\tReads: \t%16lld\n\t\tRecovered:\t%16lld\n\t\tBytes read:\t%16lld (%s)\n",
324 (long long) vol.reads,
325 (long long) vol.recovered_reads,
326 (long long) vol.bytes_read,
327 roughlength(vol.bytes_read, 1));
329 printf("\t\tAverage read:\t%16lld bytes\n",
330 (long long) (vol.bytes_read / vol.reads));
331 printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n",
332 (long long) vol.writes,
333 (long long) vol.bytes_written,
334 roughlength(vol.bytes_written, 1));
336 printf("\t\tAverage write:\t%16lld bytes\n",
337 (long long) (vol.bytes_written / vol.writes));
338 printf("\t\tActive requests:\t%8d\n", vol.active);
339 } else { /* brief stats listing */
340 printf("%-15s\t%7lld\t%15lld\t",
342 (long long) vol.reads,
343 (long long) vol.bytes_read);
346 (long long) (vol.bytes_read / vol.reads));
349 printf("%7lld\t", (long long) vol.recovered_reads);
350 printf("%7lld\t%15lld\t",
351 (long long) vol.writes,
355 (long long) (vol.bytes_written / vol.writes));
360 if (vol.plexes > 0) {
362 if (Verbose) { /* brief list */
363 for (plexno = 0; plexno < vol.plexes; plexno++) {
364 get_plex_info(&plex, vol.plex[plexno]);
365 /* Just a brief summary here */
366 printf("\t\tPlex %2d:\t%s\t(%s), %s\n",
369 plex_org(plex.organization),
370 roughlength(plex.length << DEV_BSHIFT, 0));
374 for (plexno = 0; plexno < vol.plexes; plexno++)
375 vinum_lpi(vol.plex[plexno], 0); /* first show the plexes */
376 for (plexno = 0; plexno < vol.plexes; plexno++) { /* then the subdisks */
377 get_plex_info(&plex, vol.plex[plexno]);
378 if (plex.subdisks > 0) {
381 for (sdno = 0; sdno < plex.subdisks; sdno++) {
382 get_plex_sd_info(&sd, vol.plex[plexno], sdno);
383 vinum_lsi(sd.sdno, 0);
394 vinum_lv(int argc, char *argv[], char *argv0[])
398 enum objecttype type;
400 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
401 perror("Can't get vinum config");
405 for (volno = 0; volno < vinum_conf.volumes_allocated; volno++)
406 vinum_lvi(volno, recurse);
408 for (i = 0; i < argc; i++) {
409 volno = find_object(argv[i], &type);
410 if (type == volume_object)
411 vinum_lvi(volno, recurse);
413 fprintf(stderr, "%s is not a volume\n", argv[i]);
419 vinum_lpi(int plexno, int recurse)
421 get_plex_info(&plex, plexno);
422 if (plex.state != plex_unallocated) {
424 printf("Plex %s:\tSize:\t%9lld bytes (%lld MB)\n\t\tSubdisks: %8d\n",
426 (long long) plex.length * DEV_BSIZE,
427 (long long) plex.length * DEV_BSIZE / MEGABYTE,
429 printf("\t\tState: %s\n\t\tOrganization: %s",
430 plex_state(plex.state),
431 plex_org(plex.organization));
432 if (isstriped((&plex)))
433 printf("\tStripe size: %s\n", roughlength(plex.stripesize * DEV_BSIZE, 1));
436 if ((isparity((&plex)))
437 && (plex.checkblock != 0))
438 printf("\t\tCheck block pointer:\t\t%s (%d%%)\n",
439 roughlength((plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1), 0),
440 (int) (((u_int64_t) (plex.checkblock * 100)) * (plex.subdisks - 1) / plex.length));
441 if (plex.volno >= 0) {
442 get_volume_info(&vol, plex.volno);
443 printf("\t\tPart of volume %s\n", vol.name);
445 } else if (!sflag) { /* non-verbose list */
446 char *org = ""; /* organization */
448 switch (plex.organization) {
449 case plex_disorg: /* disorganized */
452 case plex_concat: /* concatenated plex */
455 case plex_striped: /* striped plex */
458 case plex_raid4: /* RAID4 plex */
461 case plex_raid5: /* RAID5 plex */
465 printf("P %-18s %2s State: %s\tSubdisks: %5d\tSize: %s",
468 plex_state(plex.state),
470 roughlength(plex.length << DEV_BSHIFT, 0));
473 if (vflag || Verbose) {
474 printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n",
475 (long long) plex.reads,
476 (long long) plex.bytes_read,
477 roughlength(plex.bytes_read, 1));
479 printf("\t\tAverage read:\t%16lld bytes\n",
480 (long long) (plex.bytes_read / plex.reads));
481 printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n",
482 (long long) plex.writes,
483 (long long) plex.bytes_written,
484 roughlength(plex.bytes_written, 1));
485 if (plex.writes != 0)
486 printf("\t\tAverage write:\t%16lld bytes\n",
487 (long long) (plex.bytes_written / plex.writes));
488 if (((plex.reads + plex.writes) > 0)
489 && isstriped((&plex)))
490 printf("\t\tMultiblock:\t%16lld (%d%%)\n"
491 "\t\tMultistripe:\t%16lld (%d%%)\n",
492 (long long) plex.multiblock,
493 (int) (plex.multiblock * 100 / (plex.reads + plex.writes)),
494 (long long) plex.multistripe,
495 (int) (plex.multistripe * 100 / (plex.reads + plex.writes)));
496 if (plex.recovered_reads)
497 printf("\t\tRecovered reads:%16lld\n",
498 (long long) plex.recovered_reads);
499 if (plex.degraded_writes)
500 printf("\t\tDegraded writes:%16lld\n",
501 (long long) plex.degraded_writes);
502 if (plex.parityless_writes)
503 printf("\t\tParityless writes:%14lld\n",
504 (long long) plex.parityless_writes);
506 printf("%-15s\t%7lld\t%15lld\t",
508 (long long) plex.reads,
509 (long long) plex.bytes_read);
512 (long long) (plex.bytes_read / plex.reads));
515 printf("%7lld\t", (long long) plex.recovered_reads);
516 printf("%7lld\t%15lld\t",
517 (long long) plex.writes,
518 (long long) plex.bytes_written);
519 if (plex.writes != 0)
521 (long long) (plex.bytes_written / plex.writes));
524 printf("%7lld\t%7lld\n",
525 (long long) plex.multiblock,
526 (long long) plex.multistripe);
529 if (plex.subdisks > 0) {
534 for (sdno = 0; sdno < plex.subdisks; sdno++) {
535 get_plex_sd_info(&sd, plexno, sdno);
536 printf("\t\tSubdisk %d:\t%s\n\t\t state: %s\tsize %11lld (%lld MB)\n",
540 (long long) sd.sectors * DEV_BSIZE,
541 (long long) sd.sectors * DEV_BSIZE / MEGABYTE);
542 if (plex.organization == plex_concat)
543 printf("\t\t\toffset %9ld (0x%lx)\n",
544 (long) sd.plexoffset,
545 (long) sd.plexoffset);
550 for (sdno = 0; sdno < plex.subdisks; sdno++) {
551 get_plex_sd_info(&sd, plexno, sdno);
552 vinum_lsi(sd.sdno, 0);
561 vinum_lp(int argc, char *argv[], char *argv0[])
565 enum objecttype type;
567 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
568 perror("Can't get vinum config");
572 for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++)
573 vinum_lpi(plexno, recurse);
575 for (i = 0; i < argc; i++) {
576 plexno = find_object(argv[i], &type);
577 if (type == plex_object)
578 vinum_lpi(plexno, recurse);
580 fprintf(stderr, "%s is not a plex\n", argv[i]);
586 vinum_lsi(int sdno, int recurse)
588 long long revived; /* keep an eye on revive progress */
591 get_sd_info(&sd, sdno);
592 if (sd.state != sd_unallocated) {
593 get_drive_info(&drive, sd.driveno);
596 printf("Subdisk %s:\n\t\tSize: %16lld bytes (%lld MB)\n\t\tState: %s\n",
598 (long long) sd.sectors * DEV_BSIZE,
599 (long long) sd.sectors / (MEGABYTE / DEV_BSIZE),
601 if (sd.plexno >= 0) {
602 get_plex_info(&plex, sd.plexno);
603 printf("\t\tPlex %s", plex.name);
604 printf(" at offset %lld (%s)\n",
605 (long long) sd.plexoffset * DEV_BSIZE,
606 roughlength((long long) sd.plexoffset * DEV_BSIZE, 1));
608 if (sd.state == sd_reviving) {
610 printf("\t\t*** Start subdisk with 'start' command ***\n");
612 printf("\t\tReviver PID:\t%d\n", sd.reviver);
613 if (kill(sd.reviver, 0) == -1) {
614 if (errno == ESRCH) /* no process */
615 printf("\t\t*** Revive process has died ***\n");
616 /* Don't report a problem that "can't happen" */
618 revived = sd.revived; /* note how far we were */
621 * Wait for up to a second until we
622 * see some progress with the revive.
623 * Do it like this so we don't have
624 * annoying delays in the listing.
626 for (times = 0; times < STALLCOUNT; times++) {
627 get_sd_info(&sd, sdno);
628 if (sd.revived != revived) /* progress? */
632 if (times == STALLCOUNT)
633 printf("\t\t*** Revive has stalled ***\n");
636 printf("\t\tRevive pointer:\t\t%s (%d%%)\n",
637 roughlength(sd.revived << DEV_BSHIFT, 0),
638 (int) (((u_int64_t) (sd.revived * 100)) / sd.sectors));
639 printf("\t\tRevive blocksize:\t%s\n"
640 "\t\tRevive interval:\t%10d seconds\n",
641 roughlength(sd.revive_blocksize, 0),
644 if (sd.state == sd_initializing) {
645 printf("\t\tInitialize pointer:\t%s (%d%%)\n",
646 roughlength(sd.initialized << DEV_BSHIFT, 0),
647 (int) (((u_int64_t) (sd.initialized * 100)) / sd.sectors));
648 printf("\t\tInitialize blocksize:\t%s\n"
649 "\t\tInitialize interval:\t%10d seconds\n",
650 roughlength(sd.init_blocksize, 0),
653 if (sd.driveoffset < 0)
654 printf("\t\tDrive %s (%s), no offset\n",
657 else if (drive.devicename[0] != '\0') /* has a name */
658 printf("\t\tDrive %s (%s) at offset %lld (%s)\n",
661 (long long) (sd.driveoffset * DEV_BSIZE),
662 roughlength(sd.driveoffset * DEV_BSIZE, 1));
664 printf("\t\tDrive %s (*missing*) at offset %lld (%s)\n",
666 (long long) (sd.driveoffset * DEV_BSIZE),
667 roughlength(sd.driveoffset * DEV_BSIZE, 1));
668 } else if (!sflag) { /* brief listing, no stats */
669 if (sd.state == sd_reviving)
670 printf("S %-21s State: R %d%%\t",
672 (int) (((u_int64_t) (sd.revived * 100)) / sd.sectors));
673 else if (sd.state == sd_initializing)
674 printf("S %-21s State: I %d%%\t",
676 (int) (((u_int64_t) (sd.initialized * 100)) / sd.sectors));
678 printf("S %-21s State: %s\t",
681 printf("D: %-12s Size: %s\n",
683 roughlength(sd.sectors << DEV_BSHIFT, 0));
684 if (sd.state == sd_reviving) {
686 printf("\t\t\t*** Start %s with 'start' command ***\n",
688 else if (kill(sd.reviver, 0) == -1) {
689 if (errno == ESRCH) /* no process */
690 printf("\t\t\t*** Revive process for %s has died ***\n",
692 /* Don't report a problem that "can't happen" */
694 revived = sd.revived; /* note how far we were */
697 * Wait for up to a second until we
698 * see some progress with the revive.
699 * Do it like this so we don't have
700 * annoying delays in the listing.
702 for (times = 0; times < STALLCOUNT; times++) {
703 get_sd_info(&sd, sdno);
704 if (sd.revived != revived) /* progress? */
708 if (times == STALLCOUNT)
709 printf("\t\t\t*** Revive of %s has stalled ***\n",
715 if (vflag || Verbose) {
716 printf("\t\tReads: \t%16lld\n\t\tBytes read:\t%16lld (%s)\n",
717 (long long) sd.reads,
718 (long long) sd.bytes_read,
719 roughlength(sd.bytes_read, 1));
721 printf("\t\tAverage read:\t%16lld bytes\n",
722 (long long) (sd.bytes_read / sd.reads));
723 printf("\t\tWrites: \t%16lld\n\t\tBytes written:\t%16lld (%s)\n",
724 (long long) sd.writes,
725 (long long) sd.bytes_written,
726 roughlength(sd.bytes_written, 1));
728 printf("\t\tAverage write:\t%16lld bytes\n",
729 (long long) (sd.bytes_written / sd.writes));
731 printf("%-15s\t%7lld\t%15lld\t",
733 (long long) sd.reads,
734 (long long) sd.bytes_read);
737 (long long) (sd.bytes_read / sd.reads));
740 printf("%7lld\t%15lld\t",
741 (long long) sd.writes,
742 (long long) sd.bytes_written);
745 (long long) (sd.bytes_written / sd.writes));
751 vinum_ldi(sd.driveno, 0);
753 printf("\n"); /* make it more readable */
758 vinum_ls(int argc, char *argv[], char *argv0[])
763 /* Structures to read kernel data into */
764 struct __vinum_conf vinum_conf;
765 enum objecttype type;
767 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
768 perror("Can't get vinum config");
772 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++)
773 vinum_lsi(sdno, recurse);
774 } else { /* specific subdisks */
775 for (i = 0; i < argc; i++) {
776 sdno = find_object(argv[i], &type);
777 if (type == sd_object)
778 vinum_lsi(sdno, recurse);
780 fprintf(stderr, "%s is not a subdisk\n", argv[i]);
786 /* List the complete configuration.
788 * XXX Change this to specific lists */
792 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
793 perror("Can't get vinum config");
796 printf("%d drives:\n", vinum_conf.drives_used);
797 if (vinum_conf.drives_used > 0) {
798 vinum_ld(0, NULL, NULL);
801 printf("%d volumes:\n", vinum_conf.volumes_used);
802 if (vinum_conf.volumes_used > 0) {
803 vinum_lv(0, NULL, NULL);
806 printf("%d plexes:\n", vinum_conf.plexes_used);
807 if (vinum_conf.plexes_used > 0) {
808 vinum_lp(0, NULL, NULL);
811 printf("%d subdisks:\n", vinum_conf.subdisks_used);
812 if (vinum_conf.subdisks_used > 0)
813 vinum_ls(0, NULL, NULL);
816 /* Convert a timeval to Tue Oct 13 13:54:14.0434324
817 * Return pointer to text */
819 timetext(struct timeval *time)
821 static char text[30];
822 time_t t; /* to keep Bruce happy */
825 strcpy(text, ctime(&t)); /* to the second */
826 sprintf(&text[19], ".%06ld", time->tv_usec); /* and the microseconds */
831 vinum_info(int argc, char *argv[], char *argv0[])
833 struct meminfo meminfo;
838 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
839 perror("Can't get vinum config");
842 if ((vinum_conf.flags & VF_HASDEBUG) == 0)
843 fprintf(stderr, "Kernel module does not have debug support\n");
845 printf("Flags: 0x%x\n", vinum_conf.flags);
846 if (ioctl(superdev, VINUM_MEMINFO, &meminfo) < 0) {
847 perror("Can't get information");
850 printf("Total of %d blocks malloced, total memory: %d\nMaximum allocs: %8d, malloc table at 0x%08x\n",
852 meminfo.total_malloced,
854 (int) meminfo.malloced);
856 printf("%d requests active, maximum %d active\n",
858 vinum_conf.maxactive);
859 if (vflag && (!Verbose))
860 for (i = 0; i < meminfo.mallocs; i++) {
862 if (ioctl(superdev, VINUM_MALLOCINFO, &malloced) < 0) {
863 perror("Can't get information");
867 printf("Block\tSequence\t size\t address\t line\t\tfile\n\n");
868 printf("%6d\t%6d\t\t%6d\t0x%08x\t%6d\t\t%s\n",
872 (int) malloced.address,
874 (char *) &malloced.file);
877 printf("\nTime\t\t Event\t Buf\tDev\t Offset\tBytes\tSD\tSDoff\tDoffset\tGoffset\n\n");
878 for (i = RQINFO_SIZE - 1; i >= 0; i--) { /* go through the request list in order */
880 if (ioctl(superdev, VINUM_RQINFO, &rq) < 0) {
881 perror("Can't get information");
884 /* Compress devminor into something printable. */
885 rq.devminor = (rq.devminor & 0xff)
886 | ((rq.devminor & 0xfff0000) >> 8);
888 case loginfo_unused: /* never been used */
891 case loginfo_user_bp: /* this is the bp when strategy is called */
892 printf("%s %dVS %s %p\t%d.%-6d 0x%-9x\t%ld\n",
893 timetext(&rq.timestamp),
895 rq.info.b.b_iocmd == BIO_READ ? "Read " : "Write",
903 case loginfo_sdiol: /* subdisk I/O launch */
904 case loginfo_user_bpl: /* and this is the bp at launch time */
905 printf("%s %dLR %s %p\t%d.%-6d 0x%-9x\t%ld\n",
906 timetext(&rq.timestamp),
908 rq.info.b.b_iocmd == BIO_READ ? "Read " : "Write",
916 case loginfo_rqe: /* user RQE */
917 printf("%s 3RQ %s %p\t%d.%-6d 0x%-9x\t%ld\t%d\t%x\t%x\t%x\n",
918 timetext(&rq.timestamp),
919 rq.info.rqe.b.b_iocmd == BIO_READ ? "Read " : "Write",
923 rq.info.rqe.b.b_blkno,
924 rq.info.rqe.b.b_bcount,
926 rq.info.rqe.sdoffset,
927 rq.info.rqe.dataoffset,
928 rq.info.rqe.groupoffset);
931 case loginfo_iodone: /* iodone called */
932 printf("%s 4DN %s %p\t%d.%-6d 0x%-9x\t%ld\t%d\t%x\t%x\t%x\n",
933 timetext(&rq.timestamp),
934 rq.info.rqe.b.b_iocmd == BIO_READ ? "Read " : "Write",
938 rq.info.rqe.b.b_blkno,
939 rq.info.rqe.b.b_bcount,
941 rq.info.rqe.sdoffset,
942 rq.info.rqe.dataoffset,
943 rq.info.rqe.groupoffset);
946 case loginfo_raid5_data: /* RAID-5 write data block */
947 printf("%s 5RD %s %p\t%d.%-6d 0x%-9x\t%ld\t%d\t%x\t%x\t%x\n",
948 timetext(&rq.timestamp),
949 rq.info.rqe.b.b_iocmd == BIO_READ ? "Read " : "Write",
953 rq.info.rqe.b.b_blkno,
954 rq.info.rqe.b.b_bcount,
956 rq.info.rqe.sdoffset,
957 rq.info.rqe.dataoffset,
958 rq.info.rqe.groupoffset);
961 case loginfo_raid5_parity: /* RAID-5 write parity block */
962 printf("%s 6RP %s %p\t%d.%-6d 0x%-9x\t%ld\t%d\t%x\t%x\t%x\n",
963 timetext(&rq.timestamp),
964 rq.info.rqe.b.b_iocmd == BIO_READ ? "Read " : "Write",
968 rq.info.rqe.b.b_blkno,
969 rq.info.rqe.b.b_bcount,
971 rq.info.rqe.sdoffset,
972 rq.info.rqe.dataoffset,
973 rq.info.rqe.groupoffset);
976 case loginfo_sdio: /* subdisk I/O */
977 printf("%s %dVS %s %p\t\t 0x%-9x\t%ld\t%d\n",
978 timetext(&rq.timestamp),
980 rq.info.b.b_iocmd == BIO_READ ? "Read " : "Write",
987 case loginfo_sdiodone: /* subdisk I/O done */
988 printf("%s %dSD %s %p\t\t 0x%-9x\t%ld\t%d\n",
989 timetext(&rq.timestamp),
991 rq.info.b.b_iocmd == BIO_READ ? "Read " : "Write",
998 case loginfo_lockwait:
999 printf("%s Lockwait %p\t 0x%x\n",
1000 timetext(&rq.timestamp),
1002 rq.info.lockinfo.stripe);
1006 printf("%s Lock %p\t 0x%x\n",
1007 timetext(&rq.timestamp),
1009 rq.info.lockinfo.stripe);
1012 case loginfo_unlock:
1013 printf("%s Unlock\t %p\t 0x%x\n",
1014 timetext(&rq.timestamp),
1016 rq.info.lockinfo.stripe);
1025 * Print config file to a file. This is a userland version
1026 * of kernel format_config
1029 vinum_printconfig(int argc, char *argv[], char *argv0[])
1034 fprintf(stderr, "Usage: \tprintconfig [<outfile>]\n");
1036 } else if (argc == 1)
1037 of = fopen(argv[0], "w");
1041 fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno));
1044 printconfig(of, "");
1050 * The guts of printconfig. This is called from
1051 * vinum_printconfig and from vinum_create when
1052 * called without an argument, in order to give
1053 * the user something to edit.
1056 printconfig(FILE * of, char *comment)
1058 struct utsname uname_s;
1064 struct _drive drive;
1066 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1067 perror("Can't get vinum config");
1070 uname(&uname_s); /* get our system name */
1071 time(&now); /* and the current time */
1073 "# Vinum configuration of %s, saved at %s",
1075 ctime(&now)); /* say who did it */
1077 if (comment[0] != 0) /* abuse this for commented version */
1078 fprintf(of, "# Current configuration:\n");
1079 for (i = 0; i < vinum_conf.drives_allocated; i++) {
1080 get_drive_info(&drive, i);
1081 if (drive.state != drive_unallocated) {
1083 "%sdrive %s device %s\n",
1090 for (i = 0; i < vinum_conf.volumes_allocated; i++) {
1091 get_volume_info(&vol, i);
1092 if (vol.state != volume_unallocated) {
1093 if (vol.preferred_plex >= 0) /* preferences, */
1095 "%svolume %s readpol prefer %s\n",
1098 vinum_conf.plex[vol.preferred_plex].name);
1099 else /* default round-robin */
1100 fprintf(of, "%svolume %s\n", comment, vol.name);
1104 /* Then the plex configuration */
1105 for (i = 0; i < vinum_conf.plexes_allocated; i++) {
1106 get_plex_info(&plex, i);
1107 if (plex.state != plex_unallocated) {
1108 fprintf(of, "%splex name %s org %s ",
1111 plex_org(plex.organization));
1112 if (isstriped((&plex)))
1113 fprintf(of, "%ds ", (int) plex.stripesize);
1114 if (plex.volno >= 0) { /* we have a volume */
1115 get_volume_info(&vol, plex.volno);
1116 fprintf(of, "vol %s ", vol.name);
1118 fprintf(of, "detached ");
1123 /* And finally the subdisk configuration */
1124 for (i = 0; i < vinum_conf.subdisks_allocated; i++) {
1125 get_sd_info(&sd, i);
1126 if (sd.state != sd_unallocated) {
1127 get_drive_info(&drive, sd.driveno);
1128 if (sd.plexno >= 0) {
1129 get_plex_info(&plex, sd.plexno);
1131 "%ssd name %s drive %s plex %s len %llds driveoffset %llds plexoffset %llds\n",
1136 (long long) sd.sectors,
1137 (long long) sd.driveoffset,
1138 (long long) sd.plexoffset);
1141 "%ssd name %s drive %s detached len %llds driveoffset %llds\n",
1145 (long long) sd.sectors,
1146 (long long) sd.driveoffset);
1152 list_defective_objects()
1155 int heading_needed = 1;
1157 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1158 perror("Can't get vinum config");
1161 for (o = 0; o < vinum_conf.drives_allocated; o++) {
1162 get_drive_info(&drive, o);
1163 if ((drive.state != drive_unallocated) /* drive exists */
1164 &&(drive.state != drive_up)) { /* but it's not up */
1165 if (heading_needed) {
1166 printf("Warning: defective objects\n\n");
1169 vinum_ldi(o, 0); /* print info */
1173 for (o = 0; o < vinum_conf.volumes_allocated; o++) {
1174 get_volume_info(&vol, o);
1175 if ((vol.state != volume_unallocated) /* volume exists */
1176 &&(vol.state != volume_up)) { /* but it's not up */
1177 if (heading_needed) {
1178 printf("Warning: defective objects\n\n");
1181 vinum_lvi(o, 0); /* print info */
1185 for (o = 0; o < vinum_conf.plexes_allocated; o++) {
1186 get_plex_info(&plex, o);
1187 if ((plex.state != plex_unallocated) /* plex exists */
1188 &&(plex.state != plex_up)) { /* but it's not up */
1189 if (heading_needed) {
1190 printf("Warning: defective objects\n\n");
1193 vinum_lpi(o, 0); /* print info */
1197 for (o = 0; o < vinum_conf.subdisks_allocated; o++) {
1198 get_sd_info(&sd, o);
1199 if ((sd.state != sd_unallocated) /* sd exists */
1200 &&(sd.state != sd_up)) { /* but it's not up */
1201 if (heading_needed) {
1202 printf("Warning: defective objects\n\n");
1205 vinum_lsi(o, 0); /* print info */
1210 /* Dump config from specified disk drives */
1212 vinum_dumpconfig(int argc, char *argv[], char *argv0[])
1216 if (argc == 0) { /* start everything */
1217 int devs = getnumdevs();
1218 struct statinfo statinfo;
1220 char *enamelist; /* end of name list */
1222 char **token; /* list of tokens */
1223 int tokens; /* and their number */
1225 bzero(&statinfo, sizeof(struct statinfo));
1226 statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
1227 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
1228 token = malloc((devs + 1) * sizeof(char *));
1229 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
1230 fprintf(stderr, "Can't allocate memory for drive list\n");
1233 bzero(statinfo.dinfo, sizeof(struct devinfo));
1235 tokens = 0; /* no tokens yet */
1236 if (getdevs(&statinfo) < 0) { /* find out what devices we have */
1237 perror("Can't get device list");
1240 namelist[0] = '\0'; /* start with empty namelist */
1241 enamelist = namelist; /* point to the end of the list */
1243 for (i = 0; i < devs; i++) {
1244 struct devstat *stat = &statinfo.dinfo->devices[i];
1246 if (((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
1247 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
1248 &&((stat->device_name[0] != '\0'))) { /* and it has a name */
1249 sprintf(enamelist, "/dev/%s%d", stat->device_name, stat->unit_number);
1250 token[tokens] = enamelist; /* point to it */
1251 tokens++; /* one more token */
1252 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
1255 free(statinfo.dinfo); /* don't need the list any more */
1256 for (i = 0; i < tokens; i++)
1257 dumpconfig(token[i]);
1260 } else { /* list specified drives */
1261 for (i = 0; i < argc; i++)
1262 dumpconfig(argv[i]);
1268 dumpconfig(char *part)
1270 char partname[MAXPATHLEN];
1272 char partition; /* UNIX partition */
1274 int founddrive; /* flag when we find a vinum drive */
1275 struct disklabel label; /* label of this drive */
1276 int driveno; /* fd of drive */
1278 u_int64_t drivelength;
1280 if (memcmp(part, "/dev/", DEVLEN) == 0) /* starts with /dev */
1281 memcpy(partname, part, MAXPATHLEN);
1282 else { /* prepend */
1283 strcpy(partname, "/dev/");
1284 strncat(&partname[DEVLEN], part, MAXPATHLEN - DEVLEN);
1286 partid = &partname[strlen(partname)];
1287 founddrive = 0; /* no vinum drive found yet on this spindle */
1288 /* first try the partition table */
1289 for (slice = 1; slice < 5; slice++) {
1290 sprintf(partid, "s%dc", slice); /* c partition */
1291 driveno = open(partname, O_RDONLY);
1293 if (errno != ENOENT)
1294 fprintf(stderr, "Can't open %s: %s (%d)\n", partname, strerror(errno), errno);
1297 if (ioctl(driveno, DIOCGDINFO, &label) < 0) {
1298 if ((errno != EINVAL) || vflag)
1299 fprintf(stderr, "Can't get label from %s: %s (%d)\n", partname, strerror(errno), errno);
1302 for (partition = 'a'; partition < 'i'; partition++) {
1303 if ((partition != 'c') /* it's not the c partition */
1304 &&((label.d_partitions[partition - 'a'].p_fstype == FS_VINUM) /* and it's a Vinum partition */
1305 ||Verbose)) { /* or we're just plain curious */
1306 sprintf(partid, "s%d%c", slice, partition);
1307 found = check_drive(partname); /* try to open it */
1308 founddrive |= found; /* and note if we were successful at all */
1309 if (label.d_partitions[partition - 'a'].p_fstype == FS_VINUM) { /* it's a Vinum partition */
1310 drivelength = ((u_int64_t) label.d_partitions[partition - 'a'].p_size) * DEV_BSIZE;
1311 printf("Drive %s: %s (%lld bytes)\n",
1313 roughlength(drivelength, 1),
1315 if ((!found) && vflag) /* we're talkative */
1316 printf("*** no configuration found ***\n");
1321 if (founddrive == 0) { /* didn't find anything, */
1322 sprintf(partid, "c"); /* c partition */
1323 driveno = open(partname, O_RDONLY);
1325 if (errno != ENOENT)
1326 fprintf(stderr, "Can't open %s: %s (%d)\n", partname, strerror(errno), errno);
1329 if (ioctl(driveno, DIOCGDINFO, &label) < 0) {
1330 fprintf(stderr, "Can't get label from %s: %s (%d)\n", partname, strerror(errno), errno);
1333 for (partition = 'a'; partition < 'i'; partition++) { /* try the compatibility partition */
1334 if ((partition != 'c') /* it's not the c partition */
1335 &&((label.d_partitions[partition - 'a'].p_fstype == FS_VINUM) /* and it's a Vinum partition */
1336 ||Verbose)) { /* or we're just plain curious */
1337 sprintf(partid, "%c", partition);
1338 found = check_drive(partname); /* try to open it */
1339 founddrive |= found; /* and note if we were successful at all */
1340 if (label.d_partitions[partition - 'a'].p_fstype == FS_VINUM) { /* it's a Vinum partition */
1341 drivelength = ((u_int64_t) label.d_partitions[partition - 'a'].p_size) * DEV_BSIZE;
1342 printf("Drive %s: %s (%lld bytes)\n",
1344 roughlength(drivelength, 1),
1346 if ((!found) && vflag) /* we're talkative */
1347 printf("*** no configuration found ***\n");
1355 * Check a drive for a Vinum header. If found,
1356 * print configuration information from the drive.
1358 * Return 1 if Vinum config found.
1361 check_drive(char *devicename)
1364 char vinumlabel[DEV_BSIZE]; /* one sector for label */
1365 struct vinum_hdr *hdr = (struct vinum_hdr *) vinumlabel; /* with this structure */
1366 char *config_text; /* read the config info from disk into here */
1369 fd = open(devicename, O_RDONLY);
1371 if (lseek(fd, VINUM_LABEL_OFFSET, SEEK_SET) < 0) {
1373 "Can't seek label for %s: %s (%d)\n",
1380 if (read(fd, vinumlabel, DEV_BSIZE) != DEV_BSIZE) {
1381 if (errno != EINVAL)
1383 "Can't read label from %s: %s (%d)\n",
1390 if ((hdr->magic == VINUM_MAGIC)
1391 || (vflag && (hdr->magic == VINUM_NOMAGIC))) {
1392 printf("Drive %s:\tDevice %s\n",
1395 if (hdr->magic == VINUM_NOMAGIC)
1396 printf("*** Drive has been obliterated ***\n");
1397 t = hdr->label.date_of_birth.tv_sec;
1398 printf("\t\tCreated on %s at %s",
1401 t = hdr->label.last_update.tv_sec;
1402 printf("\t\tConfig last updated %s", /* care: \n at end */
1404 printf("\t\tSize: %16lld bytes (%lld MB)\n",
1405 (long long) hdr->label.drive_size, /* bytes used */
1406 (long long) (hdr->label.drive_size / MEGABYTE));
1407 config_text = (char *) malloc(MAXCONFIG);
1408 if (config_text == NULL)
1409 fprintf(stderr, "Can't allocate memory\n");
1411 if (read(fd, config_text, MAXCONFIG) != MAXCONFIG)
1413 "Can't read config from %s: %s (%d)\n",
1433 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1434 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1435 if (options & daemon_noupdate) {
1436 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n");
1442 /* Local Variables: */
1443 /* fill-column: 50 */