aboutsummaryrefslogtreecommitdiff
path: root/drivers/md/raid6main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/raid6main.c')
-rw-r--r--drivers/md/raid6main.c152
1 files changed, 117 insertions, 35 deletions
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index f618a53b98b..cd477ebf2ee 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -115,7 +115,7 @@ static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
list_add_tail(&sh->lru, &conf->inactive_list);
atomic_dec(&conf->active_stripes);
if (!conf->inactive_blocked ||
- atomic_read(&conf->active_stripes) < (NR_STRIPES*3/4))
+ atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4))
wake_up(&conf->wait_for_stripe);
}
}
@@ -273,7 +273,8 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
conf->inactive_blocked = 1;
wait_event_lock_irq(conf->wait_for_stripe,
!list_empty(&conf->inactive_list) &&
- (atomic_read(&conf->active_stripes) < (NR_STRIPES *3/4)
+ (atomic_read(&conf->active_stripes)
+ < (conf->max_nr_stripes *3/4)
|| !conf->inactive_blocked),
conf->device_lock,
unplug_slaves(conf->mddev);
@@ -302,9 +303,31 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
return sh;
}
-static int grow_stripes(raid6_conf_t *conf, int num)
+static int grow_one_stripe(raid6_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(raid6_conf_t *conf, int num)
+{
kmem_cache_t *sc;
int devs = conf->raid_disks;
@@ -316,45 +339,35 @@ static int grow_stripes(raid6_conf_t *conf, int num)
if (!sc)
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);
+ while (num--)
+ 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(raid6_conf_t *conf)
+static int drop_one_stripe(raid6_conf_t *conf)
{
struct stripe_head *sh;
+ 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;
+}
- 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);
- }
- kmem_cache_destroy(conf->slab_cache);
+static void shrink_stripes(raid6_conf_t *conf)
+{
+ while (drop_one_stripe(conf))
+ ;
+
+ if (conf->slab_cache)
+ kmem_cache_destroy(conf->slab_cache);
conf->slab_cache = NULL;
}
@@ -1912,6 +1925,74 @@ static void raid6d (mddev_t *mddev)
PRINTK("--- raid6d inactive\n");
}
+static ssize_t
+raid6_show_stripe_cache_size(mddev_t *mddev, char *page)
+{
+ raid6_conf_t *conf = mddev_to_conf(mddev);
+ if (conf)
+ return sprintf(page, "%d\n", conf->max_nr_stripes);
+ else
+ return 0;
+}
+
+static ssize_t
+raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
+{
+ raid6_conf_t *conf = mddev_to_conf(mddev);
+ char *end;
+ int new;
+ if (len >= PAGE_SIZE)
+ return -EINVAL;
+ if (!conf)
+ return -ENODEV;
+
+ 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 md_sysfs_entry
+raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
+ raid6_show_stripe_cache_size,
+ raid6_store_stripe_cache_size);
+
+static ssize_t
+stripe_cache_active_show(mddev_t *mddev, char *page)
+{
+ raid6_conf_t *conf = mddev_to_conf(mddev);
+ if (conf)
+ return sprintf(page, "%d\n", atomic_read(&conf->active_stripes));
+ else
+ return 0;
+}
+
+static struct md_sysfs_entry
+raid6_stripecache_active = __ATTR_RO(stripe_cache_active);
+
+static struct attribute *raid6_attrs[] = {
+ &raid6_stripecache_size.attr,
+ &raid6_stripecache_active.attr,
+ NULL,
+};
+static struct attribute_group raid6_attrs_group = {
+ .name = NULL,
+ .attrs = raid6_attrs,
+};
+
static int run(mddev_t *mddev)
{
raid6_conf_t *conf;
@@ -2095,6 +2176,7 @@ static int stop (mddev_t *mddev)
shrink_stripes(conf);
kfree(conf->stripe_hashtbl);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+ sysfs_remove_group(&mddev->kobj, &raid6_attrs_group);
kfree(conf);
mddev->private = NULL;
return 0;