Skip to content

Commit 44df6f4

Browse files
daimngoChuck Lever
authored andcommitted
NFSD: add delegation reaper to react to low memory condition
The delegation reaper is called by nfsd memory shrinker's on the 'count' callback. It scans the client list and sends the courtesy CB_RECALL_ANY to the clients that hold delegations. To avoid flooding the clients with CB_RECALL_ANY requests, the delegation reaper sends only one CB_RECALL_ANY request to each client per 5 seconds. Signed-off-by: Dai Ngo <[email protected]> [ cel: moved definition of RCA4_TYPE_MASK_RDATA_DLG ] Signed-off-by: Chuck Lever <[email protected]>
1 parent 3959066 commit 44df6f4

File tree

3 files changed

+102
-4
lines changed

3 files changed

+102
-4
lines changed

fs/nfsd/nfs4state.c

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,6 +2144,7 @@ static void __free_client(struct kref *k)
21442144
kfree(clp->cl_nii_domain.data);
21452145
kfree(clp->cl_nii_name.data);
21462146
idr_destroy(&clp->cl_stateids);
2147+
kfree(clp->cl_ra);
21472148
kmem_cache_free(client_slab, clp);
21482149
}
21492150

@@ -2871,6 +2872,36 @@ static const struct tree_descr client_files[] = {
28712872
[3] = {""},
28722873
};
28732874

2875+
static int
2876+
nfsd4_cb_recall_any_done(struct nfsd4_callback *cb,
2877+
struct rpc_task *task)
2878+
{
2879+
switch (task->tk_status) {
2880+
case -NFS4ERR_DELAY:
2881+
rpc_delay(task, 2 * HZ);
2882+
return 0;
2883+
default:
2884+
return 1;
2885+
}
2886+
}
2887+
2888+
static void
2889+
nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
2890+
{
2891+
struct nfs4_client *clp = cb->cb_clp;
2892+
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
2893+
2894+
spin_lock(&nn->client_lock);
2895+
clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
2896+
put_client_renew_locked(clp);
2897+
spin_unlock(&nn->client_lock);
2898+
}
2899+
2900+
static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = {
2901+
.done = nfsd4_cb_recall_any_done,
2902+
.release = nfsd4_cb_recall_any_release,
2903+
};
2904+
28742905
static struct nfs4_client *create_client(struct xdr_netobj name,
28752906
struct svc_rqst *rqstp, nfs4_verifier *verf)
28762907
{
@@ -2908,6 +2939,14 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
29082939
free_client(clp);
29092940
return NULL;
29102941
}
2942+
clp->cl_ra = kzalloc(sizeof(*clp->cl_ra), GFP_KERNEL);
2943+
if (!clp->cl_ra) {
2944+
free_client(clp);
2945+
return NULL;
2946+
}
2947+
clp->cl_ra_time = 0;
2948+
nfsd4_init_cb(&clp->cl_ra->ra_cb, clp, &nfsd4_cb_recall_any_ops,
2949+
NFSPROC4_CLNT_CB_RECALL_ANY);
29112950
return clp;
29122951
}
29132952

@@ -4363,14 +4402,16 @@ nfsd4_init_slabs(void)
43634402
static unsigned long
43644403
nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
43654404
{
4366-
int cnt;
4405+
int count;
43674406
struct nfsd_net *nn = container_of(shrink,
43684407
struct nfsd_net, nfsd_client_shrinker);
43694408

4370-
cnt = atomic_read(&nn->nfsd_courtesy_clients);
4371-
if (cnt > 0)
4409+
count = atomic_read(&nn->nfsd_courtesy_clients);
4410+
if (!count)
4411+
count = atomic_long_read(&num_delegations);
4412+
if (count)
43724413
mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0);
4373-
return (unsigned long)cnt;
4414+
return (unsigned long)count;
43744415
}
43754416

43764417
static unsigned long
@@ -6159,6 +6200,44 @@ courtesy_client_reaper(struct nfsd_net *nn)
61596200
nfs4_process_client_reaplist(&reaplist);
61606201
}
61616202

