mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
tools/sched_ext: scx_qmap - Add sub-sched cap fault injection
Add a fault-injection mode to the scx_qmap sub-scheduler that deliberately dispatches one of its own tasks to a cid it does not hold. The kernel cap check must reject it and re-enqueue with SCX_TASK_REENQ_CAP, so the nr_inject_attempts counter tracks nr_reenq_cap one to one, exercising the delivery-time cap enforcement. Signed-off-by: Tejun Heo <tj@kernel.org> Reviewed-by: Andrea Righi <arighi@nvidia.com>
This commit is contained in:
parent
e9151ed5c9
commit
eb00f4a362
|
|
@ -378,6 +378,24 @@ static u64 needs_immed(s32 cid)
|
|||
return qa.cid_shared[cid] ? SCX_ENQ_IMMED : 0;
|
||||
}
|
||||
|
||||
/* first cid this node does NOT hold for fault injection, -1 if none */
|
||||
static s32 first_unavail_cid(void)
|
||||
{
|
||||
s32 nr_cids = qa.nr_cids, c;
|
||||
|
||||
if (nr_cids > SCX_QMAP_MAX_CPUS) {
|
||||
scx_bpf_error("-ERANGE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpf_for(c, 0, nr_cids) {
|
||||
if (!cmask_test(c, &qa.held_excl.mask) &&
|
||||
!cmask_test(c, &qa.held_shared.mask))
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int weight_to_idx(u32 weight)
|
||||
{
|
||||
/* Coarsely map the compound weight to a FIFO. */
|
||||
|
|
@ -454,6 +472,28 @@ void BPF_STRUCT_OPS(qmap_enqueue, struct task_struct *p, u64 enq_flags)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fault injection: deliberately dispatch one of our own tasks to a cid
|
||||
* we don't hold. The kernel cap check must reject it and re-enqueue
|
||||
* with SCX_TASK_REENQ_CAP, so nr_inject_attempts tracks nr_reenq_cap
|
||||
* and proves delivery-time enforcement. Throttled.
|
||||
*/
|
||||
if (qa.inject_mode == QMAP_INJ_WRONG_CID && p->nr_cpus_allowed > 1 &&
|
||||
!(enq_flags & SCX_ENQ_REENQ)) {
|
||||
static u32 inj_cnt;
|
||||
|
||||
if (!(++inj_cnt % 64)) {
|
||||
s32 bad = first_unavail_cid();
|
||||
|
||||
if (bad >= 0 && cmask_test(bad, &taskc->cpus_allowed)) {
|
||||
__sync_fetch_and_add(&qa.nr_inject_attempts, 1);
|
||||
scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL_ON | bad,
|
||||
slice_ns, enq_flags);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* IMMED stress testing: Every immed_stress_nth'th enqueue, dispatch
|
||||
* directly to prev_cpu's local DSQ even when busy to force dsq->nr > 1
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ const char help_fmt[] =
|
|||
"\n"
|
||||
"Usage: %s [-s SLICE_US] [-e COUNT] [-t COUNT] [-T COUNT] [-l COUNT] [-b COUNT]\n"
|
||||
" [-N COUNT] [-P] [-M] [-H] [-c CG_PATH] [-d PID] [-D LEN] [-S] [-p] [-I]\n"
|
||||
" [-F COUNT] [-i SEC] [-R MS] [-v]\n"
|
||||
" [-F COUNT] [-i SEC] [-R MS] [-J MODE] [-v]\n"
|
||||
"\n"
|
||||
" -s SLICE_US Override slice duration\n"
|
||||
" -e COUNT Trigger scx_bpf_error() after COUNT enqueues\n"
|
||||
|
|
@ -74,6 +74,7 @@ const char help_fmt[] =
|
|||
" -C MODE cid-override test (shuffle|bad-dup|bad-range|bad-mono)\n"
|
||||
" -i SEC Stats and weight-refresh interval, seconds (default 5)\n"
|
||||
" -R MS Round-robin period for time-shared cpus, ms (default 200)\n"
|
||||
" -J MODE Fault injection (wrong-cid: dispatch to a cid not held)\n"
|
||||
" -v Print libbpf debug messages\n"
|
||||
" -h Display this help and exit\n";
|
||||
|
||||
|
|
@ -184,6 +185,7 @@ struct hier_prev {
|
|||
u64 nr_dsps[MAX_SUB_SCHEDS];
|
||||
u64 nr_reenq_cap;
|
||||
u64 nr_reenq_immed;
|
||||
u64 nr_inject_attempts;
|
||||
};
|
||||
|
||||
/* current wall-clock time as "HH:MM:SS" for the startup and interval headers */
|
||||
|
|
@ -265,12 +267,14 @@ static void print_hier(struct qmap_arena *qa, struct hier_prev *prev, u64 own_cg
|
|||
}
|
||||
|
||||
format_cid_ranges(qa, CID_SHARED, ranges, sizeof(ranges));
|
||||
printf("hier : nsub=%llu excl=%u shared=%s rr=%s reenq cap/immed +%llu/+%llu\n",
|
||||
printf("hier : nsub=%llu excl=%u shared=%s rr=%s reenq cap/immed +%llu/+%llu inj=+%llu\n",
|
||||
(unsigned long long)qa->nr_sub_scheds, qa->part.nr_excl, ranges, rr,
|
||||
(unsigned long long)(qa->nr_reenq_cap - prev->nr_reenq_cap),
|
||||
(unsigned long long)(qa->nr_reenq_immed - prev->nr_reenq_immed));
|
||||
(unsigned long long)(qa->nr_reenq_immed - prev->nr_reenq_immed),
|
||||
(unsigned long long)(qa->nr_inject_attempts - prev->nr_inject_attempts));
|
||||
prev->nr_reenq_cap = qa->nr_reenq_cap;
|
||||
prev->nr_reenq_immed = qa->nr_reenq_immed;
|
||||
prev->nr_inject_attempts = qa->nr_inject_attempts;
|
||||
|
||||
printf("hier : %-4s %10s %4s %6s %8s %s\n",
|
||||
"", "cgroup", "w", "alloc", "disp/s", "cids");
|
||||
|
|
@ -311,6 +315,7 @@ int main(int argc, char **argv)
|
|||
struct hier_prev hprev = {};
|
||||
const char *sub_cg_path = NULL;
|
||||
char tbuf[32];
|
||||
u32 inject_mode = 0;
|
||||
u64 own_cgid = 0;
|
||||
|
||||
libbpf_set_print(libbpf_print_fn);
|
||||
|
|
@ -331,7 +336,7 @@ int main(int argc, char **argv)
|
|||
skel->rodata->slice_ns = __COMPAT_ENUM_OR_ZERO("scx_public_consts", "SCX_SLICE_DFL");
|
||||
skel->rodata->max_tasks = 16384;
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:e:t:T:l:b:N:PMHc:d:D:SpIF:C:i:R:vh")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "s:e:t:T:l:b:N:PMHc:d:D:SpIF:C:i:R:J:vh")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
skel->rodata->slice_ns = strtoull(optarg, NULL, 0) * 1000;
|
||||
|
|
@ -465,6 +470,12 @@ int main(int argc, char **argv)
|
|||
if (round_robin_ms < 10)
|
||||
round_robin_ms = 10;
|
||||
break;
|
||||
case 'J':
|
||||
if (!strcmp(optarg, "wrong-cid"))
|
||||
inject_mode = QMAP_INJ_WRONG_CID;
|
||||
else
|
||||
inject_mode = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
|
|
@ -481,6 +492,7 @@ int main(int argc, char **argv)
|
|||
|
||||
qa = &skel->arena->qa;
|
||||
qa->test_error_cnt = test_error_cnt;
|
||||
qa->inject_mode = inject_mode;
|
||||
|
||||
if (sub_cg_path)
|
||||
printf("%s scx_qmap started: sub-scheduler on %s, stats every %ds\n",
|
||||
|
|
|
|||
|
|
@ -60,6 +60,12 @@ struct qmap_fifo {
|
|||
s32 idx;
|
||||
};
|
||||
|
||||
/* -J fault-injection modes. Selects inject_mode in struct qmap_arena. */
|
||||
enum qmap_inject {
|
||||
QMAP_INJ_OFF = 0,
|
||||
QMAP_INJ_WRONG_CID = 1, /* dispatch to a cid we don't hold */
|
||||
};
|
||||
|
||||
/*
|
||||
* scx_cmask's are embedded in struct qmap_arena with inline backing storage.
|
||||
* The bpf side uses &field.mask with the normal cmask_* helpers. Userspace
|
||||
|
|
@ -167,6 +173,8 @@ struct qmap_arena {
|
|||
/* bpf -> userspace: stats */
|
||||
u64 nr_reenq_cap; /* SCX_TASK_REENQ_CAP bounces */
|
||||
u64 nr_reenq_immed; /* SCX_TASK_REENQ_IMMED bounces */
|
||||
u64 nr_inject_attempts; /* fault-injection: dispatches to an unheld cid */
|
||||
u32 inject_mode; /* fault-injection mode (QMAP_INJ_*) */
|
||||
};
|
||||
|
||||
#endif /* __SCX_QMAP_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user