[PATCH] md: add kobject/sysfs support to raid5
authorNeilBrown <neilb@suse.de>
Wed, 9 Nov 2005 05:39:25 +0000 (21:39 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 9 Nov 2005 15:56:37 +0000 (07:56 -0800)
/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: Neil Brown <neilb@suse.de>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/md/raid5.c
include/linux/raid/raid5.h

index 8cf1ae8..121fbaa 100644 (file)
@@ -293,9 +293,31 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
        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;
+       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;
        int devs = conf->raid_disks;
 
@@ -308,43 +330,34 @@ static int grow_stripes(raid5_conf_t *conf, int num)
                return 1;
        conf->slab_cache = sc;
        while (num--) {
-               sh = kmem_cache_alloc(sc, GFP_KERNEL);
-               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);
+               if (!grow_one_stripe(conf))
                        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;
 }
 
-static void shrink_stripes(raid5_conf_t *conf)
+static int drop_one_stripe(raid5_conf_t *conf)
 {
        struct stripe_head *sh;
 
-       while (1) {
-               spin_lock_irq(&conf->device_lock);
-               sh = get_free_stripe(conf);
-               spin_unlock_irq(&conf->device_lock);
-               if (!sh)
-                       break;
-               if (atomic_read(&sh->count))
-                       BUG();
-               shrink_buffers(sh, conf->raid_disks);
-               kmem_cache_free(conf->slab_cache, sh);
-               atomic_dec(&conf->active_stripes);
-       }
+       spin_lock_irq(&conf->device_lock);
+       sh = get_free_stripe(conf);
+       spin_unlock_irq(&conf->device_lock);
+       if (!sh)
+               return 0;
+       if (atomic_read(&sh->count))
+               BUG();
+       shrink_buffers(sh, conf->raid_disks);
+       kmem_cache_free(conf->slab_cache, sh);
+       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);
        conf->slab_cache = NULL;
 }
@@ -1714,6 +1727,108 @@ static void raid5d (mddev_t *mddev)
        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)
 {
        raid5_conf_t *conf;
@@ -1855,6 +1970,10 @@ memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
        }
 
        /* 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)
                mddev->thread->timeout = mddev->bitmap->daemon_sleep * HZ;
@@ -1879,7 +1998,7 @@ abort:
 
 
 
-static int stop (mddev_t *mddev)
+static int stop(mddev_t *mddev)
 {
        raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 
@@ -1888,7 +2007,7 @@ static int stop (mddev_t *mddev)
        shrink_stripes(conf);
        free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER);
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
-       kfree(conf);
+       kobject_unregister(&conf->kobj);
        mddev->private = NULL;
        return 0;
 }
index f025ba6..5f4e945 100644 (file)
@@ -228,6 +228,7 @@ struct raid5_private_data {
                                            * Cleared when a sync completes.
                                            */
 
+       struct kobject          kobj;
        /*
         * Free stripes pool
         */