如何迁移内核模块中的任意进程?
How to migrate an arbitrary process in a kernel module?
我正在编写一个遍历所有进程的内核模块(使用 for_each_process
宏),现在,我想将满足特定条件的进程迁移到新的 NUMA 节点或处理器。我在 sched.h
:
中找到了一些定义为 extern
的函数
extern void sched_setnuma(struct task_struct *p, int node);
extern int migrate_task_to(struct task_struct *p, int cpu);
extern int migrate_swap(struct task_struct *, struct task_struct *);
但是不能使用它们因为内核已经编译了。
有什么方法可以使用这些功能或类似的功能来实现任务迁移吗?
编辑
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/sched.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mohammad Siavashi");
MODULE_DESCRIPTION("This is a test module");
int (*migrate_task_to_func)(struct task_struct *p, int cpu);
void start(void)
{
struct task_struct *t;
for_each_process(t)
{
if (strcmp(t->comm, "stream_task") == 0)
{
migrate_task_to_func(t, 2);
}
}
}
static int __init hello_init(void)
{
migrate_task_to_func = (void *)kallsyms_lookup_name("migrate_task_to");
start();
return 0;
}
static void __exit hello_cleanup(void)
{
printk(KERN_INFO "Cleaning up module.\n");
}
module_init(hello_init);
module_exit(hello_cleanup);
你可以用kallsyms_lookup_name
找出来再用。如果kallsyms_lookup_name
没有导出(kernel>=5.7),可以先用kprobe找
例如:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
void (*sched_setnuma_func)(struct task_struct *p, int node);
int (*migrate_task_to_func)(struct task_struct *p, int cpu);
int (*migrate_swap_func)(struct task_struct *, struct task_struct *);
static int __init test_init(void)
{
unsigned long (*kallsyms_lookup_name_func)(const char *name);
struct kprobe kp = { .symbol_name = "kallsyms_lookup_name", };
register_kprobe(&kp);
kallsyms_lookup_name_func = (void *)kp.addr;
unregister_kprobe(&kp);
if (kallsyms_lookup_name_func) {
sched_setnuma_func = (void *)kallsyms_lookup_name_func("sched_setnuma");
migrate_task_to_func = (void *)kallsyms_lookup_name_func("migrate_task_to");
migrate_swap_func = (void *)kallsyms_lookup_name_func("migrate_swap");
}
printk("sched_setnuma_func: %p\n", sched_setnuma_func);
printk("migrate_task_to_func: %p\n", migrate_task_to_func);
printk("migrate_swap_func: %p\n", migrate_swap_func);
return 0;
}
static void __exit test_exit(void)
{
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
我正在编写一个遍历所有进程的内核模块(使用 for_each_process
宏),现在,我想将满足特定条件的进程迁移到新的 NUMA 节点或处理器。我在 sched.h
:
extern
的函数
extern void sched_setnuma(struct task_struct *p, int node);
extern int migrate_task_to(struct task_struct *p, int cpu);
extern int migrate_swap(struct task_struct *, struct task_struct *);
但是不能使用它们因为内核已经编译了。
有什么方法可以使用这些功能或类似的功能来实现任务迁移吗?
编辑
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/sched.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mohammad Siavashi");
MODULE_DESCRIPTION("This is a test module");
int (*migrate_task_to_func)(struct task_struct *p, int cpu);
void start(void)
{
struct task_struct *t;
for_each_process(t)
{
if (strcmp(t->comm, "stream_task") == 0)
{
migrate_task_to_func(t, 2);
}
}
}
static int __init hello_init(void)
{
migrate_task_to_func = (void *)kallsyms_lookup_name("migrate_task_to");
start();
return 0;
}
static void __exit hello_cleanup(void)
{
printk(KERN_INFO "Cleaning up module.\n");
}
module_init(hello_init);
module_exit(hello_cleanup);
你可以用kallsyms_lookup_name
找出来再用。如果kallsyms_lookup_name
没有导出(kernel>=5.7),可以先用kprobe找
例如:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
void (*sched_setnuma_func)(struct task_struct *p, int node);
int (*migrate_task_to_func)(struct task_struct *p, int cpu);
int (*migrate_swap_func)(struct task_struct *, struct task_struct *);
static int __init test_init(void)
{
unsigned long (*kallsyms_lookup_name_func)(const char *name);
struct kprobe kp = { .symbol_name = "kallsyms_lookup_name", };
register_kprobe(&kp);
kallsyms_lookup_name_func = (void *)kp.addr;
unregister_kprobe(&kp);
if (kallsyms_lookup_name_func) {
sched_setnuma_func = (void *)kallsyms_lookup_name_func("sched_setnuma");
migrate_task_to_func = (void *)kallsyms_lookup_name_func("migrate_task_to");
migrate_swap_func = (void *)kallsyms_lookup_name_func("migrate_swap");
}
printk("sched_setnuma_func: %p\n", sched_setnuma_func);
printk("migrate_task_to_func: %p\n", migrate_task_to_func);
printk("migrate_swap_func: %p\n", migrate_swap_func);
return 0;
}
static void __exit test_exit(void)
{
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");