Exemplo 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)
Exemplo n.º 2
0
def test_unlink(tmpdir):
    dir_path = join(tmpdir, 'directory').encode()
    mkdir(dir_path)  # create directory

    file_path = join(tmpdir, 'file.txt').encode()
    with open(file_path, 'x'):  # create file
        pass

    flags = 0
    ring = io_uring()
    cqes = io_uring_cqes()
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        sqes = get_sqes(ring, 2)
        io_uring_prep_unlinkat(sqes[0], AT_FDCWD, file_path, flags)
        sqes[0].flags |= IOSQE_IO_LINK
        flags |= AT_REMOVEDIR
        io_uring_prep_unlinkat(sqes[1], AT_FDCWD, dir_path, flags)

        assert submit_wait_result(ring, cqes, 2) == [0, 0]
        assert not exists(file_path)  # file should not exist
        assert not exists(dir_path)  # dir should not exist

    finally:
        io_uring_queue_exit(ring)
Exemplo n.º 3
0
def test_statx(tmpdir):
    ring = io_uring()
    cqes = io_uring_cqes()
    file_path = join(tmpdir, 'statx_test.txt').encode()
    bad_path = join(tmpdir, 'file-that-does-not-exist').encode()

    # create sample file
    fd = open(file_path, O_CREAT, 0o700)
    close(fd)

    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        stat = statx()
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_statx(sqe, AT_FDCWD, file_path, AT_STATX_FORCE_SYNC, STATX_MODE, stat)
        sqe.user_data = 1
        assert submit_wait_result(ring, cqes) == 0
        stat[0]
        assert S_IMODE(stat[0].stx_mode) == 448 == 0o700
        assert oct(S_IMODE(stat[0].stx_mode)) == oct(0o700)

        # statx version of file, dir, ... exists or not
        assert exists(ring, cqes, file_path)
        assert not exists(ring, cqes, bad_path)

    finally:
        io_uring_queue_exit(ring)
Exemplo n.º 4
0
 def __init__(self, loop=None, queue_size=32):
     self.event_fd = libc.eventfd(0, os.O_NONBLOCK | os.O_CLOEXEC)
     self.ring = liburing.io_uring()
     self.cqes = liburing.io_uring_cqes(1)
     self.store = {}
     self.loop = loop
     self.queue_size = queue_size
     self._setup_done = False
Exemplo n.º 5
0
def test_socket_timeout():
    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    # socket
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
    server.bind(('0.0.0.0', 0))  # random port
    server.listen(32)

    # prepare
    fd = server.fileno()
    addr, addrlen = liburing.sockaddr()
    try:
        # initialization
        assert liburing.io_uring_queue_init(32, ring, 0) == 0

        # accept
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_accept(sqe, fd, addr, addrlen, 0)
        sqe.flags |= liburing.IOSQE_IO_LINK
        sqe.user_data = 1

        sqe = liburing.io_uring_get_sqe(ring)
        ts = liburing.timespec(0, 41666)  # 1000000//24 nanosecond
        liburing.io_uring_prep_link_timeout(sqe, ts, 0)
        sqe.user_data = 2

        assert liburing.io_uring_submit(ring) == 2

        while True:
            try:
                assert liburing.io_uring_peek_cqe(ring, cqes) == 0
            except BlockingIOError:
                pass  # waiting for events, do something else here.
            else:
                cqe = cqes[0]
                if cqe.user_data == 1:
                    # OSError: [Errno 125] Operation canceled
                    assert cqe.res == -125
                    liburing.io_uring_cqe_seen(ring, cqe)
                    continue
                else:
                    # Timeout value confirm
                    assert cqe.user_data == 2

                    # `OSError: [Errno 62] Timer expired` or
                    # `BlockingIOError: [Errno 114] Operation already in progress`
                    assert cqe.res in (-62, -114)
                    liburing.io_uring_cqe_seen(ring, cqe)
                    break

    finally:
        server.close()
        liburing.io_uring_queue_exit(ring)
Exemplo n.º 6
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)
Exemplo n.º 7
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)
Exemplo n.º 8
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)
Exemplo n.º 9
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)
Exemplo n.º 10
0
def onwait_flag(path):

    fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_NONBLOCK, 0o660)

    one = bytearray(6)
    two = bytearray(5)
    vec = liburing.iovec(one, two)

    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    # print()

    try:
        # WRITE
        # -----
        os.write(fd, b'hello world')
        os.fsync(fd)

        assert liburing.io_uring_queue_init(2, ring, 0) == 0

        # READ
        # ----
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_readv(sqe, fd, vec, len(vec), 0, os.RWF_NOWAIT)
        sqe.user_data = 1

        assert liburing.io_uring_submit(ring) == 1

        while True:
            try:
                liburing.io_uring_peek_cqe(ring, cqes)
            except BlockingIOError:
                pass  # print('test_rwf_nowait_flag BlockingIOError', flush=True)
            else:
                cqe = cqes[0]
                liburing.trap_error(cqe.res)
                assert cqe.res == 6 + 5
                assert cqe.user_data == 1
                assert one == b'hello '
                assert two == b'world'
                liburing.io_uring_cqe_seen(ring, cqe)
                break
    finally:
        liburing.io_uring_queue_exit(ring)
        os.close(fd)
        os.unlink(path)
