[커널 18차] 78주차
2022.11.19 22:05
softirq 완
git : https://github.com/iamroot18/5.10/commit/7695e8fe23629c8a8f73a6731f50d490e496688d
diff --git a/include/linux/percpu-rwsem.h b/include/linux/percpu-rwsem.h
index 5fda40f97fe9..887233140b07 100644
--- a/include/linux/percpu-rwsem.h
+++ b/include/linux/percpu-rwsem.h
@@ -44,6 +44,10 @@ is_static struct percpu_rw_semaphore name = { \
extern bool __percpu_down_read(struct percpu_rw_semaphore *, bool);
+/*
+ * IAMROOT, 2022.11.19:
+ * - cpu on/off시 동기화 하기 위한 lock
+ */
static inline void percpu_down_read(struct percpu_rw_semaphore *sem)
{
might_sleep();
diff --git a/include/linux/sched.h b/include/linux/sched.h
index bb20cd246c51..883b3353a48a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -90,6 +90,12 @@ struct task_group;
#define EXIT_ZOMBIE 0x0020
#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
/* Used in tsk->state again: */
+
+/*
+ * IAMROOT, 2022.11.19:
+ * - kthread에만 있는 개념.
+ * - wakeup업시 unpark할때까지 잠깐 멈추는 기능.
+ */
#define TASK_PARKED 0x0040
#define TASK_DEAD 0x0080
#define TASK_WAKEKILL 0x0100
@@ -1694,8 +1700,9 @@ extern struct pid *cad_pid;
#define PF_SIGNALED 0x00000400 /* Killed by a signal */
/*
* IAMROOT, 2022.04.16:
- * - task가 memory 회수 mode이면 set된다. memory 제한없이 사용할수있는 권한을 가질 수 있다.
- * - memory 회수 재귀등을 확인하는 flag로도 사용한다.
+ * - PF_MEMALLOC
+ * task가 memory 회수 mode이면 set된다. memory 제한없이 사용할수있는 권한을 가질 수 있다.
+ * memory 회수 재귀등을 확인하는 flag로도 사용한다.
*/
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
#define PF_NPROC_EXCEEDED 0x00001000 /* set_user() noticed that RLIMIT_NPROC was exceeded */
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 7f5de9bfd319..ab0db2b07cc9 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -307,6 +307,10 @@ static int cpu_hotplug_disabled;
DEFINE_STATIC_PERCPU_RWSEM(cpu_hotplug_lock);
+/*
+ * IAMROOT, 2022.11.19:
+ * - cpu on / off시 사용하는 lock
+ */
void cpus_read_lock(void)
{
percpu_down_read(&cpu_hotplug_lock);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index f4e4cad52d6d..9a4aae4247a1 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1698,7 +1698,7 @@ setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary)
* 2. old action이 있는지 판단하여 shared irq인지 결정.
* 3. shared 인지 아닌지 에 따라 flag검사 및, flag를 보며 irq_activate, enable_irq 결정
* 4. thread_mask set 처리.
- * 5. onshot 관련 flag 처리.
+ * 5. oneshot 관련 flag 처리.
* 6. irqt_stat에 생성된 irq번호로 자료구조 추가.
* 7. /proc/에 생성된 irq번호로 자료구조 추가.
*
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 5b37a8567168..b28ba2661b21 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -233,6 +233,11 @@ void *kthread_probe_data(struct task_struct *task)
return data;
}
+/*
+ * IAMROOT, 2022.11.19:
+ * - KTHREAD_SHOULD_PARK로 왔던걸 TASK_PARKED(schedule()) 한다.
+ * unpark할때까지 깨어나도 계속 park상태로 잠들것이다.
+ */
static void __kthread_parkme(struct kthread *self)
{
for (;;) {
@@ -353,6 +358,14 @@ static void create_kthread(struct kthread_create_info *create)
}
}
+/*
+ * IAMROOT, 2022.11.19:
+ * - TODO
+ * - thread 생성을위해 kthreadd를 wakeup해준다.
+ * kthreadd에서 thread 생성이 완료 될때까지 wait한다.
+ * thread는 동작중이 아니다. 후에 wakeup을 따로 해줘야한다.
+ * (생성과 동시에 wakeup까지 하는건 kthread_run())
+ */
static __printf(4, 0)
struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
void *data, int node,
@@ -375,12 +388,31 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
list_add_tail(&create->list, &kthread_create_list);
spin_unlock(&kthread_create_lock);
+/*
+ * IAMROOT, 2022.11.19:
+ * - kthreadd wakeup -> create_kthread()
+ * -> int kthreads(void *_create)에서 생성 완료되면 done complete.
+ *
+ * - spawn_ksoftirqd 동작시 예
+ * 1. kthreadd에서 thread 생성 <-- 이부분
+ * 2. kthreadd에서 thread 생성완료 wait
+ * 3. set TASK_PARKED
+ * 4. wakeup smpboot_thread_fn()실행
+ */
wake_up_process(kthreadd_task);
/*
* Wait for completion in killable state, for I might be chosen by
* the OOM killer while kthreadd is trying to allocate memory for
* new kernel thread.
*/
+/*
+ * IAMROOT, 2022.11.19:
+ * - spawn_ksoftirqd 동작시 예
+ * 1. kthreadd에서 thread 생성
+ * 2. kthreadd에서 thread 생성완료 wait <-- 이부분
+ * 3. set TASK_PARKED
+ * 4. wakeup smpboot_thread_fn()실행
+ */
if (unlikely(wait_for_completion_killable(&done))) {
/*
* If I was SIGKILLed before kthreadd (or new kernel thread)
@@ -441,6 +473,11 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
*
* Returns a task_struct or ERR_PTR(-ENOMEM) or ERR_PTR(-EINTR).
*/
+
+/*
+ * IAMROOT, 2022.11.19:
+ * - thread 생성
+ */
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
void *data, int node,
const char namefmt[],
@@ -508,6 +545,10 @@ EXPORT_SYMBOL(kthread_bind);
*
* Description: This helper function creates and names a kernel thread
*/
+/*
+ * IAMROOT, 2022.11.19:
+ * - thread 생성
+ */
struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
void *data, unsigned int cpu,
const char *namefmt)
@@ -524,6 +565,10 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
return p;
}
+/*
+ * IAMROOT, 2022.11.19:
+ * - @k에 @cpu id를 넣어주고 percpu thread라는걸 marking해준다.
+ */
void kthread_set_per_cpu(struct task_struct *k, int cpu)
{
struct kthread *kthread = to_kthread(k);
@@ -558,6 +603,11 @@ bool kthread_is_per_cpu(struct task_struct *p)
* waits for it to return. If the thread is marked percpu then its
* bound to the cpu again.
*/
+/*
+ * IAMROOT, 2022.11.19:
+ * - unpark. smpboot_thread_fn()의 park측 참고.
+ * park 상태에 있는것을 unpark후 깨운다.
+ */
void kthread_unpark(struct task_struct *k)
{
struct kthread *kthread = to_kthread(k);
@@ -573,6 +623,11 @@ void kthread_unpark(struct task_struct *k)
/*
* __kthread_parkme() will either see !SHOULD_PARK or get the wakeup.
*/
+
+/*
+ * IAMROOT, 2022.11.19:
+ * - parked상태였으면 깨운다.
+ */
wake_up_state(k, TASK_PARKED);
}
EXPORT_SYMBOL_GPL(kthread_unpark);
@@ -589,6 +644,11 @@ EXPORT_SYMBOL_GPL(kthread_unpark);
* Returns 0 if the thread is parked, -ENOSYS if the thread exited.
* If called by the kthread itself just the park bit is set.
*/
+/*
+ * IAMROOT, 2022.11.19:
+ * - TODO
+ * @k를 park로 하고 wakeup한후 parked가 완료될때까지 기다린다.
+ */
int kthread_park(struct task_struct *k)
{
struct kthread *kthread = to_kthread(k);
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index f6bc0bc8a2aa..57bd9ddf904d 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -103,6 +103,10 @@ enum {
*
* Returns 1 when the thread should exit, 0 otherwise.
*/
+/*
+ * IAMROOT, 2022.11.19:
+ * - thread가 run으로 되기전 동작하는 최초의 함수. park등의 state를 처리한다.
+ */
static int smpboot_thread_fn(void *data)
{
struct smpboot_thread_data *td = data;
@@ -161,11 +165,20 @@ static int smpboot_thread_fn(void *data)
} else {
__set_current_state(TASK_RUNNING);
preempt_enable();
+
+/*
+ * IAMROOT, 2022.11.19:
+ * - 실제 등록된 thread_fn
+ */
ht->thread_fn(td->cpu);
}
}
}
+/*
+ * IAMROOT, 2022.11.19:
+ * - thread 생성 및 park.
+ */
static int
__smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
{
@@ -175,12 +188,24 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
if (tsk)
return 0;
+/*
+ * IAMROOT, 2022.11.19:
+ * - 자료구조를 만들어서 기본정보를 넣어준다.
+ */
td = kzalloc_node(sizeof(*td), GFP_KERNEL, cpu_to_node(cpu));
if (!td)
return -ENOMEM;
td->cpu = cpu;
td->ht = ht;
+/*
+ * IAMROOT, 2022.11.19:
+ * - 해당 함수에서 1 ~ 2번까지 진행한다.
+ * 1. kthreadd에서 thread 생성
+ * 2. kthreadd에서 thread 생성완료 wait
+ * 3. set TASK_PARKED
+ * 4. wakeup smpboot_thread_fn()실행
+ */
tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu,
ht->thread_comm);
if (IS_ERR(tsk)) {
@@ -192,6 +217,16 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
* Park the thread so that it could start right on the CPU
* when it is available.
*/
+/*
+ * IAMROOT, 2022.11.19:
+ * - spawn_ksoftirqd 동작시 예
+ * 1. kthreadd에서 thread 생성
+ * 2. kthreadd에서 thread 생성완료 wait
+ * 3 ~ 4번이 해당함수에서 실행. 5번은 sch이 알아서 실행.
+ * 3. set TASK_PARKED
+ * 4. wakeup smpboot_thread_fn
+ * 5. smpboot_thread_fn()실행 -> park 상태로 schedule().
+ */
kthread_park(tsk);
get_task_struct(tsk);
*per_cpu_ptr(ht->store, cpu) = tsk;
@@ -225,6 +260,10 @@ int smpboot_create_threads(unsigned int cpu)
return ret;
}
+/*
+ * IAMROOT, 2022.11.19:
+ * - unpark후 깨운다.
+ */
static void smpboot_unpark_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
{
struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
@@ -286,6 +325,11 @@ static void smpboot_destroy_threads(struct smp_hotplug_thread *ht)
*
* Creates and starts the threads on all online cpus.
*/
+/*
+ * IAMROOT, 2022.11.19:
+ * - cpu마다 @plug_thread의 thread를 생성하고 hotplug_threads를 @plug_thread에 넣어준다.
+ * - thread 생성 -> parked -> unparked -> thread_fn실행
+ */
int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread)
{
unsigned int cpu;
@@ -293,6 +337,7 @@ int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread)
cpus_read_lock();
mutex_lock(&smpboot_threads_lock);
+
for_each_online_cpu(cpu) {
ret = __smpboot_create_thread(plug_thread, cpu);
if (ret) {
diff --git a/kernel/softirq.c b/kernel/softirq.c
index cba80841de7d..d9a3900311fb 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -33,6 +33,19 @@
#define CREATE_TRACE_POINTS
#include <trace/events/irq.h>
+/*
+ * IAMROOT, 2022.11.19:
+ * - open_softirq
+ * - spawn_ksoftirqd
+ * - raise_softirq
+ * - invoke_softirq
+ * __do_softirq or run_ksoftirqd
+ * - __irq_exit_rcu
+ * __do_softirq
+ * - run_ksoftirqd
+ * __do_softirq
+ */
+
/*
- No shared variables, all the data are CPU local.
- If a softirq needs serialization, let it serialize itself
@@ -58,6 +71,10 @@ EXPORT_PER_CPU_SYMBOL(irq_stat);
static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
+/*
+ * IAMROOT, 2022.11.19:
+ * -
+ */
DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
const char * const softirq_to_name[NR_SOFTIRQS] = {
@@ -175,6 +192,10 @@ bool local_bh_blocked(void)
return __this_cpu_read(softirq_ctrl.cnt) != 0;
}
+/*
+ * IAMROOT, 2022.11.19:
+ * - PREEMPT_RT
+ */
void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
{
unsigned long flags;
@@ -290,6 +311,7 @@ EXPORT_SYMBOL(__local_bh_enable_ip);
/*
* IAMROOT, 2022.11.12:
* - preempt.
+ * irq disable.
*/
static inline void ksoftirqd_run_begin(void)
{
@@ -298,6 +320,10 @@ static inline void ksoftirqd_run_begin(void)
}
/* Counterpart to ksoftirqd_run_begin() */
+/*
+ * IAMROOT, 2022.11.19:
+ * - irq enable
+ */
static inline void ksoftirqd_run_end(void)
{
__local_bh_enable(SOFTIRQ_OFFSET, true);
@@ -305,6 +331,10 @@ static inline void ksoftirqd_run_end(void)
local_irq_enable();
}
+/*
+ * IAMROOT, 2022.11.19:
+ * - PREEMPT_RT
+ */
static inline void softirq_handle_begin(void) { }
static inline void softirq_handle_end(void) { }
@@ -425,6 +455,10 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
}
EXPORT_SYMBOL(__local_bh_enable_ip);
+/*
+ * IAMROOT, 2022.11.19:
+ * - !PREEMPT
+ */
static inline void softirq_handle_begin(void)
{
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
@@ -569,7 +603,10 @@ static inline void lockdep_softirq_end(bool in_hardirq) { }
/*
* IAMROOT, 2022.11.12:
- * - TODO
+ * - pending softirq를 처리한다.
+ * pending 처리후 2ms가 초과하면 ksoftirqd를 깨운다.
+ * - softirq는 저런 시간 처리때문에 sleep을 쓰면안된다. 메모리할당도 빠르게 하기 위해
+ * GFP_ATOMIC등을 사용한다.
*/
asmlinkage __visible void __softirq_entry __do_softirq(void)
{
@@ -586,10 +623,24 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
* softirq. A softirq handled, such as network RX, might set PF_MEMALLOC
* again if the socket is related to swapping.
*/
+/*
+ * IAMROOT, 2022.11.19:
+ * - papago
+ * 현재 작업 컨텍스트가 softirq에 대해 차용되므로 PF_MEMALLOC를 마스킹합니다. 네트워크 RX와
+ * 같이 처리된 softirq는 소켓이 스와핑과 관련된 경우 PF_MEMALLOC를 다시 설정할 수 있습니다.
+ */
current->flags &= ~PF_MEMALLOC;
pending = local_softirq_pending();
+/*
+ * IAMROOT, 2022.11.19:
+ * - PREEMPT
+ * 이미 bh disable이 되있다.
+ *
+ * - !PREEMPT
+ * 이 시점에서 bh disable 수행
+ */
softirq_handle_begin();
in_hardirq = lockdep_softirq_start();
account_softirq_enter(current);
@@ -598,6 +649,11 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0);
+/*
+ * IAMROOT, 2022.11.19:
+ * - irq enable.
+ * pending bit를 가져온후 reset을 정확히 하기위해 잠시동안만 off를 했었다.
+ */
local_irq_enable();
h = softirq_vec;
@@ -614,6 +670,11 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
kstat_incr_softirqs_this_cpu(vec_nr);
trace_softirq_entry(vec_nr);
+
+/*
+ * IAMROOT, 2022.11.19:
+ * - open_softirq에서 등록된 action handler 처리
+ */
h->action(h);
trace_softirq_exit(vec_nr);
if (unlikely(prev_count != preempt_count())) {
@@ -630,8 +691,19 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
__this_cpu_read(ksoftirqd) == current)
rcu_softirq_qs();
+/*
+ * IAMROOT, 2022.11.19:
+ * - irq disable.
+ */
local_irq_disable();
+
+/*
+ * IAMROOT, 2022.11.19:
+ * - hard irq에서 동작하다가 시간이 너무 길어진 경우 동작한다.
+ * (MAX_SOFTIRQ_TIME. 2ms)이내인 경우 restart로 처리하고
+ * 그게 아니면 ksoftirqd 에서 처리한다.
+ */
pending = local_softirq_pending();
if (pending) {
if (time_before(jiffies, end) && !need_resched() &&
@@ -759,6 +831,7 @@ void irq_exit(void)
/*
* IAMROOT, 2022.11.12:
* - pending을 일단하고 현재 context가 kernel thread인 경우는 바로 깨운다.
+ * interrupt context에 있을때에는 irq가 끝낫을시에 처리한다. (__irq_exit_rcu())
*/
inline void raise_softirq_irqoff(unsigned int nr)
{
@@ -816,6 +889,20 @@ void __raise_softirq_irqoff(unsigned int nr)
/*
* IAMROOT, 2022.09.03:
* - softirq @nr에 대한 @action함수를 등록한다.
+ * - 우선순위에 따라 동작한다.
+ * --- 우선순위 높음---
+ * open_softirq(HI_SOFTIRQ, tasklet_hi_action);
+ * open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
+ * open_softirq(NET_TX_SOFTIRQ, net_tx_action);
+ * open_softirq(NET_RX_SOFTIRQ, net_rx_action);
+ * open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);
+ * open_softirq(IRQ_POLL_SOFTIRQ, irq_poll_softirq);
+ * open_softirq(TASKLET_SOFTIRQ, tasklet_action);
+ * open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);
+ * open_softirq(HRTIMER_SOFTIRQ, hrtimer_run_softirq);
+ * open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); open_softirq(RCU_SOFTIRQ, rcu_core_si);
+ * (RCU_SOFTIRQ는 조건에따라서 동작이 다르다)
+ * --- 우선순위 낮음---
*/
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
@@ -1027,6 +1114,10 @@ static int ksoftirqd_should_run(unsigned int cpu)
return local_softirq_pending();
}
+/*
+ * IAMROOT, 2022.11.19:
+ * - irq disable. 후 softirq 처리.
+ */
static void run_ksoftirqd(unsigned int cpu)
{
ksoftirqd_run_begin();
@@ -1044,6 +1135,11 @@ static void run_ksoftirqd(unsigned int cpu)
}
#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * IAMROOT, 2022.11.19:
+ * - TODO
+ * - head -> tail을 연결한다.
+ */
static int takeover_tasklets(unsigned int cpu)
{
/* CPU is dead, so no lock needed. */
@@ -1074,12 +1170,26 @@ static int takeover_tasklets(unsigned int cpu)
#endif /* CONFIG_HOTPLUG_CPU */
static struct smp_hotplug_thread softirq_threads = {
+
+/*
+ * IAMROOT, 2022.11.19:
+ * - DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
+ */
.store = &ksoftirqd,
.thread_should_run = ksoftirqd_should_run,
.thread_fn = run_ksoftirqd,
+/*
+ * IAMROOT, 2022.11.19:
+ * - %u : cpu number
+ */
.thread_comm = "ksoftirqd/%u",
};
+/*
+ * IAMROOT, 2022.11.19:
+ * - takeover_tasklets를 CPUHP_SOFTIRQ_DEAD에 등록한다.
+ * cpu가 offline으로 동작할때 실행될것이다.
+ */
static __init int spawn_ksoftirqd(void)
{
cpuhp_setup_state_nocalls(CPUHP_SOFTIRQ_DEAD, "softirq:dead", NULL,
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 626 |
167 | [커널 18차] 80주차 | kkr | 2022.12.03 | 156 |
166 | [커널 19차] 28 ~ 29 주차 | Min | 2022.12.03 | 35 |
165 | [커널 19차] 27 주차 | Min | 2022.11.22 | 82 |
» | [커널 18차] 78주차 | kkr | 2022.11.19 | 187 |
163 | [커널 19차] 25 ~ 26 주차 | Min | 2022.11.14 | 72 |
162 | [커널 18차] 76-77주차 | kkr | 2022.11.12 | 386 |
161 | [커널 19차] 24주차 | Min | 2022.10.31 | 108 |
160 | [커널 17차] 112주차 | ㅇㅇㅇ | 2022.10.30 | 81 |
159 | [커널 18차] 75주차 | kkr | 2022.10.29 | 40 |
158 | [커널 17차] 107 ~ 111주차 | ㅇㅇㅇ | 2022.10.23 | 77 |
157 | [커널 19차] 22주차 | Min | 2022.10.17 | 76 |
156 | [커널 18차] 73주차 | kkr | 2022.10.15 | 46 |
155 | [커널 18차] 72주차 | kkr | 2022.10.09 | 183 |
154 | [커널 18차] 71주차 | kkr | 2022.10.01 | 75 |
153 | [커널 18차] 70주차 | kkr | 2022.09.24 | 77 |
152 | [커널 18차] 69주차 | kkr | 2022.09.22 | 58 |
151 | [커널 17차] 105~106주차 | ㅇㅇㅇ | 2022.09.18 | 50 |
150 | [커널 17차] 104주차 | ㅇㅇㅇ | 2022.09.04 | 88 |
149 | [커널 18차] 67주차 | kkr | 2022.09.03 | 138 |
148 | [커널 17차] 103주차 | ㅇㅇㅇ | 2022.08.28 | 35 |
.