From f88fb981183e71daf40bbd84bc8251bbf7b59e19 Mon Sep 17 00:00:00 2001 From: Kiyoshi Ueda Date: Fri, 16 Oct 2009 23:18:15 +0100 Subject: [RHEL5.7 PATCH] dm: dec_pending needs locking to save error value Had to wrap 'struct dm_io' change with __GENKSYMS__ to preserve kABI. Upstream commit f88fb981183e71daf40bbd84bc8251bbf7b59e19 Author: Kiyoshi Ueda Date: Fri Oct 16 23:18:15 2009 +0100 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 Signed-off-by: Jun'ichi Nomura Signed-off-by: Alasdair G Kergon --- drivers/md/dm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) Index: linux-rhel5/drivers/md/dm.c =================================================================== --- linux-rhel5.orig/drivers/md/dm.c +++ linux-rhel5/drivers/md/dm.c @@ -41,6 +41,9 @@ struct dm_io { struct bio *bio; atomic_t io_count; unsigned long start_time; +#ifndef __GENKSYMS__ + spinlock_t endio_lock; +#endif }; /* @@ -480,8 +483,12 @@ static void dec_pending(struct dm_io *io 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) { @@ -808,6 +815,7 @@ static void __split_bio(struct mapped_de 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); ci.idx = bio->bi_idx;