Commit f385f7d2 authored by Dai Ngo's avatar Dai Ngo Committed by Chuck Lever
Browse files

NFSD: register/unregister of nfsd-client shrinker at nfsd startup/shutdown time



Currently the nfsd-client shrinker is registered and unregistered at
the time the nfsd module is loaded and unloaded. The problem with this
is the shrinker is being registered before all of the relevant fields
in nfsd_net are initialized when nfsd is started. This can lead to an
oops when memory is low and the shrinker is called while nfsd is not
running.

This patch moves the  register/unregister of nfsd-client shrinker from
module load/unload time to nfsd startup/shutdown time.

Fixes: 44df6f43 ("NFSD: add delegation reaper to react to low memory condition")
Reported-by: default avatarMike Galbraith <efault@gmx.de>
Signed-off-by: default avatarDai Ngo <dai.ngo@oracle.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent e6cf91b7
Loading
Loading
Loading
Loading
+11 −11
Original line number Diff line number Diff line
@@ -4421,7 +4421,7 @@ nfsd4_state_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc)
	return SHRINK_STOP;
}

int
void
nfsd4_init_leases_net(struct nfsd_net *nn)
{
	struct sysinfo si;
@@ -4443,16 +4443,6 @@ 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_clients, 0);
	nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
	nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
	nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;
	return register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client");
}

void
nfsd4_leases_net_shutdown(struct nfsd_net *nn)
{
	unregister_shrinker(&nn->nfsd_client_shrinker);
}

static void init_nfs4_replay(struct nfs4_replay *rp)
@@ -8069,8 +8059,17 @@ static int nfs4_state_create_net(struct net *net)
	INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
	get_net(net);

	nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan;
	nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count;
	nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS;

	if (register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client"))
		goto err_shrinker;
	return 0;

err_shrinker:
	put_net(net);
	kfree(nn->sessionid_hashtbl);
err_sessionid:
	kfree(nn->unconf_id_hashtbl);
err_unconf_id:
@@ -8163,6 +8162,7 @@ nfs4_state_shutdown_net(struct net *net)
	struct list_head *pos, *next, reaplist;
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);

	unregister_shrinker(&nn->nfsd_client_shrinker);
	cancel_delayed_work_sync(&nn->laundromat_work);
	locks_end_grace(&nn->nfsd4_manager);

+1 −6
Original line number Diff line number Diff line
@@ -1457,9 +1457,7 @@ 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;
	nfsd4_init_leases_net(nn);
	retval = nfsd_reply_cache_init(nn);
	if (retval)
		goto out_cache_error;
@@ -1469,8 +1467,6 @@ static __net_init int nfsd_init_net(struct net *net)
	return 0;

out_cache_error:
	nfsd4_leases_net_shutdown(nn);
out_drc_error:
	nfsd_idmap_shutdown(net);
out_idmap_error:
	nfsd_export_shutdown(net);
@@ -1486,7 +1482,6 @@ 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 = {
+2 −4
Original line number Diff line number Diff line
@@ -504,8 +504,7 @@ extern void unregister_cld_notifier(void);
extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn);
#endif

extern int nfsd4_init_leases_net(struct nfsd_net *nn);
extern void nfsd4_leases_net_shutdown(struct nfsd_net *nn);
extern void nfsd4_init_leases_net(struct nfsd_net *nn);

#else /* CONFIG_NFSD_V4 */
static inline int nfsd4_is_junction(struct dentry *dentry)
@@ -513,8 +512,7 @@ static inline int nfsd4_is_junction(struct dentry *dentry)
	return 0;
}

static inline int nfsd4_init_leases_net(struct nfsd_net *nn) { return 0; };
static inline void nfsd4_leases_net_shutdown(struct nfsd_net *nn) {};
static inline void nfsd4_init_leases_net(struct nfsd_net *nn) { };

#define register_cld_notifier() 0
#define unregister_cld_notifier() do { } while(0)