【问题标题】:Systemtap - Calling a syscall from kernel spaceSystemtap - 从内核空间调用系统调用
【发布时间】:2018-11-29 07:42:50
【问题描述】:

我正在尝试创建一个硬链接,直接从 Systemtap Embedded C 代码调用 sys_link。基本上,代码如下所示:

function sys_link:long(oldname, newname) %{  /* pure */
    int error;
    mm_segment_t old_fs;

    old_fs = get_fs();
    set_fs(get_ds());

    error = psys_link(STAP_ARG_oldname, STAP_ARG_newname);

    set_fs(old_fs);

    STAP_RETURN(error);
%}

sys_link 不是由内核导出的,因此 psys_link 在初始化时使用 kallsyms_lookup_name() 解析,我可以测试地址是否正确解析。 似乎正在调用系统调用,但它永远不会返回。

*我知道从内核空间调用系统调用不是最好的主意,但相信我,我需要这样做 ;) *

另一方面,我做了另一个更简单的测试,调用 filp_open,它是由内核导出的,它甚至不是系统调用,它只是一个内核函数,以创建一个同样不成功的文件结果:

function myopen:long(newname) %{  /* pure */
    struct file *file;
    mm_segment_t old_fs = get_fs();

    set_fs(get_ds());

    file = filp_open(STAP_ARG_newname, O_WRONLY|O_CREAT, 0644);

    set_fs(old_fs);

    STAP_RETURN(1);
%}

知道内核冻结的原因吗?

更新: 系统调用和函数在 syscall.open.return 探测的上下文中调用。正如在其中一个 cmets 中所讨论的,Systemtap 返回探针是使用 kretprobe ... 实现的,它替换了蹦床的函数返回地址 ... AFAIU 表示系统调用例程已经完成,这应该已经释放了与文件系统本身相关的所有锁,但我可能遗漏了一些东西。

此时调试内核给了我以下回溯显然,死锁在 kprobe 锁中。

>>> info threads
  Id   Target Id         Frame 
* 1    Thread 1 (CPU#0 [running]) __loop_delay () at arch/arm/lib/delay-loop.S:42
  2    Thread 2 (CPU#1 [running]) __loop_delay () at arch/arm/lib/delay-loop.S:42
  3    Thread 3 (CPU#2 [running]) __loop_delay () at arch/arm/lib/delay-loop.S:42
  4    Thread 4 (CPU#3 [running]) arch_spin_lock (lock=<optimised out>) at ./arch/arm/include/asm/spinlock.h:91

>>> thread 4
[Switching to thread 4 (Thread 4)]
#0  arch_spin_lock (lock=<optimised out>) at ./arch/arm/include/asm/spinlock.h:91
91          wfe();

>>> bt
#0  arch_spin_lock (lock=<optimised out>) at ./arch/arm/include/asm/spinlock.h:91
#1  do_raw_spin_lock_flags (flags=<optimised out>, lock=<optimised out>) at ./include/linux/spinlock.h:155
#2  __raw_spin_lock_irqsave (lock=<optimised out>) at ./include/linux/spinlock_api_smp.h:121
#3  _raw_spin_lock_irqsave (lock=0xc1541f80 <kretprobe_table_locks+2240>) at kernel/locking/spinlock.c:159
#4  0xc0412d18 in kretprobe_table_lock (flags=<optimised out>, hash=<optimised out>) at kernel/kprobes.c:1113
#5  kprobe_flush_task (tk=0xed165b00) at kernel/kprobes.c:1158
#6  0xc03814f8 in finish_task_switch (prev=0xed165b00) at kernel/sched/core.c:2783
#7  0xc0c19c38 in context_switch (cookie=..., next=<optimised out>, prev=<optimised out>, rq=<optimised out>) at kernel/sched/core.c:2902
#8  __schedule (preempt=<optimised out>) at kernel/sched/core.c:3402
#9  0xc0c1a1a4 in schedule () at kernel/sched/core.c:3457
#10 0xc0c1a54c in schedule_preempt_disabled () at kernel/sched/core.c:3490
#11 0xc03a23dc in cpu_idle_loop () at kernel/sched/idle.c:273
#12 cpu_startup_entry (state=<optimised out>) at kernel/sched/idle.c:302
#13 0xc031206c in secondary_start_kernel () at arch/arm/kernel/smp.c:412
#14 0x60301dec in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

注意:这是一个 ARM 机器回溯,但同样的结果发生在 i386 中。

【问题讨论】:

  • "知道内核为什么会被冻结吗?" - 与文件一起使用的函数可能会锁定某些资源(例如,inode 的互斥锁)。如果从上下文中调用此函数,而这些资源已被锁定,则会出现死锁。如果不查看函数的用法,就很难得到更具体的诊断。
  • 感谢@Tsyvarev,这是有道理的,因为这些函数是在“syscall.open.return probe”的上下文中调用的。但是,AFAIU 的返回探​​针在 Systemtap 中被实现为 kretprobe ...它替换了蹦床的函数返回地址 ...这意味着系统调用已经完成了所有操作,包括释放任何锁。

标签: linux kernel system-calls systemtap kprobe


【解决方案1】:

Systemtap 探测处理程序通常在原子上下文中运行,这意味着抢占和/或中断被禁用。如果您设法从这样的上下文中调用内核函数,目标函数最好是类似的“原子”函数,即永远不要使用任何新的锁或阻塞。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-15
    • 2013-03-28
    • 2019-08-04
    • 1970-01-01
    • 2021-02-11
    • 2014-08-02
    • 2014-11-25
    相关资源
    最近更新 更多