Commit 4b9d4d3c authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] nfsd4: fix delegation refcounting

The delegation recall callback is setting the REAP_DELEGATION state when it
drops the reference count to zero instead of just freeing the thing itself,
which is needlessly complicated and bug-prone.  It's simpler just to define a
nfs4_put_delegation() which works in the usual way and have the delegation
recall code do call that itself.

Eventually I'll convert all the nfsd4 state reference counts to struct krefs
which will be harder to abuse in this way....
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f1436409
......@@ -542,11 +542,7 @@ nfsd4_cb_recall(struct nfs4_delegation *dp)
/* Success or failure, now we're either waiting for lease expiration
* or deleg_return. */
atomic_set(&dp->dl_state, NFS4_RECALL_COMPLETE);
if (atomic_dec_and_test(&dp->dl_count))
atomic_set(&dp->dl_state, NFS4_REAP_DELEG);
BUG_ON(atomic_read(&dp->dl_count) < 0);
nfs4_put_delegation(dp);
dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
put_rpccred(msg.rpc_cred);
return;
......
......@@ -167,17 +167,14 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
return dp;
}
/*
* Free the delegation structure.
* Called with the recall_lock held.
*/
static void
nfs4_free_delegation(struct nfs4_delegation *dp)
void
nfs4_put_delegation(struct nfs4_delegation *dp)
{
dprintk("NFSD: nfs4_free_delegation freeing dp %p\n",dp);
list_del(&dp->dl_recall_lru);
kfree(dp);
free_delegation++;
if (atomic_dec_and_test(&dp->dl_count)) {
dprintk("NFSD: freeing dp %p\n",dp);
kfree(dp);
free_delegation++;
}
}
/* release_delegation:
......@@ -219,12 +216,8 @@ release_delegation(struct nfs4_delegation *dp)
remove_lease(dp->dl_flock);
list_del_init(&dp->dl_del_perfile);
list_del_init(&dp->dl_del_perclnt);
/* dl_count > 0 => outstanding recall rpc */
dprintk("NFSD: release_delegation free deleg dl_count %d\n",
atomic_read(&dp->dl_count));
if ((atomic_read(&dp->dl_state) == NFS4_REAP_DELEG)
|| atomic_dec_and_test(&dp->dl_count))
nfs4_free_delegation(dp);
list_del_init(&dp->dl_recall_lru);
nfs4_put_delegation(dp);
}
}
......@@ -1692,7 +1685,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
list_del(&dp->dl_del_perfile);
list_del(&dp->dl_del_perclnt);
kfree(dp);
nfs4_put_delegation(dp);
free_delegation++;
*flag = NFS4_OPEN_DELEGATE_NONE;
return;
......
......@@ -288,6 +288,7 @@ extern void put_nfs4_client(struct nfs4_client *clp);
extern void nfs4_free_stateowner(struct kref *kref);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
extern void nfs4_put_delegation(struct nfs4_delegation *dp);
static inline void
nfs4_put_stateowner(struct nfs4_stateowner *so)
......
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