Exemplo n.º 11
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)
Exemplo n.º 12
0
def onwait_flag_empty_file(path, flag):

    fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_NONBLOCK, 0o660)
    read = bytearray(5)
    vec = liburing.iovec(read)

    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    try:
        assert liburing.io_uring_queue_init(2, ring, 0) == 0

        # READ empty file
        # ---------------
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_readv(sqe, fd, vec, len(vec), 0, flag)
        sqe.user_data = 1

        assert liburing.io_uring_submit(ring) == 1

        while True:
            try:
                liburing.io_uring_peek_cqe(ring, cqes)
            except BlockingIOError:
                pass  # print('test_rwf_nowait_flag BlockingIOError', flush=True)
            else:
                cqe = cqes[0]
                # empty file with `RWF_NOWAIT` flag will return `-EAGAIN` rather then `0`
                if flag & os.RWF_NOWAIT:
                    assert cqe.res == -errno.EAGAIN
                else:
                    assert cqe.res == 0
                liburing.io_uring_cqe_seen(ring, cqe)
                break
    finally:
        liburing.io_uring_queue_exit(ring)
        os.close(fd)
        os.unlink(path)
Exemplo n.º 13
0
def test_clone_file_using_splice(tmpdir):
    fd_in = os.open(join(tmpdir, '1.txt'), os.O_RDWR | os.O_CREAT, 0o660)
    fd_out = os.open(join(tmpdir, '2.txt'), os.O_RDWR | os.O_CREAT, 0o660)
    flags = SPLICE_F_MOVE | SPLICE_F_MORE
    data = b'hello world'
    BUF_SIZE = len(data)
    os.write(fd_in, data)
    r, w = os.pipe()

    ring = io_uring()
    cqes = io_uring_cqes(2)

    try:
        # initialization
        assert io_uring_queue_init(2, ring, 0) == 0

        # read from file "1.txt"
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_splice(sqe, fd_in, 0, w, -1, BUF_SIZE, flags)
        sqe.user_data = 1

        # chain top and bottom sqe
        sqe.flags |= IOSQE_IO_LINK

        # write to file "2.txt"
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_splice(sqe, r, -1, fd_out, 0, BUF_SIZE, flags)
        sqe.user_data = 2

        assert submit_wait_result(ring, cqes, 2) == [BUF_SIZE, BUF_SIZE]
        assert os.read(fd_out, BUF_SIZE) == data

    finally:
        os.close(fd_in)
        os.close(fd_out)
        io_uring_queue_exit(ring)
Exemplo n.º 14
0
def test_rename_file(tmpdir):
    src_file_path = join(tmpdir, 'src_file.txt').encode()
    dst_file_path = join(tmpdir, 'dst_file.txt').encode()

    # create src file
    with open(src_file_path, 'x'):
        pass

    ring = io_uring()
    cqes = io_uring_cqes()
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        assert exists(src_file_path)
        assert not exists(dst_file_path)

        sqe = io_uring_get_sqe(ring)
        io_uring_prep_renameat(sqe, AT_FDCWD, src_file_path, AT_FDCWD, dst_file_path, 0)
        assert submit_wait_result(ring, cqes) == 0

        assert not exists(src_file_path)  # old file should not exist
        assert exists(dst_file_path)      # renamed file should exist
    finally:
        io_uring_queue_exit(ring)
Exemplo n.º 15
0
def test_event(tmpdir):
    fd = os.open(os.path.join(tmpdir, 'event.txt'), os.O_RDWR | os.O_CREAT,
                 0o660)
    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    # prepare for writing.
    data = bytearray(b'hello world')
    vecs = liburing.iovec(data)

    try:
        # initialization
        assert liburing.io_uring_queue_init(32, ring, 0) == 0

        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_writev(sqe, fd, vecs, len(vecs), 0)
        assert liburing.io_uring_submit(ring) == 1

        while True:
            try:
                liburing.io_uring_peek_cqe(ring, cqes)
            except BlockingIOError:
                pass  # waiting for events, do something else here.
            else:
                cqe = cqes[0]
                assert cqe.res == 11
                liburing.io_uring_cqe_seen(ring, cqe)
                break

        # confirm
        content = os.read(fd, 100)
        assert content == data
        assert len(content) == vecs[0].iov_len
    finally:
        os.close(fd)
        liburing.io_uring_queue_exit(ring)
