Re: [PATCH 1/1] NFSD: Fix memory shortage problem with Courteous server.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> On Jun 22, 2022, at 2:15 PM, Dai Ngo <dai.ngo@xxxxxxxxxx> wrote:
> 
> Currently the idle timeout for courtesy client is fixed at 1 day.
> If there are lots of courtesy clients remain in the system it can
> cause memory resource shortage that effects the operations of other
> modules in the kernel. This problem can be observed by running pynfs
> nfs4.0 CID5 test in a loop. Eventually system runs out of memory
> and rpc.gssd fails to add new watch:
> 
> rpc.gssd[3851]: ERROR: inotify_add_watch failed for nfsd4_cb/clnt6c2e:
> 		No space left on device
> 
> and also alloc_inode fails with out of memory:
> 
> Call Trace:
> <TASK>
>        dump_stack_lvl+0x33/0x42
>        dump_header+0x4a/0x1ed
>        oom_kill_process+0x80/0x10d
>        out_of_memory+0x237/0x25f
>        __alloc_pages_slowpath.constprop.0+0x617/0x7b6
>        __alloc_pages+0x132/0x1e3
>        alloc_slab_page+0x15/0x33
>        allocate_slab+0x78/0x1ab
>        ? alloc_inode+0x38/0x8d
>        ___slab_alloc+0x2af/0x373
>        ? alloc_inode+0x38/0x8d
>        ? slab_pre_alloc_hook.constprop.0+0x9f/0x158
>        ? alloc_inode+0x38/0x8d
>        __slab_alloc.constprop.0+0x1c/0x24
>        kmem_cache_alloc_lru+0x8c/0x142
>        alloc_inode+0x38/0x8d
>        iget_locked+0x60/0x126
>        kernfs_get_inode+0x18/0x105
>        kernfs_iop_lookup+0x6d/0xbc
>        __lookup_slow+0xb7/0xf9
>        lookup_slow+0x3a/0x52
>        walk_component+0x90/0x100
>        ? inode_permission+0x87/0x128
>        link_path_walk.part.0.constprop.0+0x266/0x2ea
>        ? path_init+0x101/0x2f2
>        path_lookupat+0x4c/0xfa
>        filename_lookup+0x63/0xd7
>        ? getname_flags+0x32/0x17a
>        ? kmem_cache_alloc+0x11f/0x144
>        ? getname_flags+0x16c/0x17a
>        user_path_at_empty+0x37/0x4b
>        do_readlinkat+0x61/0x102
>        __x64_sys_readlinkat+0x18/0x1b
>        do_syscall_64+0x57/0x72
>        entry_SYSCALL_64_after_hwframe+0x46/0xb0
>        RIP: 0033:0x7fce5410340e
> 
> This patch adds a simple policy to dynamically adjust the idle
> timeout based on the percentage of available memory in the system
> as follow:
> 
> . > 70%    : unlimited. Courtesy clients are allowed to remain valid
>             as long as memory availability is above 70%
> . 60% - 70%:  1 day.
> . 50% - 60%:  1hr
> . 40% - 50%:  30mins
> . 30% - 40%:  15mins
> . < 30%:      disable. Expire all existing courtesy clients and donot
>              allow new courtesey client

I thought our plan was to add a shrinker to do this.


> Signed-off-by: Dai Ngo <dai.ngo@xxxxxxxxxx>
> ---
> fs/nfsd/nfs4state.c | 41 +++++++++++++++++++++++++++++++++++++++--
> fs/nfsd/nfsd.h      |  5 ++++-
> 2 files changed, 43 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 9409a0dc1b76..a7feea9d07cf 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -5788,12 +5788,47 @@ nfs4_anylock_blockers(struct nfs4_client *clp)
> 	return false;
> }
> 
> +static bool
> +nfs4_allow_courtesy_client(struct nfsd_net *nn, unsigned int *idle_timeout)
> +{
> +	unsigned long avail;
> +	bool ret = true;
> +	unsigned int courtesy_expire = 0;
> +	struct sysinfo si;
> +
> +	si_meminfo(&si);
> +	avail = (si.freeram * 10) / (si.totalram - si.totalhigh);
> +	switch (avail) {
> +	case 7: case 8: case 9: case 10:
> +		courtesy_expire = 0;		/* unlimit */
> +		break;
> +	case 6:
> +		courtesy_expire = NFSD_COURTESY_CLIENT_TO_1DAY;
> +		break;
> +	case 5:
> +		courtesy_expire = NFSD_COURTESY_CLIENT_TO_1HR;
> +		break;
> +	case 4:
> +		courtesy_expire = NFSD_COURTESY_CLIENT_TO_30MINS;
> +		break;
> +	case 3:
> +		courtesy_expire = NFSD_COURTESY_CLIENT_TO_15MINS;
> +		break;
> +	default:
> +		ret = false;			/* disallow CC */
> +	}
> +	*idle_timeout = courtesy_expire;
> +	return ret;
> +}
> +
> static void
> nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
> 				struct laundry_time *lt)
> {
> 	struct list_head *pos, *next;
> 	struct nfs4_client *clp;
> +	unsigned int exptime;
> +	bool allow_cc = nfs4_allow_courtesy_client(nn, &exptime);
> 
> 	INIT_LIST_HEAD(reaplist);
> 	spin_lock(&nn->client_lock);
> @@ -5803,11 +5838,13 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist,
> 			goto exp_client;
> 		if (!state_expired(lt, clp->cl_time))
> 			break;
> +		if (!allow_cc)
> +			goto exp_client;
> 		if (!atomic_read(&clp->cl_rpc_users))
> 			clp->cl_state = NFSD4_COURTESY;
> 		if (!client_has_state(clp) ||
> -				ktime_get_boottime_seconds() >=
> -				(clp->cl_time + NFSD_COURTESY_CLIENT_TIMEOUT))
> +				(exptime && ktime_get_boottime_seconds() >=
> +				(clp->cl_time + exptime)))
> 			goto exp_client;
> 		if (nfs4_anylock_blockers(clp)) {
> exp_client:
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index 847b482155ae..9d4a5708f852 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -340,7 +340,10 @@ void		nfsd_lockd_shutdown(void);
> #define COMPOUND_ERR_SLACK_SPACE	16     /* OP_SETATTR */
> 
> #define NFSD_LAUNDROMAT_MINTIMEOUT      1   /* seconds */
> -#define	NFSD_COURTESY_CLIENT_TIMEOUT	(24 * 60 * 60)	/* seconds */
> +#define	NFSD_COURTESY_CLIENT_TO_1DAY	(24 * 60 * 60)	/* seconds */
> +#define	NFSD_COURTESY_CLIENT_TO_1HR	(60 * 60)
> +#define	NFSD_COURTESY_CLIENT_TO_30MINS	(30 * 60)
> +#define	NFSD_COURTESY_CLIENT_TO_15MINS	(15 * 60)
> 
> /*
>  * The following attributes are currently not supported by the NFSv4 server:
> -- 
> 2.9.5
> 

--
Chuck Lever







[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux