diff options
-rw-r--r-- | drivers/md/raid5.c | 65 |
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 | ||
2071 | static 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 | |||
2071 | static int resize_stripes(struct r5conf *conf, int newsize) | 2100 | static 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 | } |