[RFC PATCH] fs code: Push the BKL down into the file system ioctlhandlers

From: Alan Cox
Date: Thu May 22 2008 - 18:28:16 EST


This one is in many ways for comment - I'm not 100% up on the internal
locking of the file system layer so probably the changes here are
extremely conservative.

I'd appreciate improvements from fs people, and I suspect in many cases
the BKL isn't needed at all.

Signed-off-by: Alan Cox <alan@xxxxxxxxxx>

diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index bbfa0e2..d0d8cf4 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -116,13 +116,15 @@ static int raw_release(struct inode *inode, struct file *filp)
/*
* Forward ioctls to the underlying block device.
*/
-static int
-raw_ioctl(struct inode *inode, struct file *filp,
- unsigned int command, unsigned long arg)
+static long raw_ioctl(struct file *filp, unsigned int command,
+ unsigned long arg)
{
+ long ret;
struct block_device *bdev = filp->private_data;
-
- return blkdev_ioctl(bdev->bd_inode, NULL, command, arg);
+ lock_kernel();
+ ret = blkdev_ioctl(bdev->bd_inode, NULL, command, arg);
+ unlock_kernel();
+ return ret;
}

static void bind_device(struct raw_config_request *rq)
@@ -136,13 +138,15 @@ static void bind_device(struct raw_config_request *rq)
* Deal with ioctls against the raw-device control interface, to bind
* and unbind other raw devices.
*/
-static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
- unsigned int command, unsigned long arg)
+static long raw_ctl_ioctl(struct file *filp, unsigned int command,
+ unsigned long arg)
{
struct raw_config_request rq;
struct raw_device_data *rawdev;
int err = 0;

+ lock_kernel();
+
switch (command) {
case RAW_SETBIND:
case RAW_GETBIND:
@@ -231,28 +235,29 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
}
break;
default:
- err = -EINVAL;
+ err = -ENOTTY;
break;
}
out:
+ unlock_kernel();
return err;
}

static const struct file_operations raw_fops = {
- .read = do_sync_read,
- .aio_read = generic_file_aio_read,
- .write = do_sync_write,
- .aio_write = generic_file_aio_write_nolock,
- .open = raw_open,
- .release= raw_release,
- .ioctl = raw_ioctl,
- .owner = THIS_MODULE,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write_nolock,
+ .open = raw_open,
+ .release = raw_release,
+ .unlocked_ioctl = raw_ioctl,
+ .owner = THIS_MODULE,
};

static const struct file_operations raw_ctl_fops = {
- .ioctl = raw_ctl_ioctl,
- .open = raw_open,
- .owner = THIS_MODULE,
+ .unlocked_ioctl = raw_ctl_ioctl,
+ .open = raw_open,
+ .owner = THIS_MODULE,
};

static struct cdev raw_cdev;
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 8aacade..a81b0f3 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -24,12 +24,12 @@ static int autofs_root_symlink(struct inode *,struct dentry *,const char *);
static int autofs_root_unlink(struct inode *,struct dentry *);
static int autofs_root_rmdir(struct inode *,struct dentry *);
static int autofs_root_mkdir(struct inode *,struct dentry *,int);
-static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
+static long autofs_root_ioctl(struct file *,unsigned int,unsigned long);

const struct file_operations autofs_root_operations = {
.read = generic_read_dir,
.readdir = autofs_root_readdir,
- .ioctl = autofs_root_ioctl,
+ .unlocked_ioctl = autofs_root_ioctl,
};

const struct inode_operations autofs_root_inode_operations = {
@@ -499,11 +499,12 @@ static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi,
put_user(sbi->exp_timeout / HZ, p))
return -EFAULT;

+ lock_kernel();
if (ntimeout > ULONG_MAX/HZ)
sbi->exp_timeout = 0;
else
sbi->exp_timeout = ntimeout * HZ;
-
+ unlock_kernel();
return 0;
}

