[PATCH 16/16] dept: Distinguish each syscall context from another

Byungchul Park
2022-02-17T11:28:06Z

It enters kernel mode on each syscall and each syscall handling should
be considered independently from the point of view of Dept. Otherwise,
Dept may wrongly track dependencies across different syscalls.

That might be a real dependency from user mode. However, now that Dept
just started to work, conservatively let Dept not track dependencies
across different syscalls.

Signed-off-by: Byungchul Park <byungchul.park@lge.com>
---
include/linux/dept.h | 39 ++++++++++++++++------------
kernel/dependency/dept.c | 67 ++++++++++++++++++++++++------------------------
kernel/entry/common.c | 3 +++
3 files changed, 60 insertions(+), 49 deletions(-)

diff --git a/include/linux/dept.h b/include/linux/dept.h
index 531065a..acf4db0 100644
--- a/include/linux/dept.h
+++ b/include/linux/dept.h
@@ -25,11 +25,16 @@
#define DEPT_MAX_SUBCLASSES_USR (DEPT_MAX_SUBCLASSES / DEPT_MAX_SUBCLASSES_EVT)
#define DEPT_MAX_SUBCLASSES_CACHE 2

-#define DEPT_SIRQ 0
-#define DEPT_HIRQ 1
-#define DEPT_IRQS_NR 2
-#define DEPT_SIRQF (1UL << DEPT_SIRQ)
-#define DEPT_HIRQF (1UL << DEPT_HIRQ)
+enum {
+ DEPT_CXT_SIRQ = 0,
+ DEPT_CXT_HIRQ,
+ DEPT_CXT_IRQS_NR,
+ DEPT_CXT_PROCESS = DEPT_CXT_IRQS_NR,
+ DEPT_CXTS_NR
+};
+
+#define DEPT_SIRQF (1UL << DEPT_CXT_SIRQ)
+#define DEPT_HIRQF (1UL << DEPT_CXT_HIRQ)

