Skip to content

Commit

Permalink
md/raid5: fix allocation of 'scribble' array.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Fixes: 46d5b78 ("raid5: use flex_array for scribble data")
  • Loading branch information
neilbrown committed May 8, 2015
1 parent 6e9eac2 commit 738a273
Showing 1 changed file with 43 additions and 22 deletions.
65 changes: 43 additions & 22 deletions drivers/md/raid5.c
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,35 @@ static struct flex_array *scribble_alloc(int num, int cnt, gfp_t flags)
return ret;
}

static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors)
{
unsigned long cpu;
int err = 0;

mddev_suspend(conf->mddev);
get_online_cpus();
for_each_present_cpu(cpu) {
struct raid5_percpu *percpu;
struct flex_array *scribble;

percpu = per_cpu_ptr(conf->percpu, cpu);
scribble = scribble_alloc(new_disks,
new_sectors / STRIPE_SECTORS,
GFP_NOIO);

if (scribble) {
flex_array_free(percpu->scribble);
percpu->scribble = scribble;
} else {
err = -ENOMEM;
break;
}
}
put_online_cpus();
mddev_resume(conf->mddev);
return err;
}

static int resize_stripes(struct r5conf *conf, int newsize)
{
/* Make all the stripes able to hold 'newsize' devices.
Expand Down Expand Up @@ -2096,7 +2125,6 @@ static int resize_stripes(struct r5conf *conf, int newsize)
struct stripe_head *osh, *nsh;
LIST_HEAD(newstripes);
struct disk_info *ndisks;
unsigned long cpu;
int err;
struct kmem_cache *sc;
int i;
Expand Down Expand Up @@ -2178,25 +2206,6 @@ static int resize_stripes(struct r5conf *conf, int newsize)
} else
err = -ENOMEM;

get_online_cpus();
for_each_present_cpu(cpu) {
struct raid5_percpu *percpu;
struct flex_array *scribble;

percpu = per_cpu_ptr(conf->percpu, cpu);
scribble = scribble_alloc(newsize, conf->chunk_sectors /
STRIPE_SECTORS, GFP_NOIO);

if (scribble) {
flex_array_free(percpu->scribble);
percpu->scribble = scribble;
} else {
err = -ENOMEM;
break;
}
}
put_online_cpus();

/* Step 4, return new stripes to service */
while(!list_empty(&newstripes)) {
nsh = list_entry(newstripes.next, struct stripe_head, lru);
Expand Down Expand Up @@ -6228,8 +6237,11 @@ static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu
percpu->spare_page = alloc_page(GFP_KERNEL);
if (!percpu->scribble)
percpu->scribble = scribble_alloc(max(conf->raid_disks,
conf->previous_raid_disks), conf->chunk_sectors /
STRIPE_SECTORS, GFP_KERNEL);
conf->previous_raid_disks),
max(conf->chunk_sectors,
conf->prev_chunk_sectors)
/ STRIPE_SECTORS,
GFP_KERNEL);

if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) {
free_scratch_buffer(conf, percpu);
Expand Down Expand Up @@ -7205,6 +7217,15 @@ static int check_reshape(struct mddev *mddev)
if (!check_stripe_cache(mddev))
return -ENOSPC;

if (mddev->new_chunk_sectors > mddev->chunk_sectors ||
mddev->delta_disks > 0)
if (resize_chunks(conf,
conf->previous_raid_disks
+ max(0, mddev->delta_disks),
max(mddev->new_chunk_sectors,
mddev->chunk_sectors)
) < 0)
return -ENOMEM;
return resize_stripes(conf, (conf->previous_raid_disks
+ mddev->delta_disks));
}
Expand Down

0 comments on commit 738a273

Please sign in to comment.