aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2015-05-08 04:19:39 -0400
committerNeilBrown <neilb@suse.de>2015-05-08 04:47:48 -0400
commit738a273806ee0568369c9bb19ef3b102f54beef4 (patch)
tree0ab185c18654c98a9c5151f14aed1bdfdfb750f0
parent6e9eac2dcee5e19f125967dd2be3e36558c42fff (diff)
md/raid5: fix allocation of 'scribble' array.
As the new 'scribble' array is sized based on chunk size, we need to make sure the size matches the largest of 'old' and 'new' chunk sizes when the array is undergoing reshape. We also potentially need to resize it even when not resizing the stripe cache, as chunk size can change without changing number of devices. So move the 'resize' code into a separate function, and consider old and new sizes when allocating. Signed-off-by: NeilBrown <neilb@suse.de> Fixes: 46d5b785621a ("raid5: use flex_array for scribble data")
-rw-r--r--drivers/md/raid5.c65
1 files changed, 43 insertions, 22 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 9748e525e4c0..3873eaa6fa2e 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2068,6 +2068,35 @@ static struct flex_array *scribble_alloc(int num, int cnt, gfp_t flags)
2068 return ret; 2068 return ret;
2069} 2069}
2070 2070
2071static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors)
2072{
2073 unsigned long cpu;
2074 int err = 0;
2075
2076 mddev_suspend(conf->mddev);
2077 get_online_cpus();
2078 for_each_present_cpu(cpu) {
2079 struct raid5_percpu *percpu;
2080 struct flex_array *scribble;
2081
2082 percpu = per_cpu_ptr(conf->percpu, cpu);
2083 scribble = scribble_alloc(new_disks,
2084 new_sectors / STRIPE_SECTORS,
2085 GFP_NOIO);
2086
2087 if (scribble) {
2088 flex_array_free(percpu->scribble);
2089 percpu->scribble = scribble;
2090 } else {
2091 err = -ENOMEM;
2092 break;
2093 }
2094 }
2095 put_online_cpus();
2096 mddev_resume(conf->mddev);
2097 return err;
2098}
2099
2071static int resize_stripes(struct r5conf *conf, int newsize) 2100static int resize_stripes(struct r5conf *conf, int newsize)
2072{ 2101{
2073 /* Make all the stripes able to hold 'newsize' devices. 2102 /* Make all the stripes able to hold 'newsize' devices.
@@ -2096,7 +2125,6 @@ static int resize_stripes(struct r5conf *conf, int newsize)
2096 struct stripe_head *osh, *nsh; 2125 struct stripe_head *osh, *nsh;
2097 LIST_HEAD(newstripes); 2126 LIST_HEAD(newstripes);
2098 struct disk_info *ndisks; 2127 struct disk_info *ndisks;
2099 unsigned long cpu;
2100 int err; 2128 int err;
2101 struct kmem_cache *sc; 2129 struct kmem_cache *sc;
2102 int i; 2130 int i;
@@ -2178,25 +2206,6 @@ static int resize_stripes(struct r5conf *conf, int newsize)
2178 } else 2206 } else
2179 err = -ENOMEM; 2207 err = -ENOMEM;
2180 2208
2181 get_online_cpus();
2182 for_each_present_cpu(cpu) {
2183 struct raid5_percpu *percpu;
2184 struct flex_array *scribble;
2185
2186 percpu = per_cpu_ptr(conf->percpu, cpu);
2187 scribble = scribble_alloc(newsize, conf->chunk_sectors /
2188 STRIPE_SECTORS, GFP_NOIO);
2189
2190 if (scribble) {
2191 flex_array_free(percpu->scribble);
2192 percpu->scribble = scribble;
2193 } else {
2194 err = -ENOMEM;
2195 break;
2196 }
2197 }
2198 put_online_cpus();
2199
2200 /* Step 4, return new stripes to service */ 2209 /* Step 4, return new stripes to service */
2201 while(!list_empty(&newstripes)) { 2210 while(!list_empty(&newstripes)) {
2202 nsh = list_entry(newstripes.next, struct stripe_head, lru); 2211 nsh = list_entry(newstripes.next, struct stripe_head, lru);
@@ -6228,8 +6237,11 @@ static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu
6228 percpu->spare_page = alloc_page(GFP_KERNEL); 6237 percpu->spare_page = alloc_page(GFP_KERNEL);
6229 if (!percpu->scribble) 6238 if (!percpu->scribble)
6230 percpu->scribble = scribble_alloc(max(conf->raid_disks, 6239 percpu->scribble = scribble_alloc(max(conf->raid_disks,
6231 conf->previous_raid_disks), conf->chunk_sectors / 6240 conf->previous_raid_disks),
6232 STRIPE_SECTORS, GFP_KERNEL); 6241 max(conf->chunk_sectors,
6242 conf->prev_chunk_sectors)
6243 / STRIPE_SECTORS,
6244 GFP_KERNEL);
6233 6245
6234 if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) { 6246 if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) {
6235 free_scratch_buffer(conf, percpu); 6247 free_scratch_buffer(conf, percpu);
@@ -7205,6 +7217,15 @@ static int check_reshape(struct mddev *mddev)
7205 if (!check_stripe_cache(mddev)) 7217 if (!check_stripe_cache(mddev))
7206 return -ENOSPC; 7218 return -ENOSPC;
7207 7219
7220 if (mddev->new_chunk_sectors > mddev->chunk_sectors ||
7221 mddev->delta_disks > 0)
7222 if (resize_chunks(conf,
7223 conf->previous_raid_disks
7224 + max(0, mddev->delta_disks),
7225 max(mddev->new_chunk_sectors,
7226 mddev->chunk_sectors)
7227 ) < 0)
7228 return -ENOMEM;
7208 return resize_stripes(conf, (conf->previous_raid_disks 7229 return resize_stripes(conf, (conf->previous_raid_disks
7209 + mddev->delta_disks)); 7230 + mddev->delta_disks));
7210} 7231}