6203+
static void
6204+
deleg_reaper(struct nfsd_net *nn)
6205+
{
6206+
struct list_head *pos, *next;
6207+
struct nfs4_client *clp;
6208+
struct list_head cblist;
6209+
6210+
INIT_LIST_HEAD(&cblist);
6211+
spin_lock(&nn->client_lock);
6212+
list_for_each_safe(pos, next, &nn->client_lru) {
6213+
clp = list_entry(pos, struct nfs4_client, cl_lru);
6214+
if (clp->cl_state != NFSD4_ACTIVE ||
6215+
list_empty(&clp->cl_delegations) ||
6216+
atomic_read(&clp->cl_delegs_in_recall) ||
6217+
test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) ||
6218+
(ktime_get_boottime_seconds() -
6219+
clp->cl_ra_time < 5)) {
6220+
continue;
6221+
}
6222+
list_add(&clp->cl_ra_cblist, &cblist);
6223+
6224+
/* release in nfsd4_cb_recall_any_release */
6225+
atomic_inc(&clp->cl_rpc_users);
6226+
set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
6227+
clp->cl_ra_time = ktime_get_boottime_seconds();
6228+
}
6229+
spin_unlock(&nn->client_lock);
6230+
6231+
while (!list_empty(&cblist)) {
6232+
clp = list_first_entry(&cblist, struct nfs4_client,
6233+
cl_ra_cblist);
6234+
list_del_init(&clp->cl_ra_cblist);
6235+
clp->cl_ra->ra_keep = 0;
6236+
clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG);
6237+
nfsd4_run_cb(&clp->cl_ra->ra_cb);
6238+
}
6239+
}
6240+
61626241
static void
61636242
nfsd4_state_shrinker_worker(struct work_struct *work)
61646243
{
@@ -6167,6 +6246,7 @@ nfsd4_state_shrinker_worker(struct work_struct *work)
61676246
nfsd_shrinker_work);
61686247

61696248
courtesy_client_reaper(nn);
6249+
deleg_reaper(nn);
61706250
}
61716251

61726252
static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)

fs/nfsd/state.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ struct nfs4_client {
368368
#define NFSD4_CLIENT_UPCALL_LOCK (5) /* upcall serialization */
369369
#define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \
370370
1 << NFSD4_CLIENT_CB_KILL)
371+
#define NFSD4_CLIENT_CB_RECALL_ANY (6)
371372
unsigned long cl_flags;
372373
const struct cred *cl_cb_cred;
373374
struct rpc_clnt *cl_cb_client;
@@ -411,6 +412,10 @@ struct nfs4_client {
411412

412413
unsigned int cl_state;
413414
atomic_t cl_delegs_in_recall;
415+
416+
struct nfsd4_cb_recall_any *cl_ra;
417+
time64_t cl_ra_time;
418+
struct list_head cl_ra_cblist;
414419
};
415420

416421
/* struct nfs4_client_reset

include/linux/nfs4.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,4 +732,17 @@ enum nfs4_setxattr_options {
732732
SETXATTR4_CREATE = 1,
733733
SETXATTR4_REPLACE = 2,
734734
};
735+
736+
enum {
737+
RCA4_TYPE_MASK_RDATA_DLG = 0,
738+
RCA4_TYPE_MASK_WDATA_DLG = 1,
739+
RCA4_TYPE_MASK_DIR_DLG = 2,
740+
RCA4_TYPE_MASK_FILE_LAYOUT = 3,
741+
RCA4_TYPE_MASK_BLK_LAYOUT = 4,
742+
RCA4_TYPE_MASK_OBJ_LAYOUT_MIN = 8,
743+
RCA4_TYPE_MASK_OBJ_LAYOUT_MAX = 9,
744+
RCA4_TYPE_MASK_OTHER_LAYOUT_MIN = 12,
745+
RCA4_TYPE_MASK_OTHER_LAYOUT_MAX = 15,
746+
};
747+
735748
#endif

0 commit comments

Comments
 (0)