Merge branch 'devel' into next
[pandora-kernel.git] / fs / quota.c
index 9f237d6..db1cc9f 100644 (file)
 #include <linux/slab.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
+#include <linux/compat.h>
 #include <linux/kernel.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/buffer_head.h>
 #include <linux/capability.h>
 #include <linux/quotaops.h>
+#include <linux/types.h>
 
 /* Check validity of generic quotactl commands */
 static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
@@ -67,7 +69,6 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid
        switch (cmd) {
                case Q_GETFMT:
                case Q_GETINFO:
-               case Q_QUOTAOFF:
                case Q_SETINFO:
                case Q_SETQUOTA:
                case Q_GETQUOTA:
@@ -227,12 +228,12 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void
 
                        if (IS_ERR(pathname = getname(addr)))
                                return PTR_ERR(pathname);
-                       ret = sb->s_qcop->quota_on(sb, type, id, pathname);
+                       ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0);
                        putname(pathname);
                        return ret;
                }
                case Q_QUOTAOFF:
-                       return sb->s_qcop->quota_off(sb, type);
+                       return sb->s_qcop->quota_off(sb, type, 0);
 
                case Q_GETFMT: {
                        __u32 fmt;
@@ -339,11 +340,11 @@ static inline struct super_block *quotactl_block(const char __user *special)
        char *tmp = getname(special);
 
        if (IS_ERR(tmp))
-               return ERR_PTR(PTR_ERR(tmp));
+               return ERR_CAST(tmp);
        bdev = lookup_bdev(tmp);
        putname(tmp);
        if (IS_ERR(bdev))
-               return ERR_PTR(PTR_ERR(bdev));
+               return ERR_CAST(bdev);
        sb = get_super(bdev);
        bdput(bdev);
        if (!sb)
@@ -384,3 +385,119 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t
 
        return ret;
 }
+
+#if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT)
+/*
+ * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
+ * and is necessary due to alignment problems.
+ */
+struct compat_if_dqblk {
+       compat_u64 dqb_bhardlimit;
+       compat_u64 dqb_bsoftlimit;
+       compat_u64 dqb_curspace;
+       compat_u64 dqb_ihardlimit;
+       compat_u64 dqb_isoftlimit;
+       compat_u64 dqb_curinodes;
+       compat_u64 dqb_btime;
+       compat_u64 dqb_itime;
+       compat_uint_t dqb_valid;
+};
+
+/* XFS structures */
+struct compat_fs_qfilestat {
+       compat_u64 dqb_bhardlimit;
+       compat_u64 qfs_nblks;
+       compat_uint_t qfs_nextents;
+};
+
+struct compat_fs_quota_stat {
+       __s8            qs_version;
+       __u16           qs_flags;
+       __s8            qs_pad;
+       struct compat_fs_qfilestat      qs_uquota;
+       struct compat_fs_qfilestat      qs_gquota;
+       compat_uint_t   qs_incoredqs;
+       compat_int_t    qs_btimelimit;
+       compat_int_t    qs_itimelimit;
+       compat_int_t    qs_rtbtimelimit;
+       __u16           qs_bwarnlimit;
+       __u16           qs_iwarnlimit;
+};
+
+asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
+                                               qid_t id, void __user *addr)
+{
+       unsigned int cmds;
+       struct if_dqblk __user *dqblk;
+       struct compat_if_dqblk __user *compat_dqblk;
+       struct fs_quota_stat __user *fsqstat;
+       struct compat_fs_quota_stat __user *compat_fsqstat;
+       compat_uint_t data;
+       u16 xdata;
+       long ret;
+
+       cmds = cmd >> SUBCMDSHIFT;
+
+       switch (cmds) {
+       case Q_GETQUOTA:
+               dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
+               compat_dqblk = addr;
+               ret = sys_quotactl(cmd, special, id, dqblk);
+               if (ret)
+                       break;
+               if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
+                       get_user(data, &dqblk->dqb_valid) ||
+                       put_user(data, &compat_dqblk->dqb_valid))
+                       ret = -EFAULT;
+               break;
+       case Q_SETQUOTA:
+               dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
+               compat_dqblk = addr;
+               ret = -EFAULT;
+               if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
+                       get_user(data, &compat_dqblk->dqb_valid) ||
+                       put_user(data, &dqblk->dqb_valid))
+                       break;
+               ret = sys_quotactl(cmd, special, id, dqblk);
+               break;
+       case Q_XGETQSTAT:
+               fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
+               compat_fsqstat = addr;
+               ret = sys_quotactl(cmd, special, id, fsqstat);
+               if (ret)
+                       break;
+               ret = -EFAULT;
+               /* Copying qs_version, qs_flags, qs_pad */
+               if (copy_in_user(compat_fsqstat, fsqstat,
+                       offsetof(struct compat_fs_quota_stat, qs_uquota)))
+                       break;
+               /* Copying qs_uquota */
+               if (copy_in_user(&compat_fsqstat->qs_uquota,
+                       &fsqstat->qs_uquota,
+                       sizeof(compat_fsqstat->qs_uquota)) ||
+                       get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
+                       put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
+                       break;
+               /* Copying qs_gquota */
+               if (copy_in_user(&compat_fsqstat->qs_gquota,
+                       &fsqstat->qs_gquota,
+                       sizeof(compat_fsqstat->qs_gquota)) ||
+                       get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
+                       put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
+                       break;
+               /* Copying the rest */
+               if (copy_in_user(&compat_fsqstat->qs_incoredqs,
+                       &fsqstat->qs_incoredqs,
+                       sizeof(struct compat_fs_quota_stat) -
+                       offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
+                       get_user(xdata, &fsqstat->qs_iwarnlimit) ||
+                       put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
+                       break;
+               ret = 0;
+               break;
+       default:
+               ret = sys_quotactl(cmd, special, id, addr);
+       }
+       return ret;
+}
+#endif