@@ -524,16 +525,20 @@ static inline int autofs_expire_run(struct super_block *sb,

memset(&pkt,0,sizeof pkt);

+ lock_kernel();
+
pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
pkt.hdr.type = autofs_ptype_expire;

- if (!sbi->exp_timeout || !(ent = autofs_expire(sb,sbi,mnt)))
+ if (!sbi->exp_timeout || !(ent = autofs_expire(sb,sbi,mnt))) {
+ unlock_kernel();
return -EAGAIN;
+ }

pkt.len = ent->len;
memcpy(pkt.name, ent->name, pkt.len);
pkt.name[pkt.len] = '\0';
-
+ unlock_kernel();
if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)))
return -EFAULT;

@@ -544,9 +549,10 @@ static inline int autofs_expire_run(struct super_block *sb,
* ioctl()'s on the root directory is the chief method for the daemon to
* generate kernel reactions
*/
-static int autofs_root_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static long autofs_root_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
void __user *argp = (void __user *)arg;

diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c
index be46805..f4291e0 100644
--- a/fs/autofs/waitq.c
+++ b/fs/autofs/waitq.c
@@ -14,6 +14,7 @@
#include <linux/time.h>
#include <linux/signal.h>
#include <linux/file.h>
+#include <linux/smp_lock.h>
#include "autofs_i.h"

/* We make this a static variable rather than a part of the superblock; it
@@ -29,6 +30,7 @@ void autofs_catatonic_mode(struct autofs_sb_info *sbi)

DPRINTK(("autofs: entering catatonic mode\n"));

+ lock_kernel();
sbi->catatonic = 1;
wq = sbi->queues;
sbi->queues = NULL; /* Erase all wait queues */
@@ -43,6 +45,7 @@ void autofs_catatonic_mode(struct autofs_sb_info *sbi)
fput(sbi->pipe); /* Close the pipe */
sbi->pipe = NULL;
autofs_hash_dputall(&sbi->dirhash); /* Remove all dentry pointers */
+ unlock_kernel();
}

static int autofs_write(struct file *file, const void *addr, int bytes)
@@ -182,12 +185,16 @@ int autofs_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_toke
{
struct autofs_wait_queue *wq, **wql;

+ lock_kernel();
+
for (wql = &sbi->queues; (wq = *wql) != NULL; wql = &wq->next) {
if ( wq->wait_queue_token == wait_queue_token )
break;
}
- if ( !wq )
+ if ( !wq ) {
+ unlock_kernel();
return -EINVAL;
+ }

*wql = wq->next; /* Unlink from chain */
kfree(wq->name);
@@ -199,7 +206,7 @@ int autofs_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_toke
kfree(wq);
else
wake_up(&wq->queue);
-
+ unlock_kernel();
return 0;
}

diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index edf5b6b..605e36c 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -17,13 +17,14 @@
#include <linux/stat.h>
#include <linux/param.h>
#include <linux/time.h>
+#include <linux/smp_lock.h>
#include "autofs_i.h"

static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
static int autofs4_dir_unlink(struct inode *,struct dentry *);
static int autofs4_dir_rmdir(struct inode *,struct dentry *);
static int autofs4_dir_mkdir(struct inode *,struct dentry *,int);
-static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
+static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long);
static int autofs4_dir_open(struct inode *inode, struct file *file);
static int autofs4_dir_close(struct inode *inode, struct file *file);
static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir);
@@ -36,7 +37,7 @@ const struct file_operations autofs4_root_operations = {
.release = dcache_dir_close,
.read = generic_read_dir,
.readdir = autofs4_root_readdir,
- .ioctl = autofs4_root_ioctl,
+ .unlocked_ioctl = autofs4_root_ioctl,
};

const struct file_operations autofs4_dir_operations = {
@@ -901,11 +902,12 @@ static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi,
(rv = put_user(sbi->exp_timeout/HZ, p)))
return rv;

+ lock_kernel();
if (ntimeout > ULONG_MAX/HZ)
sbi->exp_timeout = 0;
else
sbi->exp_timeout = ntimeout * HZ;
-
+ unlock_kernel();
return 0;
}

