Commit 3f294f4f authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] md: add kobject/sysfs support to raid5

/sys/block/mdX/md/raid5/
contains raid5-related attributes.
Currently
  stripe_cache_size
is number of entries in stripe cache, and is settable.
  stripe_cache_active
is number of active entries, and in only readable.
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 86e6ffdd
...@@ -293,9 +293,31 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector ...@@ -293,9 +293,31 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
return sh; return sh;
} }
static int grow_stripes(raid5_conf_t *conf, int num) static int grow_one_stripe(raid5_conf_t *conf)
{ {
struct stripe_head *sh; struct stripe_head *sh;
sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
if (!sh)
return 0;
memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev));
sh->raid_conf = conf;
spin_lock_init(&sh->lock);
if (grow_buffers(sh, conf->raid_disks)) {
shrink_buffers(sh, conf->raid_disks);
kmem_cache_free(conf->slab_cache, sh);
return 0;
}
/* we just created an active stripe so... */
atomic_set(&sh->count, 1);
atomic_inc(&conf->active_stripes);
INIT_LIST_HEAD(&sh->lru);
release_stripe(sh);
return 1;
}
static int grow_stripes(raid5_conf_t *conf, int num)
{
kmem_cache_t *sc; kmem_cache_t *sc;
int devs = conf->raid_disks; int devs = conf->raid_disks;
...@@ -308,43 +330,34 @@ static int grow_stripes(raid5_conf_t *conf, int num) ...@@ -308,43 +330,34 @@ static int grow_stripes(raid5_conf_t *conf, int num)
return 1; return 1;
conf->slab_cache = sc; conf->slab_cache = sc;
while (num--) { while (num--) {
sh = kmem_cache_alloc(sc, GFP_KERNEL); if (!grow_one_stripe(conf))
if (!sh)
return 1;
memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev));
sh->raid_conf = conf;
spin_lock_init(&sh->lock);
if (grow_buffers(sh, conf->raid_disks)) {
shrink_buffers(sh, conf->raid_disks);
kmem_cache_free(sc, sh);
return 1; return 1;
}
/* we just created an active stripe so... */
atomic_set(&sh->count, 1);
atomic_inc(&conf->active_stripes);
INIT_LIST_HEAD(&sh->lru);
release_stripe(sh);
} }
return 0; return 0;
} }
static void shrink_stripes(raid5_conf_t *conf) static int drop_one_stripe(raid5_conf_t *conf)
{ {
struct stripe_head *sh; struct stripe_head *sh;
while (1) { spin_lock_irq(&conf->device_lock);
spin_lock_irq(&conf->device_lock); sh = get_free_stripe(conf);
sh = get_free_stripe(conf); spin_unlock_irq(&conf->device_lock);
spin_unlock_irq(&conf->device_lock); if (!sh)
if (!sh) return 0;
break; if (atomic_read(&sh->count))
if (atomic_read(&sh->count)) BUG();
BUG(); shrink_buffers(sh, conf->raid_disks);
shrink_buffers(sh, conf->raid_disks); kmem_cache_free(conf->slab_cache, sh);
kmem_cache_free(conf->slab_cache, sh); atomic_dec(&conf->active_stripes);
atomic_dec(&conf->active_stripes); return 1;
} }
static void shrink_stripes(raid5_conf_t *conf)
{
while (drop_one_stripe(conf))
;
kmem_cache_destroy(conf->slab_cache); kmem_cache_destroy(conf->slab_cache);
conf->slab_cache = NULL; conf->slab_cache = NULL;
} }
...@@ -1714,6 +1727,108 @@ static void raid5d (mddev_t *mddev) ...@@ -1714,6 +1727,108 @@ static void raid5d (mddev_t *mddev)
PRINTK("--- raid5d inactive\n"); PRINTK("--- raid5d inactive\n");
} }
struct raid5_sysfs_entry {
struct attribute attr;
ssize_t (*show)(raid5_conf_t *, char *);
ssize_t (*store)(raid5_conf_t *, const char *, ssize_t);
};
static ssize_t
raid5_show_stripe_cache_size(raid5_conf_t *conf, char *page)
{
return sprintf(page, "%d\n", conf->max_nr_stripes);
}
static ssize_t
raid5_store_stripe_cache_size(raid5_conf_t *conf, const char *page, ssize_t len)
{
char *end;
int new;
if (len >= PAGE_SIZE)
return -EINVAL;
new = simple_strtoul(page, &end, 10);
if (!*page || (*end && *end != '\n') )
return -EINVAL;
if (new <= 16 || new > 32768)
return -EINVAL;
while (new < conf->max_nr_stripes) {
if (drop_one_stripe(conf))
conf->max_nr_stripes--;
else
break;
}
while (new > conf->max_nr_stripes) {
if (grow_one_stripe(conf))
conf->max_nr_stripes++;
else break;
}
return len;
}
static struct raid5_sysfs_entry raid5_stripecache_size = {
.attr = {.name = "stripe_cache_size", .mode = S_IRUGO | S_IWUSR },
.show = raid5_show_stripe_cache_size,
.store = raid5_store_stripe_cache_size,
};
static ssize_t
raid5_show_stripe_cache_active(raid5_conf_t *conf, char *page)
{
return sprintf(page, "%d\n", atomic_read(&conf->active_stripes));
}
static struct raid5_sysfs_entry raid5_stripecache_active = {
.attr = {.name = "stripe_cache_active", .mode = S_IRUGO},
.show = raid5_show_stripe_cache_active,
};
static struct attribute *raid5_default_attrs[] = {
&raid5_stripecache_size.attr,
&raid5_stripecache_active.attr,
NULL,
};
static ssize_t
raid5_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
{
struct raid5_sysfs_entry *entry = container_of(attr, struct raid5_sysfs_entry, attr);
raid5_conf_t *conf = container_of(kobj, raid5_conf_t, kobj);
if (!entry->show)
return -EIO;
return entry->show(conf, page);
}
static ssize_t
raid5_attr_store(struct kobject *kobj, struct attribute *attr,
const char *page, size_t length)
{
struct raid5_sysfs_entry *entry = container_of(attr, struct raid5_sysfs_entry, attr);
raid5_conf_t *conf = container_of(kobj, raid5_conf_t, kobj);
if (!entry->store)
return -EIO;
return entry->store(conf, page, length);
}
static void raid5_free(struct kobject *ko)
{
raid5_conf_t *conf = container_of(ko, raid5_conf_t, kobj);
kfree(conf);
}
static struct sysfs_ops raid5_sysfs_ops = {
.show = raid5_attr_show,
.store = raid5_attr_store,
};
static struct kobj_type raid5_ktype = {
.release = raid5_free,
.sysfs_ops = &raid5_sysfs_ops,
.default_attrs = raid5_default_attrs,
};
static int run(mddev_t *mddev) static int run(mddev_t *mddev)
{ {
raid5_conf_t *conf; raid5_conf_t *conf;
...@@ -1855,6 +1970,10 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + ...@@ -1855,6 +1970,10 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
} }
/* Ok, everything is just fine now */ /* Ok, everything is just fine now */
conf->kobj.parent = kobject_get(&mddev->kobj);
strcpy(conf->kobj.name, "raid5");
conf->kobj.ktype = &raid5_ktype;
kobject_register(&conf->kobj);
if (mddev->bitmap) if (mddev->bitmap)
mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ; mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
...@@ -1879,7 +1998,7 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + ...@@ -1879,7 +1998,7 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
static int stop (mddev_t *mddev) static int stop(mddev_t *mddev)
{ {
raid5_conf_t *conf = (raid5_conf_t *) mddev->private; raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
...@@ -1888,7 +2007,7 @@ static int stop (mddev_t *mddev) ...@@ -1888,7 +2007,7 @@ static int stop (mddev_t *mddev)
shrink_stripes(conf); shrink_stripes(conf);
free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree(conf); kobject_unregister(&conf->kobj);
mddev->private = NULL; mddev->private = NULL;
return 0; return 0;
} }
......
...@@ -228,6 +228,7 @@ struct raid5_private_data { ...@@ -228,6 +228,7 @@ struct raid5_private_data {
* Cleared when a sync completes. * Cleared when a sync completes.
*/ */
struct kobject kobj;
/* /*
* Free stripes pool * Free stripes pool
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment