Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f609266b authored by Trond Myklebust's avatar Trond Myklebust Committed by Greg Kroah-Hartman
Browse files

NFSv4: Fix callback server shutdown



commit ed6473ddc704a2005b9900ca08e236ebb2d8540a upstream.

We want to use kthread_stop() in order to ensure the threads are
shut down before we tear down the nfs_callback_info in nfs_callback_down.

Tested-and-reviewed-by: default avatarKinglong Mee <kinglongmee@gmail.com>
Reported-by: default avatarKinglong Mee <kinglongmee@gmail.com>
Fixes: bb6aeba7 ("NFSv4.x: Switch to using svc_set_num_threads()...")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
Cc: Jan Hudoba <kernel@jahu.sk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d9f9b835
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -75,7 +75,10 @@ nfs4_callback_svc(void *vrqstp)

	set_freezable();

	while (!kthread_should_stop()) {
	while (!kthread_freezable_should_stop(NULL)) {

		if (signal_pending(current))
			flush_signals(current);
		/*
		 * Listen for a request on the socket
		 */
@@ -84,6 +87,8 @@ nfs4_callback_svc(void *vrqstp)
			continue;
		svc_process(rqstp);
	}
	svc_exit_thread(rqstp);
	module_put_and_exit(0);
	return 0;
}

@@ -102,9 +107,10 @@ nfs41_callback_svc(void *vrqstp)

	set_freezable();

	while (!kthread_should_stop()) {
		if (try_to_freeze())
			continue;
	while (!kthread_freezable_should_stop(NULL)) {

		if (signal_pending(current))
			flush_signals(current);

		prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
		spin_lock_bh(&serv->sv_cb_lock);
@@ -120,11 +126,13 @@ nfs41_callback_svc(void *vrqstp)
				error);
		} else {
			spin_unlock_bh(&serv->sv_cb_lock);
			if (!kthread_should_stop())
				schedule();
			finish_wait(&serv->sv_cb_waitq, &wq);
		}
		flush_signals(current);
	}
	svc_exit_thread(rqstp);
	module_put_and_exit(0);
	return 0;
}

@@ -220,14 +228,14 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
static struct svc_serv_ops nfs40_cb_sv_ops = {
	.svo_function		= nfs4_callback_svc,
	.svo_enqueue_xprt	= svc_xprt_do_enqueue,
	.svo_setup		= svc_set_num_threads,
	.svo_setup		= svc_set_num_threads_sync,
	.svo_module		= THIS_MODULE,
};
#if defined(CONFIG_NFS_V4_1)
static struct svc_serv_ops nfs41_cb_sv_ops = {
	.svo_function		= nfs41_callback_svc,
	.svo_enqueue_xprt	= svc_xprt_do_enqueue,
	.svo_setup		= svc_set_num_threads,
	.svo_setup		= svc_set_num_threads_sync,
	.svo_module		= THIS_MODULE,
};

+1 −0
Original line number Diff line number Diff line
@@ -470,6 +470,7 @@ void svc_pool_map_put(void);
struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
			struct svc_serv_ops *);
int		   svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
int		   svc_set_num_threads_sync(struct svc_serv *, struct svc_pool *, int);
int		   svc_pool_stats_open(struct svc_serv *serv, struct file *file);
void		   svc_destroy(struct svc_serv *);
void		   svc_shutdown_net(struct svc_serv *, struct net *);
+38 −0
Original line number Diff line number Diff line
@@ -795,6 +795,44 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
}
EXPORT_SYMBOL_GPL(svc_set_num_threads);

/* destroy old threads */
static int
svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
{
	struct task_struct *task;
	unsigned int state = serv->sv_nrthreads-1;

	/* destroy old threads */
	do {
		task = choose_victim(serv, pool, &state);
		if (task == NULL)
			break;
		kthread_stop(task);
		nrservs++;
	} while (nrservs < 0);
	return 0;
}

int
svc_set_num_threads_sync(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
{
	if (pool == NULL) {
		/* The -1 assumes caller has done a svc_get() */
		nrservs -= (serv->sv_nrthreads-1);
	} else {
		spin_lock_bh(&pool->sp_lock);
		nrservs -= pool->sp_nrthreads;
		spin_unlock_bh(&pool->sp_lock);
	}

	if (nrservs > 0)
		return svc_start_kthreads(serv, pool, nrservs);
	if (nrservs < 0)
		return svc_stop_kthreads(serv, pool, nrservs);
	return 0;
}
EXPORT_SYMBOL_GPL(svc_set_num_threads_sync);

/*
 * Called from a server thread as it's exiting. Caller must hold the "service
 * mutex" for the service.