Commit cc597bc3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-quota-2.6

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-quota-2.6:
  ocfs2: Remove ocfs2_dquot_initialize() and ocfs2_dquot_drop()
  quota: Improve locking
parents ed803862 c475146d
This diff is collapsed.
......@@ -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,
......
......@@ -24,10 +24,8 @@ void sync_dquots(struct super_block *sb, int type);
int dquot_initialize(struct inode *inode, int type);
int dquot_drop(struct inode *inode);
int dquot_drop_locked(struct inode *inode);
struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
void dqput(struct dquot *dquot);
int dquot_is_cached(struct super_block *sb, unsigned int id, int type);
int dquot_scan_active(struct super_block *sb,
int (*fn)(struct dquot *dquot, unsigned long priv),
unsigned long priv);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment