diff mbox series

[v2,3/3] NFSD: drop TCP connections when NFSv4 client enters courtesy state

Message ID 1713841953-19594-4-git-send-email-dai.ngo@oracle.com (mailing list archive)
State New
Headers show
Series [v2,1/3] NFSD: mark cl_cb_state as NFSD4_CB_DOWN if cl_cb_client is NULL | expand

Commit Message

Dai Ngo April 23, 2024, 3:12 a.m. UTC
When a v4.0 client enters courtesy state all its v4 states remain valid
and its fore and back channel TCP connection remained in ESTABLISHED
state until the TCP keep-alive mechanism timed out and shuts down the
back channel connection. The fore channel connection remains in ESTABLISHED
state between 6 - 12 minutes before the NFSv4 server's 6-minute idle timer
(svc_age_temp_xprts) shuts down the idle connection.

Since NFSv4.1 mount uses the same TCP connection for both fore and back
channel connection there is no TCP keep-alive packet sent from the server
to the client. The server's idle timer does not shutdown an idle v4.1
connection since the svc_xprt->xpt_ref is more than 1:  1 for sv_tempsocks
list, one for the session's nfsd4_conn and 1 for the back channel.

To conserve system resources in large configuration where there are lots
of idle clients, this patch drops the fore and back channel connection
of NFSv4 client as soon as it enters the courtesy state. The fore and back
channel connections are automatically re-established when the courtesy
client reconnects.

Signed-off-by: Dai Ngo <dai.ngo@oracle.com>
---
 fs/nfsd/nfs4state.c | 32 ++++++++++++++++++++++++++++++--
 fs/nfsd/state.h     |  1 +
 2 files changed, 31 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a20c2c9d7d45..d9f6e7dbb2e1 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -6369,6 +6369,22 @@  nfs4_anylock_blockers(struct nfs4_client *clp)
 	return false;
 }
 
+static void nfsd4_drop_conns(struct nfsd_net *nn, struct nfs4_client *clp)
+{
+	struct svc_xprt *xprt;
+
+	/* stop requeueing callback in nfsd4_run_cb_work */
+	nfsd4_kill_callback(clp);
+
+	spin_lock_bh(&nn->nfsd_serv->sv_lock);
+	list_for_each_entry(xprt, &nn->nfsd_serv->sv_tempsocks, xpt_list) {
+		if (rpc_cmp_addr((struct sockaddr *)&clp->cl_addr,
+				(struct sockaddr *)&xprt->xpt_remote))
+			svc_xprt_deferred_close(xprt);
+	}
+	spin_unlock_bh(&nn->nfsd_serv->sv_lock);
+}
+
 static void
 nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
 				struct laundry_time *lt)
@@ -6376,10 +6392,13 @@  nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
 	unsigned int maxreap, reapcnt = 0;
 	struct list_head *pos, *next;
 	struct nfs4_client *clp;
+	struct list_head conn_reaplist;
+	bool drop;
 
 	maxreap = (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) ?
 			NFSD_CLIENT_MAX_TRIM_PER_RUN : 0;
 	INIT_LIST_HEAD(reaplist);
+	INIT_LIST_HEAD(&conn_reaplist);
 	spin_lock(&nn->client_lock);
 	list_for_each_safe(pos, next, &nn->client_lru) {
 		clp = list_entry(pos, struct nfs4_client, cl_lru);
@@ -6387,16 +6406,22 @@  nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
 			goto exp_client;
 		if (!state_expired(lt, clp->cl_time))
 			break;
+		drop = false;
 		if (!atomic_read(&clp->cl_rpc_users)) {
-			if (clp->cl_state == NFSD4_ACTIVE)
+			if (clp->cl_state == NFSD4_ACTIVE) {
 				atomic_inc(&nn->nfsd_courtesy_clients);
+				drop = true;
+			}
 			clp->cl_state = NFSD4_COURTESY;
 		}
 		if (!client_has_state(clp))
 			goto exp_client;
 		if (!nfs4_anylock_blockers(clp))
-			if (reapcnt >= maxreap)
+			if (reapcnt >= maxreap) {
+				if (drop)
+					list_add(&clp->cl_conn_lru, &conn_reaplist);
 				continue;
+			}
 exp_client:
 		if (!mark_client_expired_locked(clp)) {
 			list_add(&clp->cl_lru, reaplist);
@@ -6404,6 +6429,9 @@  nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
 		}
 	}
 	spin_unlock(&nn->client_lock);
+
+	list_for_each_entry(clp, &conn_reaplist, cl_conn_lru)
+		nfsd4_drop_conns(nn, clp);
 }
 
 static void
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index cde05c26afd8..fe7b5bd6460b 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -420,6 +420,7 @@  struct nfs4_client {
 	int			cl_cb_state;
 	struct nfsd4_callback	cl_cb_null;
 	struct nfsd4_session	*cl_cb_session;
+	struct list_head	cl_conn_lru;
 
 	/* for all client information that callback code might need: */
 	spinlock_t		cl_lock;