Exemplo n.º 16
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)
Exemplo n.º 17
0
def test_files_write_read(tmpdir):
    fd = os.open(os.path.join(tmpdir, '1.txt'), os.O_RDWR | os.O_CREAT, 0o660)
    ring = liburing.io_uring()
    cqes = liburing.io_uring_cqes()

    # prepare for writing two separate writes and reads.
    one = bytearray(b'hello')
    two = bytearray(b'world')
    vec_one = liburing.iovec(one)
    vec_two = liburing.iovec(two)

    try:
        # initialization
        assert liburing.io_uring_queue_init(2, ring, 0) == 0

        # write "hello"
        sqe = liburing.io_uring_get_sqe(ring)  # get sqe (submission queue entry) to fill
        liburing.io_uring_prep_write(sqe, fd, vec_one[0].iov_base, vec_one[0].iov_len, 0)
        sqe.user_data = 1

        # write "world"
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_writev(sqe, fd, vec_two, len(vec_two), 5)
        sqe.user_data = 2

        # submit both writes
        assert liburing.io_uring_submit(ring) == 2

        # wait for ``2`` entry to complete using single syscall
        assert liburing.io_uring_wait_cqes(ring, cqes, 2) == 0
        cqe = cqes[0]
        assert cqe.res == 5
        assert cqe.user_data == 1
        liburing.io_uring_cqe_seen(ring, cqe)

        # re-uses the same resources from above?!
        assert liburing.io_uring_wait_cqes(ring, cqes, 1) == 0
        cqe = cqes[0]
        assert cqe.res == 5
        assert cqe.user_data == 2
        liburing.io_uring_cqe_seen(ring, cqe)

        # Using same ``vec*`` swap so read can be confirmed.

        # read "world"
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_readv(sqe, fd, vec_one, len(vec_one), 5)
        sqe.user_data = 3

        assert liburing.io_uring_submit(ring) == 1
        assert liburing.io_uring_wait_cqe(ring, cqes) == 0
        cqe = cqes[0]
        assert cqe.res == 5
        assert cqe.user_data == 3
        liburing.io_uring_cq_advance(ring, 1)

        # read "hello"
        sqe = liburing.io_uring_get_sqe(ring)
        liburing.io_uring_prep_read(sqe, fd, vec_two[0].iov_base, vec_two[0].iov_len, 0)
        sqe.user_data = 4

        assert liburing.io_uring_submit(ring) == 1
        assert liburing.io_uring_wait_cqe(ring, cqes) == 0
        cqe = cqes[0]
        assert cqe.res == 5
        assert cqe.user_data == 4
        liburing.io_uring_cq_advance(ring, 1)

        # use same as write buffer to read but switch values so the change is detected
        assert one == b'world'
        assert two == b'hello'
    finally:
        os.close(fd)
        liburing.io_uring_queue_exit(ring)
Exemplo n.º 18
0
def test_personality(tmpdir):
    # note: `sqe.personality` has limited use-case like its restricts to opening `fd`
    #       but not for read, write, close, ...

    ring = io_uring()
    cqes = io_uring_cqes()
    file_path = join(tmpdir, 'test_personality_root_file.txt').encode()
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        # create & open file only root can access!
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, file_path, O_CREAT, 0o700)
        fd = submit_wait_result(ring, cqes)
        close_file(ring, cqes, fd)

        root_cred_id = io_uring_register_personality(ring)
        assert root_cred_id == 1

        # normal "user"
        setegid(1000)
        seteuid(1000)

        user_cred_id = io_uring_register_personality(ring)
        assert user_cred_id == 2

        # try to open root file as normal user.
        with raises(PermissionError):
            open_file(ring, cqes, file_path, None)

        # bad personality
        with raises(OSError):  # Invalid argument
            open_file(ring, cqes, file_path, 2)

        # what about default `0` for personality
        with raises(PermissionError):
            open_file(ring, cqes, file_path, 0)

        # try again to open file with root credential
        fd = open_file(ring, cqes, file_path, root_cred_id)
        close_file(ring, cqes, fd)

        # "root" again
        setegid(0)
        seteuid(0)

        # try again to open file with root credential
        fd = open_file(ring, cqes, file_path, root_cred_id)
        close_file(ring, cqes, fd)

        # try again to open file with no credential
        fd = open_file(ring, cqes, file_path, None)
        close_file(ring, cqes, fd)

        # try again to open file with "user" credential
        with raises(PermissionError):
            open_file(ring, cqes, file_path, user_cred_id)

        # "user" again
        setegid(1000)
        seteuid(1000)

        # try to unregister "root" personality
        assert io_uring_unregister_personality(ring, root_cred_id) == 0

        # try to unregister "user" personality
        assert io_uring_unregister_personality(ring, user_cred_id) == 0

        # try to open file with unregistered old "root" credential
        with raises(OSError):  # Invalid argument
            open_file(ring, cqes, file_path, root_cred_id)

    finally:
        # make sure its "root" again to allow proper cleanup
        seteuid(0)
        setegid(0)

        if exists(file_path):
            unlink(file_path)

        io_uring_queue_exit(ring)