Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[firefly-linux-kernel-4.4.55.git] / fs / quota / dquot.c
index 69df5b239844f9395f38d2e3acb8f93f34142c0a..0ccd4ba3a2467f6783a396686b5ae20266ba515b 100644 (file)
@@ -1248,7 +1248,7 @@ static int ignore_hardlimit(struct dquot *dquot)
 
        return capable(CAP_SYS_RESOURCE) &&
               (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD ||
-               !(info->dqi_flags & V1_DQF_RSQUASH));
+               !(info->dqi_flags & DQF_ROOT_SQUASH));
 }
 
 /* needs dq_data_lock */
@@ -2385,14 +2385,84 @@ out:
 }
 EXPORT_SYMBOL(dquot_quota_on_mount);
 
-static inline qsize_t qbtos(qsize_t blocks)
+static int dquot_quota_enable(struct super_block *sb, unsigned int flags)
 {
-       return blocks << QIF_DQBLKSIZE_BITS;
+       int ret;
+       int type;
+       struct quota_info *dqopt = sb_dqopt(sb);
+
+       if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE))
+               return -ENOSYS;
+       /* Accounting cannot be turned on while fs is mounted */
+       flags &= ~(FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT | FS_QUOTA_PDQ_ACCT);
+       if (!flags)
+               return -EINVAL;
+       for (type = 0; type < MAXQUOTAS; type++) {
+               if (!(flags & qtype_enforce_flag(type)))
+                       continue;
+               /* Can't enforce without accounting */
+               if (!sb_has_quota_usage_enabled(sb, type))
+                       return -EINVAL;
+               ret = dquot_enable(dqopt->files[type], type,
+                                  dqopt->info[type].dqi_fmt_id,
+                                  DQUOT_LIMITS_ENABLED);
+               if (ret < 0)
+                       goto out_err;
+       }
+       return 0;
+out_err:
+       /* Backout enforcement enablement we already did */
+       for (type--; type >= 0; type--)  {
+               if (flags & qtype_enforce_flag(type))
+                       dquot_disable(sb, type, DQUOT_LIMITS_ENABLED);
+       }
+       /* Error code translation for better compatibility with XFS */
+       if (ret == -EBUSY)
+               ret = -EEXIST;
+       return ret;
 }
 
-static inline qsize_t stoqb(qsize_t space)
+static int dquot_quota_disable(struct super_block *sb, unsigned int flags)
 {
-       return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
+       int ret;
+       int type;
+       struct quota_info *dqopt = sb_dqopt(sb);
+
+       if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE))
+               return -ENOSYS;
+       /*
+        * We don't support turning off accounting via quotactl. In principle
+        * quota infrastructure can do this but filesystems don't expect
+        * userspace to be able to do it.
+        */
+       if (flags &
+                 (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT | FS_QUOTA_PDQ_ACCT))
+               return -EOPNOTSUPP;
+
+       /* Filter out limits not enabled */
+       for (type = 0; type < MAXQUOTAS; type++)
+               if (!sb_has_quota_limits_enabled(sb, type))
+                       flags &= ~qtype_enforce_flag(type);
+       /* Nothing left? */
+       if (!flags)
+               return -EEXIST;
+       for (type = 0; type < MAXQUOTAS; type++) {
+               if (flags & qtype_enforce_flag(type)) {
+                       ret = dquot_disable(sb, type, DQUOT_LIMITS_ENABLED);
+                       if (ret < 0)
+                               goto out_err;
+               }
+       }
+       return 0;
+out_err:
+       /* Backout enforcement disabling we already did */
+       for (type--; type >= 0; type--)  {
+               if (flags & qtype_enforce_flag(type))
+                       dquot_enable(dqopt->files[type], type,
+                                    dqopt->info[type].dqi_fmt_id,
+                                    DQUOT_LIMITS_ENABLED);
+       }
+       return ret;
 }
 
 /* Generic routine for getting common part of quota structure */
@@ -2444,13 +2514,13 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di)
                return -EINVAL;
 
        if (((di->d_fieldmask & QC_SPC_SOFT) &&
-            stoqb(di->d_spc_softlimit) > dqi->dqi_maxblimit) ||
+            di->d_spc_softlimit > dqi->dqi_max_spc_limit) ||
            ((di->d_fieldmask & QC_SPC_HARD) &&
-            stoqb(di->d_spc_hardlimit) > dqi->dqi_maxblimit) ||
+            di->d_spc_hardlimit > dqi->dqi_max_spc_limit) ||
            ((di->d_fieldmask & QC_INO_SOFT) &&
-            (di->d_ino_softlimit > dqi->dqi_maxilimit)) ||
+            (di->d_ino_softlimit > dqi->dqi_max_ino_limit)) ||
            ((di->d_fieldmask & QC_INO_HARD) &&
-            (di->d_ino_hardlimit > dqi->dqi_maxilimit)))
+            (di->d_ino_hardlimit > dqi->dqi_max_ino_limit)))
                return -ERANGE;
 
        spin_lock(&dq_data_lock);
@@ -2577,6 +2647,14 @@ int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
                goto out;
        }
        mi = sb_dqopt(sb)->info + type;
+       if (ii->dqi_valid & IIF_FLAGS) {
+               if (ii->dqi_flags & ~DQF_SETINFO_MASK ||
+                   (ii->dqi_flags & DQF_ROOT_SQUASH &&
+                    mi->dqi_format->qf_fmt_id != QFMT_VFS_OLD)) {
+                       err = -EINVAL;
+                       goto out;
+               }
+       }
        spin_lock(&dq_data_lock);
        if (ii->dqi_valid & IIF_BGRACE)
                mi->dqi_bgrace = ii->dqi_bgrace;
@@ -2606,6 +2684,17 @@ const struct quotactl_ops dquot_quotactl_ops = {
 };
 EXPORT_SYMBOL(dquot_quotactl_ops);
 
+const struct quotactl_ops dquot_quotactl_sysfile_ops = {
+       .quota_enable   = dquot_quota_enable,
+       .quota_disable  = dquot_quota_disable,
+       .quota_sync     = dquot_quota_sync,
+       .get_info       = dquot_get_dqinfo,
+       .set_info       = dquot_set_dqinfo,
+       .get_dqblk      = dquot_get_dqblk,
+       .set_dqblk      = dquot_set_dqblk
+};
+EXPORT_SYMBOL(dquot_quotactl_sysfile_ops);
+
 static int do_proc_dqstats(struct ctl_table *table, int write,
                     void __user *buffer, size_t *lenp, loff_t *ppos)
 {