From patchwork Mon Aug 29 00:47:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dai Ngo X-Patchwork-Id: 12957365 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 893F1ECAAA2 for ; Mon, 29 Aug 2022 00:47:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229487AbiH2Aru (ORCPT ); Sun, 28 Aug 2022 20:47:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34618 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229532AbiH2Art (ORCPT ); Sun, 28 Aug 2022 20:47:49 -0400 Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3CB3D33348 for ; Sun, 28 Aug 2022 17:47:48 -0700 (PDT) Received: from pps.filterd (m0246630.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 27SMnaFL022118 for ; Mon, 29 Aug 2022 00:47:47 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2022-7-12; bh=JuJzh7MywdIDV7Qq/JegSTYQ5hs9tMHamqPWU5qMuuA=; b=bb31oDdVu8Vt63HDTjVGGgu5u/v1i7Q5ksCR7lRe93ksD/dvsSxnrxILRBp96T2OQzsT FuwMA8J1HPcGWOvm6ksUHiSy7pp1Xkr9K5OIyoG1FGJ0/M+KyjtZ2xdQDIRigYt8FVNN VODa0ivo+UdRhyW+1rGxR1abEqXyXF9JQnoQl6HFuTLWS4HjsbRXOq7r8dKl7LyVmWwE q0srhq3rDZmST+qudLg80Agh/2oAEQuSYON/ycS8FCjV1NUlFPIMzD7G9PfRdjbtfZA+ uAPg1iGcghSAm0Olfzwc4P9a+9nxbtawYWMKl8vpv6A6bujJgW750eoHmdSMDUGd/06D xA== Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3j79pbt1fw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 29 Aug 2022 00:47:47 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 27T00JA0017907 for ; Mon, 29 Aug 2022 00:47:46 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3j79q1wrh4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 29 Aug 2022 00:47:46 +0000 Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 27T0hqc6003275 for ; Mon, 29 Aug 2022 00:47:45 GMT Received: from ca-common-hq.us.oracle.com (ca-common-hq.us.oracle.com [10.211.9.209]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3j79q1wrgs-2; Mon, 29 Aug 2022 00:47:45 +0000 From: Dai Ngo To: chuck.lever@oracle.com Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 1/2] NFSD: keep track of the number of courtesy clients in the system Date: Sun, 28 Aug 2022 17:47:42 -0700 Message-Id: <1661734063-22023-2-git-send-email-dai.ngo@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1661734063-22023-1-git-send-email-dai.ngo@oracle.com> References: <1661734063-22023-1-git-send-email-dai.ngo@oracle.com> X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.895,Hydra:6.0.517,FMLib:17.11.122.1 definitions=2022-08-28_16,2022-08-25_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 malwarescore=0 spamscore=0 adultscore=0 mlxscore=0 mlxlogscore=999 suspectscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2207270000 definitions=main-2208290002 X-Proofpoint-ORIG-GUID: Sm1VzJkJosSE4ySJznevIHQ9jXl3gs9P X-Proofpoint-GUID: Sm1VzJkJosSE4ySJznevIHQ9jXl3gs9P Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org 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 --- 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)) From patchwork Mon Aug 29 00:47:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dai Ngo X-Patchwork-Id: 12957366 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E6185C0502F for ; Mon, 29 Aug 2022 00:47:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229532AbiH2Aru (ORCPT ); Sun, 28 Aug 2022 20:47:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34616 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229513AbiH2Art (ORCPT ); Sun, 28 Aug 2022 20:47:49 -0400 Received: from mx0a-00069f02.pphosted.com (mx0a-00069f02.pphosted.com [205.220.165.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AA3D832EC8 for ; Sun, 28 Aug 2022 17:47:47 -0700 (PDT) Received: from pps.filterd (m0246629.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 27SNVYUX027736 for ; Mon, 29 Aug 2022 00:47:47 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2022-7-12; bh=GZOGufkW15jWXMiWyhx2BbHd93J53WvKHqFl+q8RScs=; b=hv2mQlEiutioBLv+eJK1O2+5S/iAeSlwutmoEHLGcDv4jvosiWMEjzg97VDeFjo2IEIF Vep7rujYlYP3nTpyEDXGRQXSkzcLMmmCz5N2dw/HZPmAjelG/u+VPXfT9nmzmriy6MZJ Ty00HAsM3rIyMHQoCqUwEclItpnTKwZvLhYTRJu1wpUy7pDjMqH64Mlm270ne8Pi0AB8 4byOIIGQW6vpdeMF6uvq5EWfKQ0yco4GNftCqtig9JrF4Ws0Ywu81XNqduhmjgfBUcLc egZRnNxNyzyHpHreFnabVLBtMPcFj1pMB5gTHP9Pmhw1kbkLdf686hOMjyqV5vIuy5cu AA== Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.appoci.oracle.com [147.154.114.232]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3j7b59syj4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 29 Aug 2022 00:47:47 +0000 Received: from pps.filterd (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 27SNwRmh018665 for ; Mon, 29 Aug 2022 00:47:46 GMT Received: from pps.reinject (localhost [127.0.0.1]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3j79q1wrh7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 29 Aug 2022 00:47:46 +0000 Received: from phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 27T0hqc8003275 for ; Mon, 29 Aug 2022 00:47:46 GMT Received: from ca-common-hq.us.oracle.com (ca-common-hq.us.oracle.com [10.211.9.209]) by phxpaimrmta02.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTP id 3j79q1wrgs-3; Mon, 29 Aug 2022 00:47:46 +0000 From: Dai Ngo To: chuck.lever@oracle.com Cc: linux-nfs@vger.kernel.org Subject: [PATCH v2 2/2] NFSD: add shrinker to reap courtesy clients on low memory condition Date: Sun, 28 Aug 2022 17:47:43 -0700 Message-Id: <1661734063-22023-3-git-send-email-dai.ngo@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1661734063-22023-1-git-send-email-dai.ngo@oracle.com> References: <1661734063-22023-1-git-send-email-dai.ngo@oracle.com> X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.895,Hydra:6.0.517,FMLib:17.11.122.1 definitions=2022-08-28_16,2022-08-25_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 malwarescore=0 spamscore=0 adultscore=0 mlxscore=0 mlxlogscore=999 suspectscore=0 phishscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2207270000 definitions=main-2208290002 X-Proofpoint-ORIG-GUID: QtZJMEXHWBpyZ6MWMFg4Uffhr8xv6odn X-Proofpoint-GUID: QtZJMEXHWBpyZ6MWMFg4Uffhr8xv6odn Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org Add the courtesy client shrinker to react to low memory condition triggered by the memory shrinker. On the shrinker's count callback, we increment a callback counter and return the number of outstanding courtesy clients. When the laundromat runs, it checks if this counter is not zero and starts reaping old courtesy clients. The maximum number of clients to be reaped is limited to NFSD_CIENT_MAX_TRIM_PER_RUN (128). This limit is to prevent the laundromat from spending too much time reaping the clients and not processing other tasks in a timely manner. The laundromat is rescheduled to run sooner if it detects low low memory condition and there are more clients to reap. On the shrinker's scan callback, we return the number of clients That were reaped since the last scan callback. We can not reap the clients on the scan callback context since destroying the client might require call into the underlying filesystem or other subsystems which might allocate memory which can cause deadlock. Signed-off-by: Dai Ngo --- fs/nfsd/netns.h | 3 +++ fs/nfsd/nfs4state.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- fs/nfsd/nfsctl.c | 6 ++++-- fs/nfsd/nfsd.h | 9 +++++++-- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 2695dff1378a..2a604951623f 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -194,6 +194,9 @@ struct nfsd_net { int nfs4_max_clients; atomic_t nfsd_courtesy_client_count; + atomic_t nfsd_client_shrinker_cb_count; + atomic_t nfsd_client_shrinker_reapcount; + struct shrinker nfsd_client_shrinker; }; /* 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 3d8d7ebb5b91..9d5a20f0c3c4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4341,7 +4341,39 @@ nfsd4_init_slabs(void) return -ENOMEM; } -void nfsd4_init_leases_net(struct nfsd_net *nn) +static unsigned long +nfsd_courtesy_client_count(struct shrinker *shrink, struct shrink_control *sc) +{ + struct nfsd_net *nn = container_of(shrink, + struct nfsd_net, nfsd_client_shrinker); + + atomic_inc(&nn->nfsd_client_shrinker_cb_count); + return (unsigned long)atomic_read(&nn->nfsd_courtesy_client_count); +} + +static unsigned long +nfsd_courtesy_client_scan(struct shrinker *shrink, struct shrink_control *sc) +{ + struct nfsd_net *nn = container_of(shrink, + struct nfsd_net, nfsd_client_shrinker); + unsigned long cnt; + + cnt = atomic_read(&nn->nfsd_client_shrinker_reapcount); + atomic_set(&nn->nfsd_client_shrinker_reapcount, 0); + return cnt; +} + +static int +nfsd_register_client_shrinker(struct nfsd_net *nn) +{ + nn->nfsd_client_shrinker.scan_objects = nfsd_courtesy_client_scan; + nn->nfsd_client_shrinker.count_objects = nfsd_courtesy_client_count; + nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS; + return register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client"); +} + +int +nfsd4_init_leases_net(struct nfsd_net *nn) { struct sysinfo si; u64 max_clients; @@ -4362,6 +4394,8 @@ void nfsd4_init_leases_net(struct nfsd_net *nn) nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB); atomic_set(&nn->nfsd_courtesy_client_count, 0); + atomic_set(&nn->nfsd_client_shrinker_cb_count, 0); + return nfsd_register_client_shrinker(nn); } static void init_nfs4_replay(struct nfs4_replay *rp) @@ -5870,12 +5904,17 @@ static void nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, struct laundry_time *lt) { - unsigned int oldstate, maxreap, reapcnt = 0; + unsigned int oldstate, maxreap = 0, reapcnt = 0; + int cb_cnt; struct list_head *pos, *next; struct nfs4_client *clp; - maxreap = (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) ? - NFSD_CLIENT_MAX_TRIM_PER_RUN : 0; + cb_cnt = atomic_read(&nn->nfsd_client_shrinker_cb_count); + if (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients || + cb_cnt) { + maxreap = NFSD_CLIENT_MAX_TRIM_PER_RUN; + atomic_set(&nn->nfsd_client_shrinker_cb_count, 0); + } INIT_LIST_HEAD(reaplist); spin_lock(&nn->client_lock); list_for_each_safe(pos, next, &nn->client_lru) { @@ -5902,6 +5941,8 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, } } spin_unlock(&nn->client_lock); + if (cb_cnt) + atomic_add(reapcnt, &nn->nfsd_client_shrinker_reapcount); } static time64_t @@ -5942,6 +5983,8 @@ nfs4_laundromat(struct nfsd_net *nn) list_del_init(&clp->cl_lru); expire_client(clp); } + if (atomic_read(&nn->nfsd_client_shrinker_cb_count) > 0) + lt.new_timeo = NFSD_LAUNDROMAT_MINTIMEOUT; spin_lock(&state_lock); list_for_each_safe(pos, next, &nn->del_recall_lru) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 917fa1892fd2..597a26ad4183 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1481,11 +1481,12 @@ static __net_init int nfsd_init_net(struct net *net) goto out_idmap_error; nn->nfsd_versions = NULL; nn->nfsd4_minorversions = NULL; + retval = nfsd4_init_leases_net(nn); + if (retval) + goto out_drc_error; retval = nfsd_reply_cache_init(nn); if (retval) goto out_drc_error; - nfsd4_init_leases_net(nn); - get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key)); seqlock_init(&nn->writeverf_lock); @@ -1507,6 +1508,7 @@ static __net_exit void nfsd_exit_net(struct net *net) nfsd_idmap_shutdown(net); nfsd_export_shutdown(net); nfsd_netns_free_versions(net_generic(net, nfsd_net_id)); + nfsd4_leases_net_shutdown(nn); } static struct pernet_operations nfsd_net_ops = { diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 57a468ed85c3..7e05ab7a3532 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -498,7 +498,11 @@ extern void unregister_cld_notifier(void); extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn); #endif -extern void nfsd4_init_leases_net(struct nfsd_net *nn); +extern int nfsd4_init_leases_net(struct nfsd_net *nn); +static inline void nfsd4_leases_net_shutdown(struct nfsd_net *nn) +{ + unregister_shrinker(&nn->nfsd_client_shrinker); +}; #else /* CONFIG_NFSD_V4 */ static inline int nfsd4_is_junction(struct dentry *dentry) @@ -506,7 +510,8 @@ static inline int nfsd4_is_junction(struct dentry *dentry) return 0; } -static inline void nfsd4_init_leases_net(struct nfsd_net *nn) {}; +static inline int nfsd4_init_leases_net(struct nfsd_net *nn) { return 0; }; +static inline void nfsd4_leases_net_shutdown(struct nfsd_net *nn) { }; #define register_cld_notifier() 0 #define unregister_cld_notifier() do { } while(0)