sys_ioctl: Add an unlocked_ioctl file operation
PATCH 1/1 sys_ioctl: Add an unlocked_ioctl file operation
# This is a BitKeeper generated diff -Nru style patch. #
# Add an unlocked_ioctl file operation
# It assumes if unlocked_ioctl is defined in fops
# then the driver can handle concurrency and # lock_kernel isn't called. # # Signed-off-by: Mike Werner <[email protected]> # diff -Nru a/fs/ioctl.c b/fs/ioctl.c --- a/fs/ioctl.c 2004-12-07 16:14:55 -08:00 +++ b/fs/ioctl.c 2004-12-07 16:14:55 -08:00 @@ -16,6 +16,8 @@ #include <asm/uaccess.h> #include <asm/ioctls.h>
+/* Any additions in file_ioctl need to be added to the lock_kernel filter in sys_ioctl */ +
static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) {
int error;
@@ -46,7 +48,9 @@
case FIONREAD:
return put_user(i_size_read(inode) - filp->f_pos, p);
}
- if (filp->f_op && filp->f_op->ioctl)
+ if (filp->f_op && filp->f_op->unlocked_ioctl)
+ return filp->f_op->unlocked_ioctl(inode, filp, cmd, arg);
+ else if (filp->f_op && filp->f_op->ioctl)
return filp->f_op->ioctl(inode, filp, cmd, arg);
return -ENOTTY;
}
@@ -56,7 +60,7 @@
{
struct file * filp;
unsigned int flag;
- int on, error = -EBADF;
+ int on, locked, error = -EBADF;
filp = fget(fd);
if (!filp)
@@ -68,7 +72,26 @@
goto out;
}- lock_kernel();
+ switch (cmd) {
+ case FIOCLEX:
+ case FIONCLEX:
+ case FIONBIO:
+ case FIOASYNC:
+ case FIOQSIZE:
+ case FIBMAP:
+ case FIGETBSZ:
+ case FIONREAD:
+ lock_kernel();
+ locked=1;
+ break;
+ default:
+ locked=0;
+ if (filp->f_op && !filp->f_op->unlocked_ioctl) {
+ lock_kernel();
+ locked=1;
+ }
+ }
+
switch (cmd) {
case FIOCLEX:
set_close_on_exec(fd, 1);
@@ -127,10 +150,13 @@
error = -ENOTTY;
if (S_ISREG(filp->f_dentry->d_inode->i_mode))
error = file_ioctl(filp, cmd, arg);
+ else if (filp->f_op && filp->f_op->unlocked_ioctl)
+ error = filp->f_op->unlocked_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
else if (filp->f_op && filp->f_op->ioctl)
error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
}
- unlock_kernel();
+ if (locked)
+ unlock_kernel();
fput(filp);
out:
include/linux/fs.h +1 -0
@@ -915,6 +915,7 @@int (*readdir) (struct file *,void *,filldir_t );unsigned int (*poll) (struct file *,struct poll_table_struct *);int (*ioctl) (struct inode *,struct file *,unsigned int ,unsigned long ); +int (*unlocked_ioctl) (struct inode *,struct file *,unsigned int ,unsigned long );int (*mmap) (struct file *,struct vm_area_struct *);int (*open) (struct inode *,struct file *);int (*flush) (struct file *);