diff mbox series

nfsd: Make NFS client_id increment atomic to avoid race condition

Message ID 20240315124053.24116-1-muhammad.zahid@nokia.com (mailing list archive)
State New
Headers show
Series nfsd: Make NFS client_id increment atomic to avoid race condition | expand

Commit Message

Muhammad Asim Zahid March 15, 2024, 12:39 p.m. UTC
The following log messages show conflict in clientid
       [err] kernel: [   16.228090] NFS: Server fct reports our clientid is in use
       [warning] kernel: [   16.228102] NFS: state manager: lease expired failed on NFSv4 server fct with error 1
       [warning] kernel: [   16.228102] NFS: state manager: lease expired failed on NFSv4 server fct with error 1

The increment to client_verifier counter and client_id counter is
set to atomic so as to avoid race condition which causes the
aforementioned error.

Change-Id: Ic0fa8c14a8bba043ae8882f6750f512bb5f3aac1
---
 fs/nfsd/netns.h     | 4 ++--
 fs/nfsd/nfs4state.c | 4 ++--
 fs/nfsd/nfsctl.c    | 6 +++---
 3 files changed, 7 insertions(+), 7 deletions(-)

Comments

Chuck Lever March 15, 2024, 2:29 p.m. UTC | #1
On Fri, Mar 15, 2024 at 01:39:57PM +0100, Muhammad Asim Zahid wrote:
> The following log messages show conflict in clientid
>        [err] kernel: [   16.228090] NFS: Server fct reports our clientid is in use
>        [warning] kernel: [   16.228102] NFS: state manager: lease expired failed on NFSv4 server fct with error 1
>        [warning] kernel: [   16.228102] NFS: state manager: lease expired failed on NFSv4 server fct with error 1
> 
> The increment to client_verifier counter and client_id counter is
> set to atomic so as to avoid race condition which causes the
> aforementioned error.

These client messages are in response to NFS4ERR_CLID_INUSE. This
condition is not because the server did not increment the client ID.
It's because there actually is another client (possibly more than
one) using the same clientid string and authentication principal.

Refer to:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/filesystems/nfs/client-identifier.rst


> Change-Id: Ic0fa8c14a8bba043ae8882f6750f512bb5f3aac1
> ---
>  fs/nfsd/netns.h     | 4 ++--
>  fs/nfsd/nfs4state.c | 4 ++--
>  fs/nfsd/nfsctl.c    | 6 +++---
>  3 files changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
> index 935c1028c217..67b5aa1516e2 100644
> --- a/fs/nfsd/netns.h
> +++ b/fs/nfsd/netns.h
> @@ -119,8 +119,8 @@ struct nfsd_net {
>  	unsigned int max_connections;
>  
>  	u32 clientid_base;
> -	u32 clientid_counter;
> -	u32 clverifier_counter;
> +	atomic_t clientid_counter;
> +	atomic_t clverifier_counter;
>  
>  	struct svc_serv *nfsd_serv;
>  
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 9b660491f393..d67a6a593f59 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -2321,14 +2321,14 @@ static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
>  	 * __force to keep sparse happy
>  	 */
>  	verf[0] = (__force __be32)(u32)ktime_get_real_seconds();
> -	verf[1] = (__force __be32)nn->clverifier_counter++;
> +	verf[1] = (__force __be32)atomic_inc_return(&(nn->clverifier_counter));
>  	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
>  }
>  
>  static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
>  {
>  	clp->cl_clientid.cl_boot = (u32)nn->boot_time;
> -	clp->cl_clientid.cl_id = nn->clientid_counter++;
> +	clp->cl_clientid.cl_id = atomic_inc_return(&(nn->clientid_counter));
>  	gen_confirm(clp, nn);
>  }
>  
> diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
> index cb73c1292562..a9ef86ee7250 100644
> --- a/fs/nfsd/nfsctl.c
> +++ b/fs/nfsd/nfsctl.c
> @@ -1481,10 +1481,10 @@ static __net_init int nfsd_init_net(struct net *net)
>  	nn->nfsd4_grace = 90;
>  	nn->somebody_reclaimed = false;
>  	nn->track_reclaim_completes = false;
> -	nn->clverifier_counter = prandom_u32();
> +	atomic_set(&(nn->clverifier_counter), prandom_u32());
>  	nn->clientid_base = prandom_u32();
> -	nn->clientid_counter = nn->clientid_base + 1;
> -	nn->s2s_cp_cl_id = nn->clientid_counter++;
> +	atomic_set(&(nn->clientid_counter), nn->clientid_base + 1);
> +	nn->s2s_cp_cl_id = atomic_inc_return(&(nn->clientid_counter));
>  
>  	atomic_set(&nn->ntf_refcnt, 0);
>  	init_waitqueue_head(&nn->ntf_wq);
> -- 
> 2.42.0
>
diff mbox series

Patch

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index 935c1028c217..67b5aa1516e2 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -119,8 +119,8 @@  struct nfsd_net {
 	unsigned int max_connections;
 
 	u32 clientid_base;
-	u32 clientid_counter;
-	u32 clverifier_counter;
+	atomic_t clientid_counter;
+	atomic_t clverifier_counter;
 
 	struct svc_serv *nfsd_serv;
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9b660491f393..d67a6a593f59 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2321,14 +2321,14 @@  static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
 	 * __force to keep sparse happy
 	 */
 	verf[0] = (__force __be32)(u32)ktime_get_real_seconds();
-	verf[1] = (__force __be32)nn->clverifier_counter++;
+	verf[1] = (__force __be32)atomic_inc_return(&(nn->clverifier_counter));
 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
 }
 
 static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
 {
 	clp->cl_clientid.cl_boot = (u32)nn->boot_time;
-	clp->cl_clientid.cl_id = nn->clientid_counter++;
+	clp->cl_clientid.cl_id = atomic_inc_return(&(nn->clientid_counter));
 	gen_confirm(clp, nn);
 }
 
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index cb73c1292562..a9ef86ee7250 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1481,10 +1481,10 @@  static __net_init int nfsd_init_net(struct net *net)
 	nn->nfsd4_grace = 90;
 	nn->somebody_reclaimed = false;
 	nn->track_reclaim_completes = false;
-	nn->clverifier_counter = prandom_u32();
+	atomic_set(&(nn->clverifier_counter), prandom_u32());
 	nn->clientid_base = prandom_u32();
-	nn->clientid_counter = nn->clientid_base + 1;
-	nn->s2s_cp_cl_id = nn->clientid_counter++;
+	atomic_set(&(nn->clientid_counter), nn->clientid_base + 1);
+	nn->s2s_cp_cl_id = atomic_inc_return(&(nn->clientid_counter));
 
 	atomic_set(&nn->ntf_refcnt, 0);
 	init_waitqueue_head(&nn->ntf_wq);