Commit d0ea542a authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] kNFSd: unlock-on-close fix

From: NeilBrown <neilb@cse.unsw.edu.au>

add the bookeeping necessary to remove all locks held by an nfsv4 lockowner
upon CLOSE, or upon state expiration.  calls locks_remove_posix().

replace list_del_init() with list_del on nfsv4 state structures that are
being reaped.
parent e9361d50
...@@ -772,6 +772,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str ...@@ -772,6 +772,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
INIT_LIST_HEAD(&sop->so_strhash); INIT_LIST_HEAD(&sop->so_strhash);
INIT_LIST_HEAD(&sop->so_perclient); INIT_LIST_HEAD(&sop->so_perclient);
INIT_LIST_HEAD(&sop->so_perfilestate); INIT_LIST_HEAD(&sop->so_perfilestate);
INIT_LIST_HEAD(&sop->so_perlockowner); /* not used */
list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]); list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
list_add(&sop->so_perclient, &clp->cl_perclient); list_add(&sop->so_perclient, &clp->cl_perclient);
...@@ -789,14 +790,29 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str ...@@ -789,14 +790,29 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
return sop; return sop;
} }
static void
release_stateid_lockowner(struct nfs4_stateid *open_stp)
{
struct nfs4_stateowner *lock_sop;
while (!list_empty(&open_stp->st_perlockowner)) {
lock_sop = list_entry(open_stp->st_perlockowner.next,
struct nfs4_stateowner, so_perlockowner);
/* list_del(&open_stp->st_perlockowner); */
BUG_ON(lock_sop->so_is_open_owner);
release_stateowner(lock_sop);
}
}
static void static void
release_stateowner(struct nfs4_stateowner *sop) release_stateowner(struct nfs4_stateowner *sop)
{ {
struct nfs4_stateid *stp; struct nfs4_stateid *stp;
list_del_init(&sop->so_idhash); list_del(&sop->so_idhash);
list_del_init(&sop->so_strhash); list_del(&sop->so_strhash);
list_del_init(&sop->so_perclient); list_del(&sop->so_perclient);
list_del(&sop->so_perlockowner);
del_perclient++; del_perclient++;
while (!list_empty(&sop->so_perfilestate)) { while (!list_empty(&sop->so_perfilestate)) {
stp = list_entry(sop->so_perfilestate.next, stp = list_entry(sop->so_perfilestate.next,
...@@ -815,6 +831,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateow ...@@ -815,6 +831,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateow
INIT_LIST_HEAD(&stp->st_hash); INIT_LIST_HEAD(&stp->st_hash);
INIT_LIST_HEAD(&stp->st_perfilestate); INIT_LIST_HEAD(&stp->st_perfilestate);
INIT_LIST_HEAD(&stp->st_perlockowner);
INIT_LIST_HEAD(&stp->st_perfile); INIT_LIST_HEAD(&stp->st_perfile);
list_add(&stp->st_hash, &stateid_hashtbl[hashval]); list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
list_add(&stp->st_perfilestate, &sop->so_perfilestate); list_add(&stp->st_perfilestate, &sop->so_perfilestate);
...@@ -833,17 +850,21 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateow ...@@ -833,17 +850,21 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateow
static void static void
release_stateid(struct nfs4_stateid *stp, int flags) { release_stateid(struct nfs4_stateid *stp, int flags) {
list_del_init(&stp->st_hash); list_del(&stp->st_hash);
list_del_perfile++; list_del_perfile++;
list_del_init(&stp->st_perfile); list_del(&stp->st_perfile);
list_del_init(&stp->st_perfilestate); list_del(&stp->st_perfilestate);
if((stp->st_vfs_set) && (flags & OPEN_STATE)) { if((stp->st_vfs_set) && (flags & OPEN_STATE)) {
release_stateid_lockowner(stp);
nfsd_close(&stp->st_vfs_file); nfsd_close(&stp->st_vfs_file);
vfsclose++; vfsclose++;
dput(stp->st_vfs_file.f_dentry); dput(stp->st_vfs_file.f_dentry);
mntput(stp->st_vfs_file.f_vfsmnt); mntput(stp->st_vfs_file.f_vfsmnt);
} else if ((stp->st_vfs_set) && (flags & LOCK_STATE)) {
struct file *filp = &stp->st_vfs_file;
locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
} }
/* should use a slab cache */
kfree(stp); kfree(stp);
stp = NULL; stp = NULL;
} }
...@@ -852,7 +873,7 @@ static void ...@@ -852,7 +873,7 @@ static void
release_file(struct nfs4_file *fp) release_file(struct nfs4_file *fp)
{ {
free_file++; free_file++;
list_del_init(&fp->fi_hash); list_del(&fp->fi_hash);
iput(fp->fi_inode); iput(fp->fi_inode);
kfree(fp); kfree(fp);
} }
...@@ -1723,7 +1744,7 @@ find_lockstateowner_str(unsigned int hashval, struct xdr_netobj *owner, clientid ...@@ -1723,7 +1744,7 @@ find_lockstateowner_str(unsigned int hashval, struct xdr_netobj *owner, clientid
*/ */
static struct nfs4_stateowner * static struct nfs4_stateowner *
alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_lock *lock) { alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) {
struct nfs4_stateowner *sop; struct nfs4_stateowner *sop;
struct nfs4_replay *rp; struct nfs4_replay *rp;
unsigned int idhashval; unsigned int idhashval;
...@@ -1735,9 +1756,11 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str ...@@ -1735,9 +1756,11 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
INIT_LIST_HEAD(&sop->so_strhash); INIT_LIST_HEAD(&sop->so_strhash);
INIT_LIST_HEAD(&sop->so_perclient); INIT_LIST_HEAD(&sop->so_perclient);
INIT_LIST_HEAD(&sop->so_perfilestate); INIT_LIST_HEAD(&sop->so_perfilestate);
INIT_LIST_HEAD(&sop->so_perlockowner);
list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]); list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]); list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
list_add(&sop->so_perclient, &clp->cl_perclient); list_add(&sop->so_perclient, &clp->cl_perclient);
list_add(&sop->so_perlockowner, &open_stp->st_perlockowner);
add_perclient++; add_perclient++;
sop->so_is_open_owner = 0; sop->so_is_open_owner = 0;
sop->so_id = current_ownerid++; sop->so_id = current_ownerid++;
...@@ -1761,10 +1784,10 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc ...@@ -1761,10 +1784,10 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
if ((stp = kmalloc(sizeof(struct nfs4_stateid), if ((stp = kmalloc(sizeof(struct nfs4_stateid),
GFP_KERNEL)) == NULL) GFP_KERNEL)) == NULL)
goto out; goto out;
INIT_LIST_HEAD(&stp->st_hash); INIT_LIST_HEAD(&stp->st_hash);
INIT_LIST_HEAD(&stp->st_perfile); INIT_LIST_HEAD(&stp->st_perfile);
INIT_LIST_HEAD(&stp->st_perfilestate); INIT_LIST_HEAD(&stp->st_perfilestate);
INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */
list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]); list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);
list_add(&stp->st_perfile, &fp->fi_perfile); list_add(&stp->st_perfile, &fp->fi_perfile);
list_add_perfile++; list_add_perfile++;
...@@ -1853,8 +1876,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock ...@@ -1853,8 +1876,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
&lock->v.new.clientid, &lock_sop)) &lock->v.new.clientid, &lock_sop))
goto out; goto out;
status = nfserr_resource; status = nfserr_resource;
if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
open_sop->so_client, lock)))
goto out; goto out;
if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner,
fp, open_stp)) == NULL) fp, open_stp)) == NULL)
......
...@@ -130,12 +130,15 @@ struct nfs4_replay { ...@@ -130,12 +130,15 @@ struct nfs4_replay {
* so_perfilestate: heads the list of nfs4_stateid (either open or lock) * so_perfilestate: heads the list of nfs4_stateid (either open or lock)
* and is used to ensure no dangling nfs4_stateid references when we * and is used to ensure no dangling nfs4_stateid references when we
* release a stateowner. * release a stateowner.
* so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when
* close is called to reap associated byte-range locks
*/ */
struct nfs4_stateowner { struct nfs4_stateowner {
struct list_head so_idhash; /* hash by so_id */ struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */ struct list_head so_strhash; /* hash by op_name */
struct list_head so_perclient; /* nfs4_client->cl_perclient */ struct list_head so_perclient; /* nfs4_client->cl_perclient */
struct list_head so_perfilestate; /* list: nfs4_stateid */ struct list_head so_perfilestate; /* list: nfs4_stateid */
struct list_head so_perlockowner; /* nfs4_stateid->st_perlockowner */
int so_is_open_owner; /* 1=openowner,0=lockowner */ int so_is_open_owner; /* 1=openowner,0=lockowner */
u32 so_id; u32 so_id;
struct nfs4_client * so_client; struct nfs4_client * so_client;
...@@ -166,6 +169,7 @@ struct nfs4_file { ...@@ -166,6 +169,7 @@ struct nfs4_file {
* st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry * st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry
* st_perfile: file_hashtbl[] entry. * st_perfile: file_hashtbl[] entry.
* st_perfile_state: nfs4_stateowner->so_perfilestate * st_perfile_state: nfs4_stateowner->so_perfilestate
* st_perlockowner: (open stateid) list of lock nfs4_stateowners
* st_share_access: used only for open stateid * st_share_access: used only for open stateid
* st_share_deny: used only for open stateid * st_share_deny: used only for open stateid
*/ */
...@@ -174,6 +178,7 @@ struct nfs4_stateid { ...@@ -174,6 +178,7 @@ struct nfs4_stateid {
struct list_head st_hash; struct list_head st_hash;
struct list_head st_perfile; struct list_head st_perfile;
struct list_head st_perfilestate; struct list_head st_perfilestate;
struct list_head st_perlockowner;
struct nfs4_stateowner * st_stateowner; struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file; struct nfs4_file * st_file;
stateid_t st_stateid; stateid_t st_stateid;
......
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