diff options
author | Arnd Bergmann <arnd@arndb.de> | 2005-06-23 03:10:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-23 12:45:32 -0400 |
commit | bb93e3a52f8db7210258a1a2134cced0b78a46e1 (patch) | |
tree | b6def4c3fe5624769de64e242bb2007fffea55c8 | |
parent | 0d77e5a2c23da734f5a7925f64afa1c2ed92e0f9 (diff) |
[PATCH] block: add unlocked_ioctl support for block devices
This patch allows block device drivers to convert their ioctl functions to
unlocked_ioctl() like character devices and other subsystems. All
functions that were called with the BKL held before are still used that
way, but I would not be surprised if it could be removed from the ioctl
functions in drivers/block/ioctl.c themselves.
As a side note, I found that compat_blkdev_ioctl() acquires the BKL as
well, which looks like a bug. I have checked that every user of
disk->fops->compat_ioctl() in the current git tree gets the BKL itself, so
it could easily be removed from compat_blkdev_ioctl().
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/block/ioctl.c | 74 | ||||
-rw-r--r-- | fs/block_dev.c | 5 | ||||
-rw-r--r-- | include/linux/fs.h | 1 |
3 files changed, 57 insertions, 23 deletions
diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c index 6d7bcc9da9e7..6e278474f9a8 100644 --- a/drivers/block/ioctl.c +++ b/drivers/block/ioctl.c | |||
@@ -133,11 +133,9 @@ static int put_u64(unsigned long arg, u64 val) | |||
133 | return put_user(val, (u64 __user *)arg); | 133 | return put_user(val, (u64 __user *)arg); |
134 | } | 134 | } |
135 | 135 | ||
136 | int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, | 136 | static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev, |
137 | unsigned long arg) | 137 | unsigned cmd, unsigned long arg) |
138 | { | 138 | { |
139 | struct block_device *bdev = inode->i_bdev; | ||
140 | struct gendisk *disk = bdev->bd_disk; | ||
141 | struct backing_dev_info *bdi; | 139 | struct backing_dev_info *bdi; |
142 | int ret, n; | 140 | int ret, n; |
143 | 141 | ||
@@ -190,36 +188,72 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, | |||
190 | return put_ulong(arg, bdev->bd_inode->i_size >> 9); | 188 | return put_ulong(arg, bdev->bd_inode->i_size >> 9); |
191 | case BLKGETSIZE64: | 189 | case BLKGETSIZE64: |
192 | return put_u64(arg, bdev->bd_inode->i_size); | 190 | return put_u64(arg, bdev->bd_inode->i_size); |
191 | } | ||
192 | return -ENOIOCTLCMD; | ||
193 | } | ||
194 | |||
195 | static int blkdev_driver_ioctl(struct inode *inode, struct file *file, | ||
196 | struct gendisk *disk, unsigned cmd, unsigned long arg) | ||
197 | { | ||
198 | int ret; | ||
199 | if (disk->fops->unlocked_ioctl) | ||
200 | return disk->fops->unlocked_ioctl(file, cmd, arg); | ||
201 | |||
202 | if (disk->fops->ioctl) { | ||
203 | lock_kernel(); | ||
204 | ret = disk->fops->ioctl(inode, file, cmd, arg); | ||
205 | unlock_kernel(); | ||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | return -ENOTTY; | ||
210 | } | ||
211 | |||
212 | int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, | ||
213 | unsigned long arg) | ||
214 | { | ||
215 | struct block_device *bdev = inode->i_bdev; | ||
216 | struct gendisk *disk = bdev->bd_disk; | ||
217 | int ret, n; | ||
218 | |||
219 | switch(cmd) { | ||
193 | case BLKFLSBUF: | 220 | case BLKFLSBUF: |
194 | if (!capable(CAP_SYS_ADMIN)) | 221 | if (!capable(CAP_SYS_ADMIN)) |
195 | return -EACCES; | 222 | return -EACCES; |
196 | if (disk->fops->ioctl) { | 223 | |
197 | ret = disk->fops->ioctl(inode, file, cmd, arg); | 224 | ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg); |
198 | /* -EINVAL to handle old uncorrected drivers */ | 225 | /* -EINVAL to handle old uncorrected drivers */ |
199 | if (ret != -EINVAL && ret != -ENOTTY) | 226 | if (ret != -EINVAL && ret != -ENOTTY) |
200 | return ret; | 227 | return ret; |
201 | } | 228 | |
229 | lock_kernel(); | ||
202 | fsync_bdev(bdev); | 230 | fsync_bdev(bdev); |
203 | invalidate_bdev(bdev, 0); | 231 | invalidate_bdev(bdev, 0); |
232 | unlock_kernel(); | ||
204 | return 0; | 233 | return 0; |
234 | |||
205 | case BLKROSET: | 235 | case BLKROSET: |
206 | if (disk->fops->ioctl) { | 236 | ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg); |
207 | ret = disk->fops->ioctl(inode, file, cmd, arg); | 237 | /* -EINVAL to handle old uncorrected drivers */ |
208 | /* -EINVAL to handle old uncorrected drivers */ | 238 | if (ret != -EINVAL && ret != -ENOTTY) |
209 | if (ret != -EINVAL && ret != -ENOTTY) | 239 | return ret; |
210 | return ret; | ||
211 | } | ||
212 | if (!capable(CAP_SYS_ADMIN)) | 240 | if (!capable(CAP_SYS_ADMIN)) |
213 | return -EACCES; | 241 | return -EACCES; |
214 | if (get_user(n, (int __user *)(arg))) | 242 | if (get_user(n, (int __user *)(arg))) |
215 | return -EFAULT; | 243 | return -EFAULT; |
244 | lock_kernel(); | ||
216 | set_device_ro(bdev, n); | 245 | set_device_ro(bdev, n); |
246 | unlock_kernel(); | ||
217 | return 0; | 247 | return 0; |
218 | default: | ||
219 | if (disk->fops->ioctl) | ||
220 | return disk->fops->ioctl(inode, file, cmd, arg); | ||
221 | } | 248 | } |
222 | return -ENOTTY; | 249 | |
250 | lock_kernel(); | ||
251 | ret = blkdev_locked_ioctl(file, bdev, cmd, arg); | ||
252 | unlock_kernel(); | ||
253 | if (ret != -ENOIOCTLCMD) | ||
254 | return ret; | ||
255 | |||
256 | return blkdev_driver_ioctl(inode, file, disk, cmd, arg); | ||
223 | } | 257 | } |
224 | 258 | ||
225 | /* Most of the generic ioctls are handled in the normal fallback path. | 259 | /* Most of the generic ioctls are handled in the normal fallback path. |
diff --git a/fs/block_dev.c b/fs/block_dev.c index c0cbd1bc1a02..e0df94c37b7e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -777,8 +777,7 @@ static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf, | |||
777 | return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); | 777 | return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); |
778 | } | 778 | } |
779 | 779 | ||
780 | static int block_ioctl(struct inode *inode, struct file *file, unsigned cmd, | 780 | static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) |
781 | unsigned long arg) | ||
782 | { | 781 | { |
783 | return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); | 782 | return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); |
784 | } | 783 | } |
@@ -803,7 +802,7 @@ struct file_operations def_blk_fops = { | |||
803 | .aio_write = blkdev_file_aio_write, | 802 | .aio_write = blkdev_file_aio_write, |
804 | .mmap = generic_file_mmap, | 803 | .mmap = generic_file_mmap, |
805 | .fsync = block_fsync, | 804 | .fsync = block_fsync, |
806 | .ioctl = block_ioctl, | 805 | .unlocked_ioctl = block_ioctl, |
807 | #ifdef CONFIG_COMPAT | 806 | #ifdef CONFIG_COMPAT |
808 | .compat_ioctl = compat_blkdev_ioctl, | 807 | .compat_ioctl = compat_blkdev_ioctl, |
809 | #endif | 808 | #endif |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 3622e952e98c..9b1278e21279 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -884,6 +884,7 @@ struct block_device_operations { | |||
884 | int (*open) (struct inode *, struct file *); | 884 | int (*open) (struct inode *, struct file *); |
885 | int (*release) (struct inode *, struct file *); | 885 | int (*release) (struct inode *, struct file *); |
886 | int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); | 886 | int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); |
887 | long (*unlocked_ioctl) (struct file *, unsigned, unsigned long); | ||
887 | long (*compat_ioctl) (struct file *, unsigned, unsigned long); | 888 | long (*compat_ioctl) (struct file *, unsigned, unsigned long); |
888 | int (*media_changed) (struct gendisk *); | 889 | int (*media_changed) (struct gendisk *); |
889 | int (*revalidate_disk) (struct gendisk *); | 890 | int (*revalidate_disk) (struct gendisk *); |