Esempio n. 1
0
def test_openat2_resolve_cache(tmpdir):
    ring = io_uring()
    cqes = io_uring_cqes()
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        how = open_how(O_CREAT, 0o600, RESOLVE_CACHED)
        lookup_path = join(tmpdir, 'lookup-file.txt').encode()

        for _ in range(2, 0, -1):  # countdown
            try:
                sqe = io_uring_get_sqe(ring)
                io_uring_prep_openat2(sqe, AT_FDCWD, lookup_path, how)
                fd = submit_wait_result(ring, cqes)
            except BlockingIOError:
                if how[0].resolve & RESOLVE_CACHED:
                    how[0].resolve = how[0].resolve & ~RESOLVE_CACHED
                # note:
                #   must retry without `RESOLVE_CACHED` since
                #   file path was not in kernel's lookup cache.
            else:
                assert fd > 0

                # close `fd`
                sqe = io_uring_get_sqe(ring)
                io_uring_prep_close(sqe, fd)
                assert submit_wait_result(ring, cqes) == 0
                break
        else:
            assert False  # failed to create file
    finally:
        io_uring_queue_exit(ring)
Esempio n. 2
0
def test_openat2(tmpdir):
    ring = io_uring()
    cqes = io_uring_cqes()
    # prep
    buffers = (bytearray(b'hello world'), bytearray(11))
    iov = iovec(*buffers)
    file_path = join(tmpdir, 'openat2_test.txt').encode()
    try:
        assert io_uring_queue_init(2, ring, 0) == 0
        assert io_uring_register_buffers(ring, iov, len(iov)) == 0

        # open
        how = open_how(O_CREAT | O_RDWR, 0o700)
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat2(sqe, AT_FDCWD, file_path, how)
        fd = submit_wait_result(ring, cqes)

        # write
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write(sqe, fd, iov[0].iov_base, iov[0].iov_len, 0)
        assert submit_wait_result(ring, cqes) == 11

        # read
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read(sqe, fd, iov[1].iov_base, iov[1].iov_len, 0)
        assert submit_wait_result(ring, cqes) == 11

        # confirm
        assert buffers[0] == buffers[1]

        # close
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fd)
        submit_wait_result(ring, cqes)

        if skip_os('5.12'):
            skip('RESOLVE_CACHED 5.12+ Linux required')
        else:
            # second open for resolve test
            how = open_how(O_RDWR, 0, RESOLVE_CACHED)
            sqe = io_uring_get_sqe(ring)
            io_uring_prep_openat2(sqe, AT_FDCWD, file_path, how)
            fd2 = submit_wait_result(ring, cqes)

            assert fd2 > 0

            # close `fd2`
            sqe = io_uring_get_sqe(ring)
            io_uring_prep_close(sqe, fd2)
            assert submit_wait_result(ring, cqes) == 0
    finally:
        io_uring_queue_exit(ring)
Esempio n. 3
0
def test_file_o_direct():
    # note:
    #   - `O_DIRECT` does not work if the file path is in memory, like "/dev/shm" or "/tmp"
    #   - currently only `MAP_PRIVATE` works with `io_uring_register_buffers`, `MAP_SHARED` will be fixed soon!

    ring = io_uring()
    cqes = io_uring_cqes()

    if skip_os('5.14'):  # was a bug < 5.14
        read = mmap(-1, PAGESIZE, flags=MAP_PRIVATE)
        write = mmap(-1, PAGESIZE, flags=MAP_PRIVATE)
    else:
        read = mmap(-1, PAGESIZE)  # MAP_SHARED
        write = mmap(-1, PAGESIZE)

    write[0:11] = b'hello world'
    iov = iovec(write, read)
    try:
        assert io_uring_queue_init(2, ring, 0) == 0
        assert io_uring_register_buffers(ring, iov, len(iov)) == 0

        # open - create local testing file.
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, b'.',
                             O_TMPFILE | O_RDWR | O_DIRECT, 0o700)
        fd = submit_wait_result(ring, cqes)

        # write
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write_fixed(sqe, fd, iov[0].iov_base, iov[0].iov_len, 0,
                                  0)
        assert submit_wait_result(ring, cqes) == PAGESIZE

        # read
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read_fixed(sqe, fd, iov[1].iov_base, iov[1].iov_len, 0,
                                 1)
        assert submit_wait_result(ring, cqes) == PAGESIZE

        # confirm
        assert read[:20] == write[:20]

        # close
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fd)
        assert submit_wait_result(ring, cqes) == 0

    finally:
        read.close()
        write.close()
        io_uring_queue_exit(ring)
Esempio n. 4
0
def test_register_fd_close():
    ring = io_uring()
    cqes = io_uring_cqes()
    write = bytearray(b'hello world')
    read = bytearray(11)
    iov = iovec(write, read)
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        # open - create local testing file.
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, b'.', O_TMPFILE | O_RDWR, 0o700)
        fd = submit_wait_result(ring, cqes)

        # register `fds`
        fds = files(fd)  # `int[fd]`
        index = 0
        assert io_uring_register_files(ring, fds, len(fds)) == 0

        # close - right away after registering fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fd)
        assert submit_wait_result(ring, cqes) == 0

        # write - using registered file index and closed fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write(sqe, index, iov[0].iov_base, iov[0].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # read - using registered file index and closed fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read(sqe, index, iov[1].iov_base, iov[1].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # confirm
        assert write == read

        # unregister - index
        fds = files(-1)
        assert io_uring_register_files_update(ring, index, fds, 1) == 1

        # re-read - should not be able to since index was unregistered
        with raises(OSError):  # [Errno 9] Bad file descriptor
            sqe = io_uring_get_sqe(ring)
            io_uring_prep_read(sqe, index, iov[1].iov_base, iov[1].iov_len, 0)
            sqe.flags |= IOSQE_FIXED_FILE
            assert submit_wait_result(ring, cqes) == 11
    finally:
        io_uring_queue_exit(ring)
