diff -b -r -U 5 --exclude=*.o --exclude=.??* linux-2.4.12-ac3/drivers/md/multipath.c linux-2.4.12-ac3-md/drivers/md/multipath.c --- linux-2.4.12-ac3/drivers/md/multipath.c Sun Sep 30 12:26:06 2001 +++ linux-2.4.12-ac3-md/drivers/md/multipath.c Tue Oct 23 06:12:15 2001 @@ -23,10 +23,11 @@ */ #include #include #include +#include #include #define MAJOR_NR MD_MAJOR #define MD_DRIVER #define MD_PERSONALITY @@ -44,17 +45,199 @@ #define __inline__ #else #define PRINTK(x...) do { } while (0) #endif +static char multipath_version[] = + { "MD/LVM Multipath Storage Device Driver: ver 0.0.1" }; + +static int multipath_proc_readstr (ctl_table *, int, struct file *, void *, + size_t *); +static int multipath_proc_read_dev (ctl_table *, int, struct file *, void *, + size_t *); + +static struct ctl_table_header *multipath_table_header; + +static struct multipath_dev_table multipath_dev_template = { + "", + { + {MULTIPATH_CONF, "config", NULL, 0, 0444, NULL, + &multipath_proc_read_dev}, + {0}, + }, + {{MULTIPATH_DEV, NULL, NULL, 0, 0555, NULL},{0}}, + {{DEV_MULTIPATH, "multipath", NULL, 0, 0555, NULL},{0}}, + {{CTL_DEV, "dev", NULL, 0, 0555, NULL},{0}} + +}; + +static ctl_table multipath_ver_table[] = { + {MULTIPATH_VER, "version", &multipath_version, + sizeof(multipath_version), 0444, NULL, &multipath_proc_readstr}, + {0} +}; + +static ctl_table multipath_dir_table[] = { + {DEV_MULTIPATH, "multipath", NULL, 0, 0555, multipath_ver_table}, + {0} +}; + +static ctl_table multipath_root_table[] = { + {CTL_DEV, "dev", NULL, 0, 0555, multipath_dir_table}, + {0} +}; static mdk_personality_t multipath_personality; static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED; struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail; static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state); +static int multipath_proc_register_dev(mddev_t *md ) +{ + struct multipath_dev_table *t; + multipath_conf_t *conf = mddev_to_conf(md); + + t = &(conf->ctl_tbl); + + memcpy(t, &multipath_dev_template, sizeof(*t)); + + /* fill in fields */ + sprintf( t->mdname, "%d", md->__minor ); + + t->dir[0].procname = t->mdname; + + t->md[1].data = md; + + t->dev[0].child = t->mp; + t->mp[0].child = t->dir; + t->dir[0].child = t->md; + + conf->tbl = register_sysctl_table( t->dev, 1 ); + + return 0; +} + +static int multipath_proc_unregister_dev( mddev_t *md ) +{ + multipath_conf_t *conf = mddev_to_conf(md); + + unregister_sysctl_table( conf->tbl ); + + return 0; +} + + +static int multipath_proc_readstr (ctl_table *tbl, int write, struct file *f, + void *buffer, size_t *lenp) +{ + int n; + + if ( write ) + return -EACCES; /* readonly string */ + + /* check for no or zero length data, or data allready read */ + if (!tbl->data || !tbl->maxlen || !*lenp || f->f_pos ) + { + *lenp = 0; + return 0; + } + + n = strlen(tbl->data); + + if (n > tbl->maxlen) + n = tbl->maxlen; + + if ( n > *lenp ) + n = *lenp; + + if ( n ) + if(copy_to_user( buffer, multipath_version, n)) + return -EFAULT; + if ( n < *lenp ) + { + if(put_user('\n', ((char *)buffer) + n) ) + return -EFAULT; + n++; + } + *lenp = n; + f->f_pos += n; + + return 0; +} + +static int multipath_proc_read_dev (ctl_table *t, int w, struct file *f, + void *b, size_t *s) +{ + mddev_t *md; + multipath_conf_t *conf; + struct multipath_info *info; + int path, len, i; +#define LEN_HDR 48 +#define LEN_DSK 85 + + if (!t->data || !*s || f->f_pos ) + { + *s = 0; + return 0; + } + + if ( w ) + return -EACCES; /* readonly */ + + md = t->data; + conf = mddev_to_conf( md ); + + if ( f->f_pos == 0 ) + { + if ( *s < LEN_HDR ) /* must be big enough to handle the */ + return -EFAULT; /* size of the next sprintf */ + + sprintf( b, "nr_disks %3d: raid_disks %3d: working_disks %3d\n", + conf->nr_disks&255, conf->raid_disks&255, + conf->working_disks&255 ); + + len = strlen( b ); + if ( *s < len ) /* check for overflow */ + return -EFAULT; + + if ( *s < len + LEN_DSK ) + { + *s = len; + f->f_pos = len; + return 0; + } + } + + + for ( path = 0; path < conf->nr_disks; path++ ) + { + info = &conf->multipaths[path]; + + sprintf( b + len, + "%3d: disk %3d: dev %3d.%3d\n" + "\tworking %c: write only %c: spare %c: used %c " + "ops %10d\n", + info->number&255, info->raid_disk&255, MAJOR(info->dev), + MINOR(info->dev), + info->operational? 'y' : 'n', + info->write_only? 'y' : 'n', + info->spare? 'y' : 'n', + info->used_slot? 'y' : 'n', + info->nr_ops ); + len = strlen( b ); + if ( *s < len + LEN_DSK ) + break; + } + + *s = len; + f->f_pos = len; + return 0; +#undef LEN_HDR +#undef LEN_DSK +} + struct buffer_head *multipath_alloc_bh(multipath_conf_t *conf, int cnt) { /* return a linked list of "cnt" struct buffer_heads. * don't take any off the free list unless we know we can * get all we need, otherwise we could deadlock @@ -373,10 +556,11 @@ * degrades dramatically because position is multipath, not device based. * This should be changed to be device based. Also atomic sequential * reads should be somehow balanced. */ + static int multipath_read_balance (multipath_conf_t *conf) { int disk; for (disk = 0; disk < conf->raid_disks; disk++) @@ -444,10 +628,13 @@ bh_req->b_rdev = multipath->dev; /* bh_req->b_rsector = bh->n_rsector; */ bh_req->b_end_io = multipath_end_request; bh_req->b_private = r1_bh; generic_make_request (rw, bh_req); + + multipath->nr_ops++; + return 0; } static int multipath_status (char *page, mddev_t *mddev) { @@ -1036,10 +1223,16 @@ printk(MEM_ERROR, mdidx(mddev)); goto out; } memset(conf, 0, sizeof(*conf)); + if (multipath_proc_register_dev( mddev )) + { + printk(ERRORS, mdidx(mddev)); + goto out_free_conf; + } + ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) { /* this is a "should never happen" case and if it */ /* ever does happen, a continue; won't help */ printk(ERRORS, partition_name(rdev->dev)); @@ -1224,10 +1417,11 @@ static int multipath_stop (mddev_t *mddev) { multipath_conf_t *conf = mddev_to_conf(mddev); + multipath_proc_unregister_dev( mddev ); md_unregister_thread(conf->thread); multipath_shrink_mpbh(conf); multipath_shrink_bh(conf, conf->freebh_cnt); kfree(conf); mddev->private = NULL; @@ -1246,15 +1440,19 @@ diskop: multipath_diskop, }; static int md__init multipath_init (void) { + multipath_table_header = register_sysctl_table(multipath_root_table, 1); + return register_md_personality (MULTIPATH, &multipath_personality); } static void multipath_exit (void) { + unregister_sysctl_table(multipath_table_header); + unregister_md_personality (MULTIPATH); } module_init(multipath_init); module_exit(multipath_exit); diff -b -r -U 5 --exclude=*.o --exclude=.??* linux-2.4.12-ac3/include/linux/raid/multipath.h linux-2.4.12-ac3-md/include/linux/raid/multipath.h --- linux-2.4.12-ac3/include/linux/raid/multipath.h Fri Sep 14 14:22:18 2001 +++ linux-2.4.12-ac3-md/include/linux/raid/multipath.h Tue Oct 23 06:11:44 2001 @@ -1,9 +1,18 @@ #ifndef _MULTIPATH_H #define _MULTIPATH_H #include +#include + +struct multipath_dev_table { + char mdname[8]; + ctl_table md[3]; + ctl_table dir[2]; + ctl_table mp[2]; + ctl_table dev[2]; +}; struct multipath_info { int number; int raid_disk; kdev_t dev; @@ -16,10 +25,11 @@ int operational; int write_only; int spare; int used_slot; + unsigned int nr_ops; }; struct multipath_private_data { mddev_t *mddev; struct multipath_info multipaths[MD_SB_DISKS]; @@ -50,10 +60,13 @@ int phase; int window; md_wait_queue_head_t wait_done; md_wait_queue_head_t wait_ready; md_spinlock_t segment_lock; + int last; /* last used, or prefered route */ + struct ctl_table_header *tbl; + struct multipath_dev_table ctl_tbl; }; typedef struct multipath_private_data multipath_conf_t; /* diff -b -r -U 5 --exclude=*.o --exclude=.??* linux-2.4.12-ac3/include/linux/sysctl.h linux-2.4.12-ac3-md/include/linux/sysctl.h --- linux-2.4.12-ac3/include/linux/sysctl.h Tue Oct 23 04:56:06 2001 +++ linux-2.4.12-ac3-md/include/linux/sysctl.h Tue Oct 23 04:26:42 2001 @@ -554,11 +554,12 @@ enum { DEV_CDROM=1, DEV_HWMON=2, DEV_PARPORT=3, DEV_RAID=4, - DEV_MAC_HID=5 + DEV_MAC_HID=5, + DEV_MULTIPATH=6 }; /* /proc/sys/dev/cdrom */ enum { DEV_CDROM_INFO=1, @@ -576,10 +577,22 @@ /* /proc/sys/dev/raid */ enum { DEV_RAID_SPEED_LIMIT_MIN=1, DEV_RAID_SPEED_LIMIT_MAX=2 +}; + +/* /proc/sys/dev/multipath */ +enum { + MULTIPATH_VER=1, + MULTIPATH_DEV=2 +}; + +/* /proc/sys/dev/multipath/md n */ +enum { + MULTIPATH_ROUTING=1, + MULTIPATH_CONF=2 }; /* /proc/sys/dev/parport/default */ enum { DEV_PARPORT_DEFAULT_TIMESLICE=1,