After searching many books, websites and debugging the Linux kernel, I understand the design of thread_info and I get to know why it must be the first element in task_struct.
Firstly, we need to understand Linux kernel stack.
Then, we come to the core : we need to get to kernel stack by task_struct some time, and we need to get to task_struct by kernel stack some time. So we must have some way to do it.
1. task_struct to kernel stack
It is easy to use stack like below
static inline void *task_stack_page(const struct task_struct *task)
{
return task->stack;
}
What's more, we can get to pt_regs by task_pt_regs(task)
2.kernel stack to task_struct
Here is the use of thread_info.
Let me put two version here
struct thread_info {
struct task_struct *task; /* main task structure */
__u32 flags; /* low level flags */
__u32 status; /* thread synchronous flags */
__u32 cpu; /* current CPU */
mm_segment_t addr_limit;
unsigned int sig_on_uaccess_error:1;
unsigned int uaccess_err:1; /* uaccess failed */
};
struct thread_info {
unsigned long flags; /* low level flags */
unsigned long status; /* thread synchronous flags */
};
The first one is the old version, it includes task_struct, from which we can go straightly to task_struct. But it costs too much to strore it, so the new version delete all.
In the old version, we have this function to get it.
static inline struct thread_info *current_thread_info(void)
{
return (struct thread_info *)(current_top_of_stack() - THREAD_SIZE);
}
But how can we get to task_struct by the new version?
It is because we use a new current_thread_info
#include <asm/current.h>
#define current_thread_info() ((struct thread_info *)current)
#endif
The current is defined below
struct task_struct;
DECLARE_PER_CPU(struct task_struct *, current_task);
static __always_inline struct task_struct *get_current(void)
{
return this_cpu_read_stable(current_task);
}
#define current get_current
That is to say, we have task_struct from per cpu.
Here is the last part of the source code we show
DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
......
__visible __notrace_funcgraph struct task_struct *
__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{
......
this_cpu_write(current_task, next_p);
......
return prev_p;
}
...
#define this_cpu_read_stable(var) percpu_stable_op("mov", var)
By this way, we can get task_struct easily.