[PATCH] powerpc: Updated platforms that use gianfar to match driver
[safe/jmp/linux-2.6] / fs / compat.c
index 6b06b6b..271b75d 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/nfsd/syscall.h>
 #include <linux/personality.h>
 #include <linux/rwsem.h>
+#include <linux/acct.h>
+#include <linux/mm.h>
 
 #include <net/sock.h>          /* siocdevprivate_ioctl */
 
@@ -166,8 +168,8 @@ asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs
        if (!error) {
                struct kstatfs tmp;
                error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
-               if (!error && put_compat_statfs(buf, &tmp))
-                       error = -EFAULT;
+               if (!error)
+                       error = put_compat_statfs(buf, &tmp);
                path_release(&nd);
        }
        return error;
@@ -184,8 +186,8 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user
        if (!file)
                goto out;
        error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
-       if (!error && put_compat_statfs(buf, &tmp))
-               error = -EFAULT;
+       if (!error)
+               error = put_compat_statfs(buf, &tmp);
        fput(file);
 out:
        return error;
@@ -234,8 +236,8 @@ asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, s
        if (!error) {
                struct kstatfs tmp;
                error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
-               if (!error && put_compat_statfs64(buf, &tmp))
-                       error = -EFAULT;
+               if (!error)
+                       error = put_compat_statfs64(buf, &tmp);
                path_release(&nd);
        }
        return error;
@@ -255,8 +257,8 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c
        if (!file)
                goto out;
        error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
-       if (!error && put_compat_statfs64(buf, &tmp))
-               error = -EFAULT;
+       if (!error)
+               error = put_compat_statfs64(buf, &tmp);
        fput(file);
 out:
        return error;
@@ -266,7 +268,6 @@ out:
 
 #define IOCTL_HASHSIZE 256
 static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
-static DECLARE_RWSEM(ioctl32_sem);
 
 extern struct ioctl_trans ioctl_start[];
 extern int ioctl_table_size;
@@ -310,96 +311,6 @@ static int __init init_sys32_ioctl(void)
 
 __initcall(init_sys32_ioctl);
 
-int register_ioctl32_conversion(unsigned int cmd,
-                               ioctl_trans_handler_t handler)
-{
-       struct ioctl_trans *t;
-       struct ioctl_trans *new_t;
-       unsigned long hash = ioctl32_hash(cmd);
-
-       new_t = kmalloc(sizeof(*new_t), GFP_KERNEL);
-       if (!new_t)
-               return -ENOMEM;
-
-       down_write(&ioctl32_sem);
-       for (t = ioctl32_hash_table[hash]; t; t = t->next) {
-               if (t->cmd == cmd) {
-                       printk(KERN_ERR "Trying to register duplicated ioctl32 "
-                                       "handler %x\n", cmd);
-                       up_write(&ioctl32_sem);
-                       kfree(new_t);
-                       return -EINVAL; 
-               }
-       }
-       new_t->next = NULL;
-       new_t->cmd = cmd;
-       new_t->handler = handler;
-       ioctl32_insert_translation(new_t);
-
-       up_write(&ioctl32_sem);
-       return 0;
-}
-EXPORT_SYMBOL(register_ioctl32_conversion);
-
-static inline int builtin_ioctl(struct ioctl_trans *t)
-{ 
-       return t >= ioctl_start && t < (ioctl_start + ioctl_table_size);
-} 
-
-/* Problem: 
-   This function cannot unregister duplicate ioctls, because they are not
-   unique.
-   When they happen we need to extend the prototype to pass the handler too. */
-
-int unregister_ioctl32_conversion(unsigned int cmd)
-{
-       unsigned long hash = ioctl32_hash(cmd);
-       struct ioctl_trans *t, *t1;
-
-       down_write(&ioctl32_sem);
-
-       t = ioctl32_hash_table[hash];
-       if (!t) { 
-               up_write(&ioctl32_sem);
-               return -EINVAL;
-       } 
-
-       if (t->cmd == cmd) { 
-               if (builtin_ioctl(t)) {
-                       printk("%p tried to unregister builtin ioctl %x\n",
-                              __builtin_return_address(0), cmd);
-               } else { 
-                       ioctl32_hash_table[hash] = t->next;
-                       up_write(&ioctl32_sem);
-                       kfree(t);
-                       return 0;
-               }
-       } 
-       while (t->next) {
-               t1 = t->next;
-               if (t1->cmd == cmd) { 
-                       if (builtin_ioctl(t1)) {
-                               printk("%p tried to unregister builtin "
-                                       "ioctl %x\n",
-                                       __builtin_return_address(0), cmd);
-                               goto out;
-                       } else { 
-                               t->next = t1->next;
-                               up_write(&ioctl32_sem);
-                               kfree(t1);
-                               return 0;
-                       }
-               }
-               t = t1;
-       }
-       printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n",
-                               cmd);
-out:
-       up_write(&ioctl32_sem);
-       return -EINVAL;
-}
-EXPORT_SYMBOL(unregister_ioctl32_conversion); 
-
 static void compat_ioctl_error(struct file *filp, unsigned int fd,
                unsigned int cmd, unsigned long arg)
 {
@@ -478,14 +389,10 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
                break;
        }
 
-       /* When register_ioctl32_conversion is finally gone remove
-          this lock! -AK */
-       down_read(&ioctl32_sem);
        for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) {
                if (t->cmd == cmd)
                        goto found_handler;
        }
-       up_read(&ioctl32_sem);
 
        if (S_ISSOCK(filp->f_dentry->d_inode->i_mode) &&
            cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
@@ -505,11 +412,9 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
                lock_kernel();
                error = t->handler(fd, cmd, arg, filp);
                unlock_kernel();
-               up_read(&ioctl32_sem);
                goto out_fput;
        }
 
-       up_read(&ioctl32_sem);
  do_ioctl:
        error = vfs_ioctl(filp, fd, cmd, arg);
  out_fput:
@@ -589,9 +494,21 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
                ret = sys_fcntl(fd, cmd, (unsigned long)&f);
                set_fs(old_fs);
                if (cmd == F_GETLK && ret == 0) {
-                       if ((f.l_start >= COMPAT_OFF_T_MAX) ||
-                           ((f.l_start + f.l_len) > COMPAT_OFF_T_MAX))
+                       /* GETLK was successfule and we need to return the data...
+                        * but it needs to fit in the compat structure.
+                        * l_start shouldn't be too big, unless the original
+                        * start + end is greater than COMPAT_OFF_T_MAX, in which
+                        * case the app was asking for trouble, so we return
+                        * -EOVERFLOW in that case.
+                        * l_len could be too big, in which case we just truncate it,
+                        * and only allow the app to see that part of the conflicting
+                        * lock that might make sense to it anyway
+                        */
+
+                       if (f.l_start > COMPAT_OFF_T_MAX)
                                ret = -EOVERFLOW;
+                       if (f.l_len > COMPAT_OFF_T_MAX)
+                               f.l_len = COMPAT_OFF_T_MAX;
                        if (ret == 0)
                                ret = put_compat_flock(&f, compat_ptr(arg));
                }
@@ -610,9 +527,11 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
                                (unsigned long)&f);
                set_fs(old_fs);
                if (cmd == F_GETLK64 && ret == 0) {
-                       if ((f.l_start >= COMPAT_LOFF_T_MAX) ||
-                           ((f.l_start + f.l_len) > COMPAT_LOFF_T_MAX))
+                       /* need to return lock information - see above for commentary */
+                       if (f.l_start > COMPAT_LOFF_T_MAX)
                                ret = -EOVERFLOW;
+                       if (f.l_len > COMPAT_LOFF_T_MAX)
+                               f.l_len = COMPAT_LOFF_T_MAX;
                        if (ret == 0)
                                ret = put_compat_flock64(&f, compat_ptr(arg));
                }
@@ -720,14 +639,14 @@ compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
 struct compat_ncp_mount_data {
        compat_int_t version;
        compat_uint_t ncp_fd;
-       compat_uid_t mounted_uid;
+       __compat_uid_t mounted_uid;
        compat_pid_t wdog_pid;
        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
        compat_uint_t time_out;
        compat_uint_t retry_count;
        compat_uint_t flags;
-       compat_uid_t uid;
-       compat_gid_t gid;
+       __compat_uid_t uid;
+       __compat_gid_t gid;
        compat_mode_t file_mode;
        compat_mode_t dir_mode;
 };
@@ -784,9 +703,9 @@ static void *do_ncp_super_data_conv(void *raw_data)
 
 struct compat_smb_mount_data {
        compat_int_t version;
-       compat_uid_t mounted_uid;
-       compat_uid_t uid;
-       compat_gid_t gid;
+       __compat_uid_t mounted_uid;
+       __compat_uid_t uid;
+       __compat_gid_t gid;
        compat_mode_t file_mode;
        compat_mode_t dir_mode;
 };
@@ -1265,7 +1184,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
        }
 
        ret = rw_verify_area(type, file, pos, tot_len);
-       if (ret)
+       if (ret < 0)
                goto out;
 
        fnv = NULL;
@@ -1365,6 +1284,16 @@ out:
 }
 
 /*
+ * Exactly like fs/open.c:sys_open(), except that it doesn't set the
+ * O_LARGEFILE flag.
+ */
+asmlinkage long
+compat_sys_open(const char __user *filename, int flags, int mode)
+{
+       return do_sys_open(filename, flags, mode);
+}
+
+/*
  * compat_count() counts the number of arguments/envelopes. It is basically
  * a copy of count() from fs/exec.c, except that it works with 32 bit argv
  * and envp pointers.
@@ -1567,6 +1496,7 @@ int compat_do_execve(char * filename,
 
                /* execve success */
                security_bprm_free(bprm);
+               acct_update_integrals(current);
                kfree(bprm);
                return retval;
        }
@@ -1699,6 +1629,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp
        char *bits;
        long timeout;
        int size, max_fdset, ret = -EINVAL;
+       struct fdtable *fdt;
 
        timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
@@ -1724,7 +1655,10 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp
                goto out_nofds;
 
        /* max_fdset can increase, so grab it once to avoid race */
-       max_fdset = current->files->max_fdset;
+       rcu_read_lock();
+       fdt = files_fdtable(current->files);
+       max_fdset = fdt->max_fdset;
+       rcu_read_unlock();
        if (n > max_fdset)
                n = max_fdset;
 
@@ -1808,8 +1742,8 @@ struct compat_nfsctl_export {
        compat_dev_t    ex32_dev;
        compat_ino_t    ex32_ino;
        compat_int_t    ex32_flags;
-       compat_uid_t    ex32_anon_uid;
-       compat_gid_t    ex32_anon_gid;
+       __compat_uid_t  ex32_anon_uid;
+       __compat_gid_t  ex32_anon_gid;
 };
 
 struct compat_nfsctl_fdparm {