}
 
 struct uffd_test_ops {
-       unsigned long expected_ioctls;
        void (*allocate_area)(void **alloc_area);
        void (*release_pages)(char *rel_area);
        void (*alias_mapping)(__u64 *start, size_t len, unsigned long offset);
 };
 
-#define SHMEM_EXPECTED_IOCTLS          ((1 << _UFFDIO_WAKE) | \
-                                        (1 << _UFFDIO_COPY) | \
-                                        (1 << _UFFDIO_ZEROPAGE))
-
-#define ANON_EXPECTED_IOCTLS           ((1 << _UFFDIO_WAKE) | \
-                                        (1 << _UFFDIO_COPY) | \
-                                        (1 << _UFFDIO_ZEROPAGE) | \
-                                        (1 << _UFFDIO_WRITEPROTECT))
-
 static struct uffd_test_ops anon_uffd_test_ops = {
-       .expected_ioctls = ANON_EXPECTED_IOCTLS,
        .allocate_area  = anon_allocate_area,
        .release_pages  = anon_release_pages,
        .alias_mapping = noop_alias_mapping,
 };
 
 static struct uffd_test_ops shmem_uffd_test_ops = {
-       .expected_ioctls = SHMEM_EXPECTED_IOCTLS,
        .allocate_area  = shmem_allocate_area,
        .release_pages  = shmem_release_pages,
        .alias_mapping = shmem_alias_mapping,
 };
 
 static struct uffd_test_ops hugetlb_uffd_test_ops = {
-       .expected_ioctls = UFFD_API_RANGE_IOCTLS_BASIC & ~(1 << _UFFDIO_CONTINUE),
        .allocate_area  = hugetlb_allocate_area,
        .release_pages  = hugetlb_release_pages,
        .alias_mapping = hugetlb_alias_mapping,
                return 0;
 }
 
+static uint64_t get_expected_ioctls(uint64_t mode)
+{
+       uint64_t ioctls = UFFD_API_RANGE_IOCTLS;
+
+       if (test_type == TEST_HUGETLB)
+               ioctls &= ~(1 << _UFFDIO_ZEROPAGE);
+
+       if (!((mode & UFFDIO_REGISTER_MODE_WP) && test_uffdio_wp))
+               ioctls &= ~(1 << _UFFDIO_WRITEPROTECT);
+
+       if (!((mode & UFFDIO_REGISTER_MODE_MINOR) && test_uffdio_minor))
+               ioctls &= ~(1 << _UFFDIO_CONTINUE);
+
+       return ioctls;
+}
+
+static void assert_expected_ioctls_present(uint64_t mode, uint64_t ioctls)
+{
+       uint64_t expected = get_expected_ioctls(mode);
+       uint64_t actual = ioctls & expected;
+
+       if (actual != expected) {
+               err("missing ioctl(s): expected %"PRIx64" actual: %"PRIx64,
+                   expected, actual);
+       }
+}
+
 static void userfaultfd_open(uint64_t *features)
 {
        struct uffdio_api uffdio_api;
 {
        struct uffdio_zeropage uffdio_zeropage;
        int ret;
-       unsigned long has_zeropage;
+       bool has_zeropage = get_expected_ioctls(0) & (1 << _UFFDIO_ZEROPAGE);
        __s64 res;
 
-       has_zeropage = uffd_test_ops->expected_ioctls & (1 << _UFFDIO_ZEROPAGE);
-
        if (offset >= nr_pages * page_size)
                err("unexpected offset %lu", offset);
        uffdio_zeropage.range.start = (unsigned long) area_dst + offset;
 static int userfaultfd_zeropage_test(void)
 {
        struct uffdio_register uffdio_register;
-       unsigned long expected_ioctls;
 
        printf("testing UFFDIO_ZEROPAGE: ");
        fflush(stdout);
        if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
                err("register failure");
 
-       expected_ioctls = uffd_test_ops->expected_ioctls;
-       if ((uffdio_register.ioctls & expected_ioctls) != expected_ioctls)
-               err("unexpected missing ioctl for anon memory");
+       assert_expected_ioctls_present(
+               uffdio_register.mode, uffdio_register.ioctls);
 
        if (uffdio_zeropage(uffd, 0))
                if (my_bcmp(area_dst, zeropage, page_size))
 static int userfaultfd_events_test(void)
 {
        struct uffdio_register uffdio_register;
-       unsigned long expected_ioctls;
        pthread_t uffd_mon;
        int err, features;
        pid_t pid;
        if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
                err("register failure");
 
-       expected_ioctls = uffd_test_ops->expected_ioctls;
-       if ((uffdio_register.ioctls & expected_ioctls) != expected_ioctls)
-               err("unexpected missing ioctl for anon memory");
+       assert_expected_ioctls_present(
+               uffdio_register.mode, uffdio_register.ioctls);
 
        if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &stats))
                err("uffd_poll_thread create");
 static int userfaultfd_sig_test(void)
 {
        struct uffdio_register uffdio_register;
-       unsigned long expected_ioctls;
        unsigned long userfaults;
        pthread_t uffd_mon;
        int err, features;
        if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
                err("register failure");
 
-       expected_ioctls = uffd_test_ops->expected_ioctls;
-       if ((uffdio_register.ioctls & expected_ioctls) != expected_ioctls)
-               err("unexpected missing ioctl for anon memory");
+       assert_expected_ioctls_present(
+               uffdio_register.mode, uffdio_register.ioctls);
 
        if (faulting_process(1))
                err("faulting process failed");
 static int userfaultfd_minor_test(void)
 {
        struct uffdio_register uffdio_register;
-       unsigned long expected_ioctls;
        unsigned long p;
        pthread_t uffd_mon;
        uint8_t expected_byte;
        if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
                err("register failure");
 
-       expected_ioctls = uffd_test_ops->expected_ioctls;
-       expected_ioctls |= 1 << _UFFDIO_CONTINUE;
-       if ((uffdio_register.ioctls & expected_ioctls) != expected_ioctls)
-               err("unexpected missing ioctl(s)");
+       assert_expected_ioctls_present(
+               uffdio_register.mode, uffdio_register.ioctls);
 
        /*
         * After registering with UFFD, populate the non-UFFD-registered side of
        pthread_attr_setstacksize(&attr, 16*1024*1024);
 
        while (bounces--) {
-               unsigned long expected_ioctls;
-
                printf("bounces: %d, mode:", bounces);
                if (bounces & BOUNCE_RANDOM)
                        printf(" rnd");
                        uffdio_register.mode |= UFFDIO_REGISTER_MODE_WP;
                if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))
                        err("register failure");
-               expected_ioctls = uffd_test_ops->expected_ioctls;
-               if ((uffdio_register.ioctls & expected_ioctls) !=
-                   expected_ioctls)
-                       err("unexpected missing ioctl for anon memory");
+               assert_expected_ioctls_present(
+                       uffdio_register.mode, uffdio_register.ioctls);
 
                if (area_dst_alias) {
                        uffdio_register.range.start = (unsigned long)