authorgravatar for vincent@rischmann.frVincent Rischmann <vincent@rischmann.fr> 2021-12-12 18:04:12+01:00
committergravatar for vincent@rischmann.frVincent Rischmann <vincent@rischmann.fr> 2021-12-12 18:12:15+01:00
log088c1fab4d7463bf8d50cf23b7f7dbcbeb85fb32
tree5cb58fd757232ee792ff43653ddfc79d3b5928d5
parent0229fb7c62275c5a278e9d173919da6608dc4ae5

os/linux/io_uring: implement renameat


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

lib/std/os/linux/io_uring.zig+106
...@@ -747,6 +747,23 @@ pub const IO_Uring = struct {...@@ -747,6 +747,23 @@ pub const IO_Uring = struct {
747 return sqe;747 return sqe;
748 }748 }
749749
750 /// Queues (but does not submit) an SQE to perform a `renameat2(2)`.
751 /// Returns a pointer to the SQE.
752 pub fn renameat(
753 self: *IO_Uring,
754 user_data: u64,
755 old_dir_fd: os.fd_t,
756 old_path: [*:0]const u8,
757 new_dir_fd: os.fd_t,
758 new_path: [*:0]const u8,
759 flags: u32,
760 ) !*io_uring_sqe {
761 const sqe = try self.get_sqe();
762 io_uring_prep_renameat(sqe, old_dir_fd, old_path, new_dir_fd, new_path, flags);
763 sqe.user_data = user_data;
764 return sqe;
765 }
766
750 /// Registers an array of file descriptors.767 /// Registers an array of file descriptors.
751 /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must768 /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must
752 /// retrieve a reference to the file, and once I/O has completed the file reference must be769 /// retrieve a reference to the file, and once I/O has completed the file reference must be
...@@ -1303,6 +1320,26 @@ pub fn io_uring_prep_shutdown(...@@ -1303,6 +1320,26 @@ pub fn io_uring_prep_shutdown(
1303 io_uring_prep_rw(.SHUTDOWN, sqe, sockfd, 0, how, 0);1320 io_uring_prep_rw(.SHUTDOWN, sqe, sockfd, 0, how, 0);
1304}1321}
13051322
1323pub fn io_uring_prep_renameat(
1324 sqe: *io_uring_sqe,
1325 old_dir_fd: os.fd_t,
1326 old_path: [*:0]const u8,
1327 new_dir_fd: os.fd_t,
1328 new_path: [*:0]const u8,
1329 flags: u32,
1330) void {
1331 io_uring_prep_rw(
1332 .RENAMEAT,
1333 sqe,
1334 old_dir_fd,
1335 @ptrToInt(old_path),
1336 0,
1337 @ptrToInt(new_path),
1338 );
1339 sqe.len = @bitCast(u32, new_dir_fd);
1340 sqe.rw_flags = flags;
1341}
1342
1306test "structs/offsets/entries" {1343test "structs/offsets/entries" {
1307 if (builtin.os.tag != .linux) return error.SkipZigTest;1344 if (builtin.os.tag != .linux) return error.SkipZigTest;
13081345
...@@ -2275,3 +2312,72 @@ test "shutdown" {...@@ -2275,3 +2312,72 @@ test "shutdown" {
2275 try testing.expectEqual(os.linux.E.NOTCONN, cqe.err());2312 try testing.expectEqual(os.linux.E.NOTCONN, cqe.err());
2276 }2313 }
2277}2314}
2315
2316test "renameat" {
2317 if (builtin.os.tag != .linux) return error.SkipZigTest;
2318
2319 var ring = IO_Uring.init(1, 0) catch |err| switch (err) {
2320 error.SystemOutdated => return error.SkipZigTest,
2321 error.PermissionDenied => return error.SkipZigTest,
2322 else => return err,
2323 };
2324 defer ring.deinit();
2325
2326 const old_path = "test_io_uring_renameat_old";
2327 const new_path = "test_io_uring_renameat_new";
2328
2329 // Write old file with data
2330
2331 const old_file = try std.fs.cwd().createFile(old_path, .{ .truncate = true, .mode = 0o666 });
2332 defer {
2333 old_file.close();
2334 std.fs.cwd().deleteFile(new_path) catch {};
2335 }
2336 try old_file.writeAll("hello");
2337
2338 // Submit renameat
2339
2340 var sqe = try ring.renameat(
2341 0x12121212,
2342 linux.AT.FDCWD,
2343 old_path,
2344 linux.AT.FDCWD,
2345 new_path,
2346 0,
2347 );
2348 try testing.expectEqual(linux.IORING_OP.RENAMEAT, sqe.opcode);
2349 try testing.expectEqual(@as(i32, linux.AT.FDCWD), sqe.fd);
2350 try testing.expectEqual(@as(i32, linux.AT.FDCWD), @bitCast(i32, sqe.len));
2351 try testing.expectEqual(@as(u32, 1), try ring.submit());
2352
2353 const cqe = try ring.copy_cqe();
2354 switch (cqe.err()) {
2355 .SUCCESS => {},
2356 // This kernel's io_uring does not yet implement renameat (kernel version < 5.11)
2357 .INVAL => return error.SkipZigTest,
2358 else => |errno| std.debug.panic("unhandled errno: {}", .{errno}),
2359 }
2360 try testing.expectEqual(linux.io_uring_cqe{
2361 .user_data = 0x12121212,
2362 .res = 0,
2363 .flags = 0,
2364 }, cqe);
2365
2366 // Validate that the old file doesn't exist anymore
2367 {
2368 _ = std.fs.cwd().openFile(old_path, .{}) catch |err| switch (err) {
2369 error.FileNotFound => {},
2370 else => std.debug.panic("unexpected error: {}", .{err}),
2371 };
2372 }
2373
2374 // Validate that the new file exists with the proper content
2375 {
2376 const new_file = try std.fs.cwd().openFile(new_path, .{});
2377 defer new_file.close();
2378
2379 var new_file_data: [16]u8 = undefined;
2380 const read = try new_file.readAll(&new_file_data);
2381 try testing.expectEqualStrings("hello", new_file_data[0..read]);
2382 }
2383}