From f5dce0b63bcbca7a995414b883ff65ae76d5d11b Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 26 Jan 2008 18:27:52 -0500 Subject: [PATCH] Commit patches which move ext 2/3/4 to use unlocked_ioctl(). --- ext2-unlocked-ioctl.patch | 253 +++++++++++++++++++++++++++++ ext3-unlocked-ioctl.patch | 395 +++++++++++++++++++++++++++++++++++++++++++++ ext4-unlocked-ioctl.patch | 403 ++++++++++++++++++++++++++++++++++++++++++++++ series | 5 + 4 files changed, 1056 insertions(+) create mode 100644 ext2-unlocked-ioctl.patch create mode 100644 ext3-unlocked-ioctl.patch create mode 100644 ext4-unlocked-ioctl.patch diff --git a/ext2-unlocked-ioctl.patch b/ext2-unlocked-ioctl.patch new file mode 100644 index 00000000..6d2010be --- /dev/null +++ b/ext2-unlocked-ioctl.patch @@ -0,0 +1,253 @@ +Convert EXT2 to use unlocked_ioctl + +From: Mathieu Segaud + +Change ext2_ioctl() to be an unlocked_ioctl(), explicitly +exposing BKL's uses. + +Signed-off-by: Mathieu Segaud +Signed-off-by: "Theodore Ts'o" + +--- + fs/ext2/dir.c | 2 +- + fs/ext2/ext2.h | 3 +- + fs/ext2/file.c | 4 +- + fs/ext2/ioctl.c | 103 +++++++++++++++++++++++++++++++++++++------------------ + 4 files changed, 73 insertions(+), 39 deletions(-) + +diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c +index d868e26..dbee3c9 100644 +--- a/fs/ext2/dir.c ++++ b/fs/ext2/dir.c +@@ -703,7 +703,7 @@ const struct file_operations ext2_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .readdir = ext2_readdir, +- .ioctl = ext2_ioctl, ++ .unlocked_ioctl = ext2_ioctl, + #ifdef CONFIG_COMPAT + .compat_ioctl = ext2_compat_ioctl, + #endif +diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h +index c87ae29..bb9948c 100644 +--- a/fs/ext2/ext2.h ++++ b/fs/ext2/ext2.h +@@ -139,8 +139,7 @@ int __ext2_write_begin(struct file *file, struct address_space *mapping, + struct page **pagep, void **fsdata); + + /* ioctl.c */ +-extern int ext2_ioctl (struct inode *, struct file *, unsigned int, +- unsigned long); ++extern long ext2_ioctl(struct file *, unsigned int, unsigned long); + extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long); + + /* namei.c */ +diff --git a/fs/ext2/file.c b/fs/ext2/file.c +index c051798..17fe628 100644 +--- a/fs/ext2/file.c ++++ b/fs/ext2/file.c +@@ -48,7 +48,7 @@ const struct file_operations ext2_file_operations = { + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, +- .ioctl = ext2_ioctl, ++ .unlocked_ioctl = ext2_ioctl, + #ifdef CONFIG_COMPAT + .compat_ioctl = ext2_compat_ioctl, + #endif +@@ -65,7 +65,7 @@ const struct file_operations ext2_xip_file_operations = { + .llseek = generic_file_llseek, + .read = xip_file_read, + .write = xip_file_write, +- .ioctl = ext2_ioctl, ++ .unlocked_ioctl = ext2_ioctl, + #ifdef CONFIG_COMPAT + .compat_ioctl = ext2_compat_ioctl, + #endif +diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c +index 320b2cb..0f18ac5 100644 +--- a/fs/ext2/ioctl.c ++++ b/fs/ext2/ioctl.c +@@ -17,12 +17,18 @@ + #include + + +-int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, ++long ext2_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) + { +- struct ext2_inode_info *ei = EXT2_I(inode); ++ struct ext2_inode_info *ei; ++ struct inode *inode; + unsigned int flags; + unsigned short rsv_window_size; ++ long retval = 0; ++ ++ lock_kernel(); ++ inode = filp->f_path.dentry->d_inode; ++ ei = EXT2_I(inode); + + ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); + +@@ -30,18 +36,25 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + case EXT2_IOC_GETFLAGS: + ext2_get_inode_flags(ei); + flags = ei->i_flags & EXT2_FL_USER_VISIBLE; +- return put_user(flags, (int __user *) arg); ++ retval = put_user(flags, (int __user *) arg); ++ goto out; + case EXT2_IOC_SETFLAGS: { + unsigned int oldflags; + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + +- if (!is_owner_or_cap(inode)) +- return -EACCES; ++ if (!is_owner_or_cap(inode)) { ++ retval = -EACCES; ++ goto out; ++ } + +- if (get_user(flags, (int __user *) arg)) +- return -EFAULT; ++ if (get_user(flags, (int __user *) arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + if (!S_ISDIR(inode->i_mode)) + flags &= ~EXT2_DIRSYNC_FL; +@@ -50,7 +63,8 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + /* Is it quota file? Do not allow user to mess with it */ + if (IS_NOQUOTA(inode)) { + mutex_unlock(&inode->i_mutex); +- return -EPERM; ++ retval = -EPERM; ++ goto out; + } + oldflags = ei->i_flags; + +@@ -63,7 +77,8 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { + if (!capable(CAP_LINUX_IMMUTABLE)) { + mutex_unlock(&inode->i_mutex); +- return -EPERM; ++ retval = -EPERM; ++ goto out; + } + } + +@@ -75,41 +90,59 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + ext2_set_inode_flags(inode); + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); +- return 0; ++ goto out; + } + case EXT2_IOC_GETVERSION: +- return put_user(inode->i_generation, (int __user *) arg); ++ retval = put_user(inode->i_generation, (int __user *) arg); ++ goto out; + case EXT2_IOC_SETVERSION: +- if (!is_owner_or_cap(inode)) +- return -EPERM; +- if (IS_RDONLY(inode)) +- return -EROFS; +- if (get_user(inode->i_generation, (int __user *) arg)) +- return -EFAULT; ++ if (!is_owner_or_cap(inode)) { ++ retval = -EPERM; ++ goto out; ++ } ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } ++ if (get_user(inode->i_generation, (int __user *) arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); +- return 0; ++ goto out; + case EXT2_IOC_GETRSVSZ: + 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; +- return put_user(rsv_window_size, (int __user *)arg); ++ retval = put_user(rsv_window_size, (int __user *)arg); ++ goto out; + } +- return -ENOTTY; ++ retval = -ENOTTY; ++ goto out; + case EXT2_IOC_SETRSVSZ: { + +- if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) +- return -ENOTTY; ++ if (!test_opt(inode->i_sb, RESERVATION) || ++ !S_ISREG(inode->i_mode)) { ++ retval = -ENOTTY; ++ goto out; ++ } + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + +- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) +- return -EACCES; ++ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) { ++ retval = -EACCES; ++ goto out; ++ } + +- if (get_user(rsv_window_size, (int __user *)arg)) +- return -EFAULT; ++ if (get_user(rsv_window_size, (int __user *)arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; +@@ -131,11 +164,15 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + rsv->rsv_goal_size = rsv_window_size; + } + mutex_unlock(&ei->truncate_mutex); +- return 0; ++ goto out; + } + default: +- return -ENOTTY; ++ retval = -ENOTTY; ++ goto out; + } ++out: ++ unlock_kernel(); ++ return retval; + } + + #ifdef CONFIG_COMPAT +@@ -161,9 +198,7 @@ long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + default: + return -ENOIOCTLCMD; + } +- lock_kernel(); + ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); +- unlock_kernel(); + return ret; + } + #endif +-- +1.5.3.8 diff --git a/ext3-unlocked-ioctl.patch b/ext3-unlocked-ioctl.patch new file mode 100644 index 00000000..7c2247b1 --- /dev/null +++ b/ext3-unlocked-ioctl.patch @@ -0,0 +1,395 @@ +Convert ext3_ioctl() to an unlocked_ioctl + +From: Mathieu Segaud + +Change ext3_ioctl() to be an unlocked_ioctl(), explicitly +exposing BKL's uses. + +Signed-off-by: Mathieu Segaud +Signed-off-by: "Theodore Ts'o" + +--- + fs/ext3/dir.c | 2 +- + fs/ext3/file.c | 2 +- + fs/ext3/ioctl.c | 161 ++++++++++++++++++++++++++++++++--------------- + include/linux/ext3_fs.h | 3 +- + 4 files changed, 113 insertions(+), 55 deletions(-) + +diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c +index 8ca3bfd..5ab6b88 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, + #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 023a070..a7c480a 100644 +--- a/fs/ext3/ioctl.c ++++ b/fs/ext3/ioctl.c +@@ -17,12 +17,19 @@ + #include + #include + +-int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, ++long ext3_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) + { +- struct ext3_inode_info *ei = EXT3_I(inode); ++ struct ext3_inode_info *ei; ++ struct inode *inode; + unsigned int flags; + unsigned short rsv_window_size; ++ long retval = 0; ++ ++ lock_kernel(); ++ ++ inode = filp->f_path.dentry->d_inode; ++ ei = EXT3_I(inode); + + ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); + +@@ -30,7 +37,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + case EXT3_IOC_GETFLAGS: + ext3_get_inode_flags(ei); + flags = ei->i_flags & EXT3_FL_USER_VISIBLE; +- return put_user(flags, (int __user *) arg); ++ retval = put_user(flags, (int __user *) arg); ++ goto out; + case EXT3_IOC_SETFLAGS: { + handle_t *handle = NULL; + int err; +@@ -38,14 +46,20 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + unsigned int oldflags; + unsigned int jflag; + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + +- if (!is_owner_or_cap(inode)) +- return -EACCES; ++ if (!is_owner_or_cap(inode)) { ++ retval = -EACCES; ++ goto out; ++ } + +- if (get_user(flags, (int __user *) arg)) +- return -EFAULT; ++ if (get_user(flags, (int __user *) arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + if (!S_ISDIR(inode->i_mode)) + flags &= ~EXT3_DIRSYNC_FL; +@@ -54,7 +68,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + /* Is it quota file? Do not allow user to mess with it */ + if (IS_NOQUOTA(inode)) { + mutex_unlock(&inode->i_mutex); +- return -EPERM; ++ retval = -EPERM; ++ goto out; + } + oldflags = ei->i_flags; + +@@ -70,7 +85,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { + if (!capable(CAP_LINUX_IMMUTABLE)) { + mutex_unlock(&inode->i_mutex); +- return -EPERM; ++ retval = -EPERM; ++ goto out; + } + } + +@@ -81,7 +97,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { + if (!capable(CAP_SYS_RESOURCE)) { + mutex_unlock(&inode->i_mutex); +- return -EPERM; ++ retval = -EPERM; ++ goto out; + } + } + +@@ -89,7 +106,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) { + mutex_unlock(&inode->i_mutex); +- return PTR_ERR(handle); ++ retval = PTR_ERR(handle); ++ goto out; + } + if (IS_SYNC(inode)) + handle->h_sync = 1; +@@ -109,17 +127,20 @@ flags_err: + ext3_journal_stop(handle); + if (err) { + mutex_unlock(&inode->i_mutex); +- return err; ++ retval = err; ++ goto out; + } + + if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) + err = ext3_change_inode_journal_flag(inode, jflag); + mutex_unlock(&inode->i_mutex); +- return err; ++ retval = err; ++ goto out; + } + case EXT3_IOC_GETVERSION: + case EXT3_IOC_GETVERSION_OLD: +- return put_user(inode->i_generation, (int __user *) arg); ++ retval = put_user(inode->i_generation, (int __user *) arg); ++ goto out; + case EXT3_IOC_SETVERSION: + case EXT3_IOC_SETVERSION_OLD: { + handle_t *handle; +@@ -127,16 +148,24 @@ flags_err: + __u32 generation; + int err; + +- if (!is_owner_or_cap(inode)) +- return -EPERM; +- if (IS_RDONLY(inode)) +- return -EROFS; +- if (get_user(generation, (int __user *) arg)) +- return -EFAULT; ++ if (!is_owner_or_cap(inode)) { ++ retval = -EPERM; ++ goto out; ++ } ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } ++ if (get_user(generation, (int __user *) arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + handle = ext3_journal_start(inode, 1); +- if (IS_ERR(handle)) +- return PTR_ERR(handle); ++ if (IS_ERR(handle)) { ++ retval = PTR_ERR(handle); ++ goto out; ++ } + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err == 0) { + inode->i_ctime = CURRENT_TIME_SEC; +@@ -144,7 +173,8 @@ flags_err: + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + } + ext3_journal_stop(handle); +- return err; ++ retval = err; ++ goto out; + } + #ifdef CONFIG_JBD_DEBUG + case EXT3_IOC_WAIT_FOR_READONLY: +@@ -158,7 +188,7 @@ flags_err: + { + struct super_block *sb = inode->i_sb; + DECLARE_WAITQUEUE(wait, current); +- int ret = 0; ++ long ret = 0; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); +@@ -167,6 +197,7 @@ flags_err: + ret = 1; + } + remove_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait); ++ unlock_kernel(); + return ret; + } + #endif +@@ -175,22 +206,33 @@ flags_err: + && S_ISREG(inode->i_mode) + && ei->i_block_alloc_info) { + rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; +- return put_user(rsv_window_size, (int __user *)arg); ++ retval = put_user(rsv_window_size, (int __user *)arg); ++ goto out; + } +- return -ENOTTY; ++ retval = -ENOTTY; ++ goto out; + case EXT3_IOC_SETRSVSZ: { + +- if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) +- return -ENOTTY; ++ if (!test_opt(inode->i_sb, RESERVATION) || ++ !S_ISREG(inode->i_mode)) { ++ retval = -ENOTTY; ++ goto out; ++ } + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + +- if (!is_owner_or_cap(inode)) +- return -EACCES; ++ if (!is_owner_or_cap(inode)) { ++ retval = -EACCES; ++ goto out; ++ } + +- if (get_user(rsv_window_size, (int __user *)arg)) +- return -EFAULT; ++ if (get_user(rsv_window_size, (int __user *)arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; +@@ -208,27 +250,34 @@ flags_err: + rsv->rsv_goal_size = rsv_window_size; + } + mutex_unlock(&ei->truncate_mutex); +- return 0; ++ goto out; + } + case EXT3_IOC_GROUP_EXTEND: { + ext3_fsblk_t n_blocks_count; + struct super_block *sb = inode->i_sb; + int err; + +- if (!capable(CAP_SYS_RESOURCE)) +- return -EPERM; ++ if (!capable(CAP_SYS_RESOURCE)) { ++ retval = -EPERM; ++ goto out; ++ } + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + +- if (get_user(n_blocks_count, (__u32 __user *)arg)) +- return -EFAULT; ++ if (get_user(n_blocks_count, (__u32 __user *)arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + ++ unlock_kernel(); + return err; + } + case EXT3_IOC_GROUP_ADD: { +@@ -236,28 +285,40 @@ flags_err: + struct super_block *sb = inode->i_sb; + int err; + +- if (!capable(CAP_SYS_RESOURCE)) +- return -EPERM; ++ if (!capable(CAP_SYS_RESOURCE)) { ++ retval = -EPERM; ++ goto out; ++ } + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + + if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, +- sizeof(input))) +- return -EFAULT; ++ sizeof(input))) { ++ retval = -EFAULT; ++ goto out; ++ } + + err = ext3_group_add(sb, &input); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + ++ unlock_kernel(); + return err; + } + + + default: ++ unlock_kernel(); + return -ENOTTY; + } ++ ++out: ++ unlock_kernel(); ++ return retval; + } + + #ifdef CONFIG_COMPAT +@@ -305,9 +366,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(); + return ret; + } + #endif +diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h +index 241c01c..1c925eb 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 */ +-- +1.5.3.8 + +- +To unsubscribe from this list: send the line "unsubscribe linux-ext4" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/ext4-unlocked-ioctl.patch b/ext4-unlocked-ioctl.patch new file mode 100644 index 00000000..0b92b74b --- /dev/null +++ b/ext4-unlocked-ioctl.patch @@ -0,0 +1,403 @@ +Convert ext4_ioctl to an unlocked_ioctl + +From: Mathieu Segaud + +Change ext4_ioctl() to be an unlocked_ioctl(), explicitly +exposing BKL's uses. + +Signed-off-by: Mathieu Segaud +Signed-off-by: "Theodore Ts'o" + +diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c +index 33888bb..56e6608 100644 +--- a/fs/ext4/dir.c ++++ b/fs/ext4/dir.c +@@ -42,7 +42,7 @@ const struct file_operations ext4_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .readdir = ext4_readdir, /* we take BKL. needed?*/ +- .ioctl = ext4_ioctl, /* BKL held */ ++ .unlocked_ioctl = ext4_ioctl, + #ifdef CONFIG_COMPAT + .compat_ioctl = ext4_compat_ioctl, + #endif +diff --git a/fs/ext4/file.c b/fs/ext4/file.c +index ac35ec5..c586a81 100644 +--- a/fs/ext4/file.c ++++ b/fs/ext4/file.c +@@ -129,7 +129,7 @@ const struct file_operations ext4_file_operations = { + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = ext4_file_write, +- .ioctl = ext4_ioctl, ++ .unlocked_ioctl = ext4_ioctl, + #ifdef CONFIG_COMPAT + .compat_ioctl = ext4_compat_ioctl, + #endif +diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c +index 2ed7c37..7689d2e 100644 +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -17,12 +17,18 @@ + #include + #include + +-int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, +- unsigned long arg) ++long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + { +- struct ext4_inode_info *ei = EXT4_I(inode); ++ struct ext4_inode_info *ei; ++ struct inode *inode; + unsigned int flags; + unsigned short rsv_window_size; ++ long retval = 0; ++ ++ lock_kernel(); ++ ++ inode = filp->f_path.dentry->d_inode; ++ ei = EXT4_I(inode); + + ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg); + +@@ -30,22 +36,28 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + case EXT4_IOC_GETFLAGS: + ext4_get_inode_flags(ei); + flags = ei->i_flags & EXT4_FL_USER_VISIBLE; +- return put_user(flags, (int __user *) arg); ++ retval = put_user(flags, (int __user *) arg); ++ goto out; + case EXT4_IOC_SETFLAGS: { + handle_t *handle = NULL; +- int err; + struct ext4_iloc iloc; + unsigned int oldflags; + unsigned int jflag; + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + +- if (!is_owner_or_cap(inode)) +- return -EACCES; ++ if (!is_owner_or_cap(inode)) { ++ retval = -EACCES; ++ goto out; ++ } + +- if (get_user(flags, (int __user *) arg)) +- return -EFAULT; ++ if (get_user(flags, (int __user *) arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + if (!S_ISDIR(inode->i_mode)) + flags &= ~EXT4_DIRSYNC_FL; +@@ -54,7 +66,8 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + /* Is it quota file? Do not allow user to mess with it */ + if (IS_NOQUOTA(inode)) { + mutex_unlock(&inode->i_mutex); +- return -EPERM; ++ retval = -EPERM; ++ goto out; + } + oldflags = ei->i_flags; + +@@ -70,7 +83,8 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { + if (!capable(CAP_LINUX_IMMUTABLE)) { + mutex_unlock(&inode->i_mutex); +- return -EPERM; ++ retval = -EPERM; ++ goto out; + } + } + +@@ -81,7 +95,8 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { + if (!capable(CAP_SYS_RESOURCE)) { + mutex_unlock(&inode->i_mutex); +- return -EPERM; ++ retval = -EPERM; ++ goto out; + } + } + +@@ -89,12 +104,13 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + handle = ext4_journal_start(inode, 1); + if (IS_ERR(handle)) { + mutex_unlock(&inode->i_mutex); +- return PTR_ERR(handle); ++ retval = PTR_ERR(handle); ++ goto out; + } + if (IS_SYNC(inode)) + handle->h_sync = 1; +- err = ext4_reserve_inode_write(handle, inode, &iloc); +- if (err) ++ retval = ext4_reserve_inode_write(handle, inode, &iloc); ++ if (retval) + goto flags_err; + + flags = flags & EXT4_FL_USER_MODIFIABLE; +@@ -104,47 +120,55 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + ext4_set_inode_flags(inode); + inode->i_ctime = ext4_current_time(inode); + +- err = ext4_mark_iloc_dirty(handle, inode, &iloc); ++ retval = ext4_mark_iloc_dirty(handle, inode, &iloc); + flags_err: + ext4_journal_stop(handle); +- if (err) { ++ if (retval) { + mutex_unlock(&inode->i_mutex); +- return err; ++ goto out; + } + + if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) +- err = ext4_change_inode_journal_flag(inode, jflag); ++ retval = ext4_change_inode_journal_flag(inode, jflag); + mutex_unlock(&inode->i_mutex); +- return err; ++ goto out; + } + case EXT4_IOC_GETVERSION: + case EXT4_IOC_GETVERSION_OLD: +- return put_user(inode->i_generation, (int __user *) arg); ++ retval = put_user(inode->i_generation, (int __user *) arg); ++ goto out; + case EXT4_IOC_SETVERSION: + case EXT4_IOC_SETVERSION_OLD: { + handle_t *handle; + struct ext4_iloc iloc; + __u32 generation; +- int err; + +- if (!is_owner_or_cap(inode)) +- return -EPERM; +- if (IS_RDONLY(inode)) +- return -EROFS; +- if (get_user(generation, (int __user *) arg)) +- return -EFAULT; ++ if (!is_owner_or_cap(inode)) { ++ retval = -EPERM; ++ goto out; ++ } ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } ++ if (get_user(generation, (int __user *) arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + handle = ext4_journal_start(inode, 1); +- if (IS_ERR(handle)) +- return PTR_ERR(handle); +- err = ext4_reserve_inode_write(handle, inode, &iloc); +- if (err == 0) { ++ if (IS_ERR(handle)) { ++ retval = PTR_ERR(handle); ++ goto out; ++ } ++ retval = ext4_reserve_inode_write(handle, inode, &iloc); ++ if (retval == 0) { + inode->i_ctime = ext4_current_time(inode); + inode->i_generation = generation; +- err = ext4_mark_iloc_dirty(handle, inode, &iloc); ++ retval = ext4_mark_iloc_dirty(handle, inode, &iloc); + } + ext4_journal_stop(handle); +- return err; ++ goto out; + } + #ifdef CONFIG_JBD2_DEBUG + case EXT4_IOC_WAIT_FOR_READONLY: +@@ -158,16 +182,15 @@ flags_err: + { + struct super_block *sb = inode->i_sb; + DECLARE_WAITQUEUE(wait, current); +- int ret = 0; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); + if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) { + schedule(); +- ret = 1; ++ retval = 1; + } + remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait); +- return ret; ++ goto out; + } + #endif + case EXT4_IOC_GETRSVSZ: +@@ -175,22 +198,33 @@ flags_err: + && S_ISREG(inode->i_mode) + && ei->i_block_alloc_info) { + rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; +- return put_user(rsv_window_size, (int __user *)arg); ++ retval = put_user(rsv_window_size, (int __user *)arg); ++ goto out; + } +- return -ENOTTY; ++ retval = -ENOTTY; ++ goto out; + case EXT4_IOC_SETRSVSZ: { + +- if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) +- return -ENOTTY; ++ if (!test_opt(inode->i_sb, RESERVATION) || ++ !S_ISREG(inode->i_mode)) { ++ retval = -ENOTTY; ++ goto out; ++ } + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + +- if (!is_owner_or_cap(inode)) +- return -EACCES; ++ if (!is_owner_or_cap(inode)) { ++ retval = -EACCES; ++ goto out; ++ } + +- if (get_user(rsv_window_size, (int __user *)arg)) +- return -EFAULT; ++ if (get_user(rsv_window_size, (int __user *)arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + + if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT4_MAX_RESERVE_BLOCKS; +@@ -208,58 +242,75 @@ flags_err: + rsv->rsv_goal_size = rsv_window_size; + } + up_write(&ei->i_data_sem); +- return 0; ++ goto out; + } + case EXT4_IOC_GROUP_EXTEND: { + ext4_fsblk_t n_blocks_count; + struct super_block *sb = inode->i_sb; + int err; + +- if (!capable(CAP_SYS_RESOURCE)) +- return -EPERM; ++ if (!capable(CAP_SYS_RESOURCE)) { ++ retval = -EPERM; ++ goto out; ++ } + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + +- if (get_user(n_blocks_count, (__u32 __user *)arg)) +- return -EFAULT; ++ if (get_user(n_blocks_count, (__u32 __user *)arg)) { ++ retval = -EFAULT; ++ goto out; ++ } + +- err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); ++ retval = ext4_group_extend(sb, EXT4_SB(sb)->s_es, ++ n_blocks_count); + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); + jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); + +- return err; ++ goto out; + } + case EXT4_IOC_GROUP_ADD: { + struct ext4_new_group_data input; + struct super_block *sb = inode->i_sb; + int err; + +- if (!capable(CAP_SYS_RESOURCE)) +- return -EPERM; ++ if (!capable(CAP_SYS_RESOURCE)) { ++ retval = -EPERM; ++ goto out; ++ } + +- if (IS_RDONLY(inode)) +- return -EROFS; ++ if (IS_RDONLY(inode)) { ++ retval = -EROFS; ++ goto out; ++ } + + if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, +- sizeof(input))) +- return -EFAULT; ++ sizeof(input))) { ++ retval = -EFAULT; ++ goto out; ++ } + +- err = ext4_group_add(sb, &input); ++ retval = ext4_group_add(sb, &input); + jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); + jbd2_journal_flush(EXT4_SB(sb)->s_journal); + jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); + +- return err; ++ goto out; + } + + case EXT4_IOC_MIGRATE: +- return ext4_ext_migrate(inode, filp, cmd, arg); ++ retval = ext4_ext_migrate(inode, filp, cmd, arg); ++ goto out; + + default: +- return -ENOTTY; ++ retval = -ENOTTY; + } ++out: ++ unlock_kernel(); ++ return retval; + } + + #ifdef CONFIG_COMPAT +@@ -307,9 +358,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + default: + return -ENOIOCTLCMD; + } +- lock_kernel(); + ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); +- unlock_kernel(); + return ret; + } + #endif +diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h +index 1852313..0eb31e3 100644 +--- a/include/linux/ext4_fs.h ++++ b/include/linux/ext4_fs.h +@@ -1042,8 +1042,7 @@ extern int ext4_block_truncate_page(handle_t *handle, struct page *page, + struct address_space *mapping, loff_t from); + + /* ioctl.c */ +-extern int ext4_ioctl (struct inode *, struct file *, unsigned int, +- unsigned long); ++extern long ext4_ioctl(struct file *, unsigned int, unsigned long); + extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long); + + /* migrate.c */ diff --git a/series b/series index b65757e0..1c5b5227 100644 --- a/series +++ b/series @@ -91,6 +91,11 @@ lockdep-annotate-jbd2-journal-start.patch jbd2_group_short_lived_and_reclaimable_kernel_allocations.patch jbd2_user_of_the_jiffes_rounding_code.patch jbd2-sparse-warning-fixes.patch + +ext4-unlocked-ioctl.patch +ext3-unlocked-ioctl.patch +ext2-unlocked-ioctl.patch + #################################################### # unstable patches still have outstanding comments from lkml #################################################### -- 2.11.4.GIT