kthread: NUMA aware kthread_create_on_node()
All kthreads being created from a single helper task, they all use memory from a single node for their kernel stack and task struct. This patch suite creates kthread_create_on_node(), adding a 'cpu' parameter to parameters already used by kthread_create(). This parameter serves in allocating memory for the new kthread on its memory node if possible. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Acked-by: David S. Miller <davem@davemloft.net> Reviewed-by: Andi Kleen <ak@linux.intel.com> Acked-by: Rusty Russell <rusty@rustcorp.com.au> Cc: Tejun Heo <tj@kernel.org> Cc: Tony Luck <tony.luck@intel.com> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: David Howells <dhowells@redhat.com> Cc: <linux-arch@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
b6a84016bd
commit
207205a2ba
4 changed files with 38 additions and 11 deletions
|
@ -4,10 +4,15 @@
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
struct task_struct *kthread_create(int (*threadfn)(void *data),
|
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
|
||||||
void *data,
|
void *data,
|
||||||
const char namefmt[], ...)
|
int node,
|
||||||
__attribute__((format(printf, 3, 4)));
|
const char namefmt[], ...)
|
||||||
|
__attribute__((format(printf, 4, 5)));
|
||||||
|
|
||||||
|
#define kthread_create(threadfn, data, namefmt, arg...) \
|
||||||
|
kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kthread_run - create and wake a thread.
|
* kthread_run - create and wake a thread.
|
||||||
|
@ -34,6 +39,7 @@ void *kthread_data(struct task_struct *k);
|
||||||
|
|
||||||
int kthreadd(void *unused);
|
int kthreadd(void *unused);
|
||||||
extern struct task_struct *kthreadd_task;
|
extern struct task_struct *kthreadd_task;
|
||||||
|
extern int tsk_fork_get_node(struct task_struct *tsk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simple work processor based on kthread.
|
* Simple work processor based on kthread.
|
||||||
|
|
|
@ -1471,6 +1471,7 @@ struct task_struct {
|
||||||
#ifdef CONFIG_NUMA
|
#ifdef CONFIG_NUMA
|
||||||
struct mempolicy *mempolicy; /* Protected by alloc_lock */
|
struct mempolicy *mempolicy; /* Protected by alloc_lock */
|
||||||
short il_next;
|
short il_next;
|
||||||
|
short pref_node_fork;
|
||||||
#endif
|
#endif
|
||||||
atomic_t fs_excl; /* holding fs exclusive resources */
|
atomic_t fs_excl; /* holding fs exclusive resources */
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <linux/tracehook.h>
|
#include <linux/tracehook.h>
|
||||||
#include <linux/futex.h>
|
#include <linux/futex.h>
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
#include <linux/task_io_accounting_ops.h>
|
#include <linux/task_io_accounting_ops.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
|
@ -254,7 +255,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
|
||||||
struct task_struct *tsk;
|
struct task_struct *tsk;
|
||||||
struct thread_info *ti;
|
struct thread_info *ti;
|
||||||
unsigned long *stackend;
|
unsigned long *stackend;
|
||||||
int node = numa_node_id();
|
int node = tsk_fork_get_node(orig);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
prepare_to_copy(orig);
|
prepare_to_copy(orig);
|
||||||
|
|
|
@ -27,6 +27,7 @@ struct kthread_create_info
|
||||||
/* Information passed to kthread() from kthreadd. */
|
/* Information passed to kthread() from kthreadd. */
|
||||||
int (*threadfn)(void *data);
|
int (*threadfn)(void *data);
|
||||||
void *data;
|
void *data;
|
||||||
|
int node;
|
||||||
|
|
||||||
/* Result passed back to kthread_create() from kthreadd. */
|
/* Result passed back to kthread_create() from kthreadd. */
|
||||||
struct task_struct *result;
|
struct task_struct *result;
|
||||||
|
@ -98,10 +99,23 @@ static int kthread(void *_create)
|
||||||
do_exit(ret);
|
do_exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called from do_fork() to get node information for about to be created task */
|
||||||
|
int tsk_fork_get_node(struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_NUMA
|
||||||
|
if (tsk == kthreadd_task)
|
||||||
|
return tsk->pref_node_fork;
|
||||||
|
#endif
|
||||||
|
return numa_node_id();
|
||||||
|
}
|
||||||
|
|
||||||
static void create_kthread(struct kthread_create_info *create)
|
static void create_kthread(struct kthread_create_info *create)
|
||||||
{
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
|
#ifdef CONFIG_NUMA
|
||||||
|
current->pref_node_fork = create->node;
|
||||||
|
#endif
|
||||||
/* We want our own signal handler (we take no signals by default). */
|
/* We want our own signal handler (we take no signals by default). */
|
||||||
pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
|
pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
|
@ -111,15 +125,18 @@ static void create_kthread(struct kthread_create_info *create)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kthread_create - create a kthread.
|
* kthread_create_on_node - create a kthread.
|
||||||
* @threadfn: the function to run until signal_pending(current).
|
* @threadfn: the function to run until signal_pending(current).
|
||||||
* @data: data ptr for @threadfn.
|
* @data: data ptr for @threadfn.
|
||||||
|
* @node: memory node number.
|
||||||
* @namefmt: printf-style name for the thread.
|
* @namefmt: printf-style name for the thread.
|
||||||
*
|
*
|
||||||
* Description: This helper function creates and names a kernel
|
* Description: This helper function creates and names a kernel
|
||||||
* thread. The thread will be stopped: use wake_up_process() to start
|
* thread. The thread will be stopped: use wake_up_process() to start
|
||||||
* it. See also kthread_run().
|
* it. See also kthread_run().
|
||||||
*
|
*
|
||||||
|
* If thread is going to be bound on a particular cpu, give its node
|
||||||
|
* in @node, to get NUMA affinity for kthread stack, or else give -1.
|
||||||
* When woken, the thread will run @threadfn() with @data as its
|
* When woken, the thread will run @threadfn() with @data as its
|
||||||
* argument. @threadfn() can either call do_exit() directly if it is a
|
* argument. @threadfn() can either call do_exit() directly if it is a
|
||||||
* standalone thread for which noone will call kthread_stop(), or
|
* standalone thread for which noone will call kthread_stop(), or
|
||||||
|
@ -129,15 +146,17 @@ static void create_kthread(struct kthread_create_info *create)
|
||||||
*
|
*
|
||||||
* Returns a task_struct or ERR_PTR(-ENOMEM).
|
* Returns a task_struct or ERR_PTR(-ENOMEM).
|
||||||
*/
|
*/
|
||||||
struct task_struct *kthread_create(int (*threadfn)(void *data),
|
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
|
||||||
void *data,
|
void *data,
|
||||||
const char namefmt[],
|
int node,
|
||||||
...)
|
const char namefmt[],
|
||||||
|
...)
|
||||||
{
|
{
|
||||||
struct kthread_create_info create;
|
struct kthread_create_info create;
|
||||||
|
|
||||||
create.threadfn = threadfn;
|
create.threadfn = threadfn;
|
||||||
create.data = data;
|
create.data = data;
|
||||||
|
create.node = node;
|
||||||
init_completion(&create.done);
|
init_completion(&create.done);
|
||||||
|
|
||||||
spin_lock(&kthread_create_lock);
|
spin_lock(&kthread_create_lock);
|
||||||
|
@ -164,7 +183,7 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
|
||||||
}
|
}
|
||||||
return create.result;
|
return create.result;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kthread_create);
|
EXPORT_SYMBOL(kthread_create_on_node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kthread_bind - bind a just-created kthread to a cpu.
|
* kthread_bind - bind a just-created kthread to a cpu.
|
||||||
|
|
Loading…
Add table
Reference in a new issue