Commit e6036c0b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'md/3.12-fixes' of git://neil.brown.name/md

Pull md bugfixes from Neil Brown:
 "Assorted md bug-fixes for 3.12.

  All tagged for -stable releases too"

* tag 'md/3.12-fixes' of git://neil.brown.name/md:
  raid5: avoid finding "discard" stripe
  raid5: set bio bi_vcnt 0 for discard request
  md: avoid deadlock when md_set_badblocks.
  md: Fix skipping recovery for read-only arrays.
parents be6e8c76 d47648fc
...@@ -8111,6 +8111,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors, ...@@ -8111,6 +8111,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
u64 *p; u64 *p;
int lo, hi; int lo, hi;
int rv = 1; int rv = 1;
unsigned long flags;
if (bb->shift < 0) if (bb->shift < 0)
/* badblocks are disabled */ /* badblocks are disabled */
...@@ -8125,7 +8126,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors, ...@@ -8125,7 +8126,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
sectors = next - s; sectors = next - s;
} }
write_seqlock_irq(&bb->lock); write_seqlock_irqsave(&bb->lock, flags);
p = bb->page; p = bb->page;
lo = 0; lo = 0;
...@@ -8241,7 +8242,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors, ...@@ -8241,7 +8242,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
bb->changed = 1; bb->changed = 1;
if (!acknowledged) if (!acknowledged)
bb->unacked_exist = 1; bb->unacked_exist = 1;
write_sequnlock_irq(&bb->lock); write_sequnlock_irqrestore(&bb->lock, flags);
return rv; return rv;
} }
......
...@@ -1479,6 +1479,7 @@ static int raid1_spare_active(struct mddev *mddev) ...@@ -1479,6 +1479,7 @@ static int raid1_spare_active(struct mddev *mddev)
} }
} }
if (rdev if (rdev
&& rdev->recovery_offset == MaxSector
&& !test_bit(Faulty, &rdev->flags) && !test_bit(Faulty, &rdev->flags)
&& !test_and_set_bit(In_sync, &rdev->flags)) { && !test_and_set_bit(In_sync, &rdev->flags)) {
count++; count++;
......
...@@ -1782,6 +1782,7 @@ static int raid10_spare_active(struct mddev *mddev) ...@@ -1782,6 +1782,7 @@ static int raid10_spare_active(struct mddev *mddev)
} }
sysfs_notify_dirent_safe(tmp->replacement->sysfs_state); sysfs_notify_dirent_safe(tmp->replacement->sysfs_state);
} else if (tmp->rdev } else if (tmp->rdev
&& tmp->rdev->recovery_offset == MaxSector
&& !test_bit(Faulty, &tmp->rdev->flags) && !test_bit(Faulty, &tmp->rdev->flags)
&& !test_and_set_bit(In_sync, &tmp->rdev->flags)) { && !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
count++; count++;
......
...@@ -778,6 +778,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) ...@@ -778,6 +778,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
bi->bi_io_vec[0].bv_len = STRIPE_SIZE; bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
bi->bi_io_vec[0].bv_offset = 0; bi->bi_io_vec[0].bv_offset = 0;
bi->bi_size = STRIPE_SIZE; bi->bi_size = STRIPE_SIZE;
/*
* If this is discard request, set bi_vcnt 0. We don't
* want to confuse SCSI because SCSI will replace payload
*/
if (rw & REQ_DISCARD)
bi->bi_vcnt = 0;
if (rrdev) if (rrdev)
set_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags); set_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags);
...@@ -816,6 +822,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) ...@@ -816,6 +822,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
rbi->bi_io_vec[0].bv_len = STRIPE_SIZE; rbi->bi_io_vec[0].bv_len = STRIPE_SIZE;
rbi->bi_io_vec[0].bv_offset = 0; rbi->bi_io_vec[0].bv_offset = 0;
rbi->bi_size = STRIPE_SIZE; rbi->bi_size = STRIPE_SIZE;
/*
* If this is discard request, set bi_vcnt 0. We don't
* want to confuse SCSI because SCSI will replace payload
*/
if (rw & REQ_DISCARD)
rbi->bi_vcnt = 0;
if (conf->mddev->gendisk) if (conf->mddev->gendisk)
trace_block_bio_remap(bdev_get_queue(rbi->bi_bdev), trace_block_bio_remap(bdev_get_queue(rbi->bi_bdev),
rbi, disk_devt(conf->mddev->gendisk), rbi, disk_devt(conf->mddev->gendisk),
...@@ -2910,6 +2922,14 @@ static void handle_stripe_clean_event(struct r5conf *conf, ...@@ -2910,6 +2922,14 @@ static void handle_stripe_clean_event(struct r5conf *conf,
} }
/* now that discard is done we can proceed with any sync */ /* now that discard is done we can proceed with any sync */
clear_bit(STRIPE_DISCARD, &sh->state); clear_bit(STRIPE_DISCARD, &sh->state);
/*
* SCSI discard will change some bio fields and the stripe has
* no updated data, so remove it from hash list and the stripe
* will be reinitialized
*/
spin_lock_irq(&conf->device_lock);
remove_hash(sh);
spin_unlock_irq(&conf->device_lock);
if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state)) if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state))
set_bit(STRIPE_HANDLE, &sh->state); set_bit(STRIPE_HANDLE, &sh->state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment