Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa...
[firefly-linux-kernel-4.4.55.git] / fs / quota / dquot.c
index 0ccd4ba3a2467f6783a396686b5ae20266ba515b..ecc25cf0ee6e99f96b8d4c7550d8881593c303cf 100644 (file)
@@ -900,14 +900,17 @@ static inline struct dquot **i_dquot(struct inode *inode)
 
 static int dqinit_needed(struct inode *inode, int type)
 {
+       struct dquot * const *dquots;
        int cnt;
 
        if (IS_NOQUOTA(inode))
                return 0;
+
+       dquots = i_dquot(inode);
        if (type != -1)
-               return !i_dquot(inode)[type];
+               return !dquots[type];
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               if (!i_dquot(inode)[cnt])
+               if (!dquots[cnt])
                        return 1;
        return 0;
 }
@@ -970,12 +973,13 @@ static void add_dquot_ref(struct super_block *sb, int type)
 static void remove_inode_dquot_ref(struct inode *inode, int type,
                                   struct list_head *tofree_head)
 {
-       struct dquot *dquot = i_dquot(inode)[type];
+       struct dquot **dquots = i_dquot(inode);
+       struct dquot *dquot = dquots[type];
 
-       i_dquot(inode)[type] = NULL;
        if (!dquot)
                return;
 
+       dquots[type] = NULL;
        if (list_empty(&dquot->dq_free)) {
                /*
                 * The inode still has reference to dquot so it can't be in the
@@ -1159,8 +1163,8 @@ static int need_print_warning(struct dquot_warn *warn)
                        return uid_eq(current_fsuid(), warn->w_dq_id.uid);
                case GRPQUOTA:
                        return in_group_p(warn->w_dq_id.gid);
-               case PRJQUOTA:  /* Never taken... Just make gcc happy */
-                       return 0;
+               case PRJQUOTA:
+                       return 1;
        }
        return 0;
 }
@@ -1389,16 +1393,21 @@ static int dquot_active(const struct inode *inode)
 static void __dquot_initialize(struct inode *inode, int type)
 {
        int cnt, init_needed = 0;
-       struct dquot *got[MAXQUOTAS];
+       struct dquot **dquots, *got[MAXQUOTAS];
        struct super_block *sb = inode->i_sb;
        qsize_t rsv;
 
        if (!dquot_active(inode))
                return;
 
+       dquots = i_dquot(inode);
+
        /* First get references to structures we might need. */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                struct kqid qid;
+               kprojid_t projid;
+               int rc;
+
                got[cnt] = NULL;
                if (type != -1 && cnt != type)
                        continue;
@@ -1407,8 +1416,12 @@ static void __dquot_initialize(struct inode *inode, int type)
                 * we check it without locking here to avoid unnecessary
                 * dqget()/dqput() calls.
                 */
-               if (i_dquot(inode)[cnt])
+               if (dquots[cnt])
+                       continue;
+
+               if (!sb_has_quota_active(sb, cnt))
                        continue;
+
                init_needed = 1;
 
                switch (cnt) {
@@ -1418,6 +1431,12 @@ static void __dquot_initialize(struct inode *inode, int type)
                case GRPQUOTA:
                        qid = make_kqid_gid(inode->i_gid);
                        break;
+               case PRJQUOTA:
+                       rc = inode->i_sb->dq_op->get_projid(inode, &projid);
+                       if (rc)
+                               continue;
+                       qid = make_kqid_projid(projid);
+                       break;
                }
                got[cnt] = dqget(sb, qid);
        }
@@ -1438,8 +1457,8 @@ static void __dquot_initialize(struct inode *inode, int type)
                /* We could race with quotaon or dqget() could have failed */
                if (!got[cnt])
                        continue;
-               if (!i_dquot(inode)[cnt]) {
-                       i_dquot(inode)[cnt] = got[cnt];
+               if (!dquots[cnt]) {
+                       dquots[cnt] = got[cnt];
                        got[cnt] = NULL;
                        /*
                         * Make quota reservation system happy if someone
@@ -1447,7 +1466,7 @@ static void __dquot_initialize(struct inode *inode, int type)
                         */
                        rsv = inode_get_rsv_space(inode);
                        if (unlikely(rsv))
-                               dquot_resv_space(i_dquot(inode)[cnt], rsv);
+                               dquot_resv_space(dquots[cnt], rsv);
                }
        }
 out_err:
@@ -1473,12 +1492,13 @@ EXPORT_SYMBOL(dquot_initialize);
 static void __dquot_drop(struct inode *inode)
 {
        int cnt;
+       struct dquot **dquots = i_dquot(inode);
        struct dquot *put[MAXQUOTAS];
 
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               put[cnt] = i_dquot(inode)[cnt];
-               i_dquot(inode)[cnt] = NULL;
+               put[cnt] = dquots[cnt];
+               dquots[cnt] = NULL;
        }
        spin_unlock(&dq_data_lock);
        dqput_all(put);
