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) | |||
268 | kfree(nbl); | 268 | kfree(nbl); |
269 | } | 269 | } |
270 | 270 | ||
271 | static void | ||
272 | remove_blocked_locks(struct nfs4_lockowner *lo) | ||
273 | { | ||
274 | struct nfs4_client *clp = lo->lo_owner.so_client; | ||
275 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
276 | struct nfsd4_blocked_lock *nbl; | ||
277 | LIST_HEAD(reaplist); | ||
278 | |||
279 | /* Dequeue all blocked locks */ | ||
280 | spin_lock(&nn->blocked_locks_lock); | ||
281 | while (!list_empty(&lo->lo_blocked)) { | ||
282 | nbl = list_first_entry(&lo->lo_blocked, | ||
283 | struct nfsd4_blocked_lock, | ||
284 | nbl_list); | ||
285 | list_del_init(&nbl->nbl_list); | ||
286 | list_move(&nbl->nbl_lru, &reaplist); | ||
287 | } | ||
288 | spin_unlock(&nn->blocked_locks_lock); | ||
289 | |||
290 | /* Now free them */ | ||
291 | while (!list_empty(&reaplist)) { | ||
292 | nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, | ||
293 | nbl_lru); | ||
294 | list_del_init(&nbl->nbl_lru); | ||
295 | posix_unblock_lock(&nbl->nbl_lock); | ||
296 | free_blocked_lock(nbl); | ||
297 | } | ||
298 | } | ||
299 | |||
271 | static int | 300 | static int |
272 | nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) | 301 | nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) |
273 | { | 302 | { |
@@ -1866,6 +1895,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp) | |||
1866 | static void | 1895 | static void |
1867 | __destroy_client(struct nfs4_client *clp) | 1896 | __destroy_client(struct nfs4_client *clp) |
1868 | { | 1897 | { |
1898 | int i; | ||
1869 | struct nfs4_openowner *oo; | 1899 | struct nfs4_openowner *oo; |
1870 | struct nfs4_delegation *dp; | 1900 | struct nfs4_delegation *dp; |
1871 | struct list_head reaplist; | 1901 | struct list_head reaplist; |
@@ -1895,6 +1925,16 @@ __destroy_client(struct nfs4_client *clp) | |||
1895 | nfs4_get_stateowner(&oo->oo_owner); | 1925 | nfs4_get_stateowner(&oo->oo_owner); |
1896 | release_openowner(oo); | 1926 | release_openowner(oo); |
1897 | } | 1927 | } |
1928 | for (i = 0; i < OWNER_HASH_SIZE; i++) { | ||
1929 | struct nfs4_stateowner *so, *tmp; | ||
1930 | |||
1931 | list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], | ||
1932 | so_strhash) { | ||
1933 | /* Should be no openowners at this point */ | ||
1934 | WARN_ON_ONCE(so->so_is_open_owner); | ||
1935 | remove_blocked_locks(lockowner(so)); | ||
1936 | } | ||
1937 | } | ||
1898 | nfsd4_return_all_client_layouts(clp); | 1938 | nfsd4_return_all_client_layouts(clp); |
1899 | nfsd4_shutdown_callback(clp); | 1939 | nfsd4_shutdown_callback(clp); |
1900 | if (clp->cl_cb_conn.cb_xprt) | 1940 | if (clp->cl_cb_conn.cb_xprt) |
@@ -6355,6 +6395,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
6355 | } | 6395 | } |
6356 | spin_unlock(&clp->cl_lock); | 6396 | spin_unlock(&clp->cl_lock); |
6357 | free_ol_stateid_reaplist(&reaplist); | 6397 | free_ol_stateid_reaplist(&reaplist); |
6398 | remove_blocked_locks(lo); | ||
6358 | nfs4_put_stateowner(&lo->lo_owner); | 6399 | nfs4_put_stateowner(&lo->lo_owner); |
6359 | 6400 | ||
6360 | return status; | 6401 | return status; |
@@ -7140,6 +7181,8 @@ nfs4_state_destroy_net(struct net *net) | |||
7140 | } | 7181 | } |
7141 | } | 7182 | } |
7142 | 7183 | ||
7184 | WARN_ON(!list_empty(&nn->blocked_locks_lru)); | ||
7185 | |||
7143 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 7186 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
7144 | while (!list_empty(&nn->unconf_id_hashtbl[i])) { | 7187 | while (!list_empty(&nn->unconf_id_hashtbl[i])) { |
7145 | clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); | 7188 | 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) | |||
7206 | struct nfs4_delegation *dp = NULL; | 7249 | struct nfs4_delegation *dp = NULL; |
7207 | struct list_head *pos, *next, reaplist; | 7250 | struct list_head *pos, *next, reaplist; |
7208 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 7251 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
7209 | struct nfsd4_blocked_lock *nbl; | ||
7210 | 7252 | ||
7211 | cancel_delayed_work_sync(&nn->laundromat_work); | 7253 | cancel_delayed_work_sync(&nn->laundromat_work); |
7212 | locks_end_grace(&nn->nfsd4_manager); | 7254 | locks_end_grace(&nn->nfsd4_manager); |
@@ -7227,24 +7269,6 @@ nfs4_state_shutdown_net(struct net *net) | |||
7227 | nfs4_put_stid(&dp->dl_stid); | 7269 | nfs4_put_stid(&dp->dl_stid); |
7228 | } | 7270 | } |
7229 | 7271 | ||
7230 | BUG_ON(!list_empty(&reaplist)); | ||
7231 | spin_lock(&nn->blocked_locks_lock); | ||
7232 | while (!list_empty(&nn->blocked_locks_lru)) { | ||
7233 | nbl = list_first_entry(&nn->blocked_locks_lru, | ||
7234 | struct nfsd4_blocked_lock, nbl_lru); | ||
7235 | list_move(&nbl->nbl_lru, &reaplist); | ||
7236 | list_del_init(&nbl->nbl_list); | ||
7237 | } | ||
7238 | spin_unlock(&nn->blocked_locks_lock); | ||
7239 | |||
7240 | while (!list_empty(&reaplist)) { | ||
7241 | nbl = list_first_entry(&reaplist, | ||
7242 | struct nfsd4_blocked_lock, nbl_lru); | ||
7243 | list_del_init(&nbl->nbl_lru); | ||
7244 | posix_unblock_lock(&nbl->nbl_lock); | ||
7245 | free_blocked_lock(nbl); | ||
7246 | } | ||
7247 | |||
7248 | nfsd4_client_tracking_exit(net); | 7272 | nfsd4_client_tracking_exit(net); |
7249 | nfs4_state_destroy_net(net); | 7273 | nfs4_state_destroy_net(net); |
7250 | } | 7274 | } |