From 3b28390166dc60a3cb9f0586e366a48e0d016802 Mon Sep 17 00:00:00 2001 From: Ali Chraghi Date: Sat, 24 Sep 2022 19:18:01 +0330 Subject: [PATCH] std.os: take advantage of the freebsd's copy_file_range --- lib/std/c/freebsd.zig | 2 ++ lib/std/os.zig | 75 +++++++++++++++++++++++++------------------ src/link.zig | 1 + 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig index 799040c38120..960ab85ff59b 100644 --- a/lib/std/c/freebsd.zig +++ b/lib/std/c/freebsd.zig @@ -1440,6 +1440,7 @@ pub const E = enum(u16) { CAPMODE = 94, // Not permitted in capability mode NOTRECOVERABLE = 95, // State not recoverable OWNERDEAD = 96, // Previous owner died + INTEGRITY = 97, // Integrity check failed _, }; @@ -1875,3 +1876,4 @@ pub const MFD = struct { }; pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int; +pub extern "c" fn copy_file_range(fd_in: fd_t, off_in: ?*off_t, fd_out: fd_t, off_out: ?*off_t, len: usize, flags: u32) usize; diff --git a/lib/std/os.zig b/lib/std/os.zig index 8590d0f6963f..edea8f16202c 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -6314,6 +6314,7 @@ pub const CopyFileRangeError = error{ Unseekable, PermissionDenied, SwapFile, + CorruptedData, } || PReadError || PWriteError || UnexpectedError; var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true); @@ -6339,44 +6340,56 @@ var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true); /// /// These systems support in-kernel data copying: /// * Linux 4.5 (cross-filesystem 5.3) +/// * FreeBSD 13.0 /// /// Other systems fall back to calling `pread` / `pwrite`. /// -/// Maximum offsets on Linux are `math.maxInt(i64)`. +/// Maximum offsets on Linux and FreeBSD are `math.maxInt(i64)`. pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len: usize, flags: u32) CopyFileRangeError!usize { - const call_cfr = comptime if (builtin.os.tag == .wasi) - // WASI-libc doesn't have copy_file_range. - false - else if (builtin.link_libc) - std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok - else - builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true; - - if (call_cfr and has_copy_file_range_syscall.load(.Monotonic)) { + if ((comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0 }) orelse false) or + ((comptime builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse false and + std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok) and + has_copy_file_range_syscall.load(.Monotonic))) + { var off_in_copy = @bitCast(i64, off_in); var off_out_copy = @bitCast(i64, off_out); - const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags); - switch (system.getErrno(rc)) { - .SUCCESS => return @intCast(usize, rc), - .BADF => return error.FilesOpenedWithWrongFlags, - .FBIG => return error.FileTooBig, - .IO => return error.InputOutput, - .ISDIR => return error.IsDir, - .NOMEM => return error.OutOfMemory, - .NOSPC => return error.NoSpaceLeft, - .OVERFLOW => return error.Unseekable, - .PERM => return error.PermissionDenied, - .TXTBSY => return error.SwapFile, - // these may not be regular files, try fallback - .INVAL => {}, - // support for cross-filesystem copy added in Linux 5.3, use fallback - .XDEV => {}, - // syscall added in Linux 4.5, use fallback - .NOSYS => { - has_copy_file_range_syscall.store(false, .Monotonic); - }, - else => |err| return unexpectedErrno(err), + while (true) { + const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags); + if (builtin.os.tag == .freebsd) { + switch (system.getErrno(rc)) { + .SUCCESS => return @intCast(usize, rc), + .BADF => return error.FilesOpenedWithWrongFlags, + .FBIG => return error.FileTooBig, + .IO => return error.InputOutput, + .ISDIR => return error.IsDir, + .NOSPC => return error.NoSpaceLeft, + .INVAL => break, // these may not be regular files, try fallback + .INTEGRITY => return error.CorruptedData, + .INTR => continue, + else => |err| return unexpectedErrno(err), + } + } else { // assume linux + switch (system.getErrno(rc)) { + .SUCCESS => return @intCast(usize, rc), + .BADF => return error.FilesOpenedWithWrongFlags, + .FBIG => return error.FileTooBig, + .IO => return error.InputOutput, + .ISDIR => return error.IsDir, + .NOSPC => return error.NoSpaceLeft, + .INVAL => break, // these may not be regular files, try fallback + .NOMEM => return error.OutOfMemory, + .OVERFLOW => return error.Unseekable, + .PERM => return error.PermissionDenied, + .TXTBSY => return error.SwapFile, + .XDEV => break, // support for cross-filesystem copy added in Linux 5.3, use fallback + .NOSYS => { // syscall added in Linux 4.5, use fallback + has_copy_file_range_syscall.store(false, .Monotonic); + break; + }, + else => |err| return unexpectedErrno(err), + } + } } } diff --git a/src/link.zig b/src/link.zig index ffa95c9efb3b..3097e5cf1f2e 100644 --- a/src/link.zig +++ b/src/link.zig @@ -457,6 +457,7 @@ pub const File = struct { Unseekable, PermissionDenied, SwapFile, + CorruptedData, SystemResources, OperationAborted, BrokenPipe,