Commit bb93e3a52f8db7210258a1a2134cced0b78a46e1

Authored by Arnd Bergmann
Committed by Linus Torvalds
1 parent 0d77e5a2c2

[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>

Showing 3 changed files with 57 additions and 23 deletions Side-by-side Diff

drivers/block/ioctl.c
... ... @@ -133,11 +133,9 @@
133 133 return put_user(val, (u64 __user *)arg);
134 134 }
135 135  
136   -int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
137   - unsigned long arg)
  136 +static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev,
  137 + unsigned cmd, unsigned long arg)
138 138 {
139   - struct block_device *bdev = inode->i_bdev;
140   - struct gendisk *disk = bdev->bd_disk;
141 139 struct backing_dev_info *bdi;
142 140 int ret, n;
143 141  
144 142  
145 143  
146 144  
147 145  
148 146  
149 147  
150 148  
151 149  
... ... @@ -190,36 +188,72 @@
190 188 return put_ulong(arg, bdev->bd_inode->i_size >> 9);
191 189 case BLKGETSIZE64:
192 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 220 case BLKFLSBUF:
194 221 if (!capable(CAP_SYS_ADMIN))
195 222 return -EACCES;
196   - if (disk->fops->ioctl) {
197   - ret = disk->fops->ioctl(inode, file, cmd, arg);
198   - /* -EINVAL to handle old uncorrected drivers */
199   - if (ret != -EINVAL && ret != -ENOTTY)
200   - return ret;
201   - }
  223 +
  224 + ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
  225 + /* -EINVAL to handle old uncorrected drivers */
  226 + if (ret != -EINVAL && ret != -ENOTTY)
  227 + return ret;
  228 +
  229 + lock_kernel();
202 230 fsync_bdev(bdev);
203 231 invalidate_bdev(bdev, 0);
  232 + unlock_kernel();
204 233 return 0;
  234 +
205 235 case BLKROSET:
206   - if (disk->fops->ioctl) {
207   - ret = disk->fops->ioctl(inode, file, cmd, arg);
208   - /* -EINVAL to handle old uncorrected drivers */
209   - if (ret != -EINVAL && ret != -ENOTTY)
210   - return ret;
211   - }
  236 + ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
  237 + /* -EINVAL to handle old uncorrected drivers */
  238 + if (ret != -EINVAL && ret != -ENOTTY)
  239 + return ret;
212 240 if (!capable(CAP_SYS_ADMIN))
213 241 return -EACCES;
214 242 if (get_user(n, (int __user *)(arg)))
215 243 return -EFAULT;
  244 + lock_kernel();
216 245 set_device_ro(bdev, n);
  246 + unlock_kernel();
217 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 259 /* Most of the generic ioctls are handled in the normal fallback path.
... ... @@ -777,8 +777,7 @@
777 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,
781   - unsigned long arg)
  780 +static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
782 781 {
783 782 return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
784 783 }
... ... @@ -803,7 +802,7 @@
803 802 .aio_write = blkdev_file_aio_write,
804 803 .mmap = generic_file_mmap,
805 804 .fsync = block_fsync,
806   - .ioctl = block_ioctl,
  805 + .unlocked_ioctl = block_ioctl,
807 806 #ifdef CONFIG_COMPAT
808 807 .compat_ioctl = compat_blkdev_ioctl,
809 808 #endif
... ... @@ -884,6 +884,7 @@
884 884 int (*open) (struct inode *, struct file *);
885 885 int (*release) (struct inode *, struct file *);
886 886 int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
  887 + long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
887 888 long (*compat_ioctl) (struct file *, unsigned, unsigned long);
888 889 int (*media_changed) (struct gendisk *);
889 890 int (*revalidate_disk) (struct gendisk *);