diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 83 |
1 files changed, 49 insertions, 34 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 045f98854f14..bc8f27cc4483 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -17,11 +17,13 @@ | |||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/blkpg.h> | 18 | #include <linux/blkpg.h> |
19 | #include <linux/buffer_head.h> | 19 | #include <linux/buffer_head.h> |
20 | #include <linux/writeback.h> | ||
20 | #include <linux/mpage.h> | 21 | #include <linux/mpage.h> |
21 | #include <linux/mount.h> | 22 | #include <linux/mount.h> |
22 | #include <linux/uio.h> | 23 | #include <linux/uio.h> |
23 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
26 | #include "internal.h" | ||
25 | 27 | ||
26 | struct bdev_inode { | 28 | struct bdev_inode { |
27 | struct block_device bdev; | 29 | struct block_device bdev; |
@@ -543,11 +545,11 @@ static struct kobject *bdev_get_holder(struct block_device *bdev) | |||
543 | return kobject_get(bdev->bd_disk->holder_dir); | 545 | return kobject_get(bdev->bd_disk->holder_dir); |
544 | } | 546 | } |
545 | 547 | ||
546 | static void add_symlink(struct kobject *from, struct kobject *to) | 548 | static int add_symlink(struct kobject *from, struct kobject *to) |
547 | { | 549 | { |
548 | if (!from || !to) | 550 | if (!from || !to) |
549 | return; | 551 | return 0; |
550 | sysfs_create_link(from, to, kobject_name(to)); | 552 | return sysfs_create_link(from, to, kobject_name(to)); |
551 | } | 553 | } |
552 | 554 | ||
553 | static void del_symlink(struct kobject *from, struct kobject *to) | 555 | static void del_symlink(struct kobject *from, struct kobject *to) |
@@ -648,30 +650,38 @@ static void free_bd_holder(struct bd_holder *bo) | |||
648 | * If there is no matching entry with @bo in @bdev->bd_holder_list, | 650 | * If there is no matching entry with @bo in @bdev->bd_holder_list, |
649 | * add @bo to the list, create symlinks. | 651 | * add @bo to the list, create symlinks. |
650 | * | 652 | * |
651 | * Returns 1 if @bo was added to the list. | 653 | * Returns 0 if symlinks are created or already there. |
652 | * Returns 0 if @bo wasn't used by any reason and should be freed. | 654 | * Returns -ve if something fails and @bo can be freed. |
653 | */ | 655 | */ |
654 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) | 656 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) |
655 | { | 657 | { |
656 | struct bd_holder *tmp; | 658 | struct bd_holder *tmp; |
659 | int ret; | ||
657 | 660 | ||
658 | if (!bo) | 661 | if (!bo) |
659 | return 0; | 662 | return -EINVAL; |
660 | 663 | ||
661 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) { | 664 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) { |
662 | if (tmp->sdir == bo->sdir) { | 665 | if (tmp->sdir == bo->sdir) { |
663 | tmp->count++; | 666 | tmp->count++; |
667 | /* We've already done what we need to do here. */ | ||
668 | free_bd_holder(bo); | ||
664 | return 0; | 669 | return 0; |
665 | } | 670 | } |
666 | } | 671 | } |
667 | 672 | ||
668 | if (!bd_holder_grab_dirs(bdev, bo)) | 673 | if (!bd_holder_grab_dirs(bdev, bo)) |
669 | return 0; | 674 | return -EBUSY; |
670 | 675 | ||
671 | add_symlink(bo->sdir, bo->sdev); | 676 | ret = add_symlink(bo->sdir, bo->sdev); |
672 | add_symlink(bo->hdir, bo->hdev); | 677 | if (ret == 0) { |
673 | list_add_tail(&bo->list, &bdev->bd_holder_list); | 678 | ret = add_symlink(bo->hdir, bo->hdev); |
674 | return 1; | 679 | if (ret) |
680 | del_symlink(bo->sdir, bo->sdev); | ||
681 | } | ||
682 | if (ret == 0) | ||
683 | list_add_tail(&bo->list, &bdev->bd_holder_list); | ||
684 | return ret; | ||
675 | } | 685 | } |
676 | 686 | ||
677 | /** | 687 | /** |
@@ -741,7 +751,9 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder, | |||
741 | 751 | ||
742 | mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); | 752 | mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); |
743 | res = bd_claim(bdev, holder); | 753 | res = bd_claim(bdev, holder); |
744 | if (res || !add_bd_holder(bdev, bo)) | 754 | if (res == 0) |
755 | res = add_bd_holder(bdev, bo); | ||
756 | if (res) | ||
745 | free_bd_holder(bo); | 757 | free_bd_holder(bo); |
746 | mutex_unlock(&bdev->bd_mutex); | 758 | mutex_unlock(&bdev->bd_mutex); |
747 | 759 | ||
@@ -1021,7 +1033,7 @@ do_open(struct block_device *bdev, struct file *file, unsigned int subclass) | |||
1021 | rescan_partitions(bdev->bd_disk, bdev); | 1033 | rescan_partitions(bdev->bd_disk, bdev); |
1022 | } else { | 1034 | } else { |
1023 | mutex_lock_nested(&bdev->bd_contains->bd_mutex, | 1035 | mutex_lock_nested(&bdev->bd_contains->bd_mutex, |
1024 | BD_MUTEX_PARTITION); | 1036 | BD_MUTEX_WHOLE); |
1025 | bdev->bd_contains->bd_part_count++; | 1037 | bdev->bd_contains->bd_part_count++; |
1026 | mutex_unlock(&bdev->bd_contains->bd_mutex); | 1038 | mutex_unlock(&bdev->bd_contains->bd_mutex); |
1027 | } | 1039 | } |
@@ -1142,22 +1154,6 @@ static int blkdev_close(struct inode * inode, struct file * filp) | |||
1142 | return blkdev_put(bdev); | 1154 | return blkdev_put(bdev); |
1143 | } | 1155 | } |
1144 | 1156 | ||
1145 | static ssize_t blkdev_file_write(struct file *file, const char __user *buf, | ||
1146 | size_t count, loff_t *ppos) | ||
1147 | { | ||
1148 | struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; | ||
1149 | |||
1150 | return generic_file_write_nolock(file, &local_iov, 1, ppos); | ||
1151 | } | ||
1152 | |||
1153 | static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf, | ||
1154 | size_t count, loff_t pos) | ||
1155 | { | ||
1156 | struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count }; | ||
1157 | |||
1158 | return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); | ||
1159 | } | ||
1160 | |||
1161 | static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) | 1157 | static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) |
1162 | { | 1158 | { |
1163 | return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); | 1159 | return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); |
@@ -1177,18 +1173,16 @@ const struct file_operations def_blk_fops = { | |||
1177 | .open = blkdev_open, | 1173 | .open = blkdev_open, |
1178 | .release = blkdev_close, | 1174 | .release = blkdev_close, |
1179 | .llseek = block_llseek, | 1175 | .llseek = block_llseek, |
1180 | .read = generic_file_read, | 1176 | .read = do_sync_read, |
1181 | .write = blkdev_file_write, | 1177 | .write = do_sync_write, |
1182 | .aio_read = generic_file_aio_read, | 1178 | .aio_read = generic_file_aio_read, |
1183 | .aio_write = blkdev_file_aio_write, | 1179 | .aio_write = generic_file_aio_write_nolock, |
1184 | .mmap = generic_file_mmap, | 1180 | .mmap = generic_file_mmap, |
1185 | .fsync = block_fsync, | 1181 | .fsync = block_fsync, |
1186 | .unlocked_ioctl = block_ioctl, | 1182 | .unlocked_ioctl = block_ioctl, |
1187 | #ifdef CONFIG_COMPAT | 1183 | #ifdef CONFIG_COMPAT |
1188 | .compat_ioctl = compat_blkdev_ioctl, | 1184 | .compat_ioctl = compat_blkdev_ioctl, |
1189 | #endif | 1185 | #endif |
1190 | .readv = generic_file_readv, | ||
1191 | .writev = generic_file_write_nolock, | ||
1192 | .sendfile = generic_file_sendfile, | 1186 | .sendfile = generic_file_sendfile, |
1193 | .splice_read = generic_file_splice_read, | 1187 | .splice_read = generic_file_splice_read, |
1194 | .splice_write = generic_file_splice_write, | 1188 | .splice_write = generic_file_splice_write, |
@@ -1303,3 +1297,24 @@ void close_bdev_excl(struct block_device *bdev) | |||
1303 | } | 1297 | } |
1304 | 1298 | ||
1305 | EXPORT_SYMBOL(close_bdev_excl); | 1299 | EXPORT_SYMBOL(close_bdev_excl); |
1300 | |||
1301 | int __invalidate_device(struct block_device *bdev) | ||
1302 | { | ||
1303 | struct super_block *sb = get_super(bdev); | ||
1304 | int res = 0; | ||
1305 | |||
1306 | if (sb) { | ||
1307 | /* | ||
1308 | * no need to lock the super, get_super holds the | ||
1309 | * read mutex so the filesystem cannot go away | ||
1310 | * under us (->put_super runs with the write lock | ||
1311 | * hold). | ||
1312 | */ | ||
1313 | shrink_dcache_sb(sb); | ||
1314 | res = invalidate_inodes(sb); | ||
1315 | drop_super(sb); | ||
1316 | } | ||
1317 | invalidate_bdev(bdev, 0); | ||
1318 | return res; | ||
1319 | } | ||
1320 | EXPORT_SYMBOL(__invalidate_device); | ||