gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/util/io_uring_util.h (about)

     1  // Copyright 2022 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #ifndef GVISOR_TEST_UTIL_IOURING_UTIL_H_
    16  #define GVISOR_TEST_UTIL_IOURING_UTIL_H_
    17  
    18  #include <linux/fs.h>
    19  #include <sys/ioctl.h>
    20  #include <sys/mman.h>
    21  
    22  #include <atomic>
    23  #include <cerrno>
    24  #include <cstdint>
    25  
    26  #include "test/util/file_descriptor.h"
    27  #include "test/util/posix_error.h"
    28  #include "test/util/save_util.h"
    29  
    30  namespace gvisor {
    31  namespace testing {
    32  
    33  #define __NR_io_uring_setup 425
    34  #define __NR_io_uring_enter 426
    35  
    36  // io_uring_setup(2) flags.
    37  #define IORING_SETUP_SQPOLL (1U << 1)
    38  #define IORING_SETUP_CQSIZE (1U << 3)
    39  
    40  // io_uring_enter(2) flags
    41  #define IORING_ENTER_GETEVENTS (1U << 0)
    42  
    43  #define IORING_FEAT_SINGLE_MMAP (1U << 0)
    44  
    45  #define IORING_OFF_SQ_RING 0ULL
    46  #define IORING_OFF_CQ_RING 0x8000000ULL
    47  #define IORING_OFF_SQES 0x10000000ULL
    48  
    49  // IO_URING operation codes.
    50  #define IORING_OP_NOP 0
    51  #define IORING_OP_READV 1
    52  
    53  #define BLOCK_SZ kPageSize
    54  
    55  struct io_sqring_offsets {
    56    uint32_t head;
    57    uint32_t tail;
    58    uint32_t ring_mask;
    59    uint32_t ring_entries;
    60    uint32_t flags;
    61    uint32_t dropped;
    62    uint32_t array;
    63    uint32_t resv1;
    64    uint64_t resv2;
    65  };
    66  
    67  struct io_cqring_offsets {
    68    uint32_t head;
    69    uint32_t tail;
    70    uint32_t ring_mask;
    71    uint32_t ring_entries;
    72    uint32_t overflow;
    73    uint32_t cqes;
    74    uint32_t flags;
    75    uint32_t resv1;
    76    uint64_t resv2;
    77  };
    78  
    79  struct io_uring_params {
    80    uint32_t sq_entries;
    81    uint32_t cq_entries;
    82    uint32_t flags;
    83    uint32_t sq_thread_cpu;
    84    uint32_t sq_thread_idle;
    85    uint32_t features;
    86    uint32_t wq_fd;
    87    uint32_t resv[3];
    88    struct io_sqring_offsets sq_off;
    89    struct io_cqring_offsets cq_off;
    90  };
    91  
    92  struct io_uring_cqe {
    93    uint64_t user_data;
    94    int32_t res;
    95    uint32_t flags;
    96  };
    97  
    98  struct io_uring_sqe {
    99    uint8_t opcode;
   100    uint8_t flags;
   101    uint16_t ioprio;
   102    int32_t fd;
   103    union {
   104      uint64_t off;
   105      uint64_t addr2;
   106      struct {
   107        uint32_t cmd_op;
   108        uint32_t __pad1;
   109      };
   110    };
   111    union {
   112      uint64_t addr;
   113      uint64_t splice_off_in;
   114    };
   115    uint32_t len;
   116    union {
   117      __kernel_rwf_t rw_flags;
   118      uint32_t fsync_flags;
   119      uint16_t poll_events;
   120      uint32_t poll32_events;
   121      uint32_t sync_range_flags;
   122      uint32_t msg_flags;
   123      uint32_t timeout_flags;
   124      uint32_t accept_flags;
   125      uint32_t cancel_flags;
   126      uint32_t open_flags;
   127      uint32_t statx_flags;
   128      uint32_t fadvise_advice;
   129      uint32_t splice_flags;
   130      uint32_t rename_flags;
   131      uint32_t unlink_flags;
   132      uint32_t hardlink_flags;
   133      uint32_t xattr_flags;
   134    };
   135    uint64_t user_data;
   136    union {
   137      uint16_t buf_index;
   138      uint16_t buf_group;
   139    } __attribute__((packed));
   140    uint16_t personality;
   141    union {
   142      int32_t splice_fd_in;
   143      uint32_t file_index;
   144    };
   145    union {
   146      struct {
   147        uint64_t addr3;
   148        uint64_t __pad2[1];
   149      };
   150      uint8_t cmd[0];
   151    };
   152  };
   153  
   154  using IOSqringOffsets = struct io_sqring_offsets;
   155  using ICqringOffsets = struct io_cqring_offsets;
   156  using IOUringCqe = struct io_uring_cqe;
   157  using IOUringParams = struct io_uring_params;
   158  using IOUringSqe = struct io_uring_sqe;
   159  
   160  // Helper class for IO_URING
   161  class IOUring {
   162   public:
   163    IOUring() = delete;
   164    IOUring(FileDescriptor &&fd, unsigned int entries, IOUringParams &params);
   165    ~IOUring();
   166  
   167    static PosixErrorOr<std::unique_ptr<IOUring>> InitIOUring(
   168        unsigned int entries, IOUringParams &params);
   169  
   170    uint32_t load_cq_head();
   171    uint32_t load_cq_tail();
   172    uint32_t load_sq_head();
   173    uint32_t load_sq_tail();
   174    uint32_t load_cq_overflow();
   175    uint32_t load_sq_dropped();
   176    void store_cq_head(uint32_t cq_head_val);
   177    void store_sq_tail(uint32_t sq_tail_val);
   178    int Enter(unsigned int to_submit, unsigned int min_complete,
   179              unsigned int flags, sigset_t *sig);
   180  
   181    IOUringCqe *get_cqes();
   182    IOUringSqe *get_sqes();
   183    uint32_t get_sq_mask();
   184    unsigned *get_sq_array();
   185  
   186    int Fd() { return iouringfd_.get(); }
   187  
   188   private:
   189    IOUringCqe *cqes_ = nullptr;
   190    FileDescriptor iouringfd_;
   191    size_t cring_sz_;
   192    size_t sring_sz_;
   193    size_t sqes_sz_;
   194    uint32_t sq_mask_;
   195    unsigned *sq_array_ = nullptr;
   196    uint32_t *cq_head_ptr_ = nullptr;
   197    uint32_t *cq_tail_ptr_ = nullptr;
   198    uint32_t *sq_head_ptr_ = nullptr;
   199    uint32_t *sq_tail_ptr_ = nullptr;
   200    uint32_t *cq_overflow_ptr_ = nullptr;
   201    uint32_t *sq_dropped_ptr_ = nullptr;
   202    void *sq_ptr_ = nullptr;
   203    void *cq_ptr_ = nullptr;
   204    void *sqe_ptr_ = nullptr;
   205  };
   206  
   207  // This is a wrapper for the io_uring_setup(2) system call.
   208  inline int IOUringSetup(uint32_t entries, IOUringParams *params) {
   209    return syscall(__NR_io_uring_setup, entries, params);
   210  }
   211  
   212  // This is a wrapper for the io_uring_enter(2) system call.
   213  inline int IOUringEnter(unsigned int fd, unsigned int to_submit,
   214                          unsigned int min_complete, unsigned int flags,
   215                          sigset_t *sig) {
   216    return syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, sig);
   217  }
   218  
   219  // Returns a new iouringfd with the given number of entries.
   220  inline PosixErrorOr<FileDescriptor> NewIOUringFD(uint32_t entries,
   221                                                   IOUringParams &params) {
   222    memset(&params, 0, sizeof(params));
   223    int fd = IOUringSetup(entries, &params);
   224    MaybeSave();
   225    if (fd < 0) {
   226      return PosixError(errno, "io_uring_setup");
   227    }
   228    return FileDescriptor(fd);
   229  }
   230  
   231  template <typename T>
   232  static inline void io_uring_atomic_write(T *p, T v) {
   233    std::atomic_store_explicit(reinterpret_cast<std::atomic<T> *>(p), v,
   234                               std::memory_order_release);
   235  }
   236  
   237  template <typename T>
   238  static inline T io_uring_atomic_read(const T *p) {
   239    return std::atomic_load_explicit(reinterpret_cast<const std::atomic<T> *>(p),
   240                                     std::memory_order_acquire);
   241  }
   242  
   243  }  // namespace testing
   244  }  // namespace gvisor
   245  
   246  #endif  // GVISOR_TEST_UTIL_IOURING_UTIL_H_