|
@@ -810,171 +810,6 @@ out:
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-/* This is difficult. We have to lock quota inode and start transaction
|
|
|
- * in this function but we don't want to take the penalty of exlusive
|
|
|
- * quota file lock when we are just going to use cached structures. So
|
|
|
- * we just take read lock check whether we have dquot cached and if so,
|
|
|
- * we don't have to take the write lock... */
|
|
|
-static int ocfs2_dquot_initialize(struct inode *inode, int type)
|
|
|
-{
|
|
|
- handle_t *handle = NULL;
|
|
|
- int status = 0;
|
|
|
- struct super_block *sb = inode->i_sb;
|
|
|
- struct ocfs2_mem_dqinfo *oinfo;
|
|
|
- int exclusive = 0;
|
|
|
- int cnt;
|
|
|
- qid_t id;
|
|
|
-
|
|
|
- mlog_entry_void();
|
|
|
-
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
- if (type != -1 && cnt != type)
|
|
|
- continue;
|
|
|
- if (!sb_has_quota_active(sb, cnt))
|
|
|
- continue;
|
|
|
- oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
|
|
|
- status = ocfs2_lock_global_qf(oinfo, 0);
|
|
|
- if (status < 0)
|
|
|
- goto out;
|
|
|
- /* This is just a performance optimization not a reliable test.
|
|
|
- * Since we hold an inode lock, noone can actually release
|
|
|
- * the structure until we are finished with initialization. */
|
|
|
- if (inode->i_dquot[cnt] != NODQUOT) {
|
|
|
- ocfs2_unlock_global_qf(oinfo, 0);
|
|
|
- continue;
|
|
|
- }
|
|
|
- /* When we have inode lock, we know that no dquot_release() can
|
|
|
- * run and thus we can safely check whether we need to
|
|
|
- * read+modify global file to get quota information or whether
|
|
|
- * our node already has it. */
|
|
|
- if (cnt == USRQUOTA)
|
|
|
- id = inode->i_uid;
|
|
|
- else if (cnt == GRPQUOTA)
|
|
|
- id = inode->i_gid;
|
|
|
- else
|
|
|
- BUG();
|
|
|
- /* Obtain exclusion from quota off... */
|
|
|
- down_write(&sb_dqopt(sb)->dqptr_sem);
|
|
|
- exclusive = !dquot_is_cached(sb, id, cnt);
|
|
|
- up_write(&sb_dqopt(sb)->dqptr_sem);
|
|
|
- if (exclusive) {
|
|
|
- status = ocfs2_lock_global_qf(oinfo, 1);
|
|
|
- if (status < 0) {
|
|
|
- exclusive = 0;
|
|
|
- mlog_errno(status);
|
|
|
- goto out_ilock;
|
|
|
- }
|
|
|
- handle = ocfs2_start_trans(OCFS2_SB(sb),
|
|
|
- ocfs2_calc_qinit_credits(sb, cnt));
|
|
|
- if (IS_ERR(handle)) {
|
|
|
- status = PTR_ERR(handle);
|
|
|
- mlog_errno(status);
|
|
|
- goto out_ilock;
|
|
|
- }
|
|
|
- }
|
|
|
- dquot_initialize(inode, cnt);
|
|
|
- if (exclusive) {
|
|
|
- ocfs2_commit_trans(OCFS2_SB(sb), handle);
|
|
|
- ocfs2_unlock_global_qf(oinfo, 1);
|
|
|
- }
|
|
|
- ocfs2_unlock_global_qf(oinfo, 0);
|
|
|
- }
|
|
|
- mlog_exit(0);
|
|
|
- return 0;
|
|
|
-out_ilock:
|
|
|
- if (exclusive)
|
|
|
- ocfs2_unlock_global_qf(oinfo, 1);
|
|
|
- ocfs2_unlock_global_qf(oinfo, 0);
|
|
|
-out:
|
|
|
- mlog_exit(status);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static int ocfs2_dquot_drop_slow(struct inode *inode)
|
|
|
-{
|
|
|
- int status = 0;
|
|
|
- int cnt;
|
|
|
- int got_lock[MAXQUOTAS] = {0, 0};
|
|
|
- handle_t *handle;
|
|
|
- struct super_block *sb = inode->i_sb;
|
|
|
- struct ocfs2_mem_dqinfo *oinfo;
|
|
|
-
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
- if (!sb_has_quota_active(sb, cnt))
|
|
|
- continue;
|
|
|
- oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
|
|
|
- status = ocfs2_lock_global_qf(oinfo, 1);
|
|
|
- if (status < 0)
|
|
|
- goto out;
|
|
|
- got_lock[cnt] = 1;
|
|
|
- }
|
|
|
- handle = ocfs2_start_trans(OCFS2_SB(sb),
|
|
|
- ocfs2_calc_qinit_credits(sb, USRQUOTA) +
|
|
|
- ocfs2_calc_qinit_credits(sb, GRPQUOTA));
|
|
|
- if (IS_ERR(handle)) {
|
|
|
- status = PTR_ERR(handle);
|
|
|
- mlog_errno(status);
|
|
|
- goto out;
|
|
|
- }
|
|
|
- dquot_drop(inode);
|
|
|
- ocfs2_commit_trans(OCFS2_SB(sb), handle);
|
|
|
-out:
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- if (got_lock[cnt]) {
|
|
|
- oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
|
|
|
- ocfs2_unlock_global_qf(oinfo, 1);
|
|
|
- }
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-/* See the comment before ocfs2_dquot_initialize. */
|
|
|
-static int ocfs2_dquot_drop(struct inode *inode)
|
|
|
-{
|
|
|
- int status = 0;
|
|
|
- struct super_block *sb = inode->i_sb;
|
|
|
- struct ocfs2_mem_dqinfo *oinfo;
|
|
|
- int exclusive = 0;
|
|
|
- int cnt;
|
|
|
- int got_lock[MAXQUOTAS] = {0, 0};
|
|
|
-
|
|
|
- mlog_entry_void();
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
- if (!sb_has_quota_active(sb, cnt))
|
|
|
- continue;
|
|
|
- oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
|
|
|
- status = ocfs2_lock_global_qf(oinfo, 0);
|
|
|
- if (status < 0)
|
|
|
- goto out;
|
|
|
- got_lock[cnt] = 1;
|
|
|
- }
|
|
|
- /* Lock against anyone releasing references so that when when we check
|
|
|
- * we know we are not going to be last ones to release dquot */
|
|
|
- down_write(&sb_dqopt(sb)->dqptr_sem);
|
|
|
- /* Urgh, this is a terrible hack :( */
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
|
|
|
- if (inode->i_dquot[cnt] != NODQUOT &&
|
|
|
- atomic_read(&inode->i_dquot[cnt]->dq_count) > 1) {
|
|
|
- exclusive = 1;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (!exclusive)
|
|
|
- dquot_drop_locked(inode);
|
|
|
- up_write(&sb_dqopt(sb)->dqptr_sem);
|
|
|
-out:
|
|
|
- for (cnt = 0; cnt < MAXQUOTAS; cnt++)
|
|
|
- if (got_lock[cnt]) {
|
|
|
- oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
|
|
|
- ocfs2_unlock_global_qf(oinfo, 0);
|
|
|
- }
|
|
|
- /* In case we bailed out because we had to do expensive locking
|
|
|
- * do it now... */
|
|
|
- if (exclusive)
|
|
|
- status = ocfs2_dquot_drop_slow(inode);
|
|
|
- mlog_exit(status);
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
static struct dquot *ocfs2_alloc_dquot(struct super_block *sb, int type)
|
|
|
{
|
|
|
struct ocfs2_dquot *dquot =
|
|
@@ -991,8 +826,8 @@ static void ocfs2_destroy_dquot(struct dquot *dquot)
|
|
|
}
|
|
|
|
|
|
struct dquot_operations ocfs2_quota_operations = {
|
|
|
- .initialize = ocfs2_dquot_initialize,
|
|
|
- .drop = ocfs2_dquot_drop,
|
|
|
+ .initialize = dquot_initialize,
|
|
|
+ .drop = dquot_drop,
|
|
|
.alloc_space = dquot_alloc_space,
|
|
|
.alloc_inode = dquot_alloc_inode,
|
|
|
.free_space = dquot_free_space,
|