X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fioctl.c;h=44f6e4cc44fe79326be39b229e30015960a8f894;hb=d3ec2a4ce4b4743ecf56c2ed7b32d74fd58210dc;hp=96a1b601e7c7ca701b2645009f4d8abc6513def1;hpb=c5fb35bebffd73f6c75e2947f99fceff83f187b3;p=linux-2.6.git diff --git a/fs/ioctl.c b/fs/ioctl.c index 96a1b601e..44f6e4cc4 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -4,9 +4,10 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include +#include #include #include +#include #include #include #include @@ -14,17 +15,42 @@ #include #include #include -#include #include #include -#ifdef CONFIG_VSERVER_LEGACY + +#ifdef CONFIG_VSERVER_LEGACY extern int vx_proc_ioctl(struct inode *, struct file *, unsigned int, unsigned long); #endif -static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) +static long do_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int error = -ENOTTY; + + if (!filp->f_op) + goto out; + + if (filp->f_op->unlocked_ioctl) { + error = filp->f_op->unlocked_ioctl(filp, cmd, arg); + if (error == -ENOIOCTLCMD) + error = -EINVAL; + goto out; + } else if (filp->f_op->ioctl) { + lock_kernel(); + error = filp->f_op->ioctl(filp->f_dentry->d_inode, + filp, cmd, arg); + unlock_kernel(); + } + + out: + return error; +} + +static int file_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) { int error; int block; @@ -44,7 +70,9 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) if ((error = get_user(block, p)) != 0) return error; + lock_kernel(); res = mapping->a_ops->bmap(mapping, block); + unlock_kernel(); return put_user(res, p); } case FIGETBSZ: @@ -54,29 +82,22 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) case FIONREAD: return put_user(i_size_read(inode) - filp->f_pos, p); } - if (filp->f_op && filp->f_op->ioctl) - return filp->f_op->ioctl(inode, filp, cmd, arg); - return -ENOTTY; -} + return do_ioctl(filp, cmd, arg); +} -asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct file * filp; +/* + * When you add any new common ioctls to the switches above and below + * please update compat_sys_ioctl() too. + * + * vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. + * It's just a simple helper for sys_ioctl and compat_sys_ioctl. + */ +int vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned long arg) +{ unsigned int flag; - int on, error = -EBADF; + int on, error = 0; - filp = fget(fd); - if (!filp) - goto out; - - error = security_file_ioctl(filp, cmd, arg); - if (error) { - fput(filp); - goto out; - } - - lock_kernel(); switch (cmd) { case FIOCLEX: set_close_on_exec(fd, 1); @@ -108,8 +129,11 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) /* Did FASYNC state change ? */ if ((flag ^ filp->f_flags) & FASYNC) { - if (filp->f_op && filp->f_op->fasync) + if (filp->f_op && filp->f_op->fasync) { + lock_kernel(); error = filp->f_op->fasync(fd, filp, on); + unlock_kernel(); + } else error = -ENOTTY; } if (error != 0) @@ -131,7 +155,7 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) else error = -ENOTTY; break; -#ifdef CONFIG_VSERVER_LEGACY +#ifdef CONFIG_VSERVER_LEGACY #ifndef CONFIG_INOXID_NONE case FIOC_GETXID: { struct inode *inode = filp->f_dentry->d_inode; @@ -139,7 +163,7 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) /* fixme: if stealth, return -ENOTTY */ error = -EPERM; if (capable(CAP_CONTEXT)) - error = put_user(inode->i_xid, (int *) arg); + error = put_user(inode->i_xid, (int __user *) arg); break; } case FIOC_SETXID: { @@ -157,13 +181,13 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) if (!(inode->i_sb->s_flags & MS_TAGXID)) break; error = -EFAULT; - if (get_user(xid, (int *) arg)) + if (get_user(xid, (int __user *) arg)) break; error = 0; inode->i_xid = (xid & 0xFFFF); inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); - break; + break; } #endif case FIOC_GETXFLG: @@ -173,17 +197,50 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) error = vx_proc_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); break; #endif + /* + * These cmds needed for PLK - don't lose them! + */ + case FIOC_SETIATTR: + case FIOC_GETIATTR: + /* + * Verify that this filp is a file object, + * not (say) a socket. + */ + error = -ENOTTY; + if (S_ISREG(filp->f_dentry->d_inode->i_mode) || + S_ISDIR(filp->f_dentry->d_inode->i_mode)) + error = vc_iattr_ioctl(filp->f_dentry, + cmd, arg); + break; + default: - 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->ioctl) - error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + else + error = do_ioctl(filp, cmd, arg); + break; } - unlock_kernel(); - fput(filp); + return error; +} + +asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int error = -EBADF; + int fput_needed; + + filp = fget_light(fd, &fput_needed); + if (!filp) + goto out; + + error = security_file_ioctl(filp, cmd, arg); + if (error) + goto out_fput; -out: + error = vfs_ioctl(filp, fd, cmd, arg); + out_fput: + fput_light(filp, fput_needed); + out: return error; }