diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index ef51ed87ef383ea2eaf0e7de41d49c5b76c245b9..4b20f0fd949ea81200fa3144f06d6b7d0260231e 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -406,8 +406,12 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason) BUG_ON(ctx->mm != mm); +#ifdef CONFIG_USERSWAP + VM_BUG_ON(uswap_vm_flag_bug_on(reason)); +#else VM_BUG_ON(reason & ~(VM_UFFD_MISSING|VM_UFFD_WP)); VM_BUG_ON(!(reason & VM_UFFD_MISSING) ^ !!(reason & VM_UFFD_WP)); +#endif if (ctx->features & UFFD_FEATURE_SIGBUS) goto out; diff --git a/include/linux/userswap.h b/include/linux/userswap.h index 82cc79584e4362078dda37ac7a586f0c41e6a99f..6c96cef2ec9bcc4ee4ddf206e9617434bc154c08 100644 --- a/include/linux/userswap.h +++ b/include/linux/userswap.h @@ -47,6 +47,18 @@ static inline bool uswap_validate_mremap_flags(unsigned long flags) return true; } +/* When CONFIG_USERSWAP=y, VM_UFFD_MISSING|VM_USWAP is right; + * 0 or > 1 flags set is a bug; we expect exactly 1. + */ +static inline bool uswap_vm_flag_bug_on(unsigned long reason) +{ + if (reason & ~(VM_UFFD_MISSING | VM_UFFD_WP | VM_USWAP)) + return true; + if (reason & VM_USWAP) + return !(reason & VM_UFFD_MISSING) || reason & ~(VM_USWAP|VM_UFFD_MISSING); + return !(reason & VM_UFFD_MISSING) ^ !!(reason & VM_UFFD_WP); +} + #endif /* CONFIG_USERSWAP */ #endif /* _LINUX_USERSWAP_H */