mm/huge_memory.c: use head to emphasize the purpose of page
[linux-2.6-microblaze.git] / fs / ioctl.c
index 2f5e4e5..7c9a5df 100644 (file)
@@ -467,7 +467,7 @@ EXPORT_SYMBOL(generic_block_fiemap);
  * Only the l_start, l_len and l_whence fields of the 'struct space_resv'
  * are used here, rest are ignored.
  */
-int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
+static int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
 {
        struct inode *inode = file_inode(filp);
        struct space_resv sr;
@@ -495,8 +495,8 @@ int ioctl_preallocate(struct file *filp, int mode, void __user *argp)
 /* on ia32 l_start is on a 32-bit boundary */
 #if defined CONFIG_COMPAT && defined(CONFIG_X86_64)
 /* just account for different alignment */
-int compat_ioctl_preallocate(struct file *file, int mode,
-                               struct space_resv_32 __user *argp)
+static int compat_ioctl_preallocate(struct file *file, int mode,
+                                   struct space_resv_32 __user *argp)
 {
        struct inode *inode = file_inode(file);
        struct space_resv_32 sr;
@@ -521,11 +521,9 @@ int compat_ioctl_preallocate(struct file *file, int mode,
 }
 #endif
 
-static int file_ioctl(struct file *filp, unsigned int cmd,
-               unsigned long arg)
+static int file_ioctl(struct file *filp, unsigned int cmd, int __user *p)
 {
        struct inode *inode = file_inode(filp);
-       int __user *p = (int __user *)arg;
 
        switch (cmd) {
        case FIBMAP:
@@ -542,7 +540,7 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
                return ioctl_preallocate(filp, FALLOC_FL_ZERO_RANGE, p);
        }
 
-       return vfs_ioctl(filp, cmd, arg);
+       return -ENOIOCTLCMD;
 }
 
 static int ioctl_fionbio(struct file *filp, int __user *argp)
@@ -661,53 +659,48 @@ out:
 }
 
 /*
- * When you add any new common ioctls to the switches above and below
- * please update compat_sys_ioctl() too.
- *
  * do_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.
+ *
+ * When you add any new common ioctls to the switches above and below,
+ * please ensure they have compatible arguments in compat mode.
  */
-int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
-            unsigned long arg)
+static int do_vfs_ioctl(struct file *filp, unsigned int fd,
+                       unsigned int cmd, unsigned long arg)
 {
-       int error = 0;
        void __user *argp = (void __user *)arg;
        struct inode *inode = file_inode(filp);
 
        switch (cmd) {
        case FIOCLEX:
                set_close_on_exec(fd, 1);
-               break;
+               return 0;
 
        case FIONCLEX:
                set_close_on_exec(fd, 0);
-               break;
+               return 0;
 
        case FIONBIO:
-               error = ioctl_fionbio(filp, argp);
-               break;
+               return ioctl_fionbio(filp, argp);
 
        case FIOASYNC:
-               error = ioctl_fioasync(fd, filp, argp);
-               break;
+               return ioctl_fioasync(fd, filp, argp);
 
        case FIOQSIZE:
                if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
                    S_ISLNK(inode->i_mode)) {
                        loff_t res = inode_get_bytes(inode);
-                       error = copy_to_user(argp, &res, sizeof(res)) ?
-                                       -EFAULT : 0;
-               } else
-                       error = -ENOTTY;
-               break;
+                       return copy_to_user(argp, &res, sizeof(res)) ?
+                                           -EFAULT : 0;
+               }
+
+               return -ENOTTY;
 
        case FIFREEZE:
-               error = ioctl_fsfreeze(filp);
-               break;
+               return ioctl_fsfreeze(filp);
 
        case FITHAW:
-               error = ioctl_fsthaw(filp);
-               break;
+               return ioctl_fsthaw(filp);
 
        case FS_IOC_FIEMAP:
                return ioctl_fiemap(filp, argp);
@@ -716,6 +709,7 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
                /* anon_bdev filesystems may not have a block size */
                if (!inode->i_sb->s_blocksize)
                        return -EINVAL;
+
                return put_user(inode->i_sb->s_blocksize, (int __user *)argp);
 
        case FICLONE:
@@ -729,24 +723,30 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
 
        default:
                if (S_ISREG(inode->i_mode))
-                       error = file_ioctl(filp, cmd, arg);
-               else
-                       error = vfs_ioctl(filp, cmd, arg);
+                       return file_ioctl(filp, cmd, argp);
                break;
        }
-       return error;
+
+       return -ENOIOCTLCMD;
 }
 
 int ksys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-       int error;
        struct fd f = fdget(fd);
+       int error;
 
        if (!f.file)
                return -EBADF;
+
        error = security_file_ioctl(f.file, cmd, arg);
-       if (!error)
-               error = do_vfs_ioctl(f.file, fd, cmd, arg);
+       if (error)
+               goto out;
+
+       error = do_vfs_ioctl(f.file, fd, cmd, arg);
+       if (error == -ENOIOCTLCMD)
+               error = vfs_ioctl(f.file, cmd, arg);
+
+out:
        fdput(f);
        return error;
 }
@@ -788,4 +788,65 @@ long compat_ptr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
 }
 EXPORT_SYMBOL(compat_ptr_ioctl);
+
+COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
+                      compat_ulong_t, arg)
+{
+       struct fd f = fdget(fd);
+       int error;
+
+       if (!f.file)
+               return -EBADF;
+
+       /* RED-PEN how should LSM module know it's handling 32bit? */
+       error = security_file_ioctl(f.file, cmd, arg);
+       if (error)
+               goto out;
+
+       switch (cmd) {
+       /* FICLONE takes an int argument, so don't use compat_ptr() */
+       case FICLONE:
+               error = ioctl_file_clone(f.file, arg, 0, 0, 0);
+               break;
+
+#if defined(CONFIG_X86_64)
+       /* these get messy on amd64 due to alignment differences */
+       case FS_IOC_RESVSP_32:
+       case FS_IOC_RESVSP64_32:
+               error = compat_ioctl_preallocate(f.file, 0, compat_ptr(arg));
+               break;
+       case FS_IOC_UNRESVSP_32:
+       case FS_IOC_UNRESVSP64_32:
+               error = compat_ioctl_preallocate(f.file, FALLOC_FL_PUNCH_HOLE,
+                               compat_ptr(arg));
+               break;
+       case FS_IOC_ZERO_RANGE_32:
+               error = compat_ioctl_preallocate(f.file, FALLOC_FL_ZERO_RANGE,
+                               compat_ptr(arg));
+               break;
+#endif
+
+       /*
+        * everything else in do_vfs_ioctl() takes either a compatible
+        * pointer argument or no argument -- call it with a modified
+        * argument.
+        */
+       default:
+               error = do_vfs_ioctl(f.file, fd, cmd,
+                                    (unsigned long)compat_ptr(arg));
+               if (error != -ENOIOCTLCMD)
+                       break;
+
+               if (f.file->f_op->compat_ioctl)
+                       error = f.file->f_op->compat_ioctl(f.file, cmd, arg);
+               if (error == -ENOIOCTLCMD)
+                       error = -ENOTTY;
+               break;
+       }
+
+ out:
+       fdput(f);
+
+       return error;
+}
 #endif