unsigned                hash_reg_file : 1;
        /* unbound wq insertion if file is a non-regular file */
        unsigned                unbound_nonreg_file : 1;
+       /* opcode is not supported by this kernel */
+       unsigned                not_supported : 1;
 };
 
 static const struct io_op_def io_op_defs[] = {
        return io_uring_setup(entries, params);
 }
 
+static int io_probe(struct io_ring_ctx *ctx, void __user *arg, unsigned nr_args)
+{
+       struct io_uring_probe *p;
+       size_t size;
+       int i, ret;
+
+       size = struct_size(p, ops, nr_args);
+       if (size == SIZE_MAX)
+               return -EOVERFLOW;
+       p = kzalloc(size, GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       ret = -EFAULT;
+       if (copy_from_user(p, arg, size))
+               goto out;
+       ret = -EINVAL;
+       if (memchr_inv(p, 0, size))
+               goto out;
+
+       p->last_op = IORING_OP_LAST - 1;
+       if (nr_args > IORING_OP_LAST)
+               nr_args = IORING_OP_LAST;
+
+       for (i = 0; i < nr_args; i++) {
+               p->ops[i].op = i;
+               if (!io_op_defs[i].not_supported)
+                       p->ops[i].flags = IO_URING_OP_SUPPORTED;
+       }
+       p->ops_len = i;
+
+       ret = 0;
+       if (copy_to_user(arg, p, size))
+               ret = -EFAULT;
+out:
+       kfree(p);
+       return ret;
+}
+
 static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,
                               void __user *arg, unsigned nr_args)
        __releases(ctx->uring_lock)
                return -ENXIO;
 
        if (opcode != IORING_UNREGISTER_FILES &&
-           opcode != IORING_REGISTER_FILES_UPDATE) {
+           opcode != IORING_REGISTER_FILES_UPDATE &&
+           opcode != IORING_REGISTER_PROBE) {
                percpu_ref_kill(&ctx->refs);
 
                /*
                        break;
                ret = io_eventfd_unregister(ctx);
                break;
+       case IORING_REGISTER_PROBE:
+               ret = -EINVAL;
+               if (!arg || nr_args > 256)
+                       break;
+               ret = io_probe(ctx, arg, nr_args);
+               break;
        default:
                ret = -EINVAL;
                break;
 
 
        if (opcode != IORING_UNREGISTER_FILES &&
-           opcode != IORING_REGISTER_FILES_UPDATE) {
+           opcode != IORING_REGISTER_FILES_UPDATE &&
+           opcode != IORING_REGISTER_PROBE) {
                /* bring the ctx back to life */
                percpu_ref_reinit(&ctx->refs);
 out:
 
 #define IORING_UNREGISTER_EVENTFD      5
 #define IORING_REGISTER_FILES_UPDATE   6
 #define IORING_REGISTER_EVENTFD_ASYNC  7
+#define IORING_REGISTER_PROBE          8
 
 struct io_uring_files_update {
        __u32 offset;
        __aligned_u64 /* __s32 * */ fds;
 };
 
+#define IO_URING_OP_SUPPORTED  (1U << 0)
+
+struct io_uring_probe_op {
+       __u8 op;
+       __u8 resv;
+       __u16 flags;    /* IO_URING_OP_* flags */
+       __u32 resv2;
+};
+
+struct io_uring_probe {
+       __u8 last_op;   /* last opcode supported */
+       __u8 ops_len;   /* length of ops[] array below */
+       __u16 resv;
+       __u32 resv2[3];
+       struct io_uring_probe_op ops[0];
+};
+
 #endif