[커널 18차] 113주차
2023.07.22 22:21
RCU 시작.
git : https://github.com/iamroot18/5.10/commit/1e6b7727f601fd52d5457025bf541bd1440edd37
diff --git a/iamroot18/rcu/README.md b/iamroot18/rcu/README.md
index 78d2c5d30077..7f984463adcc 100644
--- a/iamroot18/rcu/README.md
+++ b/iamroot18/rcu/README.md
@@ -12,3 +12,6 @@ http://www2.rdrop.com/users/paulmck/RCU/RCU.2018.11.21c.PSU-full.pdf
4. Tiny-RCU Code Walkthrough on LWN.net
https://lwn.net/Articles/323929/#Tiny-RCU%20Code%20Walkthrough
+
+5. 문c블로그
+http://jake.dothome.co.kr/rcu/
diff --git a/include/linux/rcu_segcblist.h b/include/linux/rcu_segcblist.h
index 3db96c4f45fd..b10ca1d7881f 100644
--- a/include/linux/rcu_segcblist.h
+++ b/include/linux/rcu_segcblist.h
@@ -57,9 +57,21 @@ struct rcu_cblist {
* are already ready to invoke) or for RCU_NEXT_TAIL (whose callbacks have
* not yet been assigned a grace-period number).
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - 제일 앞에 있는 segment.
+ */
#define RCU_DONE_TAIL 0 /* Also RCU_WAIT head. */
#define RCU_WAIT_TAIL 1 /* Also RCU_NEXT_READY head. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - 마지막 segment 전 segment
+ */
#define RCU_NEXT_READY_TAIL 2 /* Also RCU_NEXT head. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - 마지막 segment
+ */
#define RCU_NEXT_TAIL 3
#define RCU_CBLIST_NSEGS 4
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 612cc57da815..00a5dd48423f 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -36,6 +36,13 @@
#include <linux/cpumask.h>
#define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b))
+/*
+ * IAMROOT, 2023.07.22:
+ * - a < b
+ * a = 1, b = 2 => true
+ * b = 2, a = 1 => false
+ * b = 1, b = 1 => false
+ */
#define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b))
#define ulong2long(a) (*(long *)(&(a)))
#define USHORT_CMP_GE(a, b) (USHRT_MAX / 2 >= (unsigned short)((a) - (b)))
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index 24b5f2c2de87..0a60fe88d78f 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -21,6 +21,10 @@
*/
#define RCU_SEQ_CTR_SHIFT 2
+/*
+ * IAMROOT, 2023.07.22:
+ * - 0b11
+ */
#define RCU_SEQ_STATE_MASK ((1 << RCU_SEQ_CTR_SHIFT) - 1)
/*
@@ -84,6 +88,22 @@ static inline void rcu_seq_end(unsigned long *sp)
* power of the number of low-order bits reserved for state, then rounded up to
* the next value in which the state bits are all zero.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * rcu_seq_snap - 업데이트 측 시퀀스 번호의 스냅샷을 찍습니다.
+ *
+ * 이 함수는 현재 시간 이후 전체 유예 기간이 경과했음을 나타내는 유예 기간
+ * 시퀀스 번호의 가장 빠른 값을 반환합니다. 유예 기간 시퀀스 번호가 이 값에
+ * 도달하면 현재 시간 이전에 등록된 모든 콜백을 호출하는 것이 안전합니다.
+ * 이 값은 현재 유예 기간 숫자에 상태용으로 예약된 하위 비트 수의 2제곱을
+ * 더한 다음 상태 비트가 모두 0인 다음 값으로 반올림됩니다.
+ *
+ * - @sp값보다 조금 더 뒤의 값을 snap값(1 or 2칸뒤)으로 사용한다.
+ * ex) sp == 4 => 8 (idle이라 안정적인 상태. + 1칸만 하면되면 개념)
+ * sp == 5 => 12 (complete가 안된상태. +1칸만으론 global과
+ * cpu가 너무 가깝다. 그래서 2칸뒤로 하는 개념.)
+ */
static inline unsigned long rcu_seq_snap(unsigned long *sp)
{
unsigned long s;
@@ -94,6 +114,10 @@ static inline unsigned long rcu_seq_snap(unsigned long *sp)
}
/* Return the current value the update side's sequence number, no ordering. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - return @*sp
+ */
static inline unsigned long rcu_seq_current(unsigned long *sp)
{
return READ_ONCE(*sp);
@@ -120,6 +144,18 @@ static inline bool rcu_seq_done(unsigned long *sp, unsigned long s)
/*
* Has a grace period completed since the time the old gp_seq was collected?
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - @new가 complete됬으면 return true.
+ * - @new의 하위 2bit를 제외하고 비교한다. old < new
+ *
+ * - 하위 2bit는 idle / gp 여부. 상위는 seq개념. 다음과 같이 생각될수있다.
+ *
+ * - 0------1----4-------5 ------8 ...
+ * | idle | gp | idle | gp |
+ *
+ * - old = 5 new = 8 => 4에 대한 gp는 완료됬다. return true
+ */
static inline bool rcu_seq_completed_gp(unsigned long old, unsigned long new)
{
return ULONG_CMP_LT(old, new & ~RCU_SEQ_STATE_MASK);
diff --git a/kernel/rcu/rcu_segcblist.c b/kernel/rcu/rcu_segcblist.c
index aaa111237b60..f40b3fff14ce 100644
--- a/kernel/rcu/rcu_segcblist.c
+++ b/kernel/rcu/rcu_segcblist.c
@@ -79,6 +79,10 @@ struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp)
}
/* Set the length of an rcu_segcblist structure. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - @rsclp->len = v;
+ */
static void rcu_segcblist_set_len(struct rcu_segcblist *rsclp, long v)
{
#ifdef CONFIG_RCU_NOCB_CPU
@@ -107,18 +111,30 @@ long rcu_segcblist_n_segment_cbs(struct rcu_segcblist *rsclp)
}
/* Set the length of a segment of the rcu_segcblist structure. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - seglen[seg] = v;
+ */
static void rcu_segcblist_set_seglen(struct rcu_segcblist *rsclp, int seg, long v)
{
WRITE_ONCE(rsclp->seglen[seg], v);
}
/* Increase the numeric length of a segment by a specified amount. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - @seg에 해당하는 seglen을 +v 한다.
+ */
static void rcu_segcblist_add_seglen(struct rcu_segcblist *rsclp, int seg, long v)
{
WRITE_ONCE(rsclp->seglen[seg], rsclp->seglen[seg] + v);
}
/* Move from's segment length to to's segment. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - @from의 len을 @to으로 옮긴다.
+ */
static void rcu_segcblist_move_seglen(struct rcu_segcblist *rsclp, int from, int to)
{
long len;
@@ -135,6 +151,10 @@ static void rcu_segcblist_move_seglen(struct rcu_segcblist *rsclp, int from, int
}
/* Increment segment's length. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - @seg에 해당하는 seglen을 1증가시킨다.
+ */
static void rcu_segcblist_inc_seglen(struct rcu_segcblist *rsclp, int seg)
{
rcu_segcblist_add_seglen(rsclp, seg, 1);
@@ -207,6 +227,46 @@ static void rcu_segcblist_inc_seglen(struct rcu_segcblist *rsclp, int seg)
* so that the module unloading operation is completely safe.
*
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * rcu_segcblist 구조의 숫자 길이를 지정된 양(음수일 수 있음)만큼 늘립니다.
+ * 이로 인해 ->len 필드가 구조의 실제 콜백 수와 일치하지 않을 수 있습니다.
+ * 이 증가는 전후 호출자 액세스와 관련하여 완전히 정렬됩니다.
+ *
+ * 그렇다면 도대체 왜 ->len 필드에 대한 업데이트 전후에 메모리 배리어가
+ * 필요한 걸까요??? 그 이유는 rcu_barrier()가 각 CPU의 ->len 필드를 잠그지
+ * 않고 샘플링하고 주어진 CPU의 필드가 0이면 해당 CPU의 IPI를 방지하기
+ * 때문입니다.
+ * 이것은 물론 대기 및 콜백 호출과 경쟁할 수 있습니다.
+ * 이러한 경쟁 중 하나를 올바르게 처리하지 못하면 rcu_barrier()가 대기해야
+ * 하는 콜백이 실제로 대기열에 있는 CPU를 IPI하는 데 실패하는 rcu_barrier()가
+ * 발생할 수 있습니다. 그리고 rcu_barrier()가 그러한 콜백을 기다리는 데
+ * 실패하면 특정 커널 모듈을 언로드하면 코드가 커널에 더 이상 존재하지
+ * 않는 함수가 호출됩니다.
+ *
+ * 따라서 1->0 및 0->1에서 ->len 전환은 목록 수정 및 rcu_barrier() 모두와
+ * 관련하여 신중하게 정렬해야 합니다.
+ *
+ * 큐잉 케이스는 CASE 1이고 호출 케이스는 CASE 2입니다.
+ *
+ * 사례 1:
+ * CPU 0에는 대기 중인 콜백이 없지만 CPU 1이 rcu_barrier()를 호출하는
+ * 것처럼 call_rcu()를 호출한다고 가정합니다. CPU 0의 ->len 필드는
+ * 0->1에서 전환되며 이는 신중하게 처리해야 하는 전환 중 하나입니다.
+ * ->len 업데이트 후 및 rcu_barrier() 시작 시 전체 메모리 배리어가 없으면
+ * 다음과 같은 일이 발생할 수 있습니다.
+ *
+ * CPU 0 CPU 1
+ *
+ * call_rcu().
+ * rcu_barrier() sees ->len as 0.
+ * set ->len = 1.
+ * rcu_barrier() does nothing.
+ * module is unloaded.
+ *
+ *
+ */
void rcu_segcblist_add_len(struct rcu_segcblist *rsclp, long v)
{
#ifdef CONFIG_RCU_NOCB_CPU
@@ -226,6 +286,15 @@ void rcu_segcblist_add_len(struct rcu_segcblist *rsclp, long v)
* callbacks on the structure. This increase is fully ordered with respect
* to the callers accesses both before and after.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * rcu_segcblist 구조체의 숫자 길이를 1 늘립니다.
+ * 이로 인해 ->len 필드가 구조의 실제 콜백 수와 일치하지 않을 수 있습니다.
+ * 이 증가는 전후 호출자 액세스와 관련하여 완전히 정렬됩니다.
+ *
+ * - @rsclp len을 1 증가시킨다.
+ */
void rcu_segcblist_inc_len(struct rcu_segcblist *rsclp)
{
rcu_segcblist_add_len(rsclp, 1);
@@ -234,6 +303,11 @@ void rcu_segcblist_inc_len(struct rcu_segcblist *rsclp)
/*
* Initialize an rcu_segcblist structure.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - 원형리스트초기화,
+ * seglen의 모든값과 len을 0으로 초기화하고 SEGCBLIST_ENABLED을 set한다.
+ */
void rcu_segcblist_init(struct rcu_segcblist *rsclp)
{
int i;
@@ -287,6 +361,10 @@ bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp)
* Does the specified rcu_segcblist structure contain callbacks that
* are still pending, that is, not yet ready to be invoked?
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - DONE구간 이후의 대기중인 cb이 있으면 true.
+ */
bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp)
{
return rcu_segcblist_is_enabled(rsclp) &&
@@ -339,13 +417,46 @@ bool rcu_segcblist_nextgp(struct rcu_segcblist *rsclp, unsigned long *lp)
* for rcu_barrier() to sometimes post callbacks needlessly, but
* absolutely not OK for it to ever miss posting a callback.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * 지정된 rcu_segcblist 구조에 지정된 콜백을 큐에 넣고 필요에
+ * 따라 계정을 업데이트합니다. ->len 필드는 잠기지 않고 액세스할
+ * 수 있으므로 WRITE_ONCE()입니다.
+ * ->len 필드는 rcu_barrier()와 그 친구들이 이 구조에 콜백을
+ * 게시해야 하는지 여부를 결정하는 데 사용되며, rcu_barrier()가
+ * 때때로 불필요하게 콜백을 게시하는 것은 괜찮지만 콜백 게시를
+ * 놓치는 것은 절대 좋지 않습니다.
+ *
+ * - @rsclp의 마지막에 @rhp를 추가한다.
+ */
void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp,
struct rcu_head *rhp)
{
+/*
+ * IAMROOT, 2023.07.22:
+ * - len++
+ */
rcu_segcblist_inc_len(rsclp);
+/*
+ * IAMROOT, 2023.07.22:
+ * - RCU_NEXT_TAIL len++
+ */
rcu_segcblist_inc_seglen(rsclp, RCU_NEXT_TAIL);
+/*
+ * IAMROOT, 2023.07.22:
+ * - @rhp가 end이므로 next를 NULL로 한다.
+ */
rhp->next = NULL;
+/*
+ * IAMROOT, 2023.07.22:
+ * - end인 @rhp을 마지막 node로 설정한다.
+ */
WRITE_ONCE(*rsclp->tails[RCU_NEXT_TAIL], rhp);
+/*
+ * IAMROOT, 2023.07.22:
+ * - end였던 node의 next끝에 rhp를 연결한다.
+ */
WRITE_ONCE(rsclp->tails[RCU_NEXT_TAIL], &rhp->next);
}
@@ -479,11 +590,24 @@ void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp,
* Advance the callbacks in the specified rcu_segcblist structure based
* on the current value passed in for the grace-period counter.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * gp 카운터에 대해 전달된 현재 값을 기반으로 지정된 rcu_segcblist
+ * 구조에서 콜백을 진행합니다.
+ *
+ * - complete된 seq이하구간들중 wait, ready구간만 done으로 옮긴다.
+ * next_ready구간은 seq에 관계없이 wait로 옮긴다.
+ */
void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq)
{
int i, j;
WARN_ON_ONCE(!rcu_segcblist_is_enabled(rsclp));
+/*
+ * IAMROOT, 2023.07.22:
+ * - 완료 구간 이후가 비어있으면 return.
+ */
if (rcu_segcblist_restempty(rsclp, RCU_DONE_TAIL))
return;
@@ -491,7 +615,36 @@ void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq)
* Find all callbacks whose ->gp_seq numbers indicate that they
* are ready to invoke, and put them into the RCU_DONE_TAIL segment.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papgo
+ * ->gp_seq 번호가 호출 준비가 되었음을 나타내는 모든 콜백을 찾아
+ * RCU_DONE_TAIL 세그먼트에 넣습니다.
+ * - wait 구간 부터 마지막 전까지 done으로 옮기고, 개수도 옮긴다.
+ */
for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) {
+/*
+ * IAMROOT, 2023.07.22:
+ * - 이미 완료 됬다면 break.
+ * - ex) @seq를 20라고 가정.
+ *
+ * DONE WAIT NEXT_READY NEXT DONE WAIT NEXT_READY NEXT
+ * 12 16 20 24 => 12 24
+ * 16
+ * 20
+ *
+ * 20이하를 DONE으로 이동
+ *
+ * - ex) @seq를 20라고 가정. 20보다 높은 NEXT_READY는 WAIT,
+ * 20는 DONE으로 이동
+ *
+ * DONE WAIT NEXT_READY NEXT DONE WAIT NEXT_READY NEXT
+ * 16 20 24 28 => 16 24 28
+ * 20
+ * 20이하를 DONE으로 이동
+ *
+ * list개념적으론 위와 비슷해지지만 20미만은 이제 없어질것이다.
+ */
if (ULONG_CMP_LT(seq, rsclp->gp_seq[i]))
break;
WRITE_ONCE(rsclp->tails[RCU_DONE_TAIL], rsclp->tails[i]);
@@ -499,10 +652,27 @@ void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq)
}
/* If no callbacks moved, nothing more need be done. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - wait부터 break가 발생했으면 할게없다. return.
+ */
if (i == RCU_WAIT_TAIL)
return;
-
+/*
+ * IAMROOT, 2023.07.22:
+ * - ptr을 옮기기 시작한다.
+ */
/* Clean up tail pointers that might have been misordered above. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - 옮긴 seg를 done tail로 가리킨다. 즉 empty로 만드는것
+ * - WAIT까지 처리한경우 i = 2(NEXT_READY)
+ * WAIT -> DONE
+ *
+ * - NEXT_READY까지 처리 i = 3(NEXT)
+ * WAIT -> DONE
+ * NEXT_READY -> DONE
+ */
for (j = RCU_WAIT_TAIL; j < i; j++)
WRITE_ONCE(rsclp->tails[j], rsclp->tails[RCU_DONE_TAIL]);
@@ -512,9 +682,33 @@ void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq)
* callbacks. The overall effect is to copy down the later pointers
* into the gap that was created by the now-ready segments.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * 콜백이 이동되었으므로 이제 호출할 준비가 된 콜백 목록의 중간을
+ * 가리키는 잘못 정렬된 ->tails[] 포인터를 정리하십시오. 전반적인 효과는
+ * 나중 포인터를 지금 준비된 세그먼트에 의해 생성된 간격으로 복사하는
+ * 것입니다.
+ *
+ * - i = 2 로 끝났을때 NEXT_READY를 WAIT자리로 이동시키기 위한 코드.
+ * for문자체가 큰 의미는 없다.
+ */
for (j = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++, j++) {
+/*
+ * IAMROOT, 2023.07.22:
+ * - next로 향해있으면 대상이 아니다.
+ * ex) WAIT까지 처리한경우 i = 2(NEXT_READY) 에서
+ * WAIT -> DONE의 처리를 위해서 했지만
+ * NEXT_READY는 건드리지 않았다.
+ * 만약 NEXT_READY -> NEXT를 가리키고 있다면 여기서 break.
+ * 그게 아니라면 WAIT로 옮겨갈것이다.
+ */
if (rsclp->tails[j] == rsclp->tails[RCU_NEXT_TAIL])
break; /* No more callbacks. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - DONE <- WAIT, WAIT <- NEXT_READY로 옮긴다. len도 같이 옮긴다.
+ */
WRITE_ONCE(rsclp->tails[j], rsclp->tails[i]);
rcu_segcblist_move_seglen(rsclp, i, j);
rsclp->gp_seq[j] = rsclp->gp_seq[i];
@@ -536,6 +730,11 @@ void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq)
* ready to invoke. Returns true if there are callbacks that won't be
* ready to invoke until seq, false otherwise.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * - ING
+ */
bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq)
{
int i, j;
diff --git a/kernel/rcu/rcu_segcblist.h b/kernel/rcu/rcu_segcblist.h
index 04af88ed4fde..0a1401b0b0f4 100644
--- a/kernel/rcu/rcu_segcblist.h
+++ b/kernel/rcu/rcu_segcblist.h
@@ -58,6 +58,8 @@ struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp);
* 카운트는 나중에 업데이트됩니다.
*
* 따라서 rcu_segcblist_n_cbs()를 대신 사용해야 하는 경우가 많습니다.
+ *
+ * - @rsclp가 비어있으면 return true
*/
static inline bool rcu_segcblist_empty(struct rcu_segcblist *rsclp)
{
@@ -69,6 +71,8 @@ static inline bool rcu_segcblist_empty(struct rcu_segcblist *rsclp)
* IAMROOT, 2023.07.17:
* - papago
* 분할된 콜백 목록의 콜백 수를 반환합니다.
+ *
+ * - call 개수 반환.
*/
static inline long rcu_segcblist_n_cbs(struct rcu_segcblist *rsclp)
{
@@ -79,6 +83,10 @@ static inline long rcu_segcblist_n_cbs(struct rcu_segcblist *rsclp)
#endif
}
+/*
+ * IAMROOT, 2023.07.22:
+ * - @rsclp에 flags set.
+ */
static inline void rcu_segcblist_set_flags(struct rcu_segcblist *rsclp,
int flags)
{
@@ -91,6 +99,10 @@ static inline void rcu_segcblist_clear_flags(struct rcu_segcblist *rsclp,
rsclp->flags &= ~flags;
}
+/*
+ * IAMROOT, 2023.07.22:
+ * - flags에 @flags가 존재하면 return true.
+ */
static inline bool rcu_segcblist_test_flags(struct rcu_segcblist *rsclp,
int flags)
{
@@ -106,6 +118,8 @@ static inline bool rcu_segcblist_test_flags(struct rcu_segcblist *rsclp,
* - papago
* 예를 들어 지정된 rcu_segcblist가 활성화되어 오프라인 CPU에 해당하지
* 않습니까?
+ *
+ * - @rsclp 에서 SEGCBLIST_ENABLED이 있으면 return true.
*/
static inline bool rcu_segcblist_is_enabled(struct rcu_segcblist *rsclp)
{
@@ -128,6 +142,10 @@ static inline bool rcu_segcblist_is_offloaded(struct rcu_segcblist *rsclp)
return false;
}
+/*
+ * IAMROOT, 2023.07.22:
+ * - offload되있으면 true. 아니면 false
+ */
static inline bool rcu_segcblist_completely_offloaded(struct rcu_segcblist *rsclp)
{
int flags = SEGCBLIST_KTHREAD_CB | SEGCBLIST_KTHREAD_GP | SEGCBLIST_OFFLOADED;
@@ -148,6 +166,8 @@ static inline bool rcu_segcblist_completely_offloaded(struct rcu_segcblist *rscl
* - papago
* 지정된 rcu_segcblist 구조의 지정된 세그먼트를 따르는 모든 세그먼트에
* 콜백이 비어 있습니까? (지정된 세그먼트에는 콜백이 포함될 수 있습니다.)
+ *
+ * - @seg index에대한 seg가 비었다면 return true.
*/
static inline bool rcu_segcblist_restempty(struct rcu_segcblist *rsclp, int seg)
{
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 60b976fbe603..9fe4620a96d8 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -74,6 +74,10 @@
/* Data structures. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - rcu pcpu
+ */
static DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_data, rcu_data) = {
.dynticks_nesting = 1,
.dynticks_nmi_nesting = DYNTICK_IRQ_NONIDLE,
@@ -98,6 +102,11 @@ static struct rcu_state rcu_state = {
static bool dump_tree;
module_param(dump_tree, bool, 0444);
/* By default, use RCU_SOFTIRQ instead of rcuc kthreads. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - PREEMPT_RT가 아니면 사용.(default true)
+ * PREEPRT_RT kernel이면 미사용
+ */
static bool use_softirq = !IS_ENABLED(CONFIG_PREEMPT_RT);
#ifndef CONFIG_PREEMPT_RT
module_param(use_softirq, bool, 0444);
@@ -133,7 +142,7 @@ int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */
* 따라서 이 변수가 RCU_SCHEDULER_INACTIVE일 때 RCU는 단 하나의 작업만
* 있다고 가정할 수 있으므로 RCU가 (예를 들어) synchronize_rcu()를 간단한
* barrier()로 최적화할 수 있습니다. 이 변수가 RCU_SCHEDULER_INIT이면 RCU는
- * 실제 유예 기간을 감지하는 데 필요한 모든 작업을 실제로 수행해야 합니다.
+ * 실제 gp을 감지하는 데 필요한 모든 작업을 실제로 수행해야 합니다.
* 이 변수는 또한 lockdep-RCU 오류 검사에서 부팅 시 가양성을 억제하는 데
* 사용됩니다. 마지막으로 생성된 모든 kthread를 포함하여 RCU가 완전히
* 초기화된 후 RCU_SCHEDULER_INIT에서 RCU_SCHEDULER_RUNNING으로 전환됩니다.
@@ -507,6 +516,10 @@ static int rcu_is_cpu_rrupt_from_idle(void)
#define DEFAULT_RCU_BLIMIT (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD) ? 1000 : 10)
// Maximum callbacks per rcu_do_batch ...
+/*
+ * IAMROOT, 2023.07.22:
+ * - 100 ~ 10000개의 pending callback 개수 한도.
+ */
#define DEFAULT_MAX_RCU_BLIMIT 10000 // ... even during callback flood.
static long blimit = DEFAULT_RCU_BLIMIT;
#define DEFAULT_RCU_QHIMARK 10000 // If this many pending, ignore blimit.
@@ -516,6 +529,10 @@ static long qlowmark = DEFAULT_RCU_QLOMARK;
#define DEFAULT_RCU_QOVLD_MULT 2
#define DEFAULT_RCU_QOVLD (DEFAULT_RCU_QOVLD_MULT * DEFAULT_RCU_QHIMARK)
static long qovld = DEFAULT_RCU_QOVLD; // If this many pending, hammer QS.
+/*
+ * IAMROOT, 2023.07.22:
+ * - qoverload calc.
+ */
static long qovld_calc = -1; // No pre-initialization lock acquisitions!
module_param(blimit, long, 0444);
@@ -1245,6 +1262,18 @@ static void rcu_disable_urgency_upon_qs(struct rcu_data *rdp)
* Make notrace because it can be called by the internal functions of
* ftrace, and making this notrace removes unnecessary recursion calls.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * rcu_is_watching - RCU가 현재 CPU가 유휴 상태가 아니라고 생각하는지 확인
+ *
+ * RCU가 실행 중인 CPU를 감시하는 경우 true를 반환합니다. 즉, 이 CPU가 안전하게
+ * RCU 읽기 측 임계 섹션에 들어갈 수 있습니다. 즉, 현재 CPU가 유휴 루프에
+ * 있지 않거나 인터럽트 또는 NMI 처리기에 있는 경우 true를 반환합니다.
+ *
+ * ftrace의 내부 함수에 의해 호출될 수 있으므로 notrace를 만들고 이
+ * notrace를 만들면 불필요한 재귀 호출이 제거됩니다.
+ */
notrace bool rcu_is_watching(void)
{
bool ret;
@@ -1623,6 +1652,19 @@ static void rcu_gp_kthread_wake(void)
*
* The caller must hold rnp->lock with interrupts disabled.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * 공간이 있으면 이 CPU에서 아직 할당되지 않은 모든 콜백에 ->gp_seq
+ * 번호를 할당합니다. 또한 이전에 너무 보수적인 것으로 입증된 ->gp_seq
+ * 번호가 할당된 모든 콜백을 가속화합니다. 이는 RCU가 유휴 상태일 때
+ * 콜백에 ->gp_seq 번호가 할당되었지만 루트가 아닌 rcu_node 구조를
+ * 참조하는 경우 발생할 수 있습니다. 이 함수는 멱등적이므로 반복해서
+ * 호출해도 문제가 되지 않습니다. RCU gp kthread를 깨워야
+ * 한다는 플래그를 반환합니다.
+ *
+ * 호출자는 인터럽트가 비활성화된 상태에서 rnp->lock을 유지해야 합니다.
+ */
static bool rcu_accelerate_cbs(struct rcu_node *rnp, struct rcu_data *rdp)
{
unsigned long gp_seq_req;
@@ -1647,6 +1689,17 @@ static bool rcu_accelerate_cbs(struct rcu_node *rnp, struct rcu_data *rdp)
* accelerating callback invocation to an earlier grace-period
* number.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * 콜백은 종종 불완전한 gp 정보로 등록됩니다. 정확한 정보를
+ * 얻으려면 전역 잠금을 획득해야 한다는 사실에 관한 것... 따라서
+ * RCU는 주어진 콜백이 호출할 준비가 되는 gp 번호를 보수적으로
+ * 추정합니다. 다음 코드는 이 추정치를 확인하고 가능한 경우 이를
+ * 개선하여 이전 gp 번호에 대한 콜백 호출을 가속화합니다.
+ *
+ * - 전역 seq의 snap값을 가져온다. 보통 같거나 한칸(4)차 이하.
+ */
gp_seq_req = rcu_seq_snap(&rcu_state.gp_seq);
if (rcu_segcblist_accelerate(&rdp->cblist, gp_seq_req))
ret = rcu_start_this_gp(rnp, rdp, gp_seq_req);
@@ -1699,12 +1752,30 @@ static void rcu_accelerate_cbs_unlocked(struct rcu_node *rnp,
*
* The caller must hold rnp->lock with interrupts disabled.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * gp이 완료된 모든 콜백을 RCU_DONE_TAIL 하위 목록으로
+ * 이동한 다음 나머지 하위 목록을 압축하고 ->gp_seq 번호를
+ * RCU_NEXT_TAIL 하위 목록의 모든 콜백에 할당합니다. 이 함수는
+ * 멱등적이므로 반복적으로 호출해도 문제가 되지 않습니다. 너무 자주
+ * 호출되지 않는 한...
+ * RCU gp kthread를 깨워야 하는 경우 true를 반환합니다.
+ *
+ * 호출자는 인터럽트가 비활성화된 상태에서 rnp->lock을 유지해야 합니다.
+ *
+ * -
+ */
static bool rcu_advance_cbs(struct rcu_node *rnp, struct rcu_data *rdp)
{
rcu_lockdep_assert_cblist_protected(rdp);
raw_lockdep_assert_held_rcu_node(rnp);
/* If no pending (not yet ready to invoke) callbacks, nothing to do. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - pending중인 cb가 없다면 return false.
+ */
if (!rcu_segcblist_pend_cbs(&rdp->cblist))
return false;
@@ -1712,6 +1783,15 @@ static bool rcu_advance_cbs(struct rcu_node *rnp, struct rcu_data *rdp)
* Find all callbacks whose ->gp_seq numbers indicate that they
* are ready to invoke, and put them into the RCU_DONE_TAIL sublist.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * ->gp_seq 번호가 호출 준비가 되었음을 나타내는 모든 콜백을 찾아
+ * RCU_DONE_TAIL 하위 목록에 넣습니다.
+ *
+ * - accelerate를 위해서 완료된 @rnp->gp_seq이하의 cb를 done으로 옮긴다.
+ * next_ready구간은 wait로 옮긴다.
+ */
rcu_segcblist_advance(&rdp->cblist, rnp->gp_seq);
/* Classify any remaining callbacks. */
@@ -1752,6 +1832,16 @@ static void rcu_strict_gp_check_qs(void)
* structure corresponding to the current CPU, and must have irqs disabled.
* Returns true if the grace-period kthread needs to be awakened.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * CPU 로컬 rcu_data 상태를 업데이트하여 gp의 시작과 끝을
+ * 기록합니다. 호출자는 현재 CPU에 해당하는 리프 rcu_node 구조의 ->
+ * 잠금을 보유해야 하며 irqs를 비활성화해야 합니다.
+ * gp kthread를 깨워야 하는 경우 true를 반환합니다.
+ *
+ * -
+ */
static bool __note_gp_changes(struct rcu_node *rnp, struct rcu_data *rdp)
{
bool ret = false;
@@ -1760,10 +1850,18 @@ static bool __note_gp_changes(struct rcu_node *rnp, struct rcu_data *rdp)
raw_lockdep_assert_held_rcu_node(rnp);
+/*
+ * IAMROOT, 2023.07.22:
+ * - seq 변화 없으면 return.
+ */
if (rdp->gp_seq == rnp->gp_seq)
return false; /* Nothing to do. */
/* Handle the ends of any preceding grace periods first. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - gp_seq가 완료됬거나
+ */
if (rcu_seq_completed_gp(rdp->gp_seq, rnp->gp_seq) ||
unlikely(READ_ONCE(rdp->gpwrap))) {
if (!offloaded)
@@ -1799,6 +1897,10 @@ static bool __note_gp_changes(struct rcu_node *rnp, struct rcu_data *rdp)
return ret;
}
+/*
+ * IAMROOT, 2023.07.22:
+ * - gp과 시작과 끝을 검사한다.
+ */
static void note_gp_changes(struct rcu_data *rdp)
{
unsigned long flags;
@@ -1807,12 +1909,22 @@ static void note_gp_changes(struct rcu_data *rdp)
local_irq_save(flags);
rnp = rdp->mynode;
+/*
+ * IAMROOT, 2023.07.22:
+ * - this cpu와 상위 node seq가 변화가 없으면 바뀐게 없다는것 +
+ * 한바퀴 돈게 아니라면 return.
+ */
if ((rdp->gp_seq == rcu_seq_current(&rnp->gp_seq) &&
!unlikely(READ_ONCE(rdp->gpwrap))) || /* w/out lock. */
!raw_spin_trylock_rcu_node(rnp)) { /* irqs already off, so later. */
local_irq_restore(flags);
return;
}
+/*
+ * IAMROOT, 2023.07.22:
+ * - gp seq에 변화가 생긴것을 상위 node seq를 보고 확인했다.
+ */
+
needwake = __note_gp_changes(rnp, rdp);
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
rcu_strict_gp_check_qs();
@@ -2456,6 +2568,14 @@ rcu_report_qs_rdp(struct rcu_data *rdp)
* Otherwise, see if this CPU has just passed through its first
* quiescent state for this grace period, and record that fact if so.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * 이 CPU가 아직 인식하지 못하는 새로운 gp이 있는지 확인하고,
+ * 그렇다면 로컬 rcu_data 상태를 설정하십시오.
+ * 그렇지 않으면 이 gp동안 이 CPU가 첫 번째 qs를
+ * 통과했는지 확인하고 해당 사실을 기록하십시오.
+ */
static void
rcu_check_quiescent_state(struct rcu_data *rdp)
{
@@ -2480,6 +2600,10 @@ rcu_check_quiescent_state(struct rcu_data *rdp)
* Tell RCU we are done (but rcu_report_qs_rdp() will be the
* judge of that).
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - this cpu가 qs라는것을 report
+ */
rcu_report_qs_rdp(rdp);
}
@@ -2835,6 +2959,10 @@ static void strict_work_handler(struct work_struct *work)
}
/* Perform RCU core processing work for the current CPU. */
+/*
+ * IAMROOT, 2023.07.22:
+ * -
+ */
static __latent_entropy void rcu_core(void)
{
unsigned long flags;
@@ -2848,6 +2976,10 @@ static __latent_entropy void rcu_core(void)
WARN_ON_ONCE(!rdp->beenonline);
/* Report any deferred quiescent states if preemption enabled. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - SKIP
+ */
if (!(preempt_count() & PREEMPT_MASK)) {
rcu_preempt_deferred_qs(current);
} else if (rcu_preempt_need_deferred_qs(current)) {
@@ -2883,6 +3015,10 @@ static __latent_entropy void rcu_core(void)
queue_work_on(rdp->cpu, rcu_gp_wq, &rdp->strict_work);
}
+/*
+ * IAMROOT, 2023.07.22:
+ * - RCU_SOFTIRQ
+ */
static void rcu_core_si(struct softirq_action *h)
{
rcu_core();
@@ -2914,6 +3050,10 @@ static void invoke_rcu_core_kthread(void)
/*
* Wake up this CPU's rcuc kthread to do RCU core processing.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - RCU_SOFTIRQ callback(rcu_core_si()) 실행한다.
+ */
static void invoke_rcu_core(void)
{
if (!cpu_online(smp_processor_id()))
@@ -2997,6 +3137,10 @@ static int __init rcu_spawn_core_kthreads(void)
/*
* Handle any core-RCU processing required by a call_rcu() invocation.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - RCU_SOFTIRQ를 invoke한다.
+ */
static void __call_rcu_core(struct rcu_data *rdp, struct rcu_head *head,
unsigned long flags)
{
@@ -3018,6 +3162,19 @@ static void __call_rcu_core(struct rcu_data *rdp, struct rcu_head *head,
* invoking rcu_force_quiescent_state() if the newly enqueued callback
* is the only one waiting for a grace period to complete.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * 콜백이 너무 많거나 대기 시간이 너무 긴 경우 gp을 강제
+ * 적용합니다.
+ * 히스테리시스를 적용하고 다른 CPU가 최근에
+ * rcu_force_quiescent_state()를 호출한 경우
+ * rcu_force_quiescent_state()를 호출하지 마십시오. 또한 새로
+ * 대기열에 추가된 콜백이 gp이 완료되기를 기다리는 유일한
+ * 콜백인 경우 rcu_force_quiescent_state()를 호출하지 마십시오.
+ *
+ * - 너무 많이 cb가 쌓여있다. 강제로 fqs(force qs)를 한다.
+ */
if (unlikely(rcu_segcblist_n_cbs(&rdp->cblist) >
rdp->qlen_last_fqs_check + qhimark)) {
@@ -3052,11 +3209,24 @@ static void rcu_leak_callback(struct rcu_head *rhp)
* number of queued RCU callbacks. The caller must hold the leaf rcu_node
* structure's ->lock.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * 해당 CPU의 대기 중인 RCU 콜백 수를 기준으로 현재 CPU에 해당하는 리프
+ * rcu_node 구조의 ->cbovldmask 비트를 확인하고 필요한 경우 업데이트합니다.
+ * 호출자는 리프 rcu_node 구조의 -> 잠금을 보유해야 합니다.
+ *
+ * - overload면 grpmask를 set, 아니면 unset한다.
+ */
static void check_cb_ovld_locked(struct rcu_data *rdp, struct rcu_node *rnp)
{
raw_lockdep_assert_held_rcu_node(rnp);
if (qovld_calc <= 0)
return; // Early boot and wildcard value set.
+/*
+ * IAMROOT, 2023.07.22:
+ * - overload됬으면
+ */
if (rcu_segcblist_n_cbs(&rdp->cblist) >= qovld_calc)
WRITE_ONCE(rnp->cbovldmask, rnp->cbovldmask | rdp->grpmask);
else
@@ -3075,10 +3245,36 @@ static void check_cb_ovld_locked(struct rcu_data *rdp, struct rcu_node *rnp)
* be holding ->nocb_lock to do this check, which is too heavy for a
* common-case operation.
*/
+/*
+ * IAMROOT, 2023.07.22:
+ * - papago
+ * 해당 CPU의 대기 중인 RCU 콜백 수를 기준으로 현재 CPU에 해당하는
+ * 리프 rcu_node 구조의 ->cbovldmask 비트를 확인하고 필요한 경우
+ * 업데이트합니다. 잠금을 유지할 필요는 없지만 호출자는 인터럽트를
+ * 비활성화해야 합니다.
+ *
+ * 이 함수는 각각의 gp이 이미 종료된 많은 콜백이 있을
+ * 가능성을 무시합니다. 이 생략은 이 검사를 수행하기 위해
+ * ->nocb_lock을 유지해야 하는 CB가 없는 CPU가 필요하기 때문에
+ * 일반적인 경우 작업에 너무 무겁습니다.
+ *
+ * - overload여부에 따라 @rnp->cbovldmask에 rdp->grpmask를 set / unset 갱신.
+ * 이미 되있으면 아무것도 안한다.
+ */
static void check_cb_ovld(struct rcu_data *rdp)
{
struct rcu_node *const rnp = rdp->mynode;
+/*
+ * IAMROOT, 2023.07.22:
+ * - 다음과 같은경우 return.
+ * 1. qovld_calc이 아직 미설정이거나,
+ * 초기화안됨.
+ * 2. @rdp cb len >= qovld_calc && (rnp->cbovldmask) & rdp->grpmask)
+ * overload가 됬고 이미 overload가 되있으면
+ * 3. @rdp cb len < qovld_calc && !(rnp->cbovldmask) & rdp->grpmask)
+ * overload가 안됬고 overload 표시도 안되있으면
+ */
if (qovld_calc <= 0 ||
((rcu_segcblist_n_cbs(&rdp->cblist) >= qovld_calc) ==
!!(READ_ONCE(rnp->cbovldmask) & rdp->grpmask)))
@@ -3089,6 +3285,11 @@ static void check_cb_ovld(struct rcu_data *rdp)
}
/* Helper function for call_rcu() and friends. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - @head에 @func에 대한 node를 한개 추가하고 RCU_SOFTIRQ를
+ * invoke한다.
+ */
static void
__call_rcu(struct rcu_head *head, rcu_callback_t func)
{
@@ -3120,6 +3321,10 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func)
rdp = this_cpu_ptr(&rcu_data);
/* Add the callback to our list. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - SEGCBLIST_ENABLED 가 안켜져있으면 여기서 enable한다.
+ */
if (unlikely(!rcu_segcblist_is_enabled(&rdp->cblist))) {
// This can trigger due to call_rcu() from offline CPU:
WARN_ON_ONCE(rcu_scheduler_active != RCU_SCHEDULER_INACTIVE);
@@ -3130,11 +3335,24 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func)
rcu_segcblist_init(&rdp->cblist);
}
+/*
+ * IAMROOT, 2023.07.22:
+ * - overload 여부 update
+ */
check_cb_ovld(rdp);
+
+/*
+ * IAMROOT, 2023.07.22:
+ * - nocb인경우 return이거나 lock을 올수도있다. 기본값을 nocb를 사용안한다.
+ */
if (rcu_nocb_try_bypass(rdp, head, &was_alldone, flags))
return; // Enqueued onto ->nocb_bypass, so just leave.
// If no-CBs CPU gets here, rcu_nocb_try_bypass() acquired ->nocb_lock.
rcu_segcblist_enqueue(&rdp->cblist, head);
+/*
+ * IAMROOT, 2023.07.22:
+ * - debug
+ */
if (__is_kvfree_rcu_offset((unsigned long)func))
trace_rcu_kvfree_callback(rcu_state.name, head,
(unsigned long)func,
@@ -3197,11 +3415,11 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func)
/*
* IAMROOT, 2023.07.21:
* - papago
- * call_rcu() - 유예 기간 후 호출을 위해 RCU 콜백을 대기시킵니다.
+ * call_rcu() - gp 후 호출을 위해 RCU 콜백을 대기시킵니다.
* @head: RCU 업데이트를 대기하는 데 사용할 구조입니다.
- * @func: 유예 기간 후에 호출되는 실제 콜백 함수.
+ * @func: gp 후에 호출되는 실제 콜백 함수.
*
- * 콜백 함수는 전체 유예 기간이 경과한 후, 즉 기존의 모든 RCU 읽기 측 임계
+ * 콜백 함수는 전체 gp이 경과한 후, 즉 기존의 모든 RCU 읽기 측 임계
* 섹션이 완료된 후 호출됩니다. 그러나 콜백 함수는 call_rcu()가 호출된
* 후에 시작된 RCU 읽기 측 임계 섹션과 동시에 실행될 수 있습니다.
*
@@ -3211,7 +3429,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func)
* 여기에는 하드웨어 인터럽트 핸들러, softirq 핸들러 및 NMI 핸들러가
* 포함됩니다.
*
- * 모든 CPU는 유예 기간이 기존의 모든 RCU 읽기 측 중요 섹션을 넘어
+ * 모든 CPU는 gp이 기존의 모든 RCU 읽기 측 중요 섹션을 넘어
* 연장된다는 데 동의해야 합니다. CPU가 두 개 이상인 시스템에서 이것은
* "func()"가 호출될 때 각 CPU가 call_rcu() 호출보다 먼저 시작되는 마지막
* RCU 읽기 측 임계 섹션의 끝 이후로 전체 메모리 장벽을 실행했음을 의미합니다.
@@ -3228,6 +3446,8 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func)
* 경우에만 해당).
*
* 이러한 메모리 순서 보장의 구현은 여기에 설명되어 있습니다.
+ *
+ * - @head에 @func에 대한 node를 추가하고 RCU_SOFTIRQ를 invoke한다.
*/
void call_rcu(struct rcu_head *head, rcu_callback_t func)
{
@@ -3840,13 +4060,13 @@ void __init kfree_rcu_scheduler_running(void)
/*
* IAMROOT, 2023.07.21:
* - papago
- * 초기 부팅 중에 차단 유예 기간 대기는 자동으로 유예 기간을 의미합니다.
+ * 초기 부팅 중에 차단 gp 대기는 자동으로 gp을 의미합니다.
* 나중에 이것은 PREEMPTION의 경우가 아닙니다.
*
- * 그러나 컨텍스트 전환은 !PREEMPTION에 대한 유예 기간이기 때문에
+ * 그러나 컨텍스트 전환은 !PREEMPTION에 대한 gp이기 때문에
* synchronize_rcu() 또는 synchronize_rcu_expedited()를 실행하는 동안 어느
- * 시점에 온라인 CPU가 하나만 있는 경우 차단 유예 기간 대기는 자동으로
- * 유예 기간을 의미합니다. 온라인에 여러 개의 CPU가 있다고 잘못 표시해도
+ * 시점에 온라인 CPU가 하나만 있는 경우 차단 gp 대기는 자동으로
+ * gp을 의미합니다. 온라인에 여러 개의 CPU가 있다고 잘못 표시해도
* 괜찮습니다. 실제로는 전체 시간 동안 CPU가 한 개뿐이었는데 약간의 오버헤드가
* 추가될 뿐입니다.
* RCU는 여전히 올바르게 작동합니다.
@@ -3932,9 +4152,9 @@ static int rcu_blocking_is_gp(void)
/*
* IAMROOT, 2023.07.21:
* - papago
- * synchronize_rcu - 유예 기간이 경과할 때까지 기다립니다.
+ * synchronize_rcu - gp이 경과할 때까지 기다립니다.
*
- * 전체 유예 기간이 경과한 후, 즉 현재 실행 중인 모든 RCU 읽기 측 임계 섹션이
+ * 전체 gp이 경과한 후, 즉 현재 실행 중인 모든 RCU 읽기 측 임계 섹션이
* 완료된 후 제어가 호출자에게 반환됩니다. 그러나 synchronize_rcu()에서
* 반환되면 호출자는 synchronize_rcu()가 대기하는 동안 시작된 새로운 RCU 읽기
* 측 임계 섹션과 동시에 실행될 수 있습니다.
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index 305cf6aeb408..43864cbe95f0 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -156,10 +156,18 @@ struct rcu_data {
union rcu_noqs cpu_no_qs; /* No QSes yet for this CPU. */
bool core_needs_qs; /* Core waits for quiescent state. */
bool beenonline; /* CPU online at least once. */
+/*
+ * IAMROOT, 2023.07.22:
+ * - 1바퀴 돌은지에 대한 여부
+ */
bool gpwrap; /* Possible ->gp_seq wrap. */
bool exp_deferred_qs; /* This CPU awaiting a deferred QS? */
bool cpu_started; /* RCU watching this onlining CPU. */
struct rcu_node *mynode; /* This CPU's leaf of hierarchy */
+/*
+ * IAMROOT, 2023.07.22:
+ * - cpu가 속한 group에대한 bitmask
+ */
unsigned long grpmask; /* Mask to apply to leaf qsmask. */
unsigned long ticks_this_gp; /* The number of scheduling-clock */
/* ticks this CPU has handled */
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 4809ceffe565..008021498c83 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -13,6 +13,10 @@
#include "../locking/rtmutex_common.h"
+/*
+ * IAMROOT, 2023.07.22:
+ * - PASS
+ */
static bool rcu_rdp_is_offloaded(struct rcu_data *rdp)
{
/*
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 627 |
228 | [커널 20차] 20주차 [2] | 이민찬 | 2023.09.17 | 182 |
227 | [커널 20차] 19주차 | 이민찬 | 2023.09.10 | 103 |
226 | [커널 20차] 18주차 | 이민찬 | 2023.09.03 | 85 |
225 | [커널 20차] 17주차 | 이민찬 | 2023.08.27 | 129 |
224 | [커널 20차] 16주차 | 이민찬 | 2023.08.20 | 132 |
223 | [커널 19차] 64 주차 | Min | 2023.08.19 | 91 |
222 | [커널 20차] 15주차 | 이민찬 | 2023.08.13 | 126 |
221 | [커널 19차] 63 주차 | Min | 2023.08.12 | 60 |
220 | [커널 19차] 62 주차 | Min | 2023.08.05 | 79 |
219 | [커널 20차] 13주차 | 이민찬 | 2023.07.30 | 106 |
218 | [커널 19차] 61 주차 | Min | 2023.07.30 | 45 |
217 | [커널 20차] 12주차 | 이민찬 | 2023.07.22 | 87 |
216 | [커널 19차] 59 ~ 60 주차 | Min | 2023.07.22 | 37 |
» | [커널 18차] 113주차 | kkr | 2023.07.22 | 78 |
214 | [커널20차] 11주차 | 이경재 | 2023.07.15 | 86 |
213 | [커널20차] 10주차 | 이경재 | 2023.07.09 | 90 |
212 | [커널20차] 9주차 | 이경재 | 2023.07.02 | 85 |
211 | [커널 19차] 58 주차 | Min | 2023.07.01 | 41 |
210 | [커널 19차] 56 ~ 57 주차 | Min | 2023.06.25 | 40 |
209 | [커널 18차] 109주차 | kkr | 2023.06.24 | 33 |
.