@@ -931,12 +933,12 @@ static inline int autofs4_ask_reghost(struct autofs_sb_info *sbi, int __user *p)

DPRINTK("returning %d", sbi->needs_reghost);

+ lock_kernel();
status = put_user(sbi->needs_reghost, p);
- if (status)
- return status;
-
- sbi->needs_reghost = 0;
- return 0;
+ if (status == 0)
+ sbi->needs_reghost = 0;
+ unlock_kernel();
+ return status;
}

/*
@@ -955,7 +957,9 @@ static inline int autofs4_toggle_reghost(struct autofs_sb_info *sbi, int __user
return status;

/* turn on/off reghosting, with the val */
+ lock_kernel();
sbi->reghost_enabled = val;
+ unlock_kernel();
return 0;
}

@@ -992,9 +996,10 @@ int is_autofs4_dentry(struct dentry *dentry)
* ioctl()'s on the root directory is the chief method for the daemon to
* generate kernel reactions
*/
-static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static long autofs4_root_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb);
void __user *p = (void __user *)arg;

diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 75e5955..8cf2756 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -15,6 +15,7 @@
#include <linux/time.h>
#include <linux/signal.h>
#include <linux/file.h>
+#include <linux/smp_lock.h>
#include "autofs_i.h"

/* We make this a static variable rather than a part of the superblock; it
@@ -30,6 +31,8 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)

DPRINTK("entering catatonic mode");

+ lock_kernel();
+
sbi->catatonic = 1;
wq = sbi->queues;
sbi->queues = NULL; /* Erase all wait queues */
@@ -43,6 +46,8 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
}
fput(sbi->pipe); /* Close the pipe */
sbi->pipe = NULL;
+
+ unlock_kernel();
}

static int autofs4_write(struct file *file, const void *addr, int bytes)
@@ -375,6 +380,7 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok
{
struct autofs_wait_queue *wq, **wql;

+ lock_kernel();
mutex_lock(&sbi->wq_mutex);
for (wql = &sbi->queues; (wq = *wql) != NULL; wql = &wq->next) {
if (wq->wait_queue_token == wait_queue_token)
@@ -383,6 +389,7 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok

if (!wq) {
mutex_unlock(&sbi->wq_mutex);
+ unlock_kernel();
return -EINVAL;
}

@@ -397,7 +404,7 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok
kfree(wq);
else
wake_up_interruptible(&wq->queue);
-
+ unlock_kernel();
return 0;
}

diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 8ca3bfd..c626acf 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -42,7 +42,7 @@ const struct file_operations ext3_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = ext3_readdir, /* we take BKL. needed?*/
- .ioctl = ext3_ioctl, /* BKL held */
+ .unlocked_ioctl = ext3_ioctl, /* BKL not held */
#ifdef CONFIG_COMPAT
.compat_ioctl = ext3_compat_ioctl,
#endif
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index acc4913..49798ed 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -112,7 +112,7 @@ const struct file_operations ext3_file_operations = {
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = ext3_file_write,
- .ioctl = ext3_ioctl,
+ .unlocked_ioctl = ext3_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext3_compat_ioctl,
#endif
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 0d0c701..4a9132c 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -18,18 +18,21 @@
#include <linux/smp_lock.h>
#include <asm/uaccess.h>

-int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
- unsigned long arg)
+long ext3_ioctl(struct file * filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct ext3_inode_info *ei = EXT3_I(inode);
unsigned int flags;
unsigned short rsv_window_size;
+ long ret;

ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);

switch (cmd) {
case EXT3_IOC_GETFLAGS:
+ lock_kernel();
ext3_get_inode_flags(ei);
+ unlock_kernel();
flags = ei->i_flags & EXT3_FL_USER_VISIBLE;
return put_user(flags, (int __user *) arg);
case EXT3_IOC_SETFLAGS: {
@@ -39,9 +42,13 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned int oldflags;
unsigned int jflag;

+ lock_kernel();
+
err = mnt_want_write(filp->f_path.mnt);
- if (err)
+ if (err) {
+ unlock_kernel();
return err;
+ }

if (!is_owner_or_cap(inode)) {
err = -EACCES;
@@ -119,6 +126,7 @@ flags_err:
ext3_journal_stop(handle);
if (err) {
mutex_unlock(&inode->i_mutex);
+ unlock_kernel();
return err;
}

@@ -127,11 +135,16 @@ flags_err:
mutex_unlock(&inode->i_mutex);
flags_out:
mnt_drop_write(filp->f_path.mnt);
+ unlock_kernel();
return err;
}
case EXT3_IOC_GETVERSION:
case EXT3_IOC_GETVERSION_OLD:
- return put_user(inode->i_generation, (int __user *) arg);
+ /* Probably not needed but might need inode lock instead */
+ lock_kernel();
+ ret = put_user(inode->i_generation, (int __user *) arg);
+ unlock_kernel();
+ return ret;
case EXT3_IOC_SETVERSION:
case EXT3_IOC_SETVERSION_OLD: {
handle_t *handle;
@@ -141,9 +154,13 @@ flags_out:

if (!is_owner_or_cap(inode))
return -EPERM;
+
+ lock_kernel();
err = mnt_want_write(filp->f_path.mnt);
- if (err)
+ if (err) {
+ unlock_kernel();
return err;
+ }
if (get_user(generation, (int __user *) arg)) {
err = -EFAULT;
goto setversion_out;
@@ -162,6 +179,7 @@ flags_out:
ext3_journal_stop(handle);
setversion_out:
mnt_drop_write(filp->f_path.mnt);
+ unlock_kernel();
return err;
}
#ifdef CONFIG_JBD_DEBUG
@@ -189,22 +207,30 @@ setversion_out:
}
#endif
case EXT3_IOC_GETRSVSZ:
+ lock_kernel();
if (test_opt(inode->i_sb, RESERVATION)
&& S_ISREG(inode->i_mode)
&& ei->i_block_alloc_info) {
rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
+ unlock_kernel();
return put_user(rsv_window_size, (int __user *)arg);
}
+ unlock_kernel();
return -ENOTTY;
case EXT3_IOC_SETRSVSZ: {
int err;

- if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
+ lock_kernel();
+ if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) {
+ unlock_kernel();
return -ENOTTY;
+ }

err = mnt_want_write(filp->f_path.mnt);
- if (err)
+ if (err) {
+ unlock_kernel();
return err;
+ }

if (!is_owner_or_cap(inode)) {
err = -EACCES;
@@ -234,6 +260,7 @@ setversion_out:
mutex_unlock(&ei->truncate_mutex);
setrsvsz_out:
mnt_drop_write(filp->f_path.mnt);
+ unlock_kernel();
return err;
}
case EXT3_IOC_GROUP_EXTEND: {
@@ -244,9 +271,12 @@ setrsvsz_out:
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;

+ lock_kernel();
err = mnt_want_write(filp->f_path.mnt);
- if (err)
+ if (err) {
+ unlock_kernel();
return err;
+ }

if (get_user(n_blocks_count, (__u32 __user *)arg)) {
err = -EFAULT;
@@ -258,6 +288,7 @@ setrsvsz_out:
journal_unlock_updates(EXT3_SB(sb)->s_journal);
group_extend_out:
mnt_drop_write(filp->f_path.mnt);
+ unlock_kernel();
return err;
}
case EXT3_IOC_GROUP_ADD: {
@@ -268,9 +299,12 @@ group_extend_out:
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;

+ lock_kernel();
err = mnt_want_write(filp->f_path.mnt);
- if (err)
+ if (err) {
+ unlock_kernel();
return err;
+ }

if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg,
sizeof(input))) {
@@ -284,6 +318,7 @@ group_extend_out:
journal_unlock_updates(EXT3_SB(sb)->s_journal);
group_add_out:
mnt_drop_write(filp->f_path.mnt);
+ unlock_kernel();
return err;
}

@@ -338,9 +373,7 @@ long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
default:
return -ENOIOCTLCMD;
}
- lock_kernel();
- ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
- unlock_kernel();
+ ret = ext3_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
return ret;
}
#endif
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 486725e..7d6e32d 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -738,11 +738,13 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
return ret;
}

