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
This commit is contained in:
Linus Torvalds 2009-01-26 10:41:00 -08:00
commit cc597bc3d3
3 changed files with 126 additions and 267 deletions

View File

@ -87,14 +87,17 @@
#define __DQUOT_PARANOIA
/*
* There are two quota SMP locks. dq_list_lock protects all lists with quotas
* and quota formats and also dqstats structure containing statistics about the
* lists. dq_data_lock protects data from dq_dqb and also mem_dqinfo structures
* and also guards consistency of dquot->dq_dqb with inode->i_blocks, i_bytes.
* There are three quota SMP locks. dq_list_lock protects all lists with quotas
* and quota formats, dqstats structure containing statistics about the lists
* dq_data_lock protects data from dq_dqb and also mem_dqinfo structures and
* also guards consistency of dquot->dq_dqb with inode->i_blocks, i_bytes.
* i_blocks and i_bytes updates itself are guarded by i_lock acquired directly
* in inode_add_bytes() and inode_sub_bytes().
* in inode_add_bytes() and inode_sub_bytes(). dq_state_lock protects
* modifications of quota state (on quotaon and quotaoff) and readers who care
* about latest values take it as well.
*
* The spinlock ordering is hence: dq_data_lock > dq_list_lock > i_lock
* The spinlock ordering is hence: dq_data_lock > dq_list_lock > i_lock,
* dq_list_lock > dq_state_lock
*
* Note that some things (eg. sb pointer, type, id) doesn't change during
* the life of the dquot structure and so needn't to be protected by a lock
@ -103,12 +106,7 @@
* operation is just reading pointers from inode (or not using them at all) the
* read lock is enough. If pointers are altered function must hold write lock
* (these locking rules also apply for S_NOQUOTA flag in the inode - note that
* for altering the flag i_mutex is also needed). If operation is holding
* reference to dquot in other way (e.g. quotactl ops) it must be guarded by
* dqonoff_mutex.
* This locking assures that:
* a) update/access to dquot pointers in inode is serialized
* b) everyone is guarded against invalidate_dquots()
* for altering the flag i_mutex is also needed).
*
* Each dquot has its dq_lock mutex. Locked dquots might not be referenced
* from inodes (dquot_alloc_space() and such don't check the dq_lock).
@ -122,10 +120,17 @@
* Lock ordering (including related VFS locks) is the following:
* i_mutex > dqonoff_sem > journal_lock > dqptr_sem > dquot->dq_lock >
* dqio_mutex
* The lock ordering of dqptr_sem imposed by quota code is only dqonoff_sem >
* dqptr_sem. But filesystem has to count with the fact that functions such as
* dquot_alloc_space() acquire dqptr_sem and they usually have to be called
* from inside a transaction to keep filesystem consistency after a crash. Also
* filesystems usually want to do some IO on dquot from ->mark_dirty which is
* called with dqptr_sem held.
* i_mutex on quota files is special (it's below dqio_mutex)
*/
static DEFINE_SPINLOCK(dq_list_lock);
static DEFINE_SPINLOCK(dq_state_lock);
DEFINE_SPINLOCK(dq_data_lock);
static char *quotatypes[] = INITQFNAMES;
@ -428,7 +433,7 @@ static inline void do_destroy_dquot(struct dquot *dquot)
* quota is disabled and pointers from inodes removed so there cannot be new
* quota users. There can still be some users of quotas due to inodes being
* just deleted or pruned by prune_icache() (those are not attached to any
* list). We have to wait for such users.
* list) or parallel quotactl call. We have to wait for such users.
*/
static void invalidate_dquots(struct super_block *sb, int type)
{
@ -600,7 +605,6 @@ static struct shrinker dqcache_shrinker = {
/*
* Put reference to dquot
* NOTE: If you change this function please check whether dqput_blocks() works right...
* MUST be called with either dqptr_sem or dqonoff_mutex held
*/
void dqput(struct dquot *dquot)
{
@ -696,37 +700,31 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
return dquot;
}
/*
* Check whether dquot is in memory.
* MUST be called with either dqptr_sem or dqonoff_mutex held
*/
int dquot_is_cached(struct super_block *sb, unsigned int id, int type)
{
unsigned int hashent = hashfn(sb, id, type);
int ret = 0;
if (!sb_has_quota_active(sb, type))
return 0;
spin_lock(&dq_list_lock);
if (find_dquot(hashent, sb, id, type) != NODQUOT)
ret = 1;
spin_unlock(&dq_list_lock);
return ret;
}
/*
* Get reference to dquot
* MUST be called with either dqptr_sem or dqonoff_mutex held
*
* Locking is slightly tricky here. We are guarded from parallel quotaoff()
* destroying our dquot by:
* a) checking for quota flags under dq_list_lock and
* b) getting a reference to dquot before we release dq_list_lock
*/
struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
{
unsigned int hashent = hashfn(sb, id, type);
struct dquot *dquot, *empty = NODQUOT;
struct dquot *dquot = NODQUOT, *empty = NODQUOT;
if (!sb_has_quota_active(sb, type))
return NODQUOT;
we_slept:
spin_lock(&dq_list_lock);
spin_lock(&dq_state_lock);
if (!sb_has_quota_active(sb, type)) {
spin_unlock(&dq_state_lock);
spin_unlock(&dq_list_lock);
goto out;
}
spin_unlock(&dq_state_lock);
if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) {
if (empty == NODQUOT) {
spin_unlock(&dq_list_lock);
@ -735,6 +733,7 @@ we_slept:
goto we_slept;
}
dquot = empty;
empty = NODQUOT;
dquot->dq_id = id;
/* all dquots go on the inuse_list */
put_inuse(dquot);
@ -749,8 +748,6 @@ we_slept:
dqstats.cache_hits++;
dqstats.lookups++;
spin_unlock(&dq_list_lock);
if (empty)
do_destroy_dquot(empty);
}
/* Wait for dq_lock - after this we know that either dquot_release() is already
* finished or it will be canceled due to dq_count > 1 test */
@ -758,11 +755,15 @@ we_slept:
/* Read the dquot and instantiate it (everything done only if needed) */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && sb->dq_op->acquire_dquot(dquot) < 0) {
dqput(dquot);
return NODQUOT;
dquot = NODQUOT;
goto out;
}
#ifdef __DQUOT_PARANOIA
BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */
#endif
out:
if (empty)
do_destroy_dquot(empty);
return dquot;
}
@ -1198,63 +1199,76 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
}
/*
* Initialize quota pointers in inode
* Transaction must be started at entry
* We do things in a bit complicated way but by that we avoid calling
* dqget() and thus filesystem callbacks under dqptr_sem.
*/
int dquot_initialize(struct inode *inode, int type)
{
unsigned int id = 0;
int cnt, ret = 0;
struct dquot *got[MAXQUOTAS] = { NODQUOT, NODQUOT };
struct super_block *sb = inode->i_sb;
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
if (IS_NOQUOTA(inode))
return 0;
down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
/* First get references to structures we might need. */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (type != -1 && cnt != type)
continue;
switch (cnt) {
case USRQUOTA:
id = inode->i_uid;
break;
case GRPQUOTA:
id = inode->i_gid;
break;
}
got[cnt] = dqget(sb, id, cnt);
}
down_write(&sb_dqopt(sb)->dqptr_sem);
/* Having dqptr_sem we know NOQUOTA flags can't be altered... */
if (IS_NOQUOTA(inode))
goto out_err;
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (type != -1 && cnt != type)
continue;
/* Avoid races with quotaoff() */
if (!sb_has_quota_active(sb, cnt))
continue;
if (inode->i_dquot[cnt] == NODQUOT) {
switch (cnt) {
case USRQUOTA:
id = inode->i_uid;
break;
case GRPQUOTA:
id = inode->i_gid;
break;
}
inode->i_dquot[cnt] = dqget(inode->i_sb, id, cnt);
inode->i_dquot[cnt] = got[cnt];
got[cnt] = NODQUOT;
}
}
out_err:
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
up_write(&sb_dqopt(sb)->dqptr_sem);
/* Drop unused references */
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
dqput(got[cnt]);
return ret;
}
/*
* Release all quotas referenced by inode
* Transaction must be started at an entry
*/
int dquot_drop_locked(struct inode *inode)
{
int cnt;
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (inode->i_dquot[cnt] != NODQUOT) {
dqput(inode->i_dquot[cnt]);
inode->i_dquot[cnt] = NODQUOT;
}
}
return 0;
}
int dquot_drop(struct inode *inode)
{
int cnt;
struct dquot *put[MAXQUOTAS];
down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
dquot_drop_locked(inode);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
put[cnt] = inode->i_dquot[cnt];
inode->i_dquot[cnt] = NODQUOT;
}
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
dqput(put[cnt]);
return 0;
}
@ -1470,8 +1484,9 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
qsize_t space;
struct dquot *transfer_from[MAXQUOTAS];
struct dquot *transfer_to[MAXQUOTAS];
int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid,
chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid;
int cnt, ret = QUOTA_OK;
int chuid = iattr->ia_valid & ATTR_UID && inode->i_uid != iattr->ia_uid,
chgid = iattr->ia_valid & ATTR_GID && inode->i_gid != iattr->ia_gid;
char warntype_to[MAXQUOTAS];
char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS];
@ -1479,21 +1494,11 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
* re-enter the quota code and are already holding the mutex */
if (IS_NOQUOTA(inode))
return QUOTA_OK;
/* Clear the arrays */
/* Initialize the arrays */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
transfer_to[cnt] = transfer_from[cnt] = NODQUOT;
transfer_from[cnt] = NODQUOT;
transfer_to[cnt] = NODQUOT;
warntype_to[cnt] = QUOTA_NL_NOWARN;
}
down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
/* Now recheck reliably when holding dqptr_sem */
if (IS_NOQUOTA(inode)) { /* File without quota accounting? */
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
return QUOTA_OK;
}
/* First build the transfer_to list - here we can block on
* reading/instantiating of dquots. We know that the transaction for
* us was already started so we don't violate lock ranking here */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
switch (cnt) {
case USRQUOTA:
if (!chuid)
@ -1507,6 +1512,13 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
break;
}
}
down_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
/* Now recheck reliably when holding dqptr_sem */
if (IS_NOQUOTA(inode)) { /* File without quota accounting? */
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
goto put_all;
}
spin_lock(&dq_data_lock);
space = inode_get_bytes(inode);
/* Build the transfer_from list and check the limits */
@ -1517,7 +1529,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
if (check_idq(transfer_to[cnt], 1, warntype_to + cnt) ==
NO_QUOTA || check_bdq(transfer_to[cnt], space, 0,
warntype_to + cnt) == NO_QUOTA)
goto warn_put_all;
goto over_quota;
}
/*
@ -1545,28 +1557,37 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
inode->i_dquot[cnt] = transfer_to[cnt];
}
ret = QUOTA_OK;
warn_put_all:
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])
if (transfer_to[cnt]) {
mark_dquot_dirty(transfer_to[cnt]);
/* The reference we got is transferred to the inode */
transfer_to[cnt] = NODQUOT;
}
}
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++) {
if (ret == QUOTA_OK && transfer_from[cnt] != NODQUOT)
dqput(transfer_from[cnt]);
if (ret == NO_QUOTA && transfer_to[cnt] != NODQUOT)
dqput(transfer_to[cnt]);
dqput(transfer_from[cnt]);
dqput(transfer_to[cnt]);
}
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
return ret;
over_quota:
spin_unlock(&dq_data_lock);
up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
/* Clear dquot pointers we don't want to dqput() */
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
transfer_from[cnt] = NODQUOT;
ret = NO_QUOTA;
goto warn_put_all;
}
/* Wrapper for transferring ownership of an inode */
@ -1651,19 +1672,24 @@ int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags)
continue;
if (flags & DQUOT_SUSPENDED) {
spin_lock(&dq_state_lock);
dqopt->flags |=
dquot_state_flag(DQUOT_SUSPENDED, cnt);
spin_unlock(&dq_state_lock);
} else {
spin_lock(&dq_state_lock);
dqopt->flags &= ~dquot_state_flag(flags, cnt);
/* Turning off suspended quotas? */
if (!sb_has_quota_loaded(sb, cnt) &&
sb_has_quota_suspended(sb, cnt)) {
dqopt->flags &= ~dquot_state_flag(
DQUOT_SUSPENDED, cnt);
spin_unlock(&dq_state_lock);
iput(dqopt->files[cnt]);
dqopt->files[cnt] = NULL;
continue;
}
spin_unlock(&dq_state_lock);
}
/* We still have to keep quota loaded? */
@ -1830,7 +1856,9 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
}
mutex_unlock(&dqopt->dqio_mutex);
mutex_unlock(&inode->i_mutex);
spin_lock(&dq_state_lock);
dqopt->flags |= dquot_state_flag(flags, type);
spin_unlock(&dq_state_lock);
add_dquot_ref(sb, type);
mutex_unlock(&dqopt->dqonoff_mutex);
@ -1872,9 +1900,11 @@ static int vfs_quota_on_remount(struct super_block *sb, int type)
}
inode = dqopt->files[type];
dqopt->files[type] = NULL;
spin_lock(&dq_state_lock);
flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED |
DQUOT_LIMITS_ENABLED, type);
dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, type);
spin_unlock(&dq_state_lock);
mutex_unlock(&dqopt->dqonoff_mutex);
flags = dquot_generic_flag(flags, type);
@ -1952,7 +1982,9 @@ int vfs_quota_enable(struct inode *inode, int type, int format_id,
ret = -EBUSY;
goto out_lock;
}
spin_lock(&dq_state_lock);
sb_dqopt(sb)->flags |= dquot_state_flag(flags, type);
spin_unlock(&dq_state_lock);
out_lock:
mutex_unlock(&dqopt->dqonoff_mutex);
return ret;
@ -2039,14 +2071,12 @@ int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
{
struct dquot *dquot;
mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
if (!(dquot = dqget(sb, id, type))) {
mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
dquot = dqget(sb, id, type);
if (dquot == NODQUOT)
return -ESRCH;
}
do_get_dqblk(dquot, di);
dqput(dquot);
mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
return 0;
}
@ -2130,7 +2160,6 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
struct dquot *dquot;
int rc;
mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
dquot = dqget(sb, id, type);
if (!dquot) {
rc = -ESRCH;
@ -2139,7 +2168,6 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
rc = do_set_dqblk(dquot, di);
dqput(dquot);
out:
mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
return rc;
}
@ -2370,11 +2398,9 @@ EXPORT_SYMBOL(dquot_release);
EXPORT_SYMBOL(dquot_mark_dquot_dirty);
EXPORT_SYMBOL(dquot_initialize);
EXPORT_SYMBOL(dquot_drop);
EXPORT_SYMBOL(dquot_drop_locked);
EXPORT_SYMBOL(vfs_dq_drop);
EXPORT_SYMBOL(dqget);
EXPORT_SYMBOL(dqput);
EXPORT_SYMBOL(dquot_is_cached);
EXPORT_SYMBOL(dquot_alloc_space);
EXPORT_SYMBOL(dquot_alloc_inode);
EXPORT_SYMBOL(dquot_free_space);

View File

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

View File

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