654 lines
14 KiB
C
654 lines
14 KiB
C
#ifndef lint
|
|
static char *sccsid = "@(#)stripe.c 1.1 92/07/30 SMI";
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <mntent.h>
|
|
#include <sys/file.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/buf.h>
|
|
#include <sun/dkio.h>
|
|
#include <sundev/mdreg.h>
|
|
|
|
#define DEBUG 1
|
|
|
|
/*
|
|
* Data structures to support reading the /etc/stripetab file.
|
|
*/
|
|
|
|
struct stripe_dev {
|
|
char *dev_name;
|
|
};
|
|
|
|
struct stripe_row {
|
|
int stripe_width;
|
|
struct stripe_dev lower_device[MAX_MD_DISKS];
|
|
};
|
|
|
|
struct stripe_table {
|
|
struct stripe_dev upper_device;
|
|
int parity_interval; /* interlace */
|
|
struct stripe_dev mirror_device;
|
|
int active_rows;
|
|
struct stripe_row stripe_rows[MAX_MD_ROWS];
|
|
};
|
|
|
|
#define MAXSTRIPESTR 255
|
|
|
|
|
|
int Aflag = 0; /* Carry out all the striping
|
|
in /etc/stripetab */
|
|
int Nflag = 0; /* Don't carry out the operation */
|
|
int Tflag = 0;
|
|
int Cflag = 0; /* Un-stripe the file system */
|
|
int Pflag = 0; /* Perform parity operations */
|
|
int fso;
|
|
int fsi;
|
|
FILE *stripetab;
|
|
char *stripename = "/etc/stripetab";
|
|
struct md_struct mdinfo;
|
|
struct stripe_table command_line_table;
|
|
|
|
struct dk_geom g;
|
|
struct dk_map p;
|
|
struct dk_info inf;
|
|
|
|
|
|
/*
|
|
* Mainline. Crack command line arguments, and push the correct
|
|
* levers (but you knew that, didn't you)
|
|
*/
|
|
main (argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int i;
|
|
int j;
|
|
char *fsys;
|
|
|
|
#ifndef STANDALONE
|
|
argc--, argv++;
|
|
for (j = 0; argc > 0; j++) {
|
|
if (argv[0][0] == '-') {
|
|
for (i = 1; argv[0][i] != '\0'; i++) {
|
|
switch (argv[0][i]) {
|
|
case 'A':
|
|
case 'a':
|
|
Aflag++;
|
|
break;
|
|
|
|
case 'N':
|
|
case 'n':
|
|
Nflag++;
|
|
break;
|
|
|
|
case 'C':
|
|
case 'c':
|
|
Cflag++;
|
|
break;
|
|
|
|
default:
|
|
printf("%s: unknown flag\n", &argv[0][i]);
|
|
usage ();
|
|
break;
|
|
}
|
|
}
|
|
argc--, argv++;
|
|
} else
|
|
break;
|
|
}
|
|
if ((Cflag)) {
|
|
parse_command_line (argc, argv, &command_line_table);
|
|
fsys = command_line_table.upper_device.dev_name;
|
|
clear_mdinfo (&mdinfo);
|
|
mdinfo.md_status = MD_CLEAR;
|
|
} else {
|
|
if (argc > 1) {
|
|
parse_command_line (argc, argv, &command_line_table);
|
|
fsys = command_line_table.upper_device.dev_name;
|
|
table_to_mdstruct (&command_line_table, &mdinfo);
|
|
} else {
|
|
if (Aflag) {
|
|
stripe_file (stripename);
|
|
exit (0);
|
|
} else {
|
|
report_file (stripename);
|
|
exit (0);
|
|
}
|
|
}
|
|
}
|
|
stripe_the (fsys);
|
|
|
|
}
|
|
|
|
/*
|
|
* Report on each device mentioned in the stripetab file.
|
|
*/
|
|
report_file (name)
|
|
char *name;
|
|
{
|
|
struct stripe_table *table;
|
|
struct stripe_table *file_line ();
|
|
char *fsys;
|
|
|
|
while ((table = file_line (name)) != (struct stripe_table *)NULL) {
|
|
fsys = strdup(table->upper_device.dev_name);
|
|
report (fsys);
|
|
printf ("\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Open a stripe device, check that it's valid, and print out the
|
|
* striping data.
|
|
*/
|
|
report (fsys)
|
|
char *fsys;
|
|
{
|
|
int status;
|
|
|
|
open_for_stripe (fsys);
|
|
/*
|
|
* Report on enstripification.
|
|
*/
|
|
if ((status = ioctl(fsi, MD_IOCGET, &mdinfo)) >= 0) {
|
|
} else {
|
|
perror ("MD_IOCGET");
|
|
printf ("Can't perform MD_IOCGET ioctl on fd 0x%x\n", fsi);
|
|
}
|
|
|
|
dump_mdstruct (&mdinfo);
|
|
}
|
|
|
|
usage ()
|
|
{
|
|
fprintf (stderr,
|
|
"/usr/etc/stripe [-N] rows width spec1 spec2...\n");
|
|
fprintf (stderr,
|
|
" [-C] /* unstripe */\n");
|
|
}
|
|
|
|
/*
|
|
* Read a line from the stripetab file, and parse it. return
|
|
* NULL if we already read all the lines.
|
|
*/
|
|
struct stripe_table *
|
|
file_line (name)
|
|
char *name;
|
|
{
|
|
char line[MAXSTRIPESTR];
|
|
int argc;
|
|
char **argv;
|
|
|
|
|
|
if (stripetab == NULL) {
|
|
if ((stripetab = fopen(name, "r")) == NULL) {
|
|
printf ("stripe: can't open %s\n", name);
|
|
exit (1);
|
|
}
|
|
}
|
|
if (fgets(&line[0], MAXSTRIPESTR, stripetab) != NULL) {
|
|
parse_line (&line[0], &argc, &argv);
|
|
parse_command_line (argc, argv, &command_line_table);
|
|
table_to_mdstruct (&command_line_table, &mdinfo);
|
|
return (&command_line_table);
|
|
}
|
|
|
|
return ((struct stripe_table *)NULL);
|
|
}
|
|
|
|
/*
|
|
* Read and parse all the lines from the stripetab file, and then
|
|
* stripe each one.
|
|
*/
|
|
stripe_file (name)
|
|
char *name;
|
|
{
|
|
struct stripe_table *table;
|
|
char *fsys;
|
|
|
|
|
|
while ((table = file_line (name)) != (struct stripe_table *)NULL) {
|
|
fsys = table->upper_device.dev_name;
|
|
stripe_the (fsys);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Parse one line from the stripetab file.
|
|
*/
|
|
parse_line (line, argc, argv)
|
|
char *line;
|
|
int *argc;
|
|
char ***argv;
|
|
{
|
|
int local_argc = 0;
|
|
char **local_argv_start =
|
|
(char **)malloc(4 * (MAX_MD_ROWS * (MAX_MD_DISKS + 1)));
|
|
char **local_argv = local_argv_start;
|
|
char *p;
|
|
|
|
for (p = line; *p != '\0';) {
|
|
while (*p == ' ') p++;
|
|
*local_argv = p;
|
|
while ((*p != ' ') && (*p != '\n')) p++;
|
|
*p = '\0'; p++;
|
|
local_argv++; local_argc++;
|
|
}
|
|
*argc = local_argc;
|
|
*argv = local_argv_start;
|
|
}
|
|
|
|
/*
|
|
* Is a file system currently mounted.
|
|
*/
|
|
is_mounted (fsys)
|
|
char *fsys;
|
|
{
|
|
char *slash;
|
|
FILE *mnttab;
|
|
struct mntent *mntp;
|
|
char bdevname[MAXPATHLEN];
|
|
|
|
slash = (char *)rindex(fsys, '/');
|
|
if (slash && slash[1] == 'r') {
|
|
sprintf(bdevname, "/dev/%s", &slash[2]);
|
|
} else if (*fsys == 'r') {
|
|
sprintf(bdevname, "/dev/%s", &fsys[1]);
|
|
} else {
|
|
strcpy(bdevname, fsys);
|
|
}
|
|
|
|
mnttab = setmntent(MOUNTED, "r");
|
|
while ((mntp = getmntent(mnttab)) != NULL) {
|
|
if (strcmp(bdevname, mntp->mnt_fsname) == 0) {
|
|
printf("%s is mounted, can't stripe\n", bdevname);
|
|
return(1);
|
|
}
|
|
}
|
|
endmntent(mnttab);
|
|
return (0);
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
* Open a special device, and check that it is capable of being
|
|
* treated as a striped device.
|
|
*/
|
|
open_for_stripe (o_fsys)
|
|
char *o_fsys;
|
|
{
|
|
int status;
|
|
|
|
|
|
fso = creat(o_fsys, 0666);
|
|
if(fso < 0) {
|
|
perror ("open_for_stripe: creat");
|
|
printf("\n%s: cannot create\n", o_fsys);
|
|
exit(1);
|
|
}
|
|
|
|
fsi = open(o_fsys, O_RDWR);
|
|
if(fsi < 0) {
|
|
perror ("open_for_stripe: open");
|
|
printf("\n%s: cannot open\n", o_fsys);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Check that we have a stripable file system
|
|
*/
|
|
{
|
|
struct dk_info dkinfo;
|
|
|
|
if ((status = ioctl(fsi, DKIOCINFO, &dkinfo)) >= 0) {
|
|
switch (dkinfo.dki_ctype) {
|
|
|
|
case DKC_MD:
|
|
break;
|
|
|
|
default:
|
|
printf ("Bad disk type 0x%x\n", dkinfo.dki_ctype);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
perror ("DKIOCINFO");
|
|
printf ("Can't perform DKIOCINFO ioctl on fd 0x%x\n", fsi);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check that a file system can be opened for striping, open
|
|
* it, and carry oout the striping.
|
|
*/
|
|
stripe_the(s_fsys)
|
|
char *s_fsys;
|
|
{
|
|
int status;
|
|
char *fsys;
|
|
|
|
if (!Nflag) {
|
|
if (is_mounted (s_fsys)) {
|
|
printf("%s is mounted, can't stripe\n", s_fsys);
|
|
exit(1);
|
|
}
|
|
|
|
}
|
|
fsys = strdup(s_fsys);
|
|
open_for_stripe (fsys);
|
|
|
|
|
|
/*
|
|
* Carry out the enstripification.
|
|
*/
|
|
if ((status = ioctl(fsi, MD_IOCSET, &mdinfo)) >= 0) {
|
|
} else {
|
|
perror ("MD_IOCSET");
|
|
printf ("Can't perform MD_IOCSET ioctl on fd 0x%x\n", fsi);
|
|
}
|
|
#else
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Command line format.
|
|
*
|
|
* stripe [-N] upper_device #rows
|
|
* #width lower_device lower_device lower_device
|
|
* #width lower_device lower_device
|
|
* [-m another_device ]
|
|
*/
|
|
parse_command_line (argc, argv, table)
|
|
int argc;
|
|
char *argv[];
|
|
struct stripe_table *table;
|
|
{
|
|
int rows;
|
|
int width;
|
|
struct stripe_row *row;
|
|
|
|
|
|
/*
|
|
* Parse the upper device.
|
|
*
|
|
* stripe [-N] upper_device #rows
|
|
*/
|
|
table->upper_device.dev_name = argv[0];
|
|
if (argc < 4) {
|
|
printf ("Need <upper-device rows width lower-device>\n");
|
|
return;
|
|
}
|
|
argc--; argv++;
|
|
if ((table->active_rows = atoi(argv[0])) <= 0) {
|
|
printf ("Must have at least one active row\n");
|
|
exit(1);
|
|
}
|
|
argc--; argv++;
|
|
/*
|
|
* Parse the #rows lower devices.
|
|
*
|
|
* #width lower_device lower_device lower_device
|
|
*
|
|
* Each row must have at least two entries.
|
|
*/
|
|
for (rows = 0; rows < table->active_rows; rows++) {
|
|
if (argc < ((table->active_rows - rows) * 2)) {
|
|
printf ("%d remaining arguments not enough for %d remaining rows\n",
|
|
argc,
|
|
table->active_rows - rows);
|
|
exit(1);
|
|
}
|
|
row = &table->stripe_rows[rows];
|
|
if((row->stripe_width = atoi(argv[0])) <= 0) {
|
|
printf ("Row %d must have at least one active disk\n");
|
|
exit(1);
|
|
}
|
|
argc--; argv++;
|
|
for (width = 0; width < row->stripe_width; width++) {
|
|
row->lower_device[width].dev_name = argv[0];
|
|
argc--; argv++;
|
|
}
|
|
}
|
|
table->mirror_device.dev_name = (char *)0;
|
|
table->parity_interval = 0;
|
|
while (argc) {
|
|
if ((argv[0][0] == '-') && (argv[0][1] == 'm')) {
|
|
argc--; argv++;
|
|
table->mirror_device.dev_name = argv[0];
|
|
argc--; argv++;
|
|
} else {
|
|
if ((argv[0][0] == '-') && (argv[0][1] == 'p')) {
|
|
argc--; argv++;
|
|
table->parity_interval = atoi (argv[0]);
|
|
Pflag++;
|
|
argc--; argv++;
|
|
} else {
|
|
printf ("parse_command_line: bad option %s\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
dump_stripe_entry (table);
|
|
}
|
|
|
|
/*
|
|
* Convert a stripe table entry into an md_struct entry suitable
|
|
* for use in an ioctl.
|
|
*/
|
|
table_to_mdstruct (table, mdstruct)
|
|
struct stripe_table *table;
|
|
struct md_struct *mdstruct;
|
|
{
|
|
int row;
|
|
struct md_row *mdrow;
|
|
int width;
|
|
int cum_blocks = 0;
|
|
int cum_data_blocks = 0;
|
|
int disk_size = 0;
|
|
int size = 0;
|
|
struct stripe_row *trow;
|
|
|
|
clear_mdinfo (mdstruct);
|
|
mdstruct->md_status = 0;
|
|
mdstruct->md_ndisks = 0;
|
|
mdstruct->md_rows = table->active_rows;
|
|
if (table->mirror_device.dev_name != (char *)0) {
|
|
printf ("table_to_mdstruct: mirror device %s\n",
|
|
table->mirror_device.dev_name);
|
|
mdstruct->md_mirror = device_of(table->mirror_device.dev_name);
|
|
} else {
|
|
printf ("table_to_mdstruct: no mirror device\n");
|
|
mdstruct->md_mirror = 0;
|
|
}
|
|
mdstruct->md_parity_interval = table->parity_interval;
|
|
printf ("table_to_mdstruct: md_parity_interval 0x%x\n",
|
|
mdstruct->md_parity_interval);
|
|
for (row = 0; row < mdstruct->md_rows; row++) {
|
|
mdrow = &mdstruct->md_real_row[row];
|
|
trow = &table->stripe_rows[row];
|
|
mdrow->md_width = trow->stripe_width;
|
|
mdrow->md_row_disks = trow->stripe_width;
|
|
for (width = 0; width < mdrow->md_width; width++) {
|
|
mdstruct->md_ndisks += 1;
|
|
mdrow->md_real_disks[width] =
|
|
device_of(trow->lower_device[width].dev_name);
|
|
size = size_of(trow->lower_device[width].dev_name);
|
|
if (disk_size == 0) {
|
|
disk_size = size;
|
|
} else {
|
|
if (size < disk_size) {
|
|
disk_size = size;
|
|
}
|
|
}
|
|
printf ("device %s size %d\n",
|
|
trow->lower_device[width].dev_name,
|
|
size_of(trow->lower_device[width].dev_name));
|
|
}
|
|
cum_blocks += mdrow->md_width * disk_size;
|
|
mdrow->md_blocks = mdrow->md_width * disk_size;
|
|
mdrow->md_data_blocks =
|
|
(Pflag != 0) ? mdrow->md_blocks - disk_size : mdrow->md_blocks;
|
|
cum_data_blocks += mdrow->md_data_blocks;
|
|
mdrow->md_cum_blocks = cum_blocks;
|
|
mdrow->md_cum_data_blocks = cum_data_blocks;
|
|
if (Pflag != 0)
|
|
printf ("table_to_mdstruct: parity reduces effective size from %d to %d\n",
|
|
cum_blocks,
|
|
cum_data_blocks);
|
|
mdrow->md_start_block = 0;
|
|
mdrow->md_end_block = disk_size;
|
|
}
|
|
|
|
}
|
|
|
|
dump_mdstruct (mdstruct)
|
|
struct md_struct *mdstruct;
|
|
{
|
|
int row;
|
|
int width;
|
|
|
|
|
|
printf ("rows %d total disks %d mirror 0x%x\n",
|
|
mdstruct->md_rows,
|
|
mdstruct->md_ndisks,
|
|
mdstruct->md_mirror);
|
|
for (row = 0; row < mdstruct->md_rows; row++) {
|
|
printf ("\trow %d width %d disks %d blocks %d cum blocks %d start block %d end block %d\n",
|
|
row,
|
|
mdstruct->md_real_row[row].md_width,
|
|
mdstruct->md_real_row[row].md_row_disks,
|
|
mdstruct->md_real_row[row].md_blocks,
|
|
mdstruct->md_real_row[row].md_cum_blocks,
|
|
mdstruct->md_real_row[row].md_start_block,
|
|
mdstruct->md_real_row[row].md_end_block);
|
|
printf ("\t\t");
|
|
|
|
for (width = 0;
|
|
width < mdstruct->md_real_row[row].md_width; width++) {
|
|
printf (" 0x%x ",
|
|
mdstruct->md_real_row[row].md_real_disks[width]);
|
|
}
|
|
printf ("\n");
|
|
}
|
|
}
|
|
|
|
device_of (device_name)
|
|
char *device_name;
|
|
{
|
|
struct stat status;
|
|
|
|
if (stat(device_name, &status) == -1) {
|
|
perror ("device_of");
|
|
printf ("Can't stat '%s'\n", device_name);
|
|
exit(1);
|
|
}
|
|
|
|
return (status.st_rdev);
|
|
}
|
|
|
|
off_t
|
|
size_of (device_name)
|
|
char *device_name;
|
|
{
|
|
struct stat st;
|
|
int fd, c, found, nparts;
|
|
char *rawname();
|
|
|
|
if (stat(rawname(device_name), &st) == 0) {
|
|
fd = open(rawname(device_name), 0);
|
|
if (fd < 0) {
|
|
perror(device_name);
|
|
return(0);
|
|
}
|
|
if (isdisk(fd)) {
|
|
if (parts(0, fd) == 0)
|
|
printf("Not a valid partition.\n");
|
|
} else
|
|
printf("%s: Not a valid disk.\n", device_name);
|
|
close(fd);
|
|
if (p.dkl_nblk & 0xf) {
|
|
return(p.dkl_nblk & ~0xf);
|
|
}
|
|
return(p.dkl_nblk);
|
|
}
|
|
|
|
|
|
return (0);
|
|
}
|
|
|
|
isdisk(fd)
|
|
{
|
|
return (ioctl(fd, DKIOCINFO, &inf) == 0 &&
|
|
ioctl(fd, DKIOCGGEOM, &g) == 0);
|
|
}
|
|
|
|
parts(pa, fd)
|
|
{
|
|
int n;
|
|
|
|
if (ioctl(fd, DKIOCGPART, &p) == 0) {
|
|
return (p.dkl_nblk ? 1 : 0);
|
|
} else {
|
|
if (pa) printf("%c: ", pa);
|
|
printf("can't get partition info\n");
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
|
|
char *
|
|
rawname(cp)
|
|
char *cp;
|
|
{
|
|
static char rawbuf[MAXPATHLEN];
|
|
char *dp = rindex(cp, '/');
|
|
|
|
if (dp == 0)
|
|
return (0);
|
|
*dp = 0;
|
|
(void)strcpy(rawbuf, cp);
|
|
*dp = '/';
|
|
(void)strcat(rawbuf, "/r");
|
|
(void)strcat(rawbuf, dp+1);
|
|
return (rawbuf);
|
|
}
|
|
|
|
dump_stripe_entry (table)
|
|
struct stripe_table *table;
|
|
{
|
|
int rows;
|
|
int width;
|
|
struct stripe_row *row;
|
|
|
|
|
|
printf ("device:\t%s = %d rows\n",
|
|
table->upper_device.dev_name,
|
|
table->active_rows);
|
|
for (rows = 0; rows < table->active_rows; rows++) {
|
|
row = &table->stripe_rows[rows];
|
|
printf ("\trow %d width %d: ",
|
|
rows, row->stripe_width);
|
|
for (width = 0; width < row->stripe_width; width++) {
|
|
printf (" %s ",
|
|
row->lower_device[width].dev_name);
|
|
}
|
|
printf ("\n");
|
|
}
|
|
}
|
|
|
|
clear_mdinfo (mdstruct)
|
|
struct md_struct *mdstruct;
|
|
{
|
|
|
|
bzero (mdstruct, sizeof (* mdstruct));
|
|
}
|