diff options
author | NeilBrown <neilb@suse.de> | 2011-02-24 01:25:47 -0500 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2011-02-24 01:25:47 -0500 |
commit | 93b270f76e7ef3b81001576860c2701931cdc78b (patch) | |
tree | abaca0e4d3e86721815498fafd06295dd9cfd002 /include | |
parent | da9cf5050a2e3dbc3cf26a8d908482eb4485ed49 (diff) |
Fix over-zealous flush_disk when changing device size.
There are two cases when we call flush_disk.
In one, the device has disappeared (check_disk_change) so any
data will hold becomes irrelevant.
In the oter, the device has changed size (check_disk_size_change)
so data we hold may be irrelevant.
In both cases it makes sense to discard any 'clean' buffers,
so they will be read back from the device if needed.
In the former case it makes sense to discard 'dirty' buffers
as there will never be anywhere safe to write the data. In the
second case it *does*not* make sense to discard dirty buffers
as that will lead to file system corruption when you simply enlarge
the containing devices.
flush_disk calls __invalidate_devices.
__invalidate_device calls both invalidate_inodes and invalidate_bdev.
invalidate_inodes *does* discard I_DIRTY inodes and this does lead
to fs corruption.
invalidate_bev *does*not* discard dirty pages, but I don't really care
about that at present.
So this patch adds a flag to __invalidate_device (calling it
__invalidate_device2) to indicate whether dirty buffers should be
killed, and this is passed to invalidate_inodes which can choose to
skip dirty inodes.
flusk_disk then passes true from check_disk_change and false from
check_disk_size_change.
dm avoids tripping over this problem by calling i_size_write directly
rathher than using check_disk_size_change.
md does use check_disk_size_change and so is affected.
This regression was introduced by commit 608aeef17a which causes
check_disk_size_change to call flush_disk, so it is suitable for any
kernel since 2.6.27.
Cc: stable@kernel.org
Acked-by: Jeff Moyer <jmoyer@redhat.com>
Cc: Andrew Patterson <andrew.patterson@hp.com>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/fs.h | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h index 32b38cd829d3..683f4c566c82 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -2139,7 +2139,7 @@ extern void check_disk_size_change(struct gendisk *disk, | |||
2139 | struct block_device *bdev); | 2139 | struct block_device *bdev); |
2140 | extern int revalidate_disk(struct gendisk *); | 2140 | extern int revalidate_disk(struct gendisk *); |
2141 | extern int check_disk_change(struct block_device *); | 2141 | extern int check_disk_change(struct block_device *); |
2142 | extern int __invalidate_device(struct block_device *); | 2142 | extern int __invalidate_device(struct block_device *, bool); |
2143 | extern int invalidate_partition(struct gendisk *, int); | 2143 | extern int invalidate_partition(struct gendisk *, int); |
2144 | #endif | 2144 | #endif |
2145 | unsigned long invalidate_mapping_pages(struct address_space *mapping, | 2145 | unsigned long invalidate_mapping_pages(struct address_space *mapping, |