|
@@ -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
|