Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/ioctl.c         |   35 +++++++++++++++++++++++------------
 25-akpm/include/linux/fs.h |    5 ++++-
 2 files changed, 27 insertions(+), 13 deletions(-)

diff -puN fs/ioctl.c~unlocked_ioctl fs/ioctl.c
--- 25/fs/ioctl.c~unlocked_ioctl	2004-12-09 22:58:40.324038136 -0800
+++ 25-akpm/fs/ioctl.c	2004-12-09 22:59:30.425421568 -0800
@@ -35,7 +35,6 @@ asmlinkage long sys_ioctl(unsigned int f
         }
 
 	inode = filp->f_dentry->d_inode;
-	lock_kernel();
 	switch (cmd) {
 	case FIOCLEX:
 		set_close_on_exec(fd, 1);
@@ -52,30 +51,33 @@ asmlinkage long sys_ioctl(unsigned int f
 		if(O_NONBLOCK != O_NDELAY)
 			flag |= O_NDELAY;
 #endif
+		lock_kernel();
 		if (on)
 			filp->f_flags |= flag;
 		else
 			filp->f_flags &= ~flag;
+		unlock_kernel();
 		goto done;
 	case FIOASYNC:
 		if ((error = get_user(on, (int __user *)arg)) != 0)
 			goto done;
 		flag = on ? FASYNC : 0;
 
-		/* Did FASYNC state change ? */
+		lock_kernel();
 		if ((flag ^ filp->f_flags) & FASYNC) {
+			/* FASYNC state changed */
 			if (filp->f_op && filp->f_op->fasync)
 				error = filp->f_op->fasync(fd, filp, on);
 			else
 				error = -ENOTTY;
 		}
-		if (error != 0)
-			goto done;
-
-		if (on)
-			filp->f_flags |= FASYNC;
-		else
-			filp->f_flags &= ~FASYNC;
+		if (error == 0) {
+			if (on)
+				filp->f_flags |= FASYNC;
+			else
+				filp->f_flags &= ~FASYNC;
+		}
+		unlock_kernel();
 		goto done;
 	case FIOQSIZE:
 		error = -ENOTTY;
@@ -107,7 +109,9 @@ asmlinkage long sys_ioctl(unsigned int f
 			if ((error = get_user(block, p)))
 				goto done;
 
+			lock_kernel();
 			res = mapping->a_ops->bmap(mapping, block);
+			unlock_kernel();
 			error = put_user(res, p);
 			goto done;
 		}
@@ -130,10 +134,17 @@ asmlinkage long sys_ioctl(unsigned int f
 	}
 
 	error = -ENOTTY;
-	if (filp->f_op && filp->f_op->ioctl)
-		error = filp->f_op->ioctl(inode, filp, cmd, arg);
+	if (filp->f_op) {
+		if (filp->f_op->unlocked_ioctl) {
+			error = filp->f_op->unlocked_ioctl(inode, filp,
+							cmd, arg);
+		} else if (filp->f_op->ioctl) {
+			lock_kernel();
+			error = filp->f_op->ioctl(inode, filp, cmd, arg);
+			unlock_kernel();
+		}
+	}
 done:
-	unlock_kernel();
 	fput(filp);
 out:
 	return error;
diff -puN include/linux/fs.h~unlocked_ioctl include/linux/fs.h
--- 25/include/linux/fs.h~unlocked_ioctl	2004-12-09 22:58:40.326037832 -0800
+++ 25-akpm/include/linux/fs.h	2004-12-09 22:58:40.332036920 -0800
@@ -921,7 +921,10 @@ struct file_operations {
 	ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
 	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 (*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 *);
_