|
@@ -323,6 +323,30 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_mark_dquot_dirty);
|
|
|
|
|
|
+/* Dirtify all the dquots - this can block when journalling */
|
|
|
+static inline int mark_all_dquot_dirty(struct dquot * const *dquot)
|
|
|
+{
|
|
|
+ int ret, err, cnt;
|
|
|
+
|
|
|
+ ret = err = 0;
|
|
|
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
+ if (dquot[cnt])
|
|
|
+ /* Even in case of error we have to continue */
|
|
|
+ ret = mark_dquot_dirty(dquot[cnt]);
|
|
|
+ if (!err)
|
|
|
+ err = ret;
|
|
|
+ }
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void dqput_all(struct dquot **dquot)
|
|
|
+{
|
|
|
+ unsigned int cnt;
|
|
|
+
|
|
|
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
+ dqput(dquot[cnt]);
|
|
|
+}
|
|
|
+
|
|
|
/* This function needs dq_list_lock */
|
|
|
static inline int clear_dquot_dirty(struct dquot *dquot)
|
|
|
{
|
|
@@ -1268,8 +1292,7 @@ int dquot_initialize(struct inode *inode, int type)
|
|
|
out_err:
|
|
|
up_write(&sb_dqopt(sb)->dqptr_sem);
|
|
|
/* Drop unused references */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- dqput(got[cnt]);
|
|
|
+ dqput_all(got);
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_initialize);
|
|
@@ -1288,9 +1311,7 @@ int dquot_drop(struct inode *inode)
|
|
|
inode->i_dquot[cnt] = NULL;
|
|
|
}
|
|
|
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
-
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- dqput(put[cnt]);
|
|
|
+ dqput_all(put);
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_drop);
|
|
@@ -1318,6 +1339,67 @@ void vfs_dq_drop(struct inode *inode)
|
|
|
}
|
|
|
EXPORT_SYMBOL(vfs_dq_drop);
|
|
|
|
|
|
+/*
|
|
|
+ * inode_reserved_space is managed internally by quota, and protected by
|
|
|
+ * i_lock similar to i_blocks+i_bytes.
|
|
|
+ */
|
|
|
+static qsize_t *inode_reserved_space(struct inode * inode)
|
|
|
+{
|
|
|
+ /* Filesystem must explicitly define it's own method in order to use
|
|
|
+ * quota reservation interface */
|
|
|
+ BUG_ON(!inode->i_sb->dq_op->get_reserved_space);
|
|
|
+ return inode->i_sb->dq_op->get_reserved_space(inode);
|
|
|
+}
|
|
|
+
|
|
|
+static void inode_add_rsv_space(struct inode *inode, qsize_t number)
|
|
|
+{
|
|
|
+ spin_lock(&inode->i_lock);
|
|
|
+ *inode_reserved_space(inode) += number;
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void inode_claim_rsv_space(struct inode *inode, qsize_t number)
|
|
|
+{
|
|
|
+ spin_lock(&inode->i_lock);
|
|
|
+ *inode_reserved_space(inode) -= number;
|
|
|
+ __inode_add_bytes(inode, number);
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+}
|
|
|
+
|
|
|
+static void inode_sub_rsv_space(struct inode *inode, qsize_t number)
|
|
|
+{
|
|
|
+ spin_lock(&inode->i_lock);
|
|
|
+ *inode_reserved_space(inode) -= number;
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+}
|
|
|
+
|
|
|
+static qsize_t inode_get_rsv_space(struct inode *inode)
|
|
|
+{
|
|
|
+ qsize_t ret;
|
|
|
+ spin_lock(&inode->i_lock);
|
|
|
+ ret = *inode_reserved_space(inode);
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static void inode_incr_space(struct inode *inode, qsize_t number,
|
|
|
+ int reserve)
|
|
|
+{
|
|
|
+ if (reserve)
|
|
|
+ inode_add_rsv_space(inode, number);
|
|
|
+ else
|
|
|
+ inode_add_bytes(inode, number);
|
|
|
+}
|
|
|
+
|
|
|
+static void inode_decr_space(struct inode *inode, qsize_t number, int reserve)
|
|
|
+{
|
|
|
+ if (reserve)
|
|
|
+ inode_sub_rsv_space(inode, number);
|
|
|
+ else
|
|
|
+ inode_sub_bytes(inode, number);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Following four functions update i_blocks+i_bytes fields and
|
|
|
* quota information (together with appropriate checks)
|
|
@@ -1336,6 +1418,21 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
|
|
|
int cnt, ret = QUOTA_OK;
|
|
|
char warntype[MAXQUOTAS];
|
|
|
|
|
|
+ /*
|
|
|
+ * First test before acquiring mutex - solves deadlocks when we
|
|
|
+ * re-enter the quota code and are already holding the mutex
|
|
|
+ */
|
|
|
+ if (IS_NOQUOTA(inode)) {
|
|
|
+ inode_incr_space(inode, number, reserve);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
+ if (IS_NOQUOTA(inode)) {
|
|
|
+ inode_incr_space(inode, number, reserve);
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
+
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
warntype[cnt] = QUOTA_NL_NOWARN;
|
|
|
|
|
@@ -1346,7 +1443,8 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
|
|
|
if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
|
|
|
== NO_QUOTA) {
|
|
|
ret = NO_QUOTA;
|
|
|
- goto out_unlock;
|
|
|
+ spin_unlock(&dq_data_lock);
|
|
|
+ goto out_flush_warn;
|
|
|
}
|
|
|
}
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
@@ -1357,64 +1455,29 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
|
|
|
else
|
|
|
dquot_incr_space(inode->i_dquot[cnt], number);
|
|
|
}
|
|
|
- if (!reserve)
|
|
|
- inode_add_bytes(inode, number);
|
|
|
-out_unlock:
|
|
|
+ inode_incr_space(inode, number, reserve);
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
+
|
|
|
+ if (reserve)
|
|
|
+ goto out_flush_warn;
|
|
|
+ mark_all_dquot_dirty(inode->i_dquot);
|
|
|
+out_flush_warn:
|
|
|
flush_warnings(inode->i_dquot, warntype);
|
|
|
+out_unlock:
|
|
|
+ up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
+out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
|
|
|
{
|
|
|
- int cnt, ret = QUOTA_OK;
|
|
|
-
|
|
|
- /*
|
|
|
- * First test before acquiring mutex - solves deadlocks when we
|
|
|
- * re-enter the quota code and are already holding the mutex
|
|
|
- */
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
- inode_add_bytes(inode, number);
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- if (IS_NOQUOTA(inode)) {
|
|
|
- inode_add_bytes(inode, number);
|
|
|
- goto out_unlock;
|
|
|
- }
|
|
|
-
|
|
|
- ret = __dquot_alloc_space(inode, number, warn, 0);
|
|
|
- if (ret == NO_QUOTA)
|
|
|
- goto out_unlock;
|
|
|
-
|
|
|
- /* Dirtify all the dquots - this can block when journalling */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- if (inode->i_dquot[cnt])
|
|
|
- mark_dquot_dirty(inode->i_dquot[cnt]);
|
|
|
-out_unlock:
|
|
|
- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
-out:
|
|
|
- return ret;
|
|
|
+ return __dquot_alloc_space(inode, number, warn, 0);
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_alloc_space);
|
|
|
|
|
|
int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
|
|
|
{
|
|
|
- int ret = QUOTA_OK;
|
|
|
-
|
|
|
- if (IS_NOQUOTA(inode))
|
|
|
- goto out;
|
|
|
-
|
|
|
- down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- if (IS_NOQUOTA(inode))
|
|
|
- goto out_unlock;
|
|
|
-
|
|
|
- ret = __dquot_alloc_space(inode, number, warn, 1);
|
|
|
-out_unlock:
|
|
|
- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
-out:
|
|
|
- return ret;
|
|
|
+ return __dquot_alloc_space(inode, number, warn, 1);
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_reserve_space);
|
|
|
|
|
@@ -1455,10 +1518,7 @@ int dquot_alloc_inode(const struct inode *inode, qsize_t number)
|
|
|
warn_put_all:
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
if (ret == QUOTA_OK)
|
|
|
- /* Dirtify all the dquots - this can block when journalling */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- if (inode->i_dquot[cnt])
|
|
|
- mark_dquot_dirty(inode->i_dquot[cnt]);
|
|
|
+ mark_all_dquot_dirty(inode->i_dquot);
|
|
|
flush_warnings(inode->i_dquot, warntype);
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
return ret;
|
|
@@ -1471,14 +1531,14 @@ int dquot_claim_space(struct inode *inode, qsize_t number)
|
|
|
int ret = QUOTA_OK;
|
|
|
|
|
|
if (IS_NOQUOTA(inode)) {
|
|
|
- inode_add_bytes(inode, number);
|
|
|
+ inode_claim_rsv_space(inode, number);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
if (IS_NOQUOTA(inode)) {
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- inode_add_bytes(inode, number);
|
|
|
+ inode_claim_rsv_space(inode, number);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
@@ -1490,51 +1550,19 @@ int dquot_claim_space(struct inode *inode, qsize_t number)
|
|
|
number);
|
|
|
}
|
|
|
/* Update inode bytes */
|
|
|
- inode_add_bytes(inode, number);
|
|
|
+ inode_claim_rsv_space(inode, number);
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
- /* Dirtify all the dquots - this can block when journalling */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- if (inode->i_dquot[cnt])
|
|
|
- mark_dquot_dirty(inode->i_dquot[cnt]);
|
|
|
+ mark_all_dquot_dirty(inode->i_dquot);
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
out:
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_claim_space);
|
|
|
|
|
|
-/*
|
|
|
- * Release reserved quota space
|
|
|
- */
|
|
|
-void dquot_release_reserved_space(struct inode *inode, qsize_t number)
|
|
|
-{
|
|
|
- int cnt;
|
|
|
-
|
|
|
- if (IS_NOQUOTA(inode))
|
|
|
- goto out;
|
|
|
-
|
|
|
- down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
- if (IS_NOQUOTA(inode))
|
|
|
- goto out_unlock;
|
|
|
-
|
|
|
- spin_lock(&dq_data_lock);
|
|
|
- /* Release reserved dquots */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
- if (inode->i_dquot[cnt])
|
|
|
- dquot_free_reserved_space(inode->i_dquot[cnt], number);
|
|
|
- }
|
|
|
- spin_unlock(&dq_data_lock);
|
|
|
-
|
|
|
-out_unlock:
|
|
|
- up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
-out:
|
|
|
- return;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(dquot_release_reserved_space);
|
|
|
-
|
|
|
/*
|
|
|
* This operation can block, but only after everything is updated
|
|
|
*/
|
|
|
-int dquot_free_space(struct inode *inode, qsize_t number)
|
|
|
+int __dquot_free_space(struct inode *inode, qsize_t number, int reserve)
|
|
|
{
|
|
|
unsigned int cnt;
|
|
|
char warntype[MAXQUOTAS];
|
|
@@ -1543,7 +1571,7 @@ int dquot_free_space(struct inode *inode, qsize_t number)
|
|
|
* re-enter the quota code and are already holding the mutex */
|
|
|
if (IS_NOQUOTA(inode)) {
|
|
|
out_sub:
|
|
|
- inode_sub_bytes(inode, number);
|
|
|
+ inode_decr_space(inode, number, reserve);
|
|
|
return QUOTA_OK;
|
|
|
}
|
|
|
|
|
@@ -1558,20 +1586,39 @@ out_sub:
|
|
|
if (!inode->i_dquot[cnt])
|
|
|
continue;
|
|
|
warntype[cnt] = info_bdq_free(inode->i_dquot[cnt], number);
|
|
|
- dquot_decr_space(inode->i_dquot[cnt], number);
|
|
|
+ if (reserve)
|
|
|
+ dquot_free_reserved_space(inode->i_dquot[cnt], number);
|
|
|
+ else
|
|
|
+ dquot_decr_space(inode->i_dquot[cnt], number);
|
|
|
}
|
|
|
- inode_sub_bytes(inode, number);
|
|
|
+ inode_decr_space(inode, number, reserve);
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
- /* Dirtify all the dquots - this can block when journalling */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- if (inode->i_dquot[cnt])
|
|
|
- mark_dquot_dirty(inode->i_dquot[cnt]);
|
|
|
+
|
|
|
+ if (reserve)
|
|
|
+ goto out_unlock;
|
|
|
+ mark_all_dquot_dirty(inode->i_dquot);
|
|
|
+out_unlock:
|
|
|
flush_warnings(inode->i_dquot, warntype);
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
return QUOTA_OK;
|
|
|
}
|
|
|
+
|
|
|
+int dquot_free_space(struct inode *inode, qsize_t number)
|
|
|
+{
|
|
|
+ return __dquot_free_space(inode, number, 0);
|
|
|
+}
|
|
|
EXPORT_SYMBOL(dquot_free_space);
|
|
|
|
|
|
+/*
|
|
|
+ * Release reserved quota space
|
|
|
+ */
|
|
|
+void dquot_release_reserved_space(struct inode *inode, qsize_t number)
|
|
|
+{
|
|
|
+ __dquot_free_space(inode, number, 1);
|
|
|
+
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(dquot_release_reserved_space);
|
|
|
+
|
|
|
/*
|
|
|
* This operation can block, but only after everything is updated
|
|
|
*/
|
|
@@ -1599,29 +1646,13 @@ int dquot_free_inode(const struct inode *inode, qsize_t number)
|
|
|
dquot_decr_inodes(inode->i_dquot[cnt], number);
|
|
|
}
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
- /* Dirtify all the dquots - this can block when journalling */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- if (inode->i_dquot[cnt])
|
|
|
- mark_dquot_dirty(inode->i_dquot[cnt]);
|
|
|
+ mark_all_dquot_dirty(inode->i_dquot);
|
|
|
flush_warnings(inode->i_dquot, warntype);
|
|
|
up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
return QUOTA_OK;
|
|
|
}
|
|
|
EXPORT_SYMBOL(dquot_free_inode);
|
|
|
|
|
|
-/*
|
|
|
- * call back function, get reserved quota space from underlying fs
|
|
|
- */
|
|
|
-qsize_t dquot_get_reserved_space(struct inode *inode)
|
|
|
-{
|
|
|
- qsize_t reserved_space = 0;
|
|
|
-
|
|
|
- if (sb_any_quota_active(inode->i_sb) &&
|
|
|
- inode->i_sb->dq_op->get_reserved_space)
|
|
|
- reserved_space = inode->i_sb->dq_op->get_reserved_space(inode);
|
|
|
- return reserved_space;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Transfer the number of inode and blocks from one diskquota to an other.
|
|
|
*
|
|
@@ -1665,7 +1696,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
|
|
|
}
|
|
|
spin_lock(&dq_data_lock);
|
|
|
cur_space = inode_get_bytes(inode);
|
|
|
- rsv_space = dquot_get_reserved_space(inode);
|
|
|
+ rsv_space = inode_get_rsv_space(inode);
|
|
|
space = cur_space + rsv_space;
|
|
|
/* Build the transfer_from list and check the limits */
|
|
|
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
@@ -1709,25 +1740,18 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
|
|
|
spin_unlock(&dq_data_lock);
|
|
|
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
|
|
|
|
|
|
- /* Dirtify all the dquots - this can block when journalling */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
- if (transfer_from[cnt])
|
|
|
- mark_dquot_dirty(transfer_from[cnt]);
|
|
|
- if (transfer_to[cnt]) {
|
|
|
- mark_dquot_dirty(transfer_to[cnt]);
|
|
|
- /* The reference we got is transferred to the inode */
|
|
|
- transfer_to[cnt] = NULL;
|
|
|
- }
|
|
|
- }
|
|
|
+ mark_all_dquot_dirty(transfer_from);
|
|
|
+ mark_all_dquot_dirty(transfer_to);
|
|
|
+ /* The reference we got is transferred to the inode */
|
|
|
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
+ transfer_to[cnt] = NULL;
|
|
|
warn_put_all:
|
|
|
flush_warnings(transfer_to, warntype_to);
|
|
|
flush_warnings(transfer_from, warntype_from_inodes);
|
|
|
flush_warnings(transfer_from, warntype_from_space);
|
|
|
put_all:
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
- dqput(transfer_from[cnt]);
|
|
|
- dqput(transfer_to[cnt]);
|
|
|
- }
|
|
|
+ dqput_all(transfer_from);
|
|
|
+ dqput_all(transfer_to);
|
|
|
return ret;
|
|
|
over_quota:
|
|
|
spin_unlock(&dq_data_lock);
|