-static int fat_dir_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static long fat_dir_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
struct dirent __user *d1 = (struct dirent __user *)arg;
+ struct inode *inode = filp->f_path.dentry->d_inode;
int short_only, both;
+ int ret;

switch (cmd) {
case VFAT_IOCTL_READDIR_SHORT:
@@ -754,7 +756,7 @@ static int fat_dir_ioctl(struct inode *inode, struct file *filp,
both = 1;
break;
default:
- return fat_generic_ioctl(inode, filp, cmd, arg);
+ return fat_generic_ioctl(filp, cmd, arg);
}

if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2])))
@@ -767,8 +769,11 @@ static int fat_dir_ioctl(struct inode *inode, struct file *filp,
if (put_user(0, &d1->d_reclen))
return -EFAULT;

- return fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir,
+ lock_kernel();
+ ret = fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir,
short_only, both);
+ unlock_kernel();
+ return ret;
}

#ifdef CONFIG_COMPAT
@@ -815,7 +820,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
const struct file_operations fat_dir_operations = {
.read = generic_read_dir,
.readdir = fat_readdir,
- .ioctl = fat_dir_ioctl,
+ .unlocked_ioctl = fat_dir_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fat_compat_dir_ioctl,
#endif
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 27cc116..e947748 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -17,9 +17,9 @@
#include <linux/backing-dev.h>
#include <linux/blkdev.h>

-int fat_generic_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
u32 __user *user_attr = (u32 __user *)arg;

@@ -28,11 +28,12 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
{
u32 attr;

+ lock_kernel();
if (inode->i_ino == MSDOS_ROOT_INO)
attr = ATTR_DIR;
else
attr = fat_attr(inode);
-
+ unlock_kernel();
return put_user(attr, user_attr);
}
case FAT_IOCTL_SET_ATTRIBUTES:
@@ -45,6 +46,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
if (err)
return err;

+ lock_kernel();
mutex_lock(&inode->i_mutex);

err = mnt_want_write(filp->f_path.mnt);
@@ -109,6 +111,7 @@ up:
mnt_drop_write(filp->f_path.mnt);
up_no_drop_write:
mutex_unlock(&inode->i_mutex);
+ unlock_kernel();
return err;
}
default:
@@ -134,7 +137,7 @@ const struct file_operations fat_file_operations = {
.aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.release = fat_file_release,
- .ioctl = fat_generic_ioctl,
+ .unlocked_ioctl = fat_generic_ioctl,
.fsync = file_fsync,
.splice_read = generic_file_splice_read,
};
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 5f40236..764fd1b 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -494,7 +494,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
const struct file_operations hfsplus_dir_operations = {
.read = generic_read_dir,
.readdir = hfsplus_readdir,
- .ioctl = hfsplus_ioctl,
+ .unlocked_ioctl = hfsplus_ioctl,
.llseek = generic_file_llseek,
.release = hfsplus_dir_release,
};
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 9e59537..a4b7f69 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -336,8 +336,7 @@ struct inode *hfsplus_new_inode(struct super_block *, int);
void hfsplus_delete_inode(struct inode *);

/* ioctl.c */
-int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg);
+long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
int hfsplus_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index d53b2af..df3862d 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -298,7 +298,7 @@ static const struct file_operations hfsplus_file_operations = {
.fsync = file_fsync,
.open = hfsplus_file_open,
.release = hfsplus_file_release,
- .ioctl = hfsplus_ioctl,
+ .unlocked_ioctl = hfsplus_ioctl,
};

struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index f457d2c..2faca3d 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -18,28 +18,35 @@
#include <linux/sched.h>
#include <linux/xattr.h>
#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
#include "hfsplus_fs.h"

