| ... | @@ -556,6 +556,22 @@ pub const IO_Uring = struct { | ... | @@ -556,6 +556,22 @@ pub const IO_Uring = struct { |
| 556 | return sqe; | 556 | return sqe; |
| 557 | } | 557 | } |
| 558 | | 558 | |
| | 559 | /// Queues (but does not submit) an SQE to perform an `fallocate(2)`. |
| | 560 | /// Returns a pointer to the SQE. |
| | 561 | pub fn fallocate( |
| | 562 | self: *IO_Uring, |
| | 563 | user_data: u64, |
| | 564 | fd: os.fd_t, |
| | 565 | mode: i32, |
| | 566 | offset: u64, |
| | 567 | len: u64, |
| | 568 | ) !*io_uring_sqe { |
| | 569 | const sqe = try self.get_sqe(); |
| | 570 | io_uring_prep_fallocate(sqe, fd, mode, offset, len); |
| | 571 | sqe.user_data = user_data; |
| | 572 | return sqe; |
| | 573 | } |
| | 574 | |
| 559 | /// Registers an array of file descriptors. | 575 | /// Registers an array of file descriptors. |
| 560 | /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must | 576 | /// Every time a file descriptor is put in an SQE and submitted to the kernel, the kernel must |
| 561 | /// retrieve a reference to the file, and once I/O has completed the file reference must be | 577 | /// retrieve a reference to the file, and once I/O has completed the file reference must be |
| ... | @@ -894,6 +910,30 @@ pub fn io_uring_prep_timeout_remove(sqe: *io_uring_sqe, timeout_user_data: u64, | ... | @@ -894,6 +910,30 @@ pub fn io_uring_prep_timeout_remove(sqe: *io_uring_sqe, timeout_user_data: u64, |
| 894 | }; | 910 | }; |
| 895 | } | 911 | } |
| 896 | | 912 | |
| | 913 | pub fn io_uring_prep_fallocate( |
| | 914 | sqe: *io_uring_sqe, |
| | 915 | fd: os.fd_t, |
| | 916 | mode: i32, |
| | 917 | offset: u64, |
| | 918 | len: u64, |
| | 919 | ) void { |
| | 920 | sqe.* = .{ |
| | 921 | .opcode = .FALLOCATE, |
| | 922 | .flags = 0, |
| | 923 | .ioprio = 0, |
| | 924 | .fd = fd, |
| | 925 | .off = offset, |
| | 926 | .addr = len, |
| | 927 | .len = @intCast(u32, mode), |
| | 928 | .rw_flags = 0, |
| | 929 | .user_data = 0, |
| | 930 | .buf_index = 0, |
| | 931 | .personality = 0, |
| | 932 | .splice_fd_in = 0, |
| | 933 | .__pad2 = [2]u64{ 0, 0 }, |
| | 934 | }; |
| | 935 | } |
| | 936 | |
| 897 | test "structs/offsets/entries" { | 937 | test "structs/offsets/entries" { |
| 898 | if (builtin.os.tag != .linux) return error.SkipZigTest; | 938 | if (builtin.os.tag != .linux) return error.SkipZigTest; |
| 899 | | 939 | |
| ... | @@ -1395,3 +1435,47 @@ test "timeout_remove" { | ... | @@ -1395,3 +1435,47 @@ test "timeout_remove" { |
| 1395 | .flags = 0, | 1435 | .flags = 0, |
| 1396 | }, cqe_timeout_remove); | 1436 | }, cqe_timeout_remove); |
| 1397 | } | 1437 | } |
| | 1438 | |
| | 1439 | test "fallocate" { |
| | 1440 | if (builtin.os.tag != .linux) return error.SkipZigTest; |
| | 1441 | |
| | 1442 | var ring = IO_Uring.init(1, 0) catch |err| switch (err) { |
| | 1443 | error.SystemOutdated => return error.SkipZigTest, |
| | 1444 | error.PermissionDenied => return error.SkipZigTest, |
| | 1445 | else => return err, |
| | 1446 | }; |
| | 1447 | defer ring.deinit(); |
| | 1448 | |
| | 1449 | const path = "test_io_uring_fallocate"; |
| | 1450 | const file = try std.fs.cwd().createFile(path, .{ .truncate = true, .mode = 0o666 }); |
| | 1451 | defer file.close(); |
| | 1452 | defer std.fs.cwd().deleteFile(path) catch {}; |
| | 1453 | |
| | 1454 | testing.expectEqual(@as(u64, 0), (try file.stat()).size); |
| | 1455 | |
| | 1456 | const len: u64 = 65536; |
| | 1457 | const sqe = try ring.fallocate(0xaaaaaaaa, file.handle, 0, 0, len); |
| | 1458 | testing.expectEqual(linux.IORING_OP.FALLOCATE, sqe.opcode); |
| | 1459 | testing.expectEqual(file.handle, sqe.fd); |
| | 1460 | testing.expectEqual(@as(u32, 1), try ring.submit()); |
| | 1461 | |
| | 1462 | const cqe = try ring.copy_cqe(); |
| | 1463 | switch (-cqe.res) { |
| | 1464 | 0 => {}, |
| | 1465 | // This kernel's io_uring does not yet implement fallocate(): |
| | 1466 | linux.EINVAL => return error.SkipZigTest, |
| | 1467 | // This kernel does not implement fallocate(): |
| | 1468 | linux.ENOSYS => return error.SkipZigTest, |
| | 1469 | // The filesystem containing the file referred to by fd does not support this operation; |
| | 1470 | // or the mode is not supported by the filesystem containing the file referred to by fd: |
| | 1471 | linux.EOPNOTSUPP => return error.SkipZigTest, |
| | 1472 | else => |errno| std.debug.panic("unhandled errno: {}", .{errno}), |
| | 1473 | } |
| | 1474 | testing.expectEqual(linux.io_uring_cqe{ |
| | 1475 | .user_data = 0xaaaaaaaa, |
| | 1476 | .res = 0, |
| | 1477 | .flags = 0, |
| | 1478 | }, cqe); |
| | 1479 | |
| | 1480 | testing.expectEqual(len, (try file.stat()).size); |
| | 1481 | } |