Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 645102ea authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'nfsd-4.16-1' of git://linux-nfs.org/~bfields/linux

Pull nfsd fix from Bruce Fields:
 "Just one fix for an occasional panic from Jeff Layton"

* tag 'nfsd-4.16-1' of git://linux-nfs.org/~bfields/linux:
  nfsd: remove blocked locks on client teardown
parents 32d43cd3 68ef3bc3
Loading
Loading
Loading
Loading
+43 −19
Original line number Diff line number Diff line
@@ -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);
}