authorgravatar for vincent@rischmann.frVincent Rischmann <vincent@rischmann.fr> 2021-11-14 21:56:27+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-16 19:54:19-05:00
log3d528161c80c753a9b00cae84cae245526b29c10
tree741bf60a56ef77d31003e512696eb2adf21c7579
parentd94b032e926ef794b422e5abd504a7755d345eff

io_uring: implement register_files_update


1 files changed, 118 insertions(+), 0 deletions(-)

lib/std/os/linux/io_uring.zig+118
......@@ -724,6 +724,37 @@ pub const IO_Uring = struct {
724724 try handle_registration_result(res);
725725 }
726726
727 /// Updates registered file descriptors.
728 ///
729 /// Updates are applied starting at the provided offset in the original file descriptors slice.
730 /// There are three kind of updates:
731 /// * turning a sparse entry (where the fd is -1) into a real one
732 /// * removing an existing entry (set the fd to -1)
733 /// * replacing an existing entry with a new fd
734 /// Adding new file descriptors must be done with `register_files`.
735 pub fn register_files_update(self: *IO_Uring, offset: u32, fds: []const os.fd_t) !void {
736 assert(self.fd >= 0);
737
738 const FilesUpdate = struct {
739 offset: u32,
740 resv: u32,
741 fds: u64 align(8),
742 };
743 var update = FilesUpdate{
744 .offset = offset,
745 .resv = @as(u32, 0),
746 .fds = @as(u64, @ptrToInt(fds.ptr)),
747 };
748
749 const res = linux.io_uring_register(
750 self.fd,
751 .REGISTER_FILES_UPDATE,
752 @ptrCast(*const c_void, &update),
753 @intCast(u32, fds.len),
754 );
755 try handle_registration_result(res);
756 }
757
727758 /// Registers the file descriptor for an eventfd that will be notified of completion events on
728759 /// an io_uring instance.
729760 /// Only a single a eventfd can be registered at any given point in time.
......@@ -1949,3 +1980,90 @@ test "accept/connect/recv/cancel" {
19491980 .flags = 0,
19501981 }, cqe_cancel);
19511982}
1983
1984test "register_files_update" {
1985 if (builtin.os.tag != .linux) return error.SkipZigTest;
1986
1987 var ring = IO_Uring.init(1, 0) catch |err| switch (err) {
1988 error.SystemOutdated => return error.SkipZigTest,
1989 error.PermissionDenied => return error.SkipZigTest,
1990 else => return err,
1991 };
1992 defer ring.deinit();
1993
1994 const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);
1995 defer os.close(fd);
1996
1997 var registered_fds = [_]os.fd_t{0} ** 2;
1998 const fd_index = 0;
1999 const fd_index2 = 1;
2000 registered_fds[fd_index] = fd;
2001 registered_fds[fd_index2] = -1;
2002
2003 ring.register_files(registered_fds[0..]) catch |err| switch (err) {
2004 // Happens when the kernel doesn't support sparse entry (-1) in the file descriptors array.
2005 error.FileDescriptorInvalid => return error.SkipZigTest,
2006 else => |errno| std.debug.panic("unhandled errno: {}", .{errno}),
2007 };
2008
2009 // Test IORING_REGISTER_FILES_UPDATE
2010 // Only available since Linux 5.5
2011
2012 const fd2 = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);
2013 defer os.close(fd2);
2014
2015 registered_fds[fd_index] = fd2;
2016 registered_fds[fd_index2] = -1;
2017 try ring.register_files_update(0, registered_fds[0..]);
2018
2019 var buffer = [_]u8{42} ** 128;
2020 {
2021 const sqe = try ring.read(0xcccccccc, fd_index, &buffer, 0);
2022 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
2023 sqe.flags |= linux.IOSQE_FIXED_FILE;
2024
2025 try testing.expectEqual(@as(u32, 1), try ring.submit());
2026 try testing.expectEqual(linux.io_uring_cqe{
2027 .user_data = 0xcccccccc,
2028 .res = buffer.len,
2029 .flags = 0,
2030 }, try ring.copy_cqe());
2031 try testing.expectEqualSlices(u8, &([_]u8{0} ** buffer.len), buffer[0..]);
2032 }
2033
2034 // Test with a non-zero offset
2035
2036 registered_fds[fd_index] = -1;
2037 registered_fds[fd_index2] = -1;
2038 try ring.register_files_update(1, registered_fds[1..]);
2039
2040 {
2041 // Next read should still work since fd_index in the registered file descriptors hasn't been updated yet.
2042 const sqe = try ring.read(0xcccccccc, fd_index, &buffer, 0);
2043 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
2044 sqe.flags |= linux.IOSQE_FIXED_FILE;
2045
2046 try testing.expectEqual(@as(u32, 1), try ring.submit());
2047 try testing.expectEqual(linux.io_uring_cqe{
2048 .user_data = 0xcccccccc,
2049 .res = buffer.len,
2050 .flags = 0,
2051 }, try ring.copy_cqe());
2052 try testing.expectEqualSlices(u8, &([_]u8{0} ** buffer.len), buffer[0..]);
2053 }
2054
2055 try ring.register_files_update(0, registered_fds[0..]);
2056
2057 {
2058 // Now this should fail since both fds are sparse (-1)
2059 const sqe = try ring.read(0xcccccccc, fd_index, &buffer, 0);
2060 try testing.expectEqual(linux.IORING_OP.READ, sqe.opcode);
2061 sqe.flags |= linux.IOSQE_FIXED_FILE;
2062
2063 try testing.expectEqual(@as(u32, 1), try ring.submit());
2064 const cqe = try ring.copy_cqe();
2065 try testing.expectEqual(os.linux.E.BADF, cqe.err());
2066 }
2067
2068 try ring.unregister_files();
2069}