| From 570f40098349db55cd5b737d58fd1da5af1817e2 Mon Sep 17 00:00:00 2001 |
| From: Roberto Bergantinos Corpas <rbergant@redhat.com> |
| Date: Thu, 25 Apr 2019 15:36:51 +0200 |
| Subject: NFS: make nfs_match_client killable |
| |
| [ Upstream commit 950a578c6128c2886e295b9c7ecb0b6b22fcc92b ] |
| |
| Actually we don't do anything with return value from |
| nfs_wait_client_init_complete in nfs_match_client, as a |
| consequence if we get a fatal signal and client is not |
| fully initialised, we'll loop to "again" label |
| |
| This has been proven to cause soft lockups on some scenarios |
| (no-carrier but configured network interfaces) |
| |
| Signed-off-by: Roberto Bergantinos Corpas <rbergant@redhat.com> |
| Reviewed-by: Benjamin Coddington <bcodding@redhat.com> |
| Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/nfs/client.c | 7 ++++++- |
| 1 file changed, 6 insertions(+), 1 deletion(-) |
| |
| diff --git a/fs/nfs/client.c b/fs/nfs/client.c |
| index 90d71fda65cec..350cfa561e0e8 100644 |
| --- a/fs/nfs/client.c |
| +++ b/fs/nfs/client.c |
| @@ -284,6 +284,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat |
| struct nfs_client *clp; |
| const struct sockaddr *sap = data->addr; |
| struct nfs_net *nn = net_generic(data->net, nfs_net_id); |
| + int error; |
| |
| again: |
| list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { |
| @@ -296,8 +297,10 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat |
| if (clp->cl_cons_state > NFS_CS_READY) { |
| refcount_inc(&clp->cl_count); |
| spin_unlock(&nn->nfs_client_lock); |
| - nfs_wait_client_init_complete(clp); |
| + error = nfs_wait_client_init_complete(clp); |
| nfs_put_client(clp); |
| + if (error < 0) |
| + return ERR_PTR(error); |
| spin_lock(&nn->nfs_client_lock); |
| goto again; |
| } |
| @@ -407,6 +410,8 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) |
| clp = nfs_match_client(cl_init); |
| if (clp) { |
| spin_unlock(&nn->nfs_client_lock); |
| + if (IS_ERR(clp)) |
| + return clp; |
| if (new) |
| new->rpc_ops->free_client(new); |
| return nfs_found_client(cl_init, clp); |
| -- |
| 2.20.1 |
| |