aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2005-06-23 03:10:15 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-23 12:45:32 -0400
commitbb93e3a52f8db7210258a1a2134cced0b78a46e1 (patch)
treeb6def4c3fe5624769de64e242bb2007fffea55c8
parent0d77e5a2c23da734f5a7925f64afa1c2ed92e0f9 (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.c74
-rw-r--r--fs/block_dev.c5
-rw-r--r--include/linux/fs.h1
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
136int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, 136static 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
195static 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
212int 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
780static int block_ioctl(struct inode *inode, struct file *file, unsigned cmd, 780static 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 *);