@@ -1486,6 +1506,7 @@ static void __dquot_drop(struct inode *inode)
 
 void dquot_drop(struct inode *inode)
 {
+       struct dquot * const *dquots;
        int cnt;
 
        if (IS_NOQUOTA(inode))
@@ -1498,8 +1519,9 @@ void dquot_drop(struct inode *inode)
         * must assure that nobody can come after the DQUOT_DROP and
         * add quota pointers back anyway.
         */
+       dquots = i_dquot(inode);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (i_dquot(inode)[cnt])
+               if (dquots[cnt])
                        break;
        }
 
@@ -1600,8 +1622,8 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
 {
        int cnt, ret = 0, index;
        struct dquot_warn warn[MAXQUOTAS];
-       struct dquot **dquots = i_dquot(inode);
        int reserve = flags & DQUOT_SPACE_RESERVE;
+       struct dquot **dquots;
 
        if (!dquot_active(inode)) {
                inode_incr_space(inode, number, reserve);
@@ -1611,6 +1633,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                warn[cnt].w_type = QUOTA_NL_NOWARN;
 
+       dquots = i_dquot(inode);
        index = srcu_read_lock(&dquot_srcu);
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1652,13 +1675,14 @@ int dquot_alloc_inode(struct inode *inode)
 {
        int cnt, ret = 0, index;
        struct dquot_warn warn[MAXQUOTAS];
-       struct dquot * const *dquots = i_dquot(inode);
+       struct dquot * const *dquots;
 
        if (!dquot_active(inode))
                return 0;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                warn[cnt].w_type = QUOTA_NL_NOWARN;
 
+       dquots = i_dquot(inode);
        index = srcu_read_lock(&dquot_srcu);
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1690,6 +1714,7 @@ EXPORT_SYMBOL(dquot_alloc_inode);
  */
 int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
 {
+       struct dquot **dquots;
        int cnt, index;
 
        if (!dquot_active(inode)) {
@@ -1697,18 +1722,18 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
                return 0;
        }
 
+       dquots = i_dquot(inode);
        index = srcu_read_lock(&dquot_srcu);
        spin_lock(&dq_data_lock);
        /* Claim reserved quotas to allocated quotas */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (i_dquot(inode)[cnt])
-                       dquot_claim_reserved_space(i_dquot(inode)[cnt],
-                                                       number);
+               if (dquots[cnt])
+                       dquot_claim_reserved_space(dquots[cnt], number);
        }
        /* Update inode bytes */
        inode_claim_rsv_space(inode, number);
        spin_unlock(&dq_data_lock);
-       mark_all_dquot_dirty(i_dquot(inode));
+       mark_all_dquot_dirty(dquots);
        srcu_read_unlock(&dquot_srcu, index);
        return 0;
 }
@@ -1719,6 +1744,7 @@ EXPORT_SYMBOL(dquot_claim_space_nodirty);
  */
 void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
 {
+       struct dquot **dquots;
        int cnt, index;
 
        if (!dquot_active(inode)) {
@@ -1726,18 +1752,18 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
                return;
        }
 
+       dquots = i_dquot(inode);
        index = srcu_read_lock(&dquot_srcu);
        spin_lock(&dq_data_lock);
        /* Claim reserved quotas to allocated quotas */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (i_dquot(inode)[cnt])
-                       dquot_reclaim_reserved_space(i_dquot(inode)[cnt],
-                                                    number);
+               if (dquots[cnt])
+                       dquot_reclaim_reserved_space(dquots[cnt], number);
        }
        /* Update inode bytes */
        inode_reclaim_rsv_space(inode, number);
        spin_unlock(&dq_data_lock);
-       mark_all_dquot_dirty(i_dquot(inode));
+       mark_all_dquot_dirty(dquots);
        srcu_read_unlock(&dquot_srcu, index);
        return;
 }
@@ -1750,7 +1776,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
 {
        unsigned int cnt;
        struct dquot_warn warn[MAXQUOTAS];
-       struct dquot **dquots = i_dquot(inode);
+       struct dquot **dquots;
        int reserve = flags & DQUOT_SPACE_RESERVE, index;
 
        if (!dquot_active(inode)) {
@@ -1758,6 +1784,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
                return;
        }
 
+       dquots = i_dquot(inode);
        index = srcu_read_lock(&dquot_srcu);
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1793,12 +1820,13 @@ void dquot_free_inode(struct inode *inode)
 {
        unsigned int cnt;
        struct dquot_warn warn[MAXQUOTAS];
-       struct dquot * const *dquots = i_dquot(inode);
+       struct dquot * const *dquots;
        int index;
 
        if (!dquot_active(inode))
                return;
 
+       dquots = i_dquot(inode);
        index = srcu_read_lock(&dquot_srcu);
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -2161,7 +2189,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                error = -EROFS;
                goto out_fmt;
        }
-       if (!sb->s_op->quota_write || !sb->s_op->quota_read) {
+       if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
+           (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
                error = -EINVAL;
                goto out_fmt;
        }
@@ -2614,55 +2643,73 @@ out:
 EXPORT_SYMBOL(dquot_set_dqblk);
 
 /* Generic routine for getting common part of quota file information */
-int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_get_state(struct super_block *sb, struct qc_state *state)
 {
        struct mem_dqinfo *mi;
+       struct qc_type_state *tstate;
+       struct quota_info *dqopt = sb_dqopt(sb);
+       int type;
   
        mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
-       if (!sb_has_quota_active(sb, type)) {
-               mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
-               return -ESRCH;
+       memset(state, 0, sizeof(*state));
+       for (type = 0; type < MAXQUOTAS; type++) {
+               if (!sb_has_quota_active(sb, type))
+                       continue;
+               tstate = state->s_state + type;
+               mi = sb_dqopt(sb)->info + type;
+               tstate->flags = QCI_ACCT_ENABLED;
+               spin_lock(&dq_data_lock);
+               if (mi->dqi_flags & DQF_SYS_FILE)
+                       tstate->flags |= QCI_SYSFILE;
+               if (mi->dqi_flags & DQF_ROOT_SQUASH)
+                       tstate->flags |= QCI_ROOT_SQUASH;
+               if (sb_has_quota_limits_enabled(sb, type))
+                       tstate->flags |= QCI_LIMITS_ENFORCED;
+               tstate->spc_timelimit = mi->dqi_bgrace;
+               tstate->ino_timelimit = mi->dqi_igrace;
+               tstate->ino = dqopt->files[type]->i_ino;
+               tstate->blocks = dqopt->files[type]->i_blocks;
+               tstate->nextents = 1;   /* We don't know... */
+               spin_unlock(&dq_data_lock);
        }
-       mi = sb_dqopt(sb)->info + type;
-       spin_lock(&dq_data_lock);
-       ii->dqi_bgrace = mi->dqi_bgrace;
-       ii->dqi_igrace = mi->dqi_igrace;
-       ii->dqi_flags = mi->dqi_flags & DQF_GETINFO_MASK;
-       ii->dqi_valid = IIF_ALL;
-       spin_unlock(&dq_data_lock);
        mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
        return 0;
 }
-EXPORT_SYMBOL(dquot_get_dqinfo);
+EXPORT_SYMBOL(dquot_get_state);
 
 /* Generic routine for setting common part of quota file information */
-int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii)
 {
        struct mem_dqinfo *mi;
        int err = 0;
 
+       if ((ii->i_fieldmask & QC_WARNS_MASK) ||
+           (ii->i_fieldmask & QC_RT_SPC_TIMER))
+               return -EINVAL;
        mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        if (!sb_has_quota_active(sb, type)) {
                err = -ESRCH;
                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 &&
+       if (ii->i_fieldmask & QC_FLAGS) {
+               if ((ii->i_flags & QCI_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;
-       if (ii->dqi_valid & IIF_IGRACE)
-               mi->dqi_igrace = ii->dqi_igrace;
-       if (ii->dqi_valid & IIF_FLAGS)
-               mi->dqi_flags = (mi->dqi_flags & ~DQF_SETINFO_MASK) |
-                               (ii->dqi_flags & DQF_SETINFO_MASK);
+       if (ii->i_fieldmask & QC_SPC_TIMER)
+               mi->dqi_bgrace = ii->i_spc_timelimit;
+       if (ii->i_fieldmask & QC_INO_TIMER)
+               mi->dqi_igrace = ii->i_ino_timelimit;
+       if (ii->i_fieldmask & QC_FLAGS) {
+               if (ii->i_flags & QCI_ROOT_SQUASH)
+                       mi->dqi_flags |= DQF_ROOT_SQUASH;
+               else
+                       mi->dqi_flags &= ~DQF_ROOT_SQUASH;
+       }
        spin_unlock(&dq_data_lock);
        mark_info_dirty(sb, type);
        /* Force write to disk */
@@ -2677,7 +2724,7 @@ const struct quotactl_ops dquot_quotactl_ops = {
        .quota_on       = dquot_quota_on,
        .quota_off      = dquot_quota_off,
        .quota_sync     = dquot_quota_sync,
-       .get_info       = dquot_get_dqinfo,
+       .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
        .set_dqblk      = dquot_set_dqblk
@@ -2688,7 +2735,7 @@ 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,
+       .get_state      = dquot_get_state,
        .set_info       = dquot_set_dqinfo,
        .get_dqblk      = dquot_get_dqblk,
        .set_dqblk      = dquot_set_dqblk