运行 来自 tasklet 的用户空间进程

Run userspace process from tasklet

你好我正在尝试运行用户空间进程使用call_usermodehelper_exec来自在带有Allwinner SOC的ARM板(来自Olimex)的内核模块中创建的tasklet。

我的代码很简单:

#include <linux/kernel.h>
#include <linux/module.h>
char my_tasklet_data[]="tasklet executed";

static int umh_test(void)
{
  struct subprocess_info *sub_info;
  char *argv[] = { "/usr/bin/logger", "help!", NULL };
  static char *envp[] = {
    "HOME=/",
    "TERM=linux",
    "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };

  sub_info = call_usermodehelper_setup(argv[0], argv, envp, GFP_ATOMIC);
  if (sub_info == NULL) return -ENOMEM;

  return call_usermodehelper_exec(sub_info, UMH_WAIT_PROC);
}

void my_tasklet_function(unsigned long data)
{
  printk(KERN_INFO "%s\n", (char *)data);

  umh_test();

  return;
}

DECLARE_TASKLET(my_tasklet, my_tasklet_function,
            (unsigned long) &my_tasklet_data);

static int __init my_tasklet_init(void)
{
  tasklet_schedule(&my_tasklet);

  return 0;
}
module_init(my_tasklet_init);

static void __exit my_tasklet_cleanup(void)
{
  tasklet_kill(&my_tasklet);
}
module_exit(my_tasklet_cleanup);

在执行 insmod tasklet.ko tasklet 之后调用了 /usr/bin/logger,但我也遇到了像这样的讨厌的内核错误:

[  969.327698] tasklet executed
<3>BUG: scheduling while atomic: ksoftirqd/0/3/0x00000102
[  969.335769] BUG: scheduling while atomic: ksoftirqd/0/3/0x00000102
<d>Modules linked in:[  969.343861] Modules linked in:root@a20-olimex:~#tasklet(O) tasklet(O) disp_ump disp_ump mali_drm mali_drm cpufreq_powersave cpufreq_powersave cpufreq_stats cpufreq_stats drm drm cpufreq_userspace cpufreq_userspace cpufreq_conservative cpufreq_conservative mali mali g_ether g_ether pwm_sunxi pwm_sunxi sun4i_csi0 sun4i_csi0 videobuf_dma_contig videobuf_dma_contig videobuf_core videobuf_core gt2005 gt2005 sun4i_keyboard sun4i_keyboard ledtrig_heartbeat ledtrig_heartbeat leds_sunxi leds_sunxi led_class led_class sunxi_emac sunxi_emac sunxi_gmac sunxi_gmac sunxi_cedar_mod sunxi_cedar_mod 8192cu 8192cu ump ump lcd lcd [last unloaded: tasklet] [last unloaded: tasklet]

[<c0015058>] (unwind_backtrace+0x0/0x134) from [<c058455c>] (__schedule+0x744/0x7d0)
[  969.410844] [<c0015058>] (unwind_backtrace+0x0/0x134) from [<c058455c>] (__schedule+0x744/0x7d0)
[<c058455c>] (__schedule+0x744/0x7d0) from [<c0582a20>] (schedule_timeout+0x1b8/0x220)
[  969.427299] [<c058455c>] (__schedule+0x744/0x7d0) from [<c0582a20>] (schedule_timeout+0x1b8/0x220)
[<c0582a20>] (schedule_timeout+0x1b8/0x220) from [<c0583c04>] (wait_for_common+0xe4/0x138)
[  969.444267] [<c0582a20>] (schedule_timeout+0x1b8/0x220) from [<c0583c04>] (wait_for_common+0xe4/0x138)
[<c0583c04>] (wait_for_common+0xe4/0x138) from [<c0049dc0>] (call_usermodehelper_exec+0x140/0x154)
[  969.462267] [<c0583c04>] (wait_for_common+0xe4/0x138) from [<c0049dc0>] (call_usermodehelper_exec+0x140/0x154)
[<c0049dc0>] (call_usermodehelper_exec+0x140/0x154) from [<bf1c6050>] (my_tasklet_function+0x50/0x58 [tasklet])
[  969.482096] [<c0049dc0>] (call_usermodehelper_exec+0x140/0x154) from [<bf1c6050>] (my_tasklet_function+0x50/0x58 [tasklet])
[<bf1c6050>] (my_tasklet_function+0x50/0x58 [tasklet]) from [<c003c800>] (tasklet_action+0x98/0x134)
[  969.502110] [<bf1c6050>] (my_tasklet_function+0x50/0x58 [tasklet]) from [<c003c800>] (tasklet_action+0x98/0x134)
[<c003c800>] (tasklet_action+0x98/0x134) from [<c003c9d4>] (__do_softirq+0xd4/0x168)
[  969.519768] [<c003c800>] (tasklet_action+0x98/0x134) from [<c003c9d4>] (__do_softirq+0xd4/0x168)
[<c003c9d4>] (__do_softirq+0xd4/0x168) from [<c003cb58>] (run_ksoftirqd+0xf0/0x1bc)
[  969.535943] [<c003c9d4>] (__do_softirq+0xd4/0x168) from [<c003cb58>] (run_ksoftirqd+0xf0/0x1bc)
[<c003cb58>] (run_ksoftirqd+0xf0/0x1bc) from [<c00513a4>] (kthread+0x90/0x94)
[  969.551513] [<c003cb58>] (run_ksoftirqd+0xf0/0x1bc) from [<c00513a4>] (kthread+0x90/0x94)
[<c00513a4>] (kthread+0x90/0x94) from [<c000f4b8>] (kernel_thread_exit+0x0/0x8)
[  969.566739] [<c00513a4>] (kthread+0x90/0x94) from [<c000f4b8>] (kernel_thread_exit+0x0/0x8)

我尝试寻找类似的问题,因为我正在学习驱动程序开发,但我发现的只是与以下问题相关的问题,我们称之为内核损坏的构建。 我使用自己构建的内核,我不排除可能与内核相关,但如果某人是某个主题的新手,他会确保代码没有任何应受谴责的错误。

因此,我们将不胜感激

Tasklet 在软中断上下文中执行,因此无法休眠(调用 schedule 函数)。

另一方面,用户模式助手可以休眠(就像任何其他用户空间代码一样)。

这就是您收到 BUG: scheduling while atomic 消息的原因。

call_usermodehelper_exec 的评论部分说:

 * @wait: wait for the application to finish and return status.
 *        when UMH_NO_WAIT don't wait at all, but you get no useful error back
 *        when the program couldn't be exec'ed. This makes it safe to call
 *        from interrupt context.

从 tasklet 调用实际上是一个中断上下文,因此您不能在那里等待。也就是说,您不能阻止,因为没有可用于阻止的任务上下文。 (这就是 "scheduling while atomic" 告诉你的。)

您要么需要使用流程上下文部分,要么需要使用 UMH_NO_WAIT 而不是 UMH_WAIT_PROC。例如,你可以有 从 my_tasklet_init 使用 UMH_WAIT_PROC 调用用户模式助手,因为那里有一个任务上下文。