diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-29 09:17:19 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-29 09:17:19 -0700 |
commit | 68e71d1902a820c9bc7a5a6c23260841caafff33 (patch) | |
tree | a9ba52bdfef99e7bdc5f8623772d76789f7b7c8b | |
parent | 066455d471e997adbcc98dda62eaf461e8b6556e (diff) | |
parent | 592b09a42fc3ae6737a0f3ecf4fee42ecd0296f8 (diff) |
Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block:
backing-dev: ensure that a removed bdi no longer has super_block referencing it
block: use after free bug in __blkdev_get
block: silently error unsupported empty barriers too
-rw-r--r-- | block/blk-core.c | 2 | ||||
-rw-r--r-- | fs/block_dev.c | 2 | ||||
-rw-r--r-- | mm/backing-dev.c | 16 |
3 files changed, 18 insertions, 2 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index ac0fa10f8fa..71da5111120 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1161,7 +1161,7 @@ static int __make_request(struct request_queue *q, struct bio *bio) const unsigned int ff = bio->bi_rw & REQ_FAILFAST_MASK; int rw_flags; - if (bio_rw_flagged(bio, BIO_RW_BARRIER) && bio_has_data(bio) && + if (bio_rw_flagged(bio, BIO_RW_BARRIER) && (q->next_ordered == QUEUE_ORDERED_NONE)) { bio_endio(bio, -EOPNOTSUPP); return 0; diff --git a/fs/block_dev.c b/fs/block_dev.c index 9cf4b926f8e..8bed0557d88 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1248,8 +1248,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9); } } else { - put_disk(disk); module_put(disk->fops->owner); + put_disk(disk); disk = NULL; if (bdev->bd_contains == bdev) { if (bdev->bd_disk->fops->open) { diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 5a37e205571..1065b715ef6 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -610,6 +610,21 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi) kthread_stop(wb->task); } +/* + * This bdi is going away now, make sure that no super_blocks point to it + */ +static void bdi_prune_sb(struct backing_dev_info *bdi) +{ + struct super_block *sb; + + spin_lock(&sb_lock); + list_for_each_entry(sb, &super_blocks, s_list) { + if (sb->s_bdi == bdi) + sb->s_bdi = NULL; + } + spin_unlock(&sb_lock); +} + void bdi_unregister(struct backing_dev_info *bdi) { if (bdi->dev) { @@ -682,6 +697,7 @@ void bdi_destroy(struct backing_dev_info *bdi) spin_unlock(&inode_lock); } + bdi_prune_sb(bdi); bdi_unregister(bdi); for (i = 0; i < NR_BDI_STAT_ITEMS; i++) |