diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
| -rw-r--r-- | fs/nfsd/nfs4state.c | 62 | 
1 files changed, 43 insertions, 19 deletions
| diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 150521c9671b..61b770e39809 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -268,6 +268,35 @@ free_blocked_lock(struct nfsd4_blocked_lock *nbl)  	kfree(nbl);  } +static void +remove_blocked_locks(struct nfs4_lockowner *lo) +{ +	struct nfs4_client *clp = lo->lo_owner.so_client; +	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); +	struct nfsd4_blocked_lock *nbl; +	LIST_HEAD(reaplist); + +	/* Dequeue all blocked locks */ +	spin_lock(&nn->blocked_locks_lock); +	while (!list_empty(&lo->lo_blocked)) { +		nbl = list_first_entry(&lo->lo_blocked, +					struct nfsd4_blocked_lock, +					nbl_list); +		list_del_init(&nbl->nbl_list); +		list_move(&nbl->nbl_lru, &reaplist); +	} +	spin_unlock(&nn->blocked_locks_lock); + +	/* Now free them */ +	while (!list_empty(&reaplist)) { +		nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, +					nbl_lru); +		list_del_init(&nbl->nbl_lru); +		posix_unblock_lock(&nbl->nbl_lock); +		free_blocked_lock(nbl); +	} +} +  static int  nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task)  { @@ -1866,6 +1895,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)  static void  __destroy_client(struct nfs4_client *clp)  { +	int i;  	struct nfs4_openowner *oo;  	struct nfs4_delegation *dp;  	struct list_head reaplist; @@ -1895,6 +1925,16 @@ __destroy_client(struct nfs4_client *clp)  		nfs4_get_stateowner(&oo->oo_owner);  		release_openowner(oo);  	} +	for (i = 0; i < OWNER_HASH_SIZE; i++) { +		struct nfs4_stateowner *so, *tmp; + +		list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], +					 so_strhash) { +			/* Should be no openowners at this point */ +			WARN_ON_ONCE(so->so_is_open_owner); +			remove_blocked_locks(lockowner(so)); +		} +	}  	nfsd4_return_all_client_layouts(clp);  	nfsd4_shutdown_callback(clp);  	if (clp->cl_cb_conn.cb_xprt) @@ -6355,6 +6395,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,  	}  	spin_unlock(&clp->cl_lock);  	free_ol_stateid_reaplist(&reaplist); +	remove_blocked_locks(lo);  	nfs4_put_stateowner(&lo->lo_owner);  	return status; @@ -7140,6 +7181,8 @@ nfs4_state_destroy_net(struct net *net)  		}  	} +	WARN_ON(!list_empty(&nn->blocked_locks_lru)); +  	for (i = 0; i < CLIENT_HASH_SIZE; i++) {  		while (!list_empty(&nn->unconf_id_hashtbl[i])) {  			clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); @@ -7206,7 +7249,6 @@ nfs4_state_shutdown_net(struct net *net)  	struct nfs4_delegation *dp = NULL;  	struct list_head *pos, *next, reaplist;  	struct nfsd_net *nn = net_generic(net, nfsd_net_id); -	struct nfsd4_blocked_lock *nbl;  	cancel_delayed_work_sync(&nn->laundromat_work);  	locks_end_grace(&nn->nfsd4_manager); @@ -7227,24 +7269,6 @@ nfs4_state_shutdown_net(struct net *net)  		nfs4_put_stid(&dp->dl_stid);  	} -	BUG_ON(!list_empty(&reaplist)); -	spin_lock(&nn->blocked_locks_lock); -	while (!list_empty(&nn->blocked_locks_lru)) { -		nbl = list_first_entry(&nn->blocked_locks_lru, -					struct nfsd4_blocked_lock, nbl_lru); -		list_move(&nbl->nbl_lru, &reaplist); -		list_del_init(&nbl->nbl_list); -	} -	spin_unlock(&nn->blocked_locks_lock); - -	while (!list_empty(&reaplist)) { -		nbl = list_first_entry(&reaplist, -					struct nfsd4_blocked_lock, nbl_lru); -		list_del_init(&nbl->nbl_lru); -		posix_unblock_lock(&nbl->nbl_lock); -		free_blocked_lock(nbl); -	} -  	nfsd4_client_tracking_exit(net);  	nfs4_state_destroy_net(net);  } | 

