NFSD: add delegation reaper to react to low memory condition
[ Upstream commit 44df6f439a1790a5f602e3842879efa88f346672 ] 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 <dai.ngo@oracle.com> [ cel: moved definition of RCA4_TYPE_MASK_RDATA_DLG ] Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
d92173345d
commit
eb1f5350b0
3 changed files with 102 additions and 4 deletions
|
@ -2144,6 +2144,7 @@ static void __free_client(struct kref *k)
|
|||
kfree(clp->cl_nii_domain.data);
|
||||
kfree(clp->cl_nii_name.data);
|
||||
idr_destroy(&clp->cl_stateids);
|
||||
kfree(clp->cl_ra);
|
||||
kmem_cache_free(client_slab, clp);
|
||||
}
|
||||
|
||||
|
@ -2871,6 +2872,36 @@ static const struct tree_descr client_files[] = {
|
|||
[3] = {""},
|
||||
};
|
||||
|
||||
static int
|
||||
nfsd4_cb_recall_any_done(struct nfsd4_callback *cb,
|
||||
struct rpc_task *task)
|
||||
{
|
||||
switch (task->tk_status) {
|
||||
case -NFS4ERR_DELAY:
|
||||
rpc_delay(task, 2 * HZ);
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
|
||||
{
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
|
||||
put_client_renew_locked(clp);
|
||||
spin_unlock(&nn->client_lock);
|
||||
}
|
||||
|
||||
static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = {
|
||||
.done = nfsd4_cb_recall_any_done,
|
||||
.release = nfsd4_cb_recall_any_release,
|
||||
};
|
||||
|
||||
static struct nfs4_client *create_client(struct xdr_netobj name,
|
||||
struct svc_rqst *rqstp, nfs4_verifier *verf)
|
||||
{
|
||||
|
@ -2908,6 +2939,14 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
|
|||
free_client(clp);
|
||||
return NULL;
|
||||
}
|
||||
clp->cl_ra = kzalloc(sizeof(*clp->cl_ra), GFP_KERNEL);
|
||||
if (!clp->cl_ra) {
|
||||
free_client(clp);
|
||||
return NULL;
|
||||
}
|
||||
clp->cl_ra_time = 0;
|
||||
nfsd4_init_cb(&clp->cl_ra->ra_cb, clp, &nfsd4_cb_recall_any_ops,
|
||||
NFSPROC4_CLNT_CB_RECALL_ANY);
|
||||
return clp;
|
||||
}
|
||||
|
||||
|
@ -4363,14 +4402,16 @@ out:
|
|||
static unsigned long
|
||||
nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
|
||||
{
|
||||
int cnt;
|
||||
int count;
|
||||
struct nfsd_net *nn = container_of(shrink,
|
||||
struct nfsd_net, nfsd_client_shrinker);
|
||||
|
||||
cnt = atomic_read(&nn->nfsd_courtesy_clients);
|
||||
if (cnt > 0)
|
||||
count = atomic_read(&nn->nfsd_courtesy_clients);
|
||||
if (!count)
|
||||
count = atomic_long_read(&num_delegations);
|
||||
if (count)
|
||||
mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0);
|
||||
return (unsigned long)cnt;
|
||||
return (unsigned long)count;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
|
@ -6162,6 +6203,44 @@ courtesy_client_reaper(struct nfsd_net *nn)
|
|||
nfs4_process_client_reaplist(&reaplist);
|
||||
}
|
||||
|
||||
static void
|
||||
deleg_reaper(struct nfsd_net *nn)
|
||||
{
|
||||
struct list_head *pos, *next;
|
||||
struct nfs4_client *clp;
|
||||
struct list_head cblist;
|
||||
|
||||
INIT_LIST_HEAD(&cblist);
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_safe(pos, next, &nn->client_lru) {
|
||||
clp = list_entry(pos, struct nfs4_client, cl_lru);
|
||||
if (clp->cl_state != NFSD4_ACTIVE ||
|
||||
list_empty(&clp->cl_delegations) ||
|
||||
atomic_read(&clp->cl_delegs_in_recall) ||
|
||||
test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) ||
|
||||
(ktime_get_boottime_seconds() -
|
||||
clp->cl_ra_time < 5)) {
|
||||
continue;
|
||||
}
|
||||
list_add(&clp->cl_ra_cblist, &cblist);
|
||||
|
||||
/* release in nfsd4_cb_recall_any_release */
|
||||
atomic_inc(&clp->cl_rpc_users);
|
||||
set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
|
||||
clp->cl_ra_time = ktime_get_boottime_seconds();
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
while (!list_empty(&cblist)) {
|
||||
clp = list_first_entry(&cblist, struct nfs4_client,
|
||||
cl_ra_cblist);
|
||||
list_del_init(&clp->cl_ra_cblist);
|
||||
clp->cl_ra->ra_keep = 0;
|
||||
clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG);
|
||||
nfsd4_run_cb(&clp->cl_ra->ra_cb);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd4_state_shrinker_worker(struct work_struct *work)
|
||||
{
|
||||
|
@ -6170,6 +6249,7 @@ nfsd4_state_shrinker_worker(struct work_struct *work)
|
|||
nfsd_shrinker_work);
|
||||
|
||||
courtesy_client_reaper(nn);
|
||||
deleg_reaper(nn);
|
||||
}
|
||||
|
||||
static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp)
|
||||
|
|
|
@ -368,6 +368,7 @@ struct nfs4_client {
|
|||
#define NFSD4_CLIENT_UPCALL_LOCK (5) /* upcall serialization */
|
||||
#define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \
|
||||
1 << NFSD4_CLIENT_CB_KILL)
|
||||
#define NFSD4_CLIENT_CB_RECALL_ANY (6)
|
||||
unsigned long cl_flags;
|
||||
const struct cred *cl_cb_cred;
|
||||
struct rpc_clnt *cl_cb_client;
|
||||
|
@ -411,6 +412,10 @@ struct nfs4_client {
|
|||
|
||||
unsigned int cl_state;
|
||||
atomic_t cl_delegs_in_recall;
|
||||
|
||||
struct nfsd4_cb_recall_any *cl_ra;
|
||||
time64_t cl_ra_time;
|
||||
struct list_head cl_ra_cblist;
|
||||
};
|
||||
|
||||
/* struct nfs4_client_reset
|
||||
|
|
|
@ -717,4 +717,17 @@ enum nfs4_setxattr_options {
|
|||
SETXATTR4_CREATE = 1,
|
||||
SETXATTR4_REPLACE = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
RCA4_TYPE_MASK_RDATA_DLG = 0,
|
||||
RCA4_TYPE_MASK_WDATA_DLG = 1,
|
||||
RCA4_TYPE_MASK_DIR_DLG = 2,
|
||||
RCA4_TYPE_MASK_FILE_LAYOUT = 3,
|
||||
RCA4_TYPE_MASK_BLK_LAYOUT = 4,
|
||||
RCA4_TYPE_MASK_OBJ_LAYOUT_MIN = 8,
|
||||
RCA4_TYPE_MASK_OBJ_LAYOUT_MAX = 9,
|
||||
RCA4_TYPE_MASK_OTHER_LAYOUT_MIN = 12,
|
||||
RCA4_TYPE_MASK_OTHER_LAYOUT_MAX = 15,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue