mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 08:14:15 +08:00
md: fix up plugging (again).
The value returned by "mddev_check_plug" is only valid until the next 'schedule' as that will unplug things. This could happen at any call to mempool_alloc. So just calling mddev_check_plug at the start doesn't really make sense. So call it just before, or just after, queuing things for the thread. As the action that happens at unplug is to wake the thread, this makes lots of sense. If we cannot add a plug (which requires a small GFP_ATOMIC alloc) we wake thread immediately. RAID5 is a bit different. Requests are queued for the thread and the thread is woken by release_stripe. So we don't need to wake the thread on failure. However the thread doesn't perform certain actions when there is any active plug, so it is important to install a plug before waking the thread. So for RAID5 we install the plug *before* queuing the request and waking the thread. Without this patch it is possible for raid1 or raid10 to queue a request without then waking the thread, resulting in the array locking up. Also change raid10 to only flush_pending_write when there are not active plugs, just like raid1. This patch is suitable for 3.0 or later. I plan to submit it to -stable, but I'll like to let it spend a few weeks in mainline first to be sure it is completely safe. Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
parent
f456309106
commit
b357f04a67
@ -883,7 +883,6 @@ static void make_request(struct mddev *mddev, struct bio * bio)
|
||||
const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
|
||||
const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
|
||||
struct md_rdev *blocked_rdev;
|
||||
int plugged;
|
||||
int first_clone;
|
||||
int sectors_handled;
|
||||
int max_sectors;
|
||||
@ -1034,7 +1033,6 @@ read_again:
|
||||
* the bad blocks. Each set of writes gets it's own r1bio
|
||||
* with a set of bios attached.
|
||||
*/
|
||||
plugged = mddev_check_plugged(mddev);
|
||||
|
||||
disks = conf->raid_disks * 2;
|
||||
retry_write:
|
||||
@ -1191,6 +1189,8 @@ read_again:
|
||||
bio_list_add(&conf->pending_bio_list, mbio);
|
||||
conf->pending_count++;
|
||||
spin_unlock_irqrestore(&conf->device_lock, flags);
|
||||
if (!mddev_check_plugged(mddev))
|
||||
md_wakeup_thread(mddev->thread);
|
||||
}
|
||||
/* Mustn't call r1_bio_write_done before this next test,
|
||||
* as it could result in the bio being freed.
|
||||
@ -1213,9 +1213,6 @@ read_again:
|
||||
|
||||
/* In case raid1d snuck in to freeze_array */
|
||||
wake_up(&conf->wait_barrier);
|
||||
|
||||
if (do_sync || !bitmap || !plugged)
|
||||
md_wakeup_thread(mddev->thread);
|
||||
}
|
||||
|
||||
static void status(struct seq_file *seq, struct mddev *mddev)
|
||||
|
@ -1039,7 +1039,6 @@ static void make_request(struct mddev *mddev, struct bio * bio)
|
||||
const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
|
||||
unsigned long flags;
|
||||
struct md_rdev *blocked_rdev;
|
||||
int plugged;
|
||||
int sectors_handled;
|
||||
int max_sectors;
|
||||
int sectors;
|
||||
@ -1239,7 +1238,6 @@ read_again:
|
||||
* of r10_bios is recored in bio->bi_phys_segments just as with
|
||||
* the read case.
|
||||
*/
|
||||
plugged = mddev_check_plugged(mddev);
|
||||
|
||||
r10_bio->read_slot = -1; /* make sure repl_bio gets freed */
|
||||
raid10_find_phys(conf, r10_bio);
|
||||
@ -1396,6 +1394,8 @@ retry_write:
|
||||
bio_list_add(&conf->pending_bio_list, mbio);
|
||||
conf->pending_count++;
|
||||
spin_unlock_irqrestore(&conf->device_lock, flags);
|
||||
if (!mddev_check_plugged(mddev, 0, 0))
|
||||
md_wakeup_thread(mddev->thread);
|
||||
|
||||
if (!r10_bio->devs[i].repl_bio)
|
||||
continue;
|
||||
@ -1423,6 +1423,8 @@ retry_write:
|
||||
bio_list_add(&conf->pending_bio_list, mbio);
|
||||
conf->pending_count++;
|
||||
spin_unlock_irqrestore(&conf->device_lock, flags);
|
||||
if (!mddev_check_plugged(mddev))
|
||||
md_wakeup_thread(mddev->thread);
|
||||
}
|
||||
|
||||
/* Don't remove the bias on 'remaining' (one_write_done) until
|
||||
@ -1448,9 +1450,6 @@ retry_write:
|
||||
|
||||
/* In case raid10d snuck in to freeze_array */
|
||||
wake_up(&conf->wait_barrier);
|
||||
|
||||
if (do_sync || !mddev->bitmap || !plugged)
|
||||
md_wakeup_thread(mddev->thread);
|
||||
}
|
||||
|
||||
static void status(struct seq_file *seq, struct mddev *mddev)
|
||||
@ -2661,7 +2660,8 @@ static void raid10d(struct mddev *mddev)
|
||||
blk_start_plug(&plug);
|
||||
for (;;) {
|
||||
|
||||
flush_pending_writes(conf);
|
||||
if (atomic_read(&mddev->plug_cnt) == 0)
|
||||
flush_pending_writes(conf);
|
||||
|
||||
spin_lock_irqsave(&conf->device_lock, flags);
|
||||
if (list_empty(head)) {
|
||||
|
@ -3997,7 +3997,6 @@ static void make_request(struct mddev *mddev, struct bio * bi)
|
||||
struct stripe_head *sh;
|
||||
const int rw = bio_data_dir(bi);
|
||||
int remaining;
|
||||
int plugged;
|
||||
|
||||
if (unlikely(bi->bi_rw & REQ_FLUSH)) {
|
||||
md_flush_request(mddev, bi);
|
||||
@ -4016,7 +4015,6 @@ static void make_request(struct mddev *mddev, struct bio * bi)
|
||||
bi->bi_next = NULL;
|
||||
bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
|
||||
|
||||
plugged = mddev_check_plugged(mddev);
|
||||
for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
|
||||
DEFINE_WAIT(w);
|
||||
int previous;
|
||||
@ -4118,6 +4116,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
|
||||
if ((bi->bi_rw & REQ_SYNC) &&
|
||||
!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
|
||||
atomic_inc(&conf->preread_active_stripes);
|
||||
mddev_check_plugged(mddev);
|
||||
release_stripe(sh);
|
||||
} else {
|
||||
/* cannot get stripe for read-ahead, just give-up */
|
||||
@ -4125,10 +4124,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
|
||||
finish_wait(&conf->wait_for_overlap, &w);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (!plugged)
|
||||
md_wakeup_thread(mddev->thread);
|
||||
|
||||
spin_lock_irq(&conf->device_lock);
|
||||
remaining = raid5_dec_bi_phys_segments(bi);
|
||||
|
Loading…
Reference in New Issue
Block a user