diff options
Diffstat (limited to 'fs/block_dev.c')
| -rw-r--r-- | fs/block_dev.c | 218 |
1 files changed, 148 insertions, 70 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 028d9fb9c2d5..4346468139e8 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -5,14 +5,12 @@ | |||
| 5 | * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE | 5 | * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/config.h> | ||
| 9 | #include <linux/init.h> | 8 | #include <linux/init.h> |
| 10 | #include <linux/mm.h> | 9 | #include <linux/mm.h> |
| 11 | #include <linux/fcntl.h> | 10 | #include <linux/fcntl.h> |
| 12 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
| 13 | #include <linux/kmod.h> | 12 | #include <linux/kmod.h> |
| 14 | #include <linux/major.h> | 13 | #include <linux/major.h> |
| 15 | #include <linux/devfs_fs_kernel.h> | ||
| 16 | #include <linux/smp_lock.h> | 14 | #include <linux/smp_lock.h> |
| 17 | #include <linux/highmem.h> | 15 | #include <linux/highmem.h> |
| 18 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
| @@ -545,11 +543,11 @@ static struct kobject *bdev_get_holder(struct block_device *bdev) | |||
| 545 | return kobject_get(bdev->bd_disk->holder_dir); | 543 | return kobject_get(bdev->bd_disk->holder_dir); |
| 546 | } | 544 | } |
| 547 | 545 | ||
| 548 | static void add_symlink(struct kobject *from, struct kobject *to) | 546 | static int add_symlink(struct kobject *from, struct kobject *to) |
| 549 | { | 547 | { |
| 550 | if (!from || !to) | 548 | if (!from || !to) |
| 551 | return; | 549 | return 0; |
| 552 | sysfs_create_link(from, to, kobject_name(to)); | 550 | return sysfs_create_link(from, to, kobject_name(to)); |
| 553 | } | 551 | } |
| 554 | 552 | ||
| 555 | static void del_symlink(struct kobject *from, struct kobject *to) | 553 | static void del_symlink(struct kobject *from, struct kobject *to) |
| @@ -650,30 +648,38 @@ static void free_bd_holder(struct bd_holder *bo) | |||
| 650 | * If there is no matching entry with @bo in @bdev->bd_holder_list, | 648 | * If there is no matching entry with @bo in @bdev->bd_holder_list, |
| 651 | * add @bo to the list, create symlinks. | 649 | * add @bo to the list, create symlinks. |
| 652 | * | 650 | * |
| 653 | * Returns 1 if @bo was added to the list. | 651 | * Returns 0 if symlinks are created or already there. |
| 654 | * Returns 0 if @bo wasn't used by any reason and should be freed. | 652 | * Returns -ve if something fails and @bo can be freed. |
| 655 | */ | 653 | */ |
| 656 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) | 654 | static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo) |
| 657 | { | 655 | { |
| 658 | struct bd_holder *tmp; | 656 | struct bd_holder *tmp; |
| 657 | int ret; | ||
| 659 | 658 | ||
| 660 | if (!bo) | 659 | if (!bo) |
| 661 | return 0; | 660 | return -EINVAL; |
| 662 | 661 | ||
| 663 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) { | 662 | list_for_each_entry(tmp, &bdev->bd_holder_list, list) { |
| 664 | if (tmp->sdir == bo->sdir) { | 663 | if (tmp->sdir == bo->sdir) { |
| 665 | tmp->count++; | 664 | tmp->count++; |
| 665 | /* We've already done what we need to do here. */ | ||
| 666 | free_bd_holder(bo); | ||
| 666 | return 0; | 667 | return 0; |
| 667 | } | 668 | } |
| 668 | } | 669 | } |
| 669 | 670 | ||
| 670 | if (!bd_holder_grab_dirs(bdev, bo)) | 671 | if (!bd_holder_grab_dirs(bdev, bo)) |
| 671 | return 0; | 672 | return -EBUSY; |
| 672 | 673 | ||
| 673 | add_symlink(bo->sdir, bo->sdev); | 674 | ret = add_symlink(bo->sdir, bo->sdev); |
| 674 | add_symlink(bo->hdir, bo->hdev); | 675 | if (ret == 0) { |
| 675 | list_add_tail(&bo->list, &bdev->bd_holder_list); | 676 | ret = add_symlink(bo->hdir, bo->hdev); |
| 676 | return 1; | 677 | if (ret) |
| 678 | del_symlink(bo->sdir, bo->sdev); | ||
| 679 | } | ||
| 680 | if (ret == 0) | ||
| 681 | list_add_tail(&bo->list, &bdev->bd_holder_list); | ||
| 682 | return ret; | ||
| 677 | } | 683 | } |
| 678 | 684 | ||
| 679 | /** | 685 | /** |
| @@ -741,9 +747,11 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder, | |||
| 741 | if (!bo) | 747 | if (!bo) |
| 742 | return -ENOMEM; | 748 | return -ENOMEM; |
| 743 | 749 | ||
| 744 | mutex_lock(&bdev->bd_mutex); | 750 | mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); |
| 745 | res = bd_claim(bdev, holder); | 751 | res = bd_claim(bdev, holder); |
| 746 | if (res || !add_bd_holder(bdev, bo)) | 752 | if (res == 0) |
| 753 | res = add_bd_holder(bdev, bo); | ||
| 754 | if (res) | ||
| 747 | free_bd_holder(bo); | 755 | free_bd_holder(bo); |
| 748 | mutex_unlock(&bdev->bd_mutex); | 756 | mutex_unlock(&bdev->bd_mutex); |
| 749 | 757 | ||
| @@ -766,7 +774,7 @@ static void bd_release_from_kobject(struct block_device *bdev, | |||
| 766 | if (!kobj) | 774 | if (!kobj) |
| 767 | return; | 775 | return; |
| 768 | 776 | ||
| 769 | mutex_lock(&bdev->bd_mutex); | 777 | mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); |
| 770 | bd_release(bdev); | 778 | bd_release(bdev); |
| 771 | if ((bo = del_bd_holder(bdev, kobj))) | 779 | if ((bo = del_bd_holder(bdev, kobj))) |
| 772 | free_bd_holder(bo); | 780 | free_bd_holder(bo); |
| @@ -824,6 +832,22 @@ struct block_device *open_by_devnum(dev_t dev, unsigned mode) | |||
| 824 | 832 | ||
| 825 | EXPORT_SYMBOL(open_by_devnum); | 833 | EXPORT_SYMBOL(open_by_devnum); |
| 826 | 834 | ||
| 835 | static int | ||
| 836 | blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags); | ||
| 837 | |||
| 838 | struct block_device *open_partition_by_devnum(dev_t dev, unsigned mode) | ||
| 839 | { | ||
| 840 | struct block_device *bdev = bdget(dev); | ||
| 841 | int err = -ENOMEM; | ||
| 842 | int flags = mode & FMODE_WRITE ? O_RDWR : O_RDONLY; | ||
| 843 | if (bdev) | ||
| 844 | err = blkdev_get_partition(bdev, mode, flags); | ||
| 845 | return err ? ERR_PTR(err) : bdev; | ||
| 846 | } | ||
| 847 | |||
| 848 | EXPORT_SYMBOL(open_partition_by_devnum); | ||
| 849 | |||
| 850 | |||
| 827 | /* | 851 | /* |
| 828 | * This routine checks whether a removable media has been changed, | 852 | * This routine checks whether a removable media has been changed, |
| 829 | * and invalidates all buffer-cache-entries in that case. This | 853 | * and invalidates all buffer-cache-entries in that case. This |
| @@ -870,7 +894,66 @@ void bd_set_size(struct block_device *bdev, loff_t size) | |||
| 870 | } | 894 | } |
| 871 | EXPORT_SYMBOL(bd_set_size); | 895 | EXPORT_SYMBOL(bd_set_size); |
| 872 | 896 | ||
| 873 | static int do_open(struct block_device *bdev, struct file *file) | 897 | static int __blkdev_put(struct block_device *bdev, unsigned int subclass) |
| 898 | { | ||
| 899 | int ret = 0; | ||
| 900 | struct inode *bd_inode = bdev->bd_inode; | ||
| 901 | struct gendisk *disk = bdev->bd_disk; | ||
| 902 | |||
| 903 | mutex_lock_nested(&bdev->bd_mutex, subclass); | ||
| 904 | lock_kernel(); | ||
| 905 | if (!--bdev->bd_openers) { | ||
| 906 | sync_blockdev(bdev); | ||
| 907 | kill_bdev(bdev); | ||
| 908 | } | ||
| 909 | if (bdev->bd_contains == bdev) { | ||
| 910 | if (disk->fops->release) | ||
| 911 | ret = disk->fops->release(bd_inode, NULL); | ||
| 912 | } else { | ||
| 913 | mutex_lock_nested(&bdev->bd_contains->bd_mutex, | ||
| 914 | subclass + 1); | ||
| 915 | bdev->bd_contains->bd_part_count--; | ||
| 916 | mutex_unlock(&bdev->bd_contains->bd_mutex); | ||
| 917 | } | ||
| 918 | if (!bdev->bd_openers) { | ||
| 919 | struct module *owner = disk->fops->owner; | ||
| 920 | |||
| 921 | put_disk(disk); | ||
| 922 | module_put(owner); | ||
| 923 | |||
| 924 | if (bdev->bd_contains != bdev) { | ||
| 925 | kobject_put(&bdev->bd_part->kobj); | ||
| 926 | bdev->bd_part = NULL; | ||
| 927 | } | ||
| 928 | bdev->bd_disk = NULL; | ||
| 929 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | ||
| 930 | if (bdev != bdev->bd_contains) | ||
| 931 | __blkdev_put(bdev->bd_contains, subclass + 1); | ||
| 932 | bdev->bd_contains = NULL; | ||
| 933 | } | ||
| 934 | unlock_kernel(); | ||
| 935 | mutex_unlock(&bdev->bd_mutex); | ||
| 936 | bdput(bdev); | ||
| 937 | return ret; | ||
| 938 | } | ||
| 939 | |||
| 940 | int blkdev_put(struct block_device *bdev) | ||
| 941 | { | ||
| 942 | return __blkdev_put(bdev, BD_MUTEX_NORMAL); | ||
| 943 | } | ||
| 944 | EXPORT_SYMBOL(blkdev_put); | ||
| 945 | |||
| 946 | int blkdev_put_partition(struct block_device *bdev) | ||
| 947 | { | ||
| 948 | return __blkdev_put(bdev, BD_MUTEX_PARTITION); | ||
| 949 | } | ||
| 950 | EXPORT_SYMBOL(blkdev_put_partition); | ||
| 951 | |||
| 952 | static int | ||
| 953 | blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags); | ||
| 954 | |||
| 955 | static int | ||
| 956 | do_open(struct block_device *bdev, struct file *file, unsigned int subclass) | ||
| 874 | { | 957 | { |
| 875 | struct module *owner = NULL; | 958 | struct module *owner = NULL; |
| 876 | struct gendisk *disk; | 959 | struct gendisk *disk; |
| @@ -887,7 +970,8 @@ static int do_open(struct block_device *bdev, struct file *file) | |||
| 887 | } | 970 | } |
| 888 | owner = disk->fops->owner; | 971 | owner = disk->fops->owner; |
| 889 | 972 | ||
| 890 | mutex_lock(&bdev->bd_mutex); | 973 | mutex_lock_nested(&bdev->bd_mutex, subclass); |
| 974 | |||
| 891 | if (!bdev->bd_openers) { | 975 | if (!bdev->bd_openers) { |
| 892 | bdev->bd_disk = disk; | 976 | bdev->bd_disk = disk; |
| 893 | bdev->bd_contains = bdev; | 977 | bdev->bd_contains = bdev; |
| @@ -914,11 +998,11 @@ static int do_open(struct block_device *bdev, struct file *file) | |||
| 914 | ret = -ENOMEM; | 998 | ret = -ENOMEM; |
| 915 | if (!whole) | 999 | if (!whole) |
| 916 | goto out_first; | 1000 | goto out_first; |
| 917 | ret = blkdev_get(whole, file->f_mode, file->f_flags); | 1001 | ret = blkdev_get_whole(whole, file->f_mode, file->f_flags); |
| 918 | if (ret) | 1002 | if (ret) |
| 919 | goto out_first; | 1003 | goto out_first; |
| 920 | bdev->bd_contains = whole; | 1004 | bdev->bd_contains = whole; |
| 921 | mutex_lock(&whole->bd_mutex); | 1005 | mutex_lock_nested(&whole->bd_mutex, BD_MUTEX_WHOLE); |
| 922 | whole->bd_part_count++; | 1006 | whole->bd_part_count++; |
| 923 | p = disk->part[part - 1]; | 1007 | p = disk->part[part - 1]; |
| 924 | bdev->bd_inode->i_data.backing_dev_info = | 1008 | bdev->bd_inode->i_data.backing_dev_info = |
| @@ -946,7 +1030,8 @@ static int do_open(struct block_device *bdev, struct file *file) | |||
| 946 | if (bdev->bd_invalidated) | 1030 | if (bdev->bd_invalidated) |
| 947 | rescan_partitions(bdev->bd_disk, bdev); | 1031 | rescan_partitions(bdev->bd_disk, bdev); |
| 948 | } else { | 1032 | } else { |
| 949 | mutex_lock(&bdev->bd_contains->bd_mutex); | 1033 | mutex_lock_nested(&bdev->bd_contains->bd_mutex, |
| 1034 | BD_MUTEX_WHOLE); | ||
| 950 | bdev->bd_contains->bd_part_count++; | 1035 | bdev->bd_contains->bd_part_count++; |
| 951 | mutex_unlock(&bdev->bd_contains->bd_mutex); | 1036 | mutex_unlock(&bdev->bd_contains->bd_mutex); |
| 952 | } | 1037 | } |
| @@ -960,7 +1045,7 @@ out_first: | |||
| 960 | bdev->bd_disk = NULL; | 1045 | bdev->bd_disk = NULL; |
| 961 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | 1046 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; |
| 962 | if (bdev != bdev->bd_contains) | 1047 | if (bdev != bdev->bd_contains) |
| 963 | blkdev_put(bdev->bd_contains); | 1048 | __blkdev_put(bdev->bd_contains, BD_MUTEX_WHOLE); |
| 964 | bdev->bd_contains = NULL; | 1049 | bdev->bd_contains = NULL; |
| 965 | put_disk(disk); | 1050 | put_disk(disk); |
| 966 | module_put(owner); | 1051 | module_put(owner); |
| @@ -987,11 +1072,49 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags) | |||
| 987 | fake_file.f_dentry = &fake_dentry; | 1072 | fake_file.f_dentry = &fake_dentry; |
| 988 | fake_dentry.d_inode = bdev->bd_inode; | 1073 | fake_dentry.d_inode = bdev->bd_inode; |
| 989 | 1074 | ||
| 990 | return do_open(bdev, &fake_file); | 1075 | return do_open(bdev, &fake_file, BD_MUTEX_NORMAL); |
| 991 | } | 1076 | } |
| 992 | 1077 | ||
| 993 | EXPORT_SYMBOL(blkdev_get); | 1078 | EXPORT_SYMBOL(blkdev_get); |
| 994 | 1079 | ||
| 1080 | static int | ||
| 1081 | blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags) | ||
| 1082 | { | ||
| 1083 | /* | ||
| 1084 | * This crockload is due to bad choice of ->open() type. | ||
| 1085 | * It will go away. | ||
| 1086 | * For now, block device ->open() routine must _not_ | ||
| 1087 | * examine anything in 'inode' argument except ->i_rdev. | ||
| 1088 | */ | ||
| 1089 | struct file fake_file = {}; | ||
| 1090 | struct dentry fake_dentry = {}; | ||
| 1091 | fake_file.f_mode = mode; | ||
| 1092 | fake_file.f_flags = flags; | ||
| 1093 | fake_file.f_dentry = &fake_dentry; | ||
| 1094 | fake_dentry.d_inode = bdev->bd_inode; | ||
| 1095 | |||
| 1096 | return do_open(bdev, &fake_file, BD_MUTEX_WHOLE); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | static int | ||
| 1100 | blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags) | ||
| 1101 | { | ||
| 1102 | /* | ||
| 1103 | * This crockload is due to bad choice of ->open() type. | ||
| 1104 | * It will go away. | ||
| 1105 | * For now, block device ->open() routine must _not_ | ||
| 1106 | * examine anything in 'inode' argument except ->i_rdev. | ||
| 1107 | */ | ||
| 1108 | struct file fake_file = {}; | ||
| 1109 | struct dentry fake_dentry = {}; | ||
| 1110 | fake_file.f_mode = mode; | ||
| 1111 | fake_file.f_flags = flags; | ||
| 1112 | fake_file.f_dentry = &fake_dentry; | ||
| 1113 | fake_dentry.d_inode = bdev->bd_inode; | ||
| 1114 | |||
| 1115 | return do_open(bdev, &fake_file, BD_MUTEX_PARTITION); | ||
| 1116 | } | ||
| 1117 | |||
| 995 | static int blkdev_open(struct inode * inode, struct file * filp) | 1118 | static int blkdev_open(struct inode * inode, struct file * filp) |
| 996 | { | 1119 | { |
| 997 | struct block_device *bdev; | 1120 | struct block_device *bdev; |
| @@ -1007,7 +1130,7 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
| 1007 | 1130 | ||
| 1008 | bdev = bd_acquire(inode); | 1131 | bdev = bd_acquire(inode); |
| 1009 | 1132 | ||
| 1010 | res = do_open(bdev, filp); | 1133 | res = do_open(bdev, filp, BD_MUTEX_NORMAL); |
| 1011 | if (res) | 1134 | if (res) |
| 1012 | return res; | 1135 | return res; |
| 1013 | 1136 | ||
| @@ -1021,51 +1144,6 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
| 1021 | return res; | 1144 | return res; |
| 1022 | } | 1145 | } |
| 1023 | 1146 | ||
| 1024 | int blkdev_put(struct block_device *bdev) | ||
| 1025 | { | ||
| 1026 | int ret = 0; | ||
| 1027 | struct inode *bd_inode = bdev->bd_inode; | ||
| 1028 | struct gendisk *disk = bdev->bd_disk; | ||
| 1029 | |||
| 1030 | mutex_lock(&bdev->bd_mutex); | ||
| 1031 | lock_kernel(); | ||
| 1032 | if (!--bdev->bd_openers) { | ||
| 1033 | sync_blockdev(bdev); | ||
| 1034 | kill_bdev(bdev); | ||
| 1035 | } | ||
| 1036 | if (bdev->bd_contains == bdev) { | ||
| 1037 | if (disk->fops->release) | ||
| 1038 | ret = disk->fops->release(bd_inode, NULL); | ||
| 1039 | } else { | ||
| 1040 | mutex_lock(&bdev->bd_contains->bd_mutex); | ||
| 1041 | bdev->bd_contains->bd_part_count--; | ||
| 1042 | mutex_unlock(&bdev->bd_contains->bd_mutex); | ||
| 1043 | } | ||
| 1044 | if (!bdev->bd_openers) { | ||
| 1045 | struct module *owner = disk->fops->owner; | ||
| 1046 | |||
| 1047 | put_disk(disk); | ||
| 1048 | module_put(owner); | ||
| 1049 | |||
| 1050 | if (bdev->bd_contains != bdev) { | ||
| 1051 | kobject_put(&bdev->bd_part->kobj); | ||
| 1052 | bdev->bd_part = NULL; | ||
| 1053 | } | ||
| 1054 | bdev->bd_disk = NULL; | ||
| 1055 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | ||
| 1056 | if (bdev != bdev->bd_contains) { | ||
| 1057 | blkdev_put(bdev->bd_contains); | ||
| 1058 | } | ||
| 1059 | bdev->bd_contains = NULL; | ||
| 1060 | } | ||
| 1061 | unlock_kernel(); | ||
| 1062 | mutex_unlock(&bdev->bd_mutex); | ||
| 1063 | bdput(bdev); | ||
| 1064 | return ret; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | EXPORT_SYMBOL(blkdev_put); | ||
| 1068 | |||
| 1069 | static int blkdev_close(struct inode * inode, struct file * filp) | 1147 | static int blkdev_close(struct inode * inode, struct file * filp) |
| 1070 | { | 1148 | { |
| 1071 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); | 1149 | struct block_device *bdev = I_BDEV(filp->f_mapping->host); |
| @@ -1095,7 +1173,7 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
| 1095 | return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); | 1173 | return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); |
| 1096 | } | 1174 | } |
| 1097 | 1175 | ||
| 1098 | struct address_space_operations def_blk_aops = { | 1176 | const struct address_space_operations def_blk_aops = { |
| 1099 | .readpage = blkdev_readpage, | 1177 | .readpage = blkdev_readpage, |
| 1100 | .writepage = blkdev_writepage, | 1178 | .writepage = blkdev_writepage, |
| 1101 | .sync_page = block_sync_page, | 1179 | .sync_page = block_sync_page, |
