authorgravatar for vincent@rischmann.frVincent Rischmann <vincent@rischmann.fr> 2021-12-12 18:49:17+01:00
committergravatar for vincent@rischmann.frVincent Rischmann <vincent@rischmann.fr> 2021-12-12 18:49:17+01:00
logf9b8808d7494757fc47dfd506264669270f4e573
tree9ffedb1f5f2479d383ebdbef00691218c6f99706
parent5dd53c1986039ddf93d7eada8ceaa7ff2ad2b9bb

os/linux/io_uring: implement linkat


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

lib/std/os/linux/io_uring.zig+97
......@@ -809,6 +809,23 @@ pub const IO_Uring = struct {
809809 return sqe;
810810 }
811811
812 /// Queues (but does not submit) an SQE to perform a `linkat(2)`.
813 /// Returns a pointer to the SQE.
814 pub fn linkat(
815 self: *IO_Uring,
816 user_data: u64,
817 old_dir_fd: os.fd_t,
818 old_path: [*:0]const u8,
819 new_dir_fd: os.fd_t,
820 new_path: [*:0]const u8,
821 flags: u32,
822 ) !*io_uring_sqe {
823 const sqe = try self.get_sqe();
824 io_uring_prep_linkat(sqe, old_dir_fd, old_path, new_dir_fd, new_path, flags);
825 sqe.user_data = user_data;
826 return sqe;
827 }
828
812829 /// Registers an array of file descriptors.
813830 /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must
814831 /// retrieve a reference to the file, and once I/O has completed the file reference must be
......@@ -1420,6 +1437,26 @@ pub fn io_uring_prep_symlinkat(
14201437 );
14211438}
14221439
1440pub fn io_uring_prep_linkat(
1441 sqe: *io_uring_sqe,
1442 old_dir_fd: os.fd_t,
1443 old_path: [*:0]const u8,
1444 new_dir_fd: os.fd_t,
1445 new_path: [*:0]const u8,
1446 flags: u32,
1447) void {
1448 io_uring_prep_rw(
1449 .LINKAT,
1450 sqe,
1451 old_dir_fd,
1452 @ptrToInt(old_path),
1453 0,
1454 @ptrToInt(new_path),
1455 );
1456 sqe.len = @bitCast(u32, new_dir_fd);
1457 sqe.rw_flags = flags;
1458}
1459
14231460test "structs/offsets/entries" {
14241461 if (builtin.os.tag != .linux) return error.SkipZigTest;
14251462
......@@ -2603,3 +2640,63 @@ test "symlinkat" {
26032640 // Validate that the symlink exist
26042641 _ = try std.fs.cwd().openFile(link_path, .{});
26052642}
2643
2644test "linkat" {
2645 if (builtin.os.tag != .linux) return error.SkipZigTest;
2646
2647 var ring = IO_Uring.init(1, 0) catch |err| switch (err) {
2648 error.SystemOutdated => return error.SkipZigTest,
2649 error.PermissionDenied => return error.SkipZigTest,
2650 else => return err,
2651 };
2652 defer ring.deinit();
2653
2654 const first_path = "test_io_uring_linkat_first";
2655 const second_path = "test_io_uring_linkat_second";
2656
2657 // Write file with data
2658
2659 const first_file = try std.fs.cwd().createFile(first_path, .{ .truncate = true, .mode = 0o666 });
2660 defer {
2661 first_file.close();
2662 std.fs.cwd().deleteFile(first_path) catch {};
2663 std.fs.cwd().deleteFile(second_path) catch {};
2664 }
2665 try first_file.writeAll("hello");
2666
2667 // Submit linkat
2668
2669 var sqe = try ring.linkat(
2670 0x12121212,
2671 linux.AT.FDCWD,
2672 first_path,
2673 linux.AT.FDCWD,
2674 second_path,
2675 0,
2676 );
2677 try testing.expectEqual(linux.IORING_OP.LINKAT, sqe.opcode);
2678 try testing.expectEqual(@as(i32, linux.AT.FDCWD), sqe.fd);
2679 try testing.expectEqual(@as(i32, linux.AT.FDCWD), @bitCast(i32, sqe.len));
2680 try testing.expectEqual(@as(u32, 1), try ring.submit());
2681
2682 const cqe = try ring.copy_cqe();
2683 switch (cqe.err()) {
2684 .SUCCESS => {},
2685 // This kernel's io_uring does not yet implement linkat (kernel version < 5.15)
2686 .INVAL => return error.SkipZigTest,
2687 else => |errno| std.debug.panic("unhandled errno: {}", .{errno}),
2688 }
2689 try testing.expectEqual(linux.io_uring_cqe{
2690 .user_data = 0x12121212,
2691 .res = 0,
2692 .flags = 0,
2693 }, cqe);
2694
2695 // Validate the second file
2696 const second_file = try std.fs.cwd().openFile(second_path, .{});
2697 defer second_file.close();
2698
2699 var second_file_data: [16]u8 = undefined;
2700 const read = try second_file.readAll(&second_file_data);
2701 try testing.expectEqualStrings("hello", second_file_data[0..read]);
2702}