当前位置: 首页 > 面试题库 >

使用Cpuset将内核模块隔离到特定的内核

应涵容
2023-03-14
问题内容

从用户空间,我们可以使用cpuset实际
隔离系统中 的特定核心,并仅对该核心执行一个特定进程。

我正在尝试对内核模块执行相同的操作。因此,我希望模块在隔离的内核中执行。换句话说: 如何cpuset在内核模块内部使用?*

在我的内核模块中使用linux / cpuset.h不起作用。所以,我有一个像这样的模块:

#include <linux/module.h>
#include <linux/cpuset.h>

...
#ifdef CONFIG_CPUSETS
    printk(KERN_INFO, "cpusets is enabled!");
#endif
cpuset_init(); // this function is declared in cpuset.h
...

尝试加载此模块时,我收到dmesg以下消息cpusets is enabled!。但是我也收到消息Unknown symbol cpu_init (err 0)

同样,我尝试使用sched_setaffinityfrom
linux/sched.h来将所有正在运行的过程移至特定的内核,然后将模块运行至隔离的内核。我收到了相同的错误消息:Unknown symbolsched_setaffinity (err0)。我猜我得到了“未知符号”,因为这些功能EXPORT_SYMBOL在内核中没有。所以我去,并试图调用`sys_sched_setaffinity

此外,我不是在寻找使用的解决方案,该解决方案isolcpus是在引导时设置的。我只想加载模块,然后进行隔离操作。

  • (更确切地说,我希望其内核线程在 隔离的 内核中执行。我知道我可以使用亲和力将线程绑定到特定的内核,但这不能保证我将被运行在其上的其他进程隔离这些内核。 )

问题答案:

因此,我希望模块在隔离的内核中执行。

实际上隔离了我们系统中的特定核心并仅对该核心执行一个特定过程

这是一个有效的源代码,使用内核3.16在Debian机器上进行了编译和测试。我将描述如何首先加载和卸载以及传递的参数的含义。

所有资源都可以在github上找到…

https://github.com/harryjackson/doc/tree/master/linux/kernel/toy/toy

构建并加载模块…

make
insmod toy param_cpu_id=2

卸载模块使用

rmmod toy

我没有使用modprobe,因为它需要一些配置等。我们传递给toy内核模块的参数是我们要隔离的CPU。除非被调用的设备操作正在该CPU上执行,否则它们将不会运行。

加载模块后,您可以在此处找到它

/dev/toy

简单的操作,例如

cat /dev/toy

创建内核模块捕获的事件并产生一些输出。您可以使用查看输出dmesg

源代码…

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harry");
MODULE_DESCRIPTION("toy kernel module");
MODULE_VERSION("0.1"); 
#define  DEVICE_NAME "toy"
#define  CLASS_NAME  "toy"

static int    param_cpu_id;
module_param(param_cpu_id    , int, (S_IRUSR | S_IRGRP | S_IROTH));
MODULE_PARM_DESC(param_cpu_id, "CPU ID that operations run on");

//static void    bar(void *arg);
//static void    foo(void *cpu);
static int     toy_open(   struct inode *inodep, struct file *fp);
static ssize_t toy_read(   struct file *fp     , char *buffer, size_t len, loff_t * offset);
static ssize_t toy_write(  struct file *fp     , const char *buffer, size_t len, loff_t *);
static int     toy_release(struct inode *inodep, struct file *fp);

static struct file_operations toy_fops = {
  .owner = THIS_MODULE,
  .open = toy_open,
  .read = toy_read,
  .write = toy_write,
  .release = toy_release,
};

static struct miscdevice toy_device = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "toy",
  .fops = &toy_fops
};

//static int CPU_IDS[64] = {0};
static int toy_open(struct inode *inodep, struct file *filep) {
  int this_cpu = get_cpu();
  printk(KERN_INFO "open: called on CPU:%d\n", this_cpu);
  if(this_cpu == param_cpu_id) {
    printk(KERN_INFO "open: is on requested CPU: %d\n", smp_processor_id());
  }
  else {
    printk(KERN_INFO "open: not on requested CPU:%d\n", smp_processor_id());
  }
  put_cpu();
  return 0;
}
static ssize_t toy_read(struct file *filep, char *buffer, size_t len, loff_t *offset){
  int this_cpu = get_cpu();
  printk(KERN_INFO "read: called on CPU:%d\n", this_cpu);
  if(this_cpu == param_cpu_id) {
    printk(KERN_INFO "read: is on requested CPU: %d\n", smp_processor_id());
  }
  else {
    printk(KERN_INFO "read: not on requested CPU:%d\n", smp_processor_id());
  }
  put_cpu();
  return 0;
}
static ssize_t toy_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){
  int this_cpu = get_cpu();
  printk(KERN_INFO "write called on CPU:%d\n", this_cpu);
  if(this_cpu == param_cpu_id) {
    printk(KERN_INFO "write: is on requested CPU: %d\n", smp_processor_id());
  }
  else {
    printk(KERN_INFO "write: not on requested CPU:%d\n", smp_processor_id());
  }
  put_cpu();
  return 0;
}
static int toy_release(struct inode *inodep, struct file *filep){
  int this_cpu = get_cpu();
  printk(KERN_INFO "release called on CPU:%d\n", this_cpu);
  if(this_cpu == param_cpu_id) {
    printk(KERN_INFO "release: is on requested CPU: %d\n", smp_processor_id());
  }
  else {
    printk(KERN_INFO "release: not on requested CPU:%d\n", smp_processor_id());
  }
  put_cpu();
  return 0;
}

static int __init toy_init(void) {
  int cpu_id;
  if(param_cpu_id < 0 || param_cpu_id > 4) {
    printk(KERN_INFO "toy: unable to load module without cpu parameter\n");
    return -1;
  }
  printk(KERN_INFO "toy: loading to device driver, param_cpu_id: %d\n", param_cpu_id);
  //preempt_disable(); // See notes below
  cpu_id = get_cpu();
  printk(KERN_INFO "toy init called and running on CPU: %d\n", cpu_id);
  misc_register(&toy_device);
  //preempt_enable(); // See notes below
  put_cpu();
  //smp_call_function_single(1,foo,(void *)(uintptr_t) 1,1);
  return 0;
}

static void __exit toy_exit(void) {
    misc_deregister(&toy_device);
    printk(KERN_INFO "toy exit called\n");
}

module_init(toy_init);
module_exit(toy_exit);

上面的代码包含您要求的两种方法,即隔离CPU和在init隔离的内核上运行。

初始化时get_cpu会禁用抢占,即之后发生的任何事情都不会被内核抢占,而是会在一个内核上运行。请注意,这是使用3.16内核完成的,根据您的内核版本,您的工作量可能会有所不同,但我认为这些API已经存在了很长时间

这是Makefile …

obj-m += toy.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

笔记。get_cpu被声明linux/smp.h

#define get_cpu()   ({ preempt_disable(); smp_processor_id(); })
#define put_cpu()   preempt_enable()

因此您实际上不需要在致电preempt_disable之前致电get_cpu。get_cpu调用是以下调用序列的包装。

preempt_count_inc();
barrier();

而put_cpu实际上就是这样做的…

barrier();
if (unlikely(preempt_count_dec_and_test())) {
  __preempt_schedule();
}

使用上面的方法,您可以任意选择。几乎所有这些都来自以下来源。

Google for … smp_call_function_single

Linux内核开发,Robert Love着书。

http://derekmolloy.ie/writing-a-linux-kernel-module-part-2-a-character-
device/

https://github.com/vsinitsyn/reverse/blob/master/reverse.c



 类似资料:
  • 内核模块 对于模块而言,引导选项只能用于直接编译到核心中的模块,格式是"模块名.选项=值",比如"usbcore.blinkenlights=1"。 动态加载的模块则可以在 modprobe 命令行上指定相应的选项值,比如"modprobe usbcore blinkenlights=1"。 可以使用"modinfo -p ${modulename}"命令显示可加载模块的所有可用选项。已经加载到内

  • 主要内容:initramfe虚拟文件系统GRUB 加载了内核之后,内核首先会再进行二次系统的自检,而不一定使用 BIOS 检测的硬件信息。这时内核终于开始替代 BIOS 接管 Linux 的启动过程了。 内核完成再次系统自检之后,开始采用动态的方式加载每个硬件的模块,这个动态模块大家可以想象成硬件的驱动(默认 Linux 硬件的驱动是不需要手工安装的,如果是重要的功能,则会直接编译到内核当中;如果是非重要的功能,比如硬件驱动会编译为模块

  • Important 要用内核模块操作,必须有一个在运行的 Ceph 集群。 获取映像列表 要挂载块设备映像,先罗列出所有的映像。 rbd list 映射块设备 用 rbd 把映像名映射为内核模块。必须指定映像名、存储池名、和用户名。若 RBD 内核模块尚未加载, rbd 命令会自动加载。 sudo rbd map {pool-name}/{image-name} --id {user-name}

  • 问题内容: 我有两段代码用于学习Python 3.1中的多处理。我的目标是使用所有可用处理器中的100%。但是,此处的代码段在所有处理器上仅达到30%-50%。 无论如何,要“强制” python使用全部100%?操作系统(Windows 7、64位)是否限制了Python对处理器的访问?当下面的代码段运行时,我打开任务管理器并观察处理器的峰值,但从未达到并维持100%。除此之外,我还可以看到在此

  • 主要内容:内核模块保存位置与模块保存文件,内核模块的查看,内核模块的添加与删除Linux 的内核会在启动过程中自动检验和加载硬件与文件系统的驱动。一般这些驱动都是用模块的形式加载的,使用模块的形式保存驱动,可以不直接把驱动放入内核,有利于控制内核大小。 模块的全称是 动态可加载内核模块,它是具有独立功能的程序,可以被单独编译,但不能独立运行。模块是为内核或其他模块提供功能的代码集合。这些模块可以是 Linux 源码中自带的,也可以是由硬件厂商开发的(可以想象成驱动)。不过内

  • 问题内容: 我尝试安装内核模块。它已成功安装在容器内。确实令人惊讶,但是没有在容器内或主机系统中列出此模块。如何在容器中装入新的内核模块?(容器,主机) 问题答案: 容器通过系统调用与内核交互,并且不包含内核的任何部分或容器内部的内核模块。这就是为什么容器设计轻巧且便于携带的原因之一。xfsprogs也是用户空间程序,而不是内核模块。 如何在容器中加载新的内核模块?(CentOS容器,Ubuntu