diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 333a7bb4cb9c..889287019599 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -873,6 +873,11 @@ int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) | |||
873 | ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); | 873 | ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); |
874 | if (ret) | 874 | if (ret) |
875 | goto out_del; | 875 | goto out_del; |
876 | /* | ||
877 | * bdev could be deleted beneath us which would implicitly destroy | ||
878 | * the holder directory. Hold on to it. | ||
879 | */ | ||
880 | kobject_get(bdev->bd_part->holder_dir); | ||
876 | 881 | ||
877 | list_add(&holder->list, &bdev->bd_holder_disks); | 882 | list_add(&holder->list, &bdev->bd_holder_disks); |
878 | goto out_unlock; | 883 | goto out_unlock; |
@@ -909,6 +914,7 @@ void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk) | |||
909 | del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); | 914 | del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); |
910 | del_symlink(bdev->bd_part->holder_dir, | 915 | del_symlink(bdev->bd_part->holder_dir, |
911 | &disk_to_dev(disk)->kobj); | 916 | &disk_to_dev(disk)->kobj); |
917 | kobject_put(bdev->bd_part->holder_dir); | ||
912 | list_del_init(&holder->list); | 918 | list_del_init(&holder->list); |
913 | kfree(holder); | 919 | kfree(holder); |
914 | } | 920 | } |
@@ -922,14 +928,15 @@ EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); | |||
922 | * flush_disk - invalidates all buffer-cache entries on a disk | 928 | * flush_disk - invalidates all buffer-cache entries on a disk |
923 | * | 929 | * |
924 | * @bdev: struct block device to be flushed | 930 | * @bdev: struct block device to be flushed |
931 | * @kill_dirty: flag to guide handling of dirty inodes | ||
925 | * | 932 | * |
926 | * Invalidates all buffer-cache entries on a disk. It should be called | 933 | * Invalidates all buffer-cache entries on a disk. It should be called |
927 | * when a disk has been changed -- either by a media change or online | 934 | * when a disk has been changed -- either by a media change or online |
928 | * resize. | 935 | * resize. |
929 | */ | 936 | */ |
930 | static void flush_disk(struct block_device *bdev) | 937 | static void flush_disk(struct block_device *bdev, bool kill_dirty) |
931 | { | 938 | { |
932 | if (__invalidate_device(bdev)) { | 939 | if (__invalidate_device(bdev, kill_dirty)) { |
933 | char name[BDEVNAME_SIZE] = ""; | 940 | char name[BDEVNAME_SIZE] = ""; |
934 | 941 | ||
935 | if (bdev->bd_disk) | 942 | if (bdev->bd_disk) |
@@ -966,7 +973,7 @@ void check_disk_size_change(struct gendisk *disk, struct block_device *bdev) | |||
966 | "%s: detected capacity change from %lld to %lld\n", | 973 | "%s: detected capacity change from %lld to %lld\n", |
967 | name, bdev_size, disk_size); | 974 | name, bdev_size, disk_size); |
968 | i_size_write(bdev->bd_inode, disk_size); | 975 | i_size_write(bdev->bd_inode, disk_size); |
969 | flush_disk(bdev); | 976 | flush_disk(bdev, false); |
970 | } | 977 | } |
971 | } | 978 | } |
972 | EXPORT_SYMBOL(check_disk_size_change); | 979 | EXPORT_SYMBOL(check_disk_size_change); |
@@ -1019,7 +1026,7 @@ int check_disk_change(struct block_device *bdev) | |||
1019 | if (!(events & DISK_EVENT_MEDIA_CHANGE)) | 1026 | if (!(events & DISK_EVENT_MEDIA_CHANGE)) |
1020 | return 0; | 1027 | return 0; |
1021 | 1028 | ||
1022 | flush_disk(bdev); | 1029 | flush_disk(bdev, true); |
1023 | if (bdops->revalidate_disk) | 1030 | if (bdops->revalidate_disk) |
1024 | bdops->revalidate_disk(bdev->bd_disk); | 1031 | bdops->revalidate_disk(bdev->bd_disk); |
1025 | return 1; | 1032 | return 1; |
@@ -1215,12 +1222,6 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) | |||
1215 | 1222 | ||
1216 | res = __blkdev_get(bdev, mode, 0); | 1223 | res = __blkdev_get(bdev, mode, 0); |
1217 | 1224 | ||
1218 | /* __blkdev_get() may alter read only status, check it afterwards */ | ||
1219 | if (!res && (mode & FMODE_WRITE) && bdev_read_only(bdev)) { | ||
1220 | __blkdev_put(bdev, mode, 0); | ||
1221 | res = -EACCES; | ||
1222 | } | ||
1223 | |||
1224 | if (whole) { | 1225 | if (whole) { |
1225 | /* finish claiming */ | 1226 | /* finish claiming */ |
1226 | mutex_lock(&bdev->bd_mutex); | 1227 | mutex_lock(&bdev->bd_mutex); |
@@ -1298,6 +1299,11 @@ struct block_device *blkdev_get_by_path(const char *path, fmode_t mode, | |||
1298 | if (err) | 1299 | if (err) |
1299 | return ERR_PTR(err); | 1300 | return ERR_PTR(err); |
1300 | 1301 | ||
1302 | if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) { | ||
1303 | blkdev_put(bdev, mode); | ||
1304 | return ERR_PTR(-EACCES); | ||
1305 | } | ||
1306 | |||
1301 | return bdev; | 1307 | return bdev; |
1302 | } | 1308 | } |
1303 | EXPORT_SYMBOL(blkdev_get_by_path); | 1309 | EXPORT_SYMBOL(blkdev_get_by_path); |
@@ -1601,7 +1607,7 @@ fail: | |||
1601 | } | 1607 | } |
1602 | EXPORT_SYMBOL(lookup_bdev); | 1608 | EXPORT_SYMBOL(lookup_bdev); |
1603 | 1609 | ||
1604 | int __invalidate_device(struct block_device *bdev) | 1610 | int __invalidate_device(struct block_device *bdev, bool kill_dirty) |
1605 | { | 1611 | { |
1606 | struct super_block *sb = get_super(bdev); | 1612 | struct super_block *sb = get_super(bdev); |
1607 | int res = 0; | 1613 | int res = 0; |
@@ -1614,7 +1620,7 @@ int __invalidate_device(struct block_device *bdev) | |||
1614 | * hold). | 1620 | * hold). |
1615 | */ | 1621 | */ |
1616 | shrink_dcache_sb(sb); | 1622 | shrink_dcache_sb(sb); |
1617 | res = invalidate_inodes(sb); | 1623 | res = invalidate_inodes(sb, kill_dirty); |
1618 | drop_super(sb); | 1624 | drop_super(sb); |
1619 | } | 1625 | } |
1620 | invalidate_bdev(bdev); | 1626 | invalidate_bdev(bdev); |