Commit c46501b2deaa06efcaaf82917281941f02c6b307
1 parent
b721420e87
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
md/raid5: use seqcount to protect access to shape in make_request.
make_request() access various shape parameters (raid_disks, chunk_size etc) which might be changed by raid5_start_reshape(). If the later is called at and awkward time during the form, the wrong stripe_head might be used. So introduce a 'seqcount' and after finding a stripe_head make sure there is no reason to expect that we got the wrong one. Signed-off-by: NeilBrown <neilb@suse.de>
Showing 2 changed files with 14 additions and 1 deletions Side-by-side Diff
drivers/md/raid5.c
... | ... | @@ -4408,8 +4408,10 @@ |
4408 | 4408 | for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { |
4409 | 4409 | DEFINE_WAIT(w); |
4410 | 4410 | int previous; |
4411 | + int seq; | |
4411 | 4412 | |
4412 | 4413 | retry: |
4414 | + seq = read_seqcount_begin(&conf->gen_lock); | |
4413 | 4415 | previous = 0; |
4414 | 4416 | prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); |
4415 | 4417 | if (unlikely(conf->reshape_progress != MaxSector)) { |
... | ... | @@ -4442,7 +4444,7 @@ |
4442 | 4444 | previous, |
4443 | 4445 | &dd_idx, NULL); |
4444 | 4446 | pr_debug("raid456: make_request, sector %llu logical %llu\n", |
4445 | - (unsigned long long)new_sector, | |
4447 | + (unsigned long long)new_sector, | |
4446 | 4448 | (unsigned long long)logical_sector); |
4447 | 4449 | |
4448 | 4450 | sh = get_active_stripe(conf, new_sector, previous, |
... | ... | @@ -4471,6 +4473,13 @@ |
4471 | 4473 | goto retry; |
4472 | 4474 | } |
4473 | 4475 | } |
4476 | + if (read_seqcount_retry(&conf->gen_lock, seq)) { | |
4477 | + /* Might have got the wrong stripe_head | |
4478 | + * by accident | |
4479 | + */ | |
4480 | + release_stripe(sh); | |
4481 | + goto retry; | |
4482 | + } | |
4474 | 4483 | |
4475 | 4484 | if (rw == WRITE && |
4476 | 4485 | logical_sector >= mddev->suspend_lo && |
... | ... | @@ -5437,6 +5446,7 @@ |
5437 | 5446 | if (alloc_thread_groups(conf, 0)) |
5438 | 5447 | goto abort; |
5439 | 5448 | spin_lock_init(&conf->device_lock); |
5449 | + seqcount_init(&conf->gen_lock); | |
5440 | 5450 | init_waitqueue_head(&conf->wait_for_stripe); |
5441 | 5451 | init_waitqueue_head(&conf->wait_for_overlap); |
5442 | 5452 | INIT_LIST_HEAD(&conf->handle_list); |
... | ... | @@ -6249,6 +6259,7 @@ |
6249 | 6259 | |
6250 | 6260 | atomic_set(&conf->reshape_stripes, 0); |
6251 | 6261 | spin_lock_irq(&conf->device_lock); |
6262 | + write_seqcount_begin(&conf->gen_lock); | |
6252 | 6263 | conf->previous_raid_disks = conf->raid_disks; |
6253 | 6264 | conf->raid_disks += mddev->delta_disks; |
6254 | 6265 | conf->prev_chunk_sectors = conf->chunk_sectors; |
... | ... | @@ -6265,6 +6276,7 @@ |
6265 | 6276 | else |
6266 | 6277 | conf->reshape_progress = 0; |
6267 | 6278 | conf->reshape_safe = conf->reshape_progress; |
6279 | + write_seqcount_end(&conf->gen_lock); | |
6268 | 6280 | spin_unlock_irq(&conf->device_lock); |
6269 | 6281 | |
6270 | 6282 | /* Add some new drives, as many as will fit. |
drivers/md/raid5.h
... | ... | @@ -400,6 +400,7 @@ |
400 | 400 | int prev_chunk_sectors; |
401 | 401 | int prev_algo; |
402 | 402 | short generation; /* increments with every reshape */ |
403 | + seqcount_t gen_lock; /* lock against generation changes */ | |
403 | 404 | unsigned long reshape_checkpoint; /* Time we last updated |
404 | 405 | * metadata */ |
405 | 406 | long long min_offset_diff; /* minimum difference between |