-int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned int flags;
+ struct inode *inode = filp->f_path.dentry->d_inode;

switch (cmd) {
case HFSPLUS_IOC_EXT2_GETFLAGS:
flags = 0;
+ lock_kernel();
if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE)
flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */
if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND)
flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */
if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP)
flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */
+ unlock_kernel();
return put_user(flags, (int __user *)arg);
case HFSPLUS_IOC_EXT2_SETFLAGS: {
int err = 0;
+
+ lock_kernel();
err = mnt_want_write(filp->f_path.mnt);
- if (err)
+ if (err) {
+ unlock_kernel();
return err;
+ }

if (!is_owner_or_cap(inode)) {
err = -EACCES;
@@ -85,6 +92,7 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
mark_inode_dirty(inode);
setflags_out:
mnt_drop_write(filp->f_path.mnt);
+ unlock_kernel();
return err;
}
default:
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index e6b03d2..f267cf9 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -20,7 +20,7 @@ const struct file_operations reiserfs_dir_operations = {
.read = generic_read_dir,
.readdir = reiserfs_readdir,
.fsync = reiserfs_dir_fsync,
- .ioctl = reiserfs_ioctl,
+ .unlocked_ioctl = reiserfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index a804903..e4d415c 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -284,7 +284,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
const struct file_operations reiserfs_file_operations = {
.read = do_sync_read,
.write = reiserfs_file_write,
- .ioctl = reiserfs_ioctl,
+ .unlocked_ioctl = reiserfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = reiserfs_compat_ioctl,
#endif
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 8303320..dd73dd5 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -20,37 +20,47 @@
** 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
** 3) That's all for a while ...
*/
-int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = filp->f_path.dentry->d_inode;
unsigned int flags;
- int err = 0;
+ long err = 0;

switch (cmd) {
case REISERFS_IOC_UNPACK:
+ lock_kernel();
if (S_ISREG(inode->i_mode)) {
if (arg)
- return reiserfs_unpack(inode, filp);
- else
- return 0;
+ err = reiserfs_unpack(inode, filp);
} else
- return -ENOTTY;
+ err = -ENOTTY;
+ unlock_kernel();
+ return err;
/* following two cases are taken from fs/ext2/ioctl.c by Remy
Card (card@xxxxxxxxxxx) */
case REISERFS_IOC_GETFLAGS:
+ lock_kernel();
if (!reiserfs_attrs(inode->i_sb))
- return -ENOTTY;
-
- flags = REISERFS_I(inode)->i_attrs;
- i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
- return put_user(flags, (int __user *)arg);
+ err = -ENOTTY;
+ else {
+ flags = REISERFS_I(inode)->i_attrs;
+ i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
+ err = put_user(flags, (int __user *)arg);
+ }
+ unlock_kernel();
+ return err;
case REISERFS_IOC_SETFLAGS:{
- if (!reiserfs_attrs(inode->i_sb))
+ lock_kernel();
+ if (!reiserfs_attrs(inode->i_sb)) {
+ unlock_kernel();
return -ENOTTY;
+ }

err = mnt_want_write(filp->f_path.mnt);
- if (err)
+ if (err) {
+ unlock_kernel();
return err;
+ }

if (!is_owner_or_cap(inode)) {
err = -EPERM;
@@ -90,16 +100,24 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
mark_inode_dirty(inode);
setflags_out:
mnt_drop_write(filp->f_path.mnt);
+ unlock_kernel();
return err;
}
case REISERFS_IOC_GETVERSION:
- return put_user(inode->i_generation, (int __user *)arg);
+ lock_kernel();
+ err = put_user(inode->i_generation, (int __user *)arg);
+ unlock_kernel();
+ return err;
case REISERFS_IOC_SETVERSION:
+ lock_kernel();
if (!is_owner_or_cap(inode))
- return -EPERM;
- err = mnt_want_write(filp->f_path.mnt);
- if (err)
+ err = -EPERM;
+ else
+ err = mnt_want_write(filp->f_path.mnt);
+ if (err) {
+ unlock_kernel();
return err;
+ }
if (get_user(inode->i_generation, (int __user *)arg)) {
err = -EFAULT;
goto setversion_out;
@@ -108,6 +126,7 @@ setflags_out:
mark_inode_dirty(inode);
setversion_out:
mnt_drop_write(filp->f_path.mnt);
+ unlock_kernel();
return err;
default:
return -ENOTTY;
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 62dc270..a54557a 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -209,6 +209,6 @@ static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
const struct file_operations udf_dir_operations = {
.read = generic_read_dir,
.readdir = udf_readdir,
- .ioctl = udf_ioctl,
+ .unlocked_ioctl = udf_ioctl,
.fsync = udf_fsync_file,
};
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 0ed6e14..52edc5c 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -143,11 +143,11 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
return retval;
}

-int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
long old_block, new_block;
int result = -EINVAL;
+ struct inode *inode = filp->f_path.dentry->d_inode;

if (file_permission(filp, MAY_READ) != 0) {
udf_debug("no permission to access inode %lu\n",
@@ -162,6 +162,7 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,

switch (cmd) {
case UDF_GETVOLIDENT:
+ /* Could block anyway so no BKL ? */
if (copy_to_user((char __user *)arg,
UDF_SB(inode->i_sb)->s_volume_ident, 32))
return -EFAULT;
@@ -172,15 +173,20 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
return -EACCES;
if (get_user(old_block, (long __user *)arg))
return -EFAULT;
+ lock_kernel();
result = udf_relocate_blocks(inode->i_sb,
old_block, &new_block);
+ unlock_kernel();
if (result == 0)
result = put_user(new_block, (long __user *)arg);
return result;
case UDF_GETEASIZE:
+ lock_kernel();
result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
+ unlock_kernel();
break;
case UDF_GETEABLOCK:
+ /* Could block anyway so no BKL ? */
result = copy_to_user((char __user *)arg,
UDF_I(inode)->i_ext.i_data,
UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
@@ -203,7 +209,7 @@ static int udf_release_file(struct inode *inode, struct file *filp)
const struct file_operations udf_file_operations = {
.read = do_sync_read,
.aio_read = generic_file_aio_read,
- .ioctl = udf_ioctl,
+ .unlocked_ioctl = udf_ioctl,
.open = generic_file_open,
.mmap = generic_file_mmap,
.write = do_sync_write,
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 8fa9c2d..e9ae67c 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -120,8 +120,7 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
uint8_t *, uint8_t *);

/* file.c */
-extern int udf_ioctl(struct inode *, struct file *, unsigned int,
- unsigned long);
+extern long udf_ioctl(struct file *, unsigned int, unsigned long);

/* inode.c */
extern struct inode *udf_iget(struct super_block *, kernel_lb_addr);
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 36c5403..5aa14c2 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -838,8 +838,7 @@ extern void ext3_get_inode_flags(struct ext3_inode_info *);
extern void ext3_set_aops(struct inode *inode);

/* ioctl.c */
-extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
- unsigned long);
+extern long ext3_ioctl (struct file *, unsigned int, unsigned long);
extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long);

/* namei.c */
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index b03b274..43ad2c2 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -403,8 +403,8 @@ extern int fat_free_clusters(struct inode *inode, int cluster);
extern int fat_count_free_clusters(struct super_block *sb);

/* fat/file.c */
-extern int fat_generic_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern long fat_generic_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
extern const struct file_operations fat_file_operations;
extern const struct inode_operations fat_file_inode_operations;
extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index 4aacaee..807b6ed 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -2172,8 +2172,7 @@ __u32 r5_hash(const signed char *msg, int len);
#define SPARE_SPACE 500

/* prototypes from ioctl.c */
-int reiserfs_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
long reiserfs_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg);
int reiserfs_unpack(struct inode *inode, struct file *filp);
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/