Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The implementation of Linux kernel current macro

Generally speaking, if we want to use current macro in Linux kernel, we should:

#include <asm/current.h>

but there is a asm-generic version:

#include <asm-generic/current.h>

the asm version implements the current macro through per-cpu variable, but asm-generic version implements the current macro through thread_info, these two are totally different. Linux kernel headers' organization says we should use asm version, which include asm/current.h, but so many blogs or books says x86 use asm-generic version to implement current macro, including Linux Kernel Development, 3rd, 3 Process Management, Storing the Process Descriptor. So, which version the x86 Linux kernel really use, asm or asm-generic? How could I make sure which version the Linux kernel really use?

like image 237
cong Avatar asked Nov 20 '21 01:11

cong


People also ask

How the current macro is implemented in Linux kernel?

the asm version implements the current macro through per-cpu variable, but asm-generic version implements the current macro through thread_info, these two are totally different. Linux kernel headers' organization says we should use asm version, which include asm/current.

What is current macro?

The purpose of the current macro is to find a pointer to the task structure of the currently running process. So regarding its usage when developing a kernel module, and according to its definition does this macro return the PID of the current running user-space process or what?

What is current in kernel Linux?

The current pointer refers to the user process currently executing. During the execution of a system call, such as open or read, the current process is the one that invoked the call. Kernel code can use process-specific information by using current, if it needs to do so.


1 Answers

The correct header to use is asm/current.h, do not use asm-generic. This applies to anything under asm really. Headers in the asm-generic folder are provided (as the name suggests) as a "generic" default implementation of macros/functions, then each architecture /arch/xxx has its own asm include folder, where if needed it can define the same macros/functions in an architecture-specific way.

This is done both because it could be actually needed (some archs might have an implementation that is not compatible with the generic one) and for performance since there might be a better and more optimized way of achieving the same result under a specific arch.

Indeed, if we look at how each arch defines get_current() or get_current_thread_info() we can see that some of them (e.g. alpha, spark) keep a reference to the current task in the thread_info struct and keep a pointer to the current thread_info in a register for performance. Others directly keep a pointer to current in a register (e.g. powerpc 32bit), and others define a global per-cpu variable (e.g. x86). On x86 in particular, the thread_info struct doesn't even have a pointer to the current task, it's a very simple 16-byte structure made to fit in a cache line for performance.

// example from /arch/powerpc/include/asm/current.h

/*
 * We keep `current' in r2 for speed.
 */
register struct task_struct *current asm ("r2");

How could I make sure which version the Linux kernel really use?

Well, let's just take a simple look:

$ rg '#include.+current\.h' | cat
security/landlock/ptrace.c:#include <asm/current.h>       
security/landlock/syscalls.c:#include <asm/current.h>     
sound/pci/rme9652/hdsp.c:#include <asm/current.h>         
sound/pci/rme9652/rme9652.c:#include <asm/current.h>      
net/ipv4/raw.c:#include <asm/current.h>                 
net/core/dev.c:#include <asm/current.h>                   
ipc/msg.c:#include <asm/current.h>                        
fs/quota/quota.c:#include <asm/current.h>                 
drivers/staging/media/atomisp/pci/hmm/hmm_bo.c:#include <asm/current.h>                                             
fs/jfs/ioctl.c:#include <asm/current.h>                   
fs/hugetlbfs/inode.c:#include <asm/current.h>             
drivers/parport/daisy.c:#include <asm/current.h>          
...

As you can see asm/current.h is the only header actually used.

We can also see that (as of v5.14 at least) only arc seems to be using the "generic" version:

$ rg '#include.+generic.+current\.h' | cat     
arch/arc/include/asm/current.h:#include <asm-generic/current.h>

many blogs or books says x86 use asm-generic version to implement current macro, including Linux Kernel Development, 3rd

I can only speculate that these resources were written a long time ago and based on pretty old kernel versions, which at the time of writing might have used a different include system (maybe x86 used to use the generic version as well). If not, then those resources are most probably wrong.

like image 145
Marco Bonelli Avatar answered Oct 17 '22 03:10

Marco Bonelli