2022-08-26 23:10:28

by Dai Ngo

[permalink] [raw]
Subject: [PATCH 0/2] NFSD: memory shrinker for NFSv4 clients

This patch series implements the memory shrinker for NFSv4 clients
to react to system low memory condition.

The memory shrinker's count callback is used to trigger the laundromat.
The actual work of destroying the expired clients is done by the
laundromat itself. We can not destroying the expired clients on the
memory shrinler's scan callback context to avoid possible deadlock.

By destroying the expired clients, all states associated with these
clients are also released.

---

Dai Ngo (2):
NFSD: keep track of the number of courtesy clients in the system
NFSD: add shrinker to reap courtesy clients on low memory condition

fs/nfsd/netns.h | 5 ++++
fs/nfsd/nfs4state.c | 69 ++++++++++++++++++++++++++++++++++++++++++------
fs/nfsd/nfsctl.c | 6 +++--
fs/nfsd/nfsd.h | 9 +++++--
4 files changed, 77 insertions(+), 12 deletions(-)


2022-08-26 23:11:14

by Dai Ngo

[permalink] [raw]
Subject: [PATCH 1/2] NFSD: keep track of the number of courtesy clients in the system

Add counter nfs4_courtesy_client_count to nfsd_net to keep track
of the number of courtesy clients in the system.

Signed-off-by: Dai Ngo <[email protected]>
---
fs/nfsd/netns.h | 2 ++
fs/nfsd/nfs4state.c | 20 +++++++++++++++-----
2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index ffe17743cc74..2695dff1378a 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -192,6 +192,8 @@ struct nfsd_net {

atomic_t nfs4_client_count;
int nfs4_max_clients;
+
+ atomic_t nfsd_courtesy_client_count;
};

/* Simple check to find out if a given net was properly initialized */
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c5d199d7e6b4..3d8d7ebb5b91 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -169,7 +169,8 @@ static __be32 get_client_locked(struct nfs4_client *clp)
if (is_client_expired(clp))
return nfserr_expired;
atomic_inc(&clp->cl_rpc_users);
- clp->cl_state = NFSD4_ACTIVE;
+ if (xchg(&clp->cl_state, NFSD4_ACTIVE) != NFSD4_ACTIVE)
+ atomic_add_unless(&nn->nfsd_courtesy_client_count, -1, 0);
return nfs_ok;
}

@@ -190,7 +191,8 @@ renew_client_locked(struct nfs4_client *clp)

list_move_tail(&clp->cl_lru, &nn->client_lru);
clp->cl_time = ktime_get_boottime_seconds();
- clp->cl_state = NFSD4_ACTIVE;
+ if (xchg(&clp->cl_state, NFSD4_ACTIVE) != NFSD4_ACTIVE)
+ atomic_add_unless(&nn->nfsd_courtesy_client_count, -1, 0);
}

static void put_client_renew_locked(struct nfs4_client *clp)
@@ -2233,6 +2235,8 @@ __destroy_client(struct nfs4_client *clp)
if (clp->cl_cb_conn.cb_xprt)
svc_xprt_put(clp->cl_cb_conn.cb_xprt);
atomic_add_unless(&nn->nfs4_client_count, -1, 0);
+ if (clp->cl_state != NFSD4_ACTIVE)
+ atomic_add_unless(&nn->nfsd_courtesy_client_count, -1, 0);
free_client(clp);
wake_up_all(&expiry_wq);
}
@@ -4356,6 +4360,8 @@ void nfsd4_init_leases_net(struct nfsd_net *nn)
max_clients = (u64)si.totalram * si.mem_unit / (1024 * 1024 * 1024);
max_clients *= NFS4_CLIENTS_PER_GB;
nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB);
+
+ atomic_set(&nn->nfsd_courtesy_client_count, 0);
}

static void init_nfs4_replay(struct nfs4_replay *rp)
@@ -5864,7 +5870,7 @@ static void
nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
struct laundry_time *lt)
{
- unsigned int maxreap, reapcnt = 0;
+ unsigned int oldstate, maxreap, reapcnt = 0;
struct list_head *pos, *next;
struct nfs4_client *clp;

@@ -5878,8 +5884,12 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
goto exp_client;
if (!state_expired(lt, clp->cl_time))
break;
- if (!atomic_read(&clp->cl_rpc_users))
- clp->cl_state = NFSD4_COURTESY;
+ oldstate = NFSD4_ACTIVE;
+ if (!atomic_read(&clp->cl_rpc_users)) {
+ oldstate = xchg(&clp->cl_state, NFSD4_COURTESY);
+ if (oldstate == NFSD4_ACTIVE)
+ atomic_inc(&nn->nfsd_courtesy_client_count);
+ }
if (!client_has_state(clp))
goto exp_client;
if (!nfs4_anylock_blockers(clp))
--
2.9.5