Issue
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?
Solution
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.
Answered By - Marco Bonelli