aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorJens Axboe2008-11-18 08:07:05 -0600
committerJens Axboe2008-11-18 08:08:56 -0600
commitc26156b2534c75bb3cdedf76f6ad1340971cf5bd (patch)
treeb95ed72f569c105fcc9e8f38df3d47628e689059 /block
parent98ba4031ab2adc8b394295e68aa4c8fe9d5060db (diff)
downloadkernel-common-c26156b2534c75bb3cdedf76f6ad1340971cf5bd.tar.gz
kernel-common-c26156b2534c75bb3cdedf76f6ad1340971cf5bd.tar.xz
kernel-common-c26156b2534c75bb3cdedf76f6ad1340971cf5bd.zip
block: hold extra reference to bio in blk_rq_map_user_iov()
If the size passed in is OK but we end up mapping too many segments, we call the unmap path directly like from IO completion. But from IO completion we have an extra reference to the bio, so this error case goes OOPS when it attempts to free and already free bio. Fix it by getting an extra reference to the bio before calling the unmap failure case. Reported-by: Petr Vandrovec <vandrove@vc.cvut.cz> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-map.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/block/blk-map.c b/block/blk-map.c
index 4849fa36161..0f4b4b88181 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -217,6 +217,12 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
217 return PTR_ERR(bio); 217 return PTR_ERR(bio);
218 218
219 if (bio->bi_size != len) { 219 if (bio->bi_size != len) {
220 /*
221 * Grab an extra reference to this bio, as bio_unmap_user()
222 * expects to be able to drop it twice as it happens on the
223 * normal IO completion path
224 */
225 bio_get(bio);
220 bio_endio(bio, 0); 226 bio_endio(bio, 0);
221 bio_unmap_user(bio); 227 bio_unmap_user(bio);
222 return -EINVAL; 228 return -EINVAL;