Skip to content

Commit f47491d

Browse files
sean-jcbonzini
authored andcommitted
KVM: x86/mmu: Handle "default" period when selectively waking kthread
Account for the '0' being a default, "let KVM choose" period, when determining whether or not the recovery worker needs to be awakened in response to userspace reducing the period. Failure to do so results in the worker not being awakened properly, e.g. when changing the period from '0' to any small-ish value. Fixes: 4dfe4f4 ("kvm: x86: mmu: Make NX huge page recovery period configurable") Cc: [email protected] Cc: Junaid Shahid <[email protected]> Signed-off-by: Sean Christopherson <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 28f091b commit f47491d

File tree

1 file changed

+33
-15
lines changed

1 file changed

+33
-15
lines changed

arch/x86/kvm/mmu/mmu.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6171,23 +6171,46 @@ void kvm_mmu_module_exit(void)
61716171
mmu_audit_disable();
61726172
}
61736173

6174+
/*
6175+
* Calculate the effective recovery period, accounting for '0' meaning "let KVM
6176+
* select a halving time of 1 hour". Returns true if recovery is enabled.
6177+
*/
6178+
static bool calc_nx_huge_pages_recovery_period(uint *period)
6179+
{
6180+
/*
6181+
* Use READ_ONCE to get the params, this may be called outside of the
6182+
* param setters, e.g. by the kthread to compute its next timeout.
6183+
*/
6184+
bool enabled = READ_ONCE(nx_huge_pages);
6185+
uint ratio = READ_ONCE(nx_huge_pages_recovery_ratio);
6186+
6187+
if (!enabled || !ratio)
6188+
return false;
6189+
6190+
*period = READ_ONCE(nx_huge_pages_recovery_period_ms);
6191+
if (!*period) {
6192+
/* Make sure the period is not less than one second. */
6193+
ratio = min(ratio, 3600u);
6194+
*period = 60 * 60 * 1000 / ratio;
6195+
}
6196+
return true;
6197+
}
6198+
61746199
static int set_nx_huge_pages_recovery_param(const char *val, const struct kernel_param *kp)
61756200
{
61766201
bool was_recovery_enabled, is_recovery_enabled;
61776202
uint old_period, new_period;
61786203
int err;
61796204

6180-
was_recovery_enabled = nx_huge_pages_recovery_ratio;
6181-
old_period = nx_huge_pages_recovery_period_ms;
6205+
was_recovery_enabled = calc_nx_huge_pages_recovery_period(&old_period);
61826206

61836207
err = param_set_uint(val, kp);
61846208
if (err)
61856209
return err;
61866210

6187-
is_recovery_enabled = nx_huge_pages_recovery_ratio;
6188-
new_period = nx_huge_pages_recovery_period_ms;
6211+
is_recovery_enabled = calc_nx_huge_pages_recovery_period(&new_period);
61896212

6190-
if (READ_ONCE(nx_huge_pages) && is_recovery_enabled &&
6213+
if (is_recovery_enabled &&
61916214
(!was_recovery_enabled || old_period > new_period)) {
61926215
struct kvm *kvm;
61936216

@@ -6251,18 +6274,13 @@ static void kvm_recover_nx_lpages(struct kvm *kvm)
62516274

62526275
static long get_nx_lpage_recovery_timeout(u64 start_time)
62536276
{
6254-
uint ratio = READ_ONCE(nx_huge_pages_recovery_ratio);
6255-
uint period = READ_ONCE(nx_huge_pages_recovery_period_ms);
6277+
bool enabled;
6278+
uint period;
62566279

6257-
if (!period && ratio) {
6258-
/* Make sure the period is not less than one second. */
6259-
ratio = min(ratio, 3600u);
6260-
period = 60 * 60 * 1000 / ratio;
6261-
}
6280+
enabled = calc_nx_huge_pages_recovery_period(&period);
62626281

6263-
return READ_ONCE(nx_huge_pages) && ratio
6264-
? start_time + msecs_to_jiffies(period) - get_jiffies_64()
6265-
: MAX_SCHEDULE_TIMEOUT;
6282+
return enabled ? start_time + msecs_to_jiffies(period) - get_jiffies_64()
6283+
: MAX_SCHEDULE_TIMEOUT;
62666284
}
62676285

62686286
static int kvm_nx_lpage_recovery_worker(struct kvm *kvm, uintptr_t data)

0 commit comments

Comments
 (0)