struct dept_ecxt;
struct dept_iecxt {
@@ -89,8 +94,8 @@ struct dept_class {
/*
* for tracking IRQ dependencies
*/
- struct dept_iecxt iecxt[DEPT_IRQS_NR];
- struct dept_iwait iwait[DEPT_IRQS_NR];
+ struct dept_iecxt iecxt[DEPT_CXT_IRQS_NR];
+ struct dept_iwait iwait[DEPT_CXT_IRQS_NR];
};

struct dept_stack {
@@ -144,8 +149,8 @@ struct dept_ecxt {
/*
* where the IRQ-enabled happened
*/
- unsigned long enirq_ip[DEPT_IRQS_NR];
- struct dept_stack *enirq_stack[DEPT_IRQS_NR];
+ unsigned long enirq_ip[DEPT_CXT_IRQS_NR];
+ struct dept_stack *enirq_stack[DEPT_CXT_IRQS_NR];

/*
* where the event context started
@@ -188,8 +193,8 @@ struct dept_wait {
/*
* where the IRQ wait happened
*/
- unsigned long irq_ip[DEPT_IRQS_NR];
- struct dept_stack *irq_stack[DEPT_IRQS_NR];
+ unsigned long irq_ip[DEPT_CXT_IRQS_NR];
+ struct dept_stack *irq_stack[DEPT_CXT_IRQS_NR];

/*
* where the wait happened
@@ -389,19 +394,19 @@ struct dept_task {
int wait_hist_pos;

/*
- * sequential id to identify each IRQ context
+ * sequential id to identify each context
*/
- unsigned int irq_id[DEPT_IRQS_NR];
+ unsigned int cxt_id[DEPT_CXTS_NR];

/*
* for tracking IRQ-enabled points with cross-event
*/
- unsigned int wgen_enirq[DEPT_IRQS_NR];
+ unsigned int wgen_enirq[DEPT_CXT_IRQS_NR];

/*
* for keeping up-to-date IRQ-enabled points
*/
- unsigned long enirq_ip[DEPT_IRQS_NR];
+ unsigned long enirq_ip[DEPT_CXT_IRQS_NR];

/*
* current effective IRQ-enabled flag
@@ -438,7 +443,7 @@ struct dept_task {
.dept_task.wait_hist = { { .wait = NULL, } }, \
.dept_task.ecxt_held_pos = 0, \
.dept_task.wait_hist_pos = 0, \
- .dept_task.irq_id = { 0 }, \
+ .dept_task.cxt_id = { 0 }, \
.dept_task.wgen_enirq = { 0 }, \
.dept_task.enirq_ip = { 0 }, \
.dept_task.recursive = 0, \
@@ -470,6 +475,7 @@ struct dept_task {
extern void dept_wait_split_map(struct dept_map_each *me, struct dept_map_common *mc, unsigned long ip, const char *w_fn, int ne);
extern void dept_event_split_map(struct dept_map_each *me, struct dept_map_common *mc, unsigned long ip, const char *e_fn);
extern void dept_ask_event_split_map(struct dept_map_each *me, struct dept_map_common *mc);
+extern void dept_kernel_enter(void);

/*
* for users who want to manage external keys
@@ -510,6 +516,7 @@ struct dept_task {
#define dept_wait_split_map(me, mc, ip, w_fn, ne) do { } while (0)
#define dept_event_split_map(me, mc, ip, e_fn) do { } while (0)
#define dept_ask_event_split_map(me, mc) do { } while (0)
+#define dept_kernel_enter() do { } while (0)
#define dept_key_init(k) do { (void)(k); } while (0)
#define dept_key_destroy(k) do { (void)(k); } while (0)
#endif
diff --git a/kernel/dependency/dept.c b/kernel/dependency/dept.c
index 4510dbb..f728500 100644
--- a/kernel/dependency/dept.c
+++ b/kernel/dependency/dept.c
@@ -229,9 +229,9 @@ static inline struct dept_class *dep_tc(struct dept_dep *d)

static inline const char *irq_str(int irq)
{
- if (irq == DEPT_SIRQ)
+ if (irq == DEPT_CXT_SIRQ)
return "softirq";
- if (irq == DEPT_HIRQ)
+ if (irq == DEPT_CXT_HIRQ)
return "hardirq";
return "(unknown)";
}
@@ -389,7 +389,7 @@ static void initialize_class(struct dept_class *c)
{
int i;

- for (i = 0; i < DEPT_IRQS_NR; i++) {
+ for (i = 0; i < DEPT_CXT_IRQS_NR; i++) {
struct dept_iecxt *ie = &c->iecxt[i];
struct dept_iwait *iw = &c->iwait[i];

@@ -414,7 +414,7 @@ static void initialize_ecxt(struct dept_ecxt *e)
{
int i;

- for (i = 0; i < DEPT_IRQS_NR; i++) {
+ for (i = 0; i < DEPT_CXT_IRQS_NR; i++) {
e->enirq_stack[i] = NULL;
e->enirq_ip[i] = 0UL;
}
@@ -429,7 +429,7 @@ static void initialize_wait(struct dept_wait *w)
{
int i;

- for (i = 0; i < DEPT_IRQS_NR; i++) {
+ for (i = 0; i < DEPT_CXT_IRQS_NR; i++) {
w->irq_stack[i] = NULL;
w->irq_ip[i] = 0UL;
}
@@ -468,7 +468,7 @@ static void destroy_ecxt(struct dept_ecxt *e)
{
int i;

- for (i = 0; i < DEPT_IRQS_NR; i++)
+ for (i = 0; i < DEPT_CXT_IRQS_NR; i++)
if (e->enirq_stack[i])
put_stack(e->enirq_stack[i]);
if (e->class)
@@ -484,7 +484,7 @@ static void destroy_wait(struct dept_wait *w)
{
int i;

- for (i = 0; i < DEPT_IRQS_NR; i++)
+ for (i = 0; i < DEPT_CXT_IRQS_NR; i++)
if (w->irq_stack[i])
put_stack(w->irq_stack[i]);
if (w->class)
@@ -628,7 +628,7 @@ static void print_diagram(struct dept_dep *d)
const char *c_fn = e->ecxt_fn ?: "(unknown)";

irqf = e->enirqf & w->irqf;
- for_each_set_bit(irq, &irqf, DEPT_IRQS_NR) {
+ for_each_set_bit(irq, &irqf, DEPT_CXT_IRQS_NR) {
if (!firstline)
pr_warn("\nor\n\n");
firstline = false;
@@ -659,7 +659,7 @@ static void print_dep(struct dept_dep *d)
const char *c_fn = e->ecxt_fn ?: "(unknown)";

irqf = e->enirqf & w->irqf;
- for_each_set_bit(irq, &irqf, DEPT_IRQS_NR) {
+ for_each_set_bit(irq, &irqf, DEPT_CXT_IRQS_NR) {
pr_warn("%s has been enabled:\n", irq_str(irq));
print_ip_stack(e->enirq_ip[irq], e->enirq_stack[irq]);
pr_warn("\n");
@@ -885,7 +885,7 @@ static void bfs(struct dept_class *c, bfs_f *cb, void *in, void **out)
*/

static inline unsigned long cur_enirqf(void);
-static inline int cur_irq(void);
+static inline int cur_cxt(void);
static inline unsigned int cur_ctxt_id(void);

static inline struct dept_iecxt *iecxt(struct dept_class *c, int irq)
@@ -1411,7 +1411,7 @@ static void add_dep(struct dept_ecxt *e, struct dept_wait *w)
if (d) {
check_dl_bfs(d);

- for (i = 0; i < DEPT_IRQS_NR; i++) {
+ for (i = 0; i < DEPT_CXT_IRQS_NR; i++) {
struct dept_iwait *fiw = iwait(fc, i);
struct dept_iecxt *found_ie;
struct dept_iwait *found_iw;
@@ -1447,7 +1447,7 @@ static void add_wait(struct dept_class *c, unsigned long ip,
struct dept_task *dt = dept_task();
struct dept_wait *w;
unsigned int wg = 0U;
- int irq;
+ int cxt;
int i;

w = new_wait();
@@ -1459,9 +1459,9 @@ static void add_wait(struct dept_class *c, unsigned long ip,
w->wait_fn = w_fn;
w->wait_stack = get_current_stack();

- irq = cur_irq();
- if (irq < DEPT_IRQS_NR)
- add_iwait(c, irq, w);
+ cxt = cur_cxt();
+ if (cxt == DEPT_CXT_HIRQ || cxt == DEPT_CXT_SIRQ)
+ add_iwait(c, cxt, w);

/*
* Avoid adding dependency between user aware nested ecxt and
@@ -1526,7 +1526,7 @@ static void add_ecxt(void *obj, struct dept_class *c, unsigned long ip,
eh->nest = ne;

irqf = cur_enirqf();
- for_each_set_bit(irq, &irqf, DEPT_IRQS_NR)
+ for_each_set_bit(irq, &irqf, DEPT_CXT_IRQS_NR)
add_iecxt(c, irq, e, false);

del_ecxt(e);
@@ -1653,7 +1653,7 @@ static void do_event(void *obj, struct dept_class *c, unsigned int wg,
break;
}

- for (i = 0; i < DEPT_IRQS_NR; i++) {
+ for (i = 0; i < DEPT_CXT_IRQS_NR; i++) {
struct dept_ecxt *e;

if (before(dt->wgen_enirq[i], wg))
@@ -1695,7 +1695,7 @@ static void disconnect_class(struct dept_class *c)
call_rcu(&d->rh, del_dep_rcu);
}

- for (i = 0; i < DEPT_IRQS_NR; i++) {
+ for (i = 0; i < DEPT_CXT_IRQS_NR; i++) {
stale_iecxt(iecxt(c, i));
stale_iwait(iwait(c, i));
}
@@ -1720,27 +1720,21 @@ static inline unsigned long cur_enirqf(void)
return 0UL;
}

-static inline int cur_irq(void)
+static inline int cur_cxt(void)
{
if (lockdep_softirq_context(current))
- return DEPT_SIRQ;
+ return DEPT_CXT_SIRQ;
if (lockdep_hardirq_context())
- return DEPT_HIRQ;
- return DEPT_IRQS_NR;
+ return DEPT_CXT_HIRQ;
+ return DEPT_CXT_PROCESS;
}

static inline unsigned int cur_ctxt_id(void)
{
struct dept_task *dt = dept_task();
- int irq = cur_irq();
+ int cxt = cur_cxt();

- /*
- * Normal process context
- */
- if (irq == DEPT_IRQS_NR)
- return 0U;
-
- return dt->irq_id[irq] | (1UL << irq);
+ return dt->cxt_id[cxt] | (1UL << cxt);
}

static void enirq_transition(int irq)
@@ -1790,7 +1784,7 @@ static void enirq_update(unsigned long ip)
/*
* Do enirq_transition() only on an OFF -> ON transition.
*/
- for_each_set_bit(irq, &irqf, DEPT_IRQS_NR) {
+ for_each_set_bit(irq, &irqf, DEPT_CXT_IRQS_NR) {
if (prev & (1UL << irq))
continue;

@@ -1893,6 +1887,13 @@ void dept_disable_hardirq(unsigned long ip)
dept_exit(flags);
}

+void dept_kernel_enter(void)
+{
+ struct dept_task *dt = dept_task();
+
+ dt->cxt_id[DEPT_CXT_PROCESS] += (1UL << DEPT_CXTS_NR);
+}
+
/*
* Ensure it's the outmost softirq context.
*/
@@ -1900,7 +1901,7 @@ void dept_softirq_enter(void)
{
struct dept_task *dt = dept_task();

- dt->irq_id[DEPT_SIRQ] += (1UL << DEPT_IRQS_NR);
+ dt->cxt_id[DEPT_CXT_SIRQ] += (1UL << DEPT_CXTS_NR);
}

/*
@@ -1910,7 +1911,7 @@ void dept_hardirq_enter(void)
{
struct dept_task *dt = dept_task();

- dt->irq_id[DEPT_HIRQ] += (1UL << DEPT_IRQS_NR);
+ dt->cxt_id[DEPT_CXT_HIRQ] += (1UL << DEPT_CXTS_NR);
}

/*
diff --git a/kernel/entry/common.c b/kernel/entry/common.c
index bad7136..1826508 100644
--- a/kernel/entry/common.c
+++ b/kernel/entry/common.c
@@ -6,6 +6,7 @@
#include <linux/livepatch.h>
#include <linux/audit.h>
#include <linux/tick.h>
+#include <linux/dept.h>

#include "common.h"

@@ -102,6 +103,7 @@ noinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
long ret;

__enter_from_user_mode(regs);
+ dept_kernel_enter();

instrumentation_begin();
local_irq_enable();
@@ -114,6 +116,7 @@ noinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
noinstr void syscall_enter_from_user_mode_prepare(struct pt_regs *regs)
{
__enter_from_user_mode(regs);
+ dept_kernel_enter();
instrumentation_begin();
local_irq_enable();
instrumentation_end();
--
1.9.1