All of lore.kernel.org
 help / color / mirror / Atom feed
From: Shaohua Li <shli@kernel.org>
To: linux-raid@vger.kernel.org, neilb@suse.de
Subject: [patch 2/2]raid5: add a sysfs entry to change stripe size
Date: Tue, 8 Jul 2014 09:01:33 +0800	[thread overview]
Message-ID: <20140708010133.GB8941@kernel.org> (raw)


Add a sysfs entry to change stripe size.

Signed-off-by: Shaohua Li <shli@fusionio.com>
---
 drivers/md/raid5.c |  109 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 98 insertions(+), 11 deletions(-)

Index: linux/drivers/md/raid5.c
===================================================================
--- linux.orig/drivers/md/raid5.c	2014-07-08 08:48:02.788106833 +0800
+++ linux/drivers/md/raid5.c	2014-07-08 08:48:02.780106934 +0800
@@ -1906,10 +1906,10 @@ static void init_stripe_pointer(struct r
 	}
 }
 
-static int grow_one_stripe(struct r5conf *conf, int hash)
+static int grow_one_stripe(struct r5conf *conf, int hash, gfp_t gfp)
 {
 	struct stripe_head *sh;
-	sh = kmem_cache_zalloc(conf->slab_cache, GFP_KERNEL);
+	sh = kmem_cache_zalloc(conf->slab_cache, gfp);
 	if (!sh)
 		return 0;
 
@@ -1932,7 +1932,7 @@ static int grow_one_stripe(struct r5conf
 	return 1;
 }
 
-static int grow_stripes(struct r5conf *conf, int num)
+static int grow_stripes(struct r5conf *conf, int num, gfp_t gfp)
 {
 	struct kmem_cache *sc;
 	int devs = max(conf->raid_disks, conf->previous_raid_disks);
@@ -1956,7 +1956,7 @@ static int grow_stripes(struct r5conf *c
 	conf->pool_size = devs;
 	hash = conf->max_nr_stripes % NR_STRIPE_HASH_LOCKS;
 	while (num--) {
-		if (!grow_one_stripe(conf, hash))
+		if (!grow_one_stripe(conf, hash, gfp))
 			return 1;
 		conf->max_nr_stripes++;
 		hash = (hash + 1) % NR_STRIPE_HASH_LOCKS;
@@ -5537,7 +5537,7 @@ raid5_set_cache_size(struct mddev *mddev
 		return err;
 	hash = conf->max_nr_stripes % NR_STRIPE_HASH_LOCKS;
 	while (size > conf->max_nr_stripes) {
-		if (grow_one_stripe(conf, hash))
+		if (grow_one_stripe(conf, hash, GFP_KERNEL))
 			conf->max_nr_stripes++;
 		else break;
 		hash = (hash + 1) % NR_STRIPE_HASH_LOCKS;
@@ -5729,12 +5729,97 @@ raid5_group_thread_cnt = __ATTR(group_th
 				raid5_show_group_thread_cnt,
 				raid5_store_group_thread_cnt);
 
+static ssize_t
+raid5_show_stripe_size(struct mddev *mddev, char *page)
+{
+	struct r5conf *conf = mddev->private;
+	if (conf)
+		return sprintf(page, "%ld\n", PAGE_SIZE << conf->stripe_size_order);
+	else
+		return 0;
+}
+
+static void free_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu);
+static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu,
+	gfp_t gfp);
+static ssize_t
+raid5_store_stripe_size(struct mddev *mddev, const char *page, size_t len)
+{
+	struct r5conf *conf = mddev->private;
+	unsigned long new, chunk_size;
+	int err = 0;
+	int cpu;
+	int nr_stripes;
+
+	if (len >= PAGE_SIZE)
+		return -EINVAL;
+	if (!conf)
+		return -ENODEV;
+
+	if (kstrtoul(page, 10, &new))
+		return -EINVAL;
+
+	new = ilog2(new);
+	if (new == (PAGE_SIZE << conf->stripe_size_order))
+		return len;
+	chunk_size = conf->chunk_sectors * 512;
+	if ((1 << new) > chunk_size || (1 << new) < PAGE_SIZE)
+		return -EINVAL;
+	new -= PAGE_SHIFT;
+
+	mddev_suspend(mddev);
+
+	if (conf->worker_groups)
+		flush_workqueue(raid5_wq);
+
+	nr_stripes = conf->max_nr_stripes;
+	shrink_stripes(conf);
+	conf->max_nr_stripes = 0;
+
+	get_online_cpus();
+	for_each_possible_cpu(cpu) {
+		struct raid5_percpu *percpu;
+
+		percpu = per_cpu_ptr(conf->percpu, cpu);
+		free_scratch_buffer(conf, percpu);
+	}
+
+	conf->stripe_size_order = new;
+
+	conf->scribble_len = scribble_len(conf, conf->pool_size);
+	for_each_present_cpu(cpu) {
+		struct raid5_percpu *percpu;
+
+		percpu = per_cpu_ptr(conf->percpu, cpu);
+		err = alloc_scratch_buffer(conf, percpu, GFP_NOIO);
+		if (err)
+			break;
+	}
+
+	put_online_cpus();
+
+	if (!err)
+		err = grow_stripes(conf, nr_stripes, GFP_NOIO);
+
+	mddev_resume(mddev);
+
+	if (err)
+		return err;
+	return len;
+}
+static struct md_sysfs_entry
+raid5_stripe_size = __ATTR(stripe_size, S_IRUGO | S_IWUSR,
+				raid5_show_stripe_size,
+				raid5_store_stripe_size);
+
+
 static struct attribute *raid5_attrs[] =  {
 	&raid5_stripecache_size.attr,
 	&raid5_stripecache_active.attr,
 	&raid5_preread_bypass_threshold.attr,
 	&raid5_group_thread_cnt.attr,
 	&raid5_skip_copy.attr,
+	&raid5_stripe_size.attr,
 	NULL,
 };
 static struct attribute_group raid5_attrs_group = {
@@ -5822,12 +5907,13 @@ static void free_scratch_buffer(struct r
 	percpu->scribble = NULL;
 }
 
-static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
+static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu,
+	gfp_t gfp)
 {
 	if (conf->level == 6 && !percpu->spare_page)
-		percpu->spare_page = alloc_pages(GFP_KERNEL, conf->stripe_size_order);
+		percpu->spare_page = alloc_pages(gfp, conf->stripe_size_order);
 	if (!percpu->scribble)
-		percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
+		percpu->scribble = kmalloc(conf->scribble_len, gfp);
 
 	if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) {
 		free_scratch_buffer(conf, percpu);
@@ -5877,7 +5963,7 @@ static int raid456_cpu_notify(struct not
 	switch (action) {
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
-		if (alloc_scratch_buffer(conf, percpu)) {
+		if (alloc_scratch_buffer(conf, percpu, GFP_KERNEL)) {
 			pr_err("%s: failed memory allocation for cpu%ld\n",
 			       __func__, cpu);
 			return notifier_from_errno(-ENOMEM);
@@ -5913,7 +5999,8 @@ static int raid5_alloc_percpu(struct r5c
 
 	get_online_cpus();
 	for_each_present_cpu(cpu) {
-		err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
+		err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu),
+			GFP_KERNEL);
 		if (err) {
 			pr_err("%s: failed memory allocation for cpu%ld\n",
 			       __func__, cpu);
@@ -6073,7 +6160,7 @@ static struct r5conf *setup_conf(struct
 	memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
 		 max_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
 	atomic_set(&conf->empty_inactive_list_nr, NR_STRIPE_HASH_LOCKS);
-	if (grow_stripes(conf, NR_STRIPES)) {
+	if (grow_stripes(conf, NR_STRIPES, GFP_KERNEL)) {
 		printk(KERN_ERR
 		       "md/raid:%s: couldn't allocate %dkB for buffers\n",
 		       mdname(mddev), memory);

                 reply	other threads:[~2014-07-08  1:01 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140708010133.GB8941@kernel.org \
    --to=shli@kernel.org \
    --cc=linux-raid@vger.kernel.org \
    --cc=neilb@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.