diff options
author | Kiyoshi Ueda <k-ueda@ct.jp.nec.com> | 2009-10-16 23:18:15 +0100 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2009-10-16 23:18:15 +0100 |
commit | f88fb981183e71daf40bbd84bc8251bbf7b59e19 (patch) | |
tree | b1de0c32afb6a540624a0e53a25ce522a9935202 /drivers | |
parent | 03022c54b9725026c0370a810168975c387ad04c (diff) | |
download | linux-f88fb981183e71daf40bbd84bc8251bbf7b59e19.tar.gz linux-f88fb981183e71daf40bbd84bc8251bbf7b59e19.tar.bz2 linux-f88fb981183e71daf40bbd84bc8251bbf7b59e19.zip |
dm: dec_pending needs locking to save error value
Multiple instances of dec_pending() can run concurrently so a lock is
needed when it saves the first error code.
I have never experienced actual problem without locking and just found
this during code inspection while implementing the barrier support
patch for request-based dm.
This patch adds the locking.
I've done compile, boot and basic I/O testings.
Cc: stable@kernel.org
Signed-off-by: Kiyoshi Ueda <k-ueda@ct.jp.nec.com>
Signed-off-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/dm.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index c5f9918dab24..724efc63904d 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -47,6 +47,7 @@ struct dm_io { atomic_t io_count; struct bio *bio; unsigned long start_time; + spinlock_t endio_lock; }; /* @@ -578,8 +579,12 @@ static void dec_pending(struct dm_io *io, int error) struct mapped_device *md = io->md; /* Push-back supersedes any I/O errors */ - if (error && !(io->error > 0 && __noflush_suspending(md))) - io->error = error; + if (unlikely(error)) { + spin_lock_irqsave(&io->endio_lock, flags); + if (!(io->error > 0 && __noflush_suspending(md))) + io->error = error; + spin_unlock_irqrestore(&io->endio_lock, flags); + } if (atomic_dec_and_test(&io->io_count)) { if (io->error == DM_ENDIO_REQUEUE) { @@ -1226,6 +1231,7 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio) atomic_set(&ci.io->io_count, 1); ci.io->bio = bio; ci.io->md = md; + spin_lock_init(&ci.io->endio_lock); ci.sector = bio->bi_sector; ci.sector_count = bio_sectors(bio); if (unlikely(bio_empty_barrier(bio))) |