Esempio n. 5
0
def test_register_file_update():
    ring = io_uring()
    cqes = io_uring_cqes()
    write = bytearray(b'hello world')
    read = bytearray(11)
    iov = iovec(write, read)
    fds = files(-1, -1, -1, -1)  # prep 4 fd spots
    index = 2  # only use index ``2`` of the `fds`
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        # register 4 `fds`
        assert io_uring_register_files(ring, fds, len(fds)) == 0

        # open - create local testing file.
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, b'.', O_TMPFILE | O_RDWR, 0o700)
        fd = submit_wait_result(ring, cqes)
        fds[index] = fd

        fd2 = files(fd)  # `int[fd]`
        # register - update only the index ``2`` value
        assert io_uring_register_files_update(ring, index, fd2, 1) == 1

        # close
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fds[index])
        assert submit_wait_result(ring, cqes) == 0

        # write - using registered file index vs fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write(sqe, index, iov[0].iov_base, iov[0].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # read - using registered file index vs fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read(sqe, index, iov[1].iov_base, iov[1].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # confirm
        assert write == read

        # unregister
        assert io_uring_unregister_files(ring) == 0
    finally:
        io_uring_queue_exit(ring)
Esempio n. 6
0
def test_register_file():
    ring = io_uring()
    cqes = io_uring_cqes()
    write = bytearray(b'hello world')
    read = bytearray(11)
    iov = iovec(write, read)
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        # open - create local testing file.
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, b'.', O_TMPFILE | O_RDWR, 0o700)
        fd = submit_wait_result(ring, cqes)

        # register `fds`
        fds = files(fd)  # `int[fd]`
        index = 0
        assert io_uring_register_files(ring, fds, len(fds)) == 0

        # close
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fd)
        assert submit_wait_result(ring, cqes) == 0

        # write - using registered file index vs fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write(sqe, index, iov[0].iov_base, iov[0].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # read - using registered file index vs fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read(sqe, index, iov[1].iov_base, iov[1].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # confirm
        assert write == read
    finally:
        # note: let exit also unregister fds
        io_uring_queue_exit(ring)
Esempio n. 7
0
def test_multiple_register_fd_mix(tmpdir):
    ring = io_uring()
    cqes = io_uring_cqes()
    loop = randint(2, 5)
    data = b'hello world'
    write = [bytearray(data) for _ in range(loop)]
    iov = iovec(*write)
    fds = files(-1 for _ in range(loop))  # prep fds
    try:
        assert io_uring_queue_init(2, ring, 0) == 0
        # initialize register
        assert io_uring_register_files(ring, fds, len(fds)) == 0

        for index in range(loop):  # index = 0, 1, ...
            path = join(tmpdir, f'register-fd-mix-{index}.txt').encode()
            # open
            sqe = io_uring_get_sqe(ring)
            io_uring_prep_openat(sqe, AT_FDCWD, path, O_CREAT | O_RDWR, 0o700)
            fd = submit_wait_result(ring, cqes)

            # register update
            if index == 1:  # skip registering middle one!
                fd1 = fd
            else:
                fds = files(fd)
                assert io_uring_register_files_update(ring, index, fds, 1) == 1

                # close registered fd only
                sqe = io_uring_get_sqe(ring)
                io_uring_prep_close(sqe, fd)
                assert submit_wait_result(ring, cqes) == 0

        # write
        for index in range(loop):
            sqe = io_uring_get_sqe(ring)
            if index == 1:  # write using fd
                io_uring_prep_write(sqe, fd1, iov[index].iov_base, iov[index].iov_len, 0)
            else:  # write using registered file index
                io_uring_prep_write(sqe, index, iov[index].iov_base, iov[index].iov_len, 0)
                sqe.flags |= IOSQE_FIXED_FILE
            assert submit_wait_result(ring, cqes) == 11

        # read
        for index in range(loop):
            path = join(tmpdir, f'register-fd-mix-{index}.txt').encode()
            stat = statx()
            sqe = io_uring_get_sqe(ring)
            io_uring_prep_statx(sqe, AT_FDCWD, path, 0, 0, stat)
            assert submit_wait_result(ring, cqes) == 0
            length = stat[0].stx_size  # get written file size
            # note: even though size is known, get it using statx

            read = bytearray(length)
            buffer = from_buffer(read)

            sqe = io_uring_get_sqe(ring)
            if index == 1:
                io_uring_prep_read(sqe, fd1, buffer, length, 0)
            else:  # read using registered file index
                io_uring_prep_read(sqe, index, buffer, length, 0)
                sqe.flags |= IOSQE_FIXED_FILE
            assert submit_wait_result(ring, cqes) == 11
            assert read == data

        # close
        for index in range(loop):
            if index == 1:
                sqe = io_uring_get_sqe(ring)
                io_uring_prep_close(sqe, fd1)
                assert submit_wait_result(ring, cqes) == 0
            else:  # unregister file index
                fds = files(-1)
                assert io_uring_register_files_update(ring, index, fds, 1) == 1
    finally:
        io_uring_queue_exit(ring)
Esempio n. 8
0
def close_file(ring, cqes, fd):
    sqe = io_uring_get_sqe(ring)
    io_uring_prep_close(sqe, fd)
    assert submit_wait_result(ring, cqes) == 0
Esempio n. 9
0
 def submit_close_entry(self, fd):
     sqe = self._get_sqe()
     liburing.io_uring_prep_close(sqe, fd)
     return self._submit(RequestType.CLOSE, sqe)