put_user() 只能在进行系统调用的进程上下文中调用。
考虑一个调用ptrace(2)(参见kernel/ptrace.c)的应用程序。
内核将调用特定于架构的ptrace 助手:
SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
unsigned long, data)
{
/* arch-independent code */
/* ... */
ret = arch_ptrace(child, request, addr, data);
在x86平台上,arch_ptrace()在arch/x86/kernel/ptrace.c中定义:
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
int ret;
unsigned long __user *datap = (unsigned long __user *)data;
switch (request) {
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
unsigned long tmp;
ret = -EIO;
if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
break;
tmp = 0; /* Default return condition */
if (addr < sizeof(struct user_regs_struct))
tmp = getreg(child, addr);
else if (addr >= offsetof(struct user, u_debugreg[0]) &&
addr <= offsetof(struct user, u_debugreg[7])) {
addr -= offsetof(struct user, u_debugreg[0]);
tmp = ptrace_get_debugreg(child, addr / sizeof(data));
}
ret = put_user(tmp, datap);
break;
}
当进程调用ptrace(2) 并要求执行PTRACE_PEEKUSR 时,内核需要将信息(ret)返回给用户。内核使用datap 指向用户提供的缓冲区 的指针来了解在进程中的何处写入tmp 的值。
几乎所有调用put_user() 的情况都将由用户级进程启动。向用户空间发送信号是一个明显的区别,其中内核启动发送信号,但内核有代码(参见arch/x86/kernel/signal.c 函数__setup_frame())来查找堆栈帧并将其写入处理信号的需要。
因此,经过长时间的讨论:您将通过您给内核写入的任何缓冲区访问进程中的数据——它可能是特定于驱动程序的缓冲区ioctl(2),它可能是您创建的新系统调用的缓冲区参数,您有很多选择。