diff options
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r-- | fs/block_dev.c | 44 |
1 files changed, 27 insertions, 17 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 88a776fa0ef6..99e0ae1a4c78 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -986,7 +986,6 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); | |||
986 | static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | 986 | static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) |
987 | { | 987 | { |
988 | struct gendisk *disk; | 988 | struct gendisk *disk; |
989 | struct hd_struct *part = NULL; | ||
990 | int ret; | 989 | int ret; |
991 | int partno; | 990 | int partno; |
992 | int perm = 0; | 991 | int perm = 0; |
@@ -1004,24 +1003,25 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1004 | return ret; | 1003 | return ret; |
1005 | } | 1004 | } |
1006 | 1005 | ||
1007 | ret = -ENXIO; | ||
1008 | |||
1009 | lock_kernel(); | 1006 | lock_kernel(); |
1010 | 1007 | ||
1008 | ret = -ENXIO; | ||
1011 | disk = get_gendisk(bdev->bd_dev, &partno); | 1009 | disk = get_gendisk(bdev->bd_dev, &partno); |
1012 | if (!disk) | 1010 | if (!disk) |
1013 | goto out_unlock_kernel; | 1011 | goto out_unlock_kernel; |
1014 | part = disk_get_part(disk, partno); | ||
1015 | if (!part) | ||
1016 | goto out_unlock_kernel; | ||
1017 | 1012 | ||
1018 | mutex_lock_nested(&bdev->bd_mutex, for_part); | 1013 | mutex_lock_nested(&bdev->bd_mutex, for_part); |
1019 | if (!bdev->bd_openers) { | 1014 | if (!bdev->bd_openers) { |
1020 | bdev->bd_disk = disk; | 1015 | bdev->bd_disk = disk; |
1021 | bdev->bd_part = part; | ||
1022 | bdev->bd_contains = bdev; | 1016 | bdev->bd_contains = bdev; |
1023 | if (!partno) { | 1017 | if (!partno) { |
1024 | struct backing_dev_info *bdi; | 1018 | struct backing_dev_info *bdi; |
1019 | |||
1020 | ret = -ENXIO; | ||
1021 | bdev->bd_part = disk_get_part(disk, partno); | ||
1022 | if (!bdev->bd_part) | ||
1023 | goto out_clear; | ||
1024 | |||
1025 | if (disk->fops->open) { | 1025 | if (disk->fops->open) { |
1026 | ret = disk->fops->open(bdev, mode); | 1026 | ret = disk->fops->open(bdev, mode); |
1027 | if (ret) | 1027 | if (ret) |
@@ -1049,18 +1049,17 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1049 | bdev->bd_contains = whole; | 1049 | bdev->bd_contains = whole; |
1050 | bdev->bd_inode->i_data.backing_dev_info = | 1050 | bdev->bd_inode->i_data.backing_dev_info = |
1051 | whole->bd_inode->i_data.backing_dev_info; | 1051 | whole->bd_inode->i_data.backing_dev_info; |
1052 | bdev->bd_part = disk_get_part(disk, partno); | ||
1052 | if (!(disk->flags & GENHD_FL_UP) || | 1053 | if (!(disk->flags & GENHD_FL_UP) || |
1053 | !part || !part->nr_sects) { | 1054 | !bdev->bd_part || !bdev->bd_part->nr_sects) { |
1054 | ret = -ENXIO; | 1055 | ret = -ENXIO; |
1055 | goto out_clear; | 1056 | goto out_clear; |
1056 | } | 1057 | } |
1057 | bd_set_size(bdev, (loff_t)part->nr_sects << 9); | 1058 | bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9); |
1058 | } | 1059 | } |
1059 | } else { | 1060 | } else { |
1060 | disk_put_part(part); | ||
1061 | put_disk(disk); | 1061 | put_disk(disk); |
1062 | module_put(disk->fops->owner); | 1062 | module_put(disk->fops->owner); |
1063 | part = NULL; | ||
1064 | disk = NULL; | 1063 | disk = NULL; |
1065 | if (bdev->bd_contains == bdev) { | 1064 | if (bdev->bd_contains == bdev) { |
1066 | if (bdev->bd_disk->fops->open) { | 1065 | if (bdev->bd_disk->fops->open) { |
@@ -1080,6 +1079,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1080 | return 0; | 1079 | return 0; |
1081 | 1080 | ||
1082 | out_clear: | 1081 | out_clear: |
1082 | disk_put_part(bdev->bd_part); | ||
1083 | bdev->bd_disk = NULL; | 1083 | bdev->bd_disk = NULL; |
1084 | bdev->bd_part = NULL; | 1084 | bdev->bd_part = NULL; |
1085 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | 1085 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; |
@@ -1091,7 +1091,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1091 | out_unlock_kernel: | 1091 | out_unlock_kernel: |
1092 | unlock_kernel(); | 1092 | unlock_kernel(); |
1093 | 1093 | ||
1094 | disk_put_part(part); | ||
1095 | if (disk) | 1094 | if (disk) |
1096 | module_put(disk->fops->owner); | 1095 | module_put(disk->fops->owner); |
1097 | put_disk(disk); | 1096 | put_disk(disk); |
@@ -1136,12 +1135,15 @@ static int blkdev_open(struct inode * inode, struct file * filp) | |||
1136 | if (res) | 1135 | if (res) |
1137 | return res; | 1136 | return res; |
1138 | 1137 | ||
1139 | if (!(filp->f_mode & FMODE_EXCL)) | 1138 | if (filp->f_mode & FMODE_EXCL) { |
1140 | return 0; | 1139 | res = bd_claim(bdev, filp); |
1140 | if (res) | ||
1141 | goto out_blkdev_put; | ||
1142 | } | ||
1141 | 1143 | ||
1142 | if (!(res = bd_claim(bdev, filp))) | 1144 | return 0; |
1143 | return 0; | ||
1144 | 1145 | ||
1146 | out_blkdev_put: | ||
1145 | blkdev_put(bdev, filp->f_mode); | 1147 | blkdev_put(bdev, filp->f_mode); |
1146 | return res; | 1148 | return res; |
1147 | } | 1149 | } |
@@ -1204,8 +1206,16 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
1204 | { | 1206 | { |
1205 | struct block_device *bdev = I_BDEV(file->f_mapping->host); | 1207 | struct block_device *bdev = I_BDEV(file->f_mapping->host); |
1206 | fmode_t mode = file->f_mode; | 1208 | fmode_t mode = file->f_mode; |
1209 | |||
1210 | /* | ||
1211 | * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have | ||
1212 | * to updated it before every ioctl. | ||
1213 | */ | ||
1207 | if (file->f_flags & O_NDELAY) | 1214 | if (file->f_flags & O_NDELAY) |
1208 | mode |= FMODE_NDELAY_NOW; | 1215 | mode |= FMODE_NDELAY; |
1216 | else | ||
1217 | mode &= ~FMODE_NDELAY; | ||
1218 | |||
1209 | return blkdev_ioctl(bdev, mode, cmd, arg); | 1219 | return blkdev_ioctl(bdev, mode, cmd, arg); |
1210 | } | 1220 | } |
1211 | 1221 | ||