Skip to content

Commit ef4ae6e

Browse files
Fenghua YuKAGA-KOKO
authored andcommitted
x86/bus_lock: Set rate limit for bus lock
A bus lock can be thousands of cycles slower than atomic operation within one cache line. It also disrupts performance on other cores. Malicious users can generate multiple bus locks to degrade the whole system performance. The current mitigation is to kill the offending process, but for certain scenarios it's desired to identify and throttle the offending application. Add a system wide rate limit for bus locks. When the system detects bus locks at a rate higher than N/sec (where N can be set by the kernel boot argument in the range [1..1000]) any task triggering a bus lock will be forced to sleep for at least 20ms until the overall system rate of bus locks drops below the threshold. Signed-off-by: Fenghua Yu <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Tony Luck <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 1897907 commit ef4ae6e

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

arch/x86/kernel/cpu/intel.c

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/thread_info.h>
1111
#include <linux/init.h>
1212
#include <linux/uaccess.h>
13+
#include <linux/delay.h>
1314

1415
#include <asm/cpufeature.h>
1516
#include <asm/msr.h>
@@ -41,6 +42,7 @@ enum split_lock_detect_state {
4142
sld_off = 0,
4243
sld_warn,
4344
sld_fatal,
45+
sld_ratelimit,
4446
};
4547

4648
/*
@@ -997,13 +999,30 @@ static const struct {
997999
{ "off", sld_off },
9981000
{ "warn", sld_warn },
9991001
{ "fatal", sld_fatal },
1002+
{ "ratelimit:", sld_ratelimit },
10001003
};
10011004

1005+
static struct ratelimit_state bld_ratelimit;
1006+
10021007
static inline bool match_option(const char *arg, int arglen, const char *opt)
10031008
{
1004-
int len = strlen(opt);
1009+
int len = strlen(opt), ratelimit;
1010+
1011+
if (strncmp(arg, opt, len))
1012+
return false;
1013+
1014+
/*
1015+
* Min ratelimit is 1 bus lock/sec.
1016+
* Max ratelimit is 1000 bus locks/sec.
1017+
*/
1018+
if (sscanf(arg, "ratelimit:%d", &ratelimit) == 1 &&
1019+
ratelimit > 0 && ratelimit <= 1000) {
1020+
ratelimit_state_init(&bld_ratelimit, HZ, ratelimit);
1021+
ratelimit_set_flags(&bld_ratelimit, RATELIMIT_MSG_ON_RELEASE);
1022+
return true;
1023+
}
10051024

1006-
return len == arglen && !strncmp(arg, opt, len);
1025+
return len == arglen;
10071026
}
10081027

10091028
static bool split_lock_verify_msr(bool on)
@@ -1082,6 +1101,15 @@ static void sld_update_msr(bool on)
10821101

10831102
static void split_lock_init(void)
10841103
{
1104+
/*
1105+
* #DB for bus lock handles ratelimit and #AC for split lock is
1106+
* disabled.
1107+
*/
1108+
if (sld_state == sld_ratelimit) {
1109+
split_lock_verify_msr(false);
1110+
return;
1111+
}
1112+
10851113
if (cpu_model_supports_sld)
10861114
split_lock_verify_msr(sld_state != sld_off);
10871115
}
@@ -1154,6 +1182,12 @@ void handle_bus_lock(struct pt_regs *regs)
11541182
switch (sld_state) {
11551183
case sld_off:
11561184
break;
1185+
case sld_ratelimit:
1186+
/* Enforce no more than bld_ratelimit bus locks/sec. */
1187+
while (!__ratelimit(&bld_ratelimit))
1188+
msleep(20);
1189+
/* Warn on the bus lock. */
1190+
fallthrough;
11571191
case sld_warn:
11581192
pr_warn_ratelimited("#DB: %s/%d took a bus_lock trap at address: 0x%lx\n",
11591193
current->comm, current->pid, regs->ip);
@@ -1259,6 +1293,10 @@ static void sld_state_show(void)
12591293
" from non-WB" : "");
12601294
}
12611295
break;
1296+
case sld_ratelimit:
1297+
if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT))
1298+
pr_info("#DB: setting system wide bus lock rate limit to %u/sec\n", bld_ratelimit.burst);
1299+
break;
12621300
}
12631301
}
12641302

0 commit comments

Comments
 (0)