authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2022-09-24 19:18:01+03:30
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-05 15:43:39-04:00
logaea617c60be848ed372343e08465bb0ac6cb7b85
tree4408094ab9c82d28d2b5486308b73ba1226e7649
parent28288dcbbf5258fe7461bbe0f6b2feeba0c2de5d

std.os: take advantage of the freebsd's copy_file_range


3 files changed, 47 insertions(+), 31 deletions(-)

lib/std/c/freebsd.zig+2
......@@ -1440,6 +1440,7 @@ pub const E = enum(u16) {
14401440 CAPMODE = 94, // Not permitted in capability mode
14411441 NOTRECOVERABLE = 95, // State not recoverable
14421442 OWNERDEAD = 96, // Previous owner died
1443 INTEGRITY = 97, // Integrity check failed
14431444 _,
14441445};
14451446
......@@ -1875,3 +1876,4 @@ pub const MFD = struct {
18751876};
18761877
18771878pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
1879pub 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;
lib/std/os.zig+44-31
......@@ -6314,6 +6314,7 @@ pub const CopyFileRangeError = error{
63146314 Unseekable,
63156315 PermissionDenied,
63166316 SwapFile,
6317 CorruptedData,
63176318} || PReadError || PWriteError || UnexpectedError;
63186319
63196320var 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);
63396340///
63406341/// These systems support in-kernel data copying:
63416342/// * Linux 4.5 (cross-filesystem 5.3)
6343/// * FreeBSD 13.0
63426344///
63436345/// Other systems fall back to calling `pread` / `pwrite`.
63446346///
6345/// Maximum offsets on Linux are `math.maxInt(i64)`.
6347/// Maximum offsets on Linux and FreeBSD are `math.maxInt(i64)`.
63466348pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len: usize, flags: u32) CopyFileRangeError!usize {
6347 const call_cfr = comptime if (builtin.os.tag == .wasi)
6348 // WASI-libc doesn't have copy_file_range.
6349 false
6350 else if (builtin.link_libc)
6351 std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok
6352 else
6353 builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true;
6354
6355 if (call_cfr and has_copy_file_range_syscall.load(.Monotonic)) {
6349 if ((comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0 }) orelse false) or
6350 ((comptime builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse false and
6351 std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok) and
6352 has_copy_file_range_syscall.load(.Monotonic)))
6353 {
63566354 var off_in_copy = @bitCast(i64, off_in);
63576355 var off_out_copy = @bitCast(i64, off_out);
63586356
6359 const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
6360 switch (system.getErrno(rc)) {
6361 .SUCCESS => return @intCast(usize, rc),
6362 .BADF => return error.FilesOpenedWithWrongFlags,
6363 .FBIG => return error.FileTooBig,
6364 .IO => return error.InputOutput,
6365 .ISDIR => return error.IsDir,
6366 .NOMEM => return error.OutOfMemory,
6367 .NOSPC => return error.NoSpaceLeft,
6368 .OVERFLOW => return error.Unseekable,
6369 .PERM => return error.PermissionDenied,
6370 .TXTBSY => return error.SwapFile,
6371 // these may not be regular files, try fallback
6372 .INVAL => {},
6373 // support for cross-filesystem copy added in Linux 5.3, use fallback
6374 .XDEV => {},
6375 // syscall added in Linux 4.5, use fallback
6376 .NOSYS => {
6377 has_copy_file_range_syscall.store(false, .Monotonic);
6378 },
6379 else => |err| return unexpectedErrno(err),
6357 while (true) {
6358 const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
6359 if (builtin.os.tag == .freebsd) {
6360 switch (system.getErrno(rc)) {
6361 .SUCCESS => return @intCast(usize, rc),
6362 .BADF => return error.FilesOpenedWithWrongFlags,
6363 .FBIG => return error.FileTooBig,
6364 .IO => return error.InputOutput,
6365 .ISDIR => return error.IsDir,
6366 .NOSPC => return error.NoSpaceLeft,
6367 .INVAL => break, // these may not be regular files, try fallback
6368 .INTEGRITY => return error.CorruptedData,
6369 .INTR => continue,
6370 else => |err| return unexpectedErrno(err),
6371 }
6372 } else { // assume linux
6373 switch (system.getErrno(rc)) {
6374 .SUCCESS => return @intCast(usize, rc),
6375 .BADF => return error.FilesOpenedWithWrongFlags,
6376 .FBIG => return error.FileTooBig,
6377 .IO => return error.InputOutput,
6378 .ISDIR => return error.IsDir,
6379 .NOSPC => return error.NoSpaceLeft,
6380 .INVAL => break, // these may not be regular files, try fallback
6381 .NOMEM => return error.OutOfMemory,
6382 .OVERFLOW => return error.Unseekable,
6383 .PERM => return error.PermissionDenied,
6384 .TXTBSY => return error.SwapFile,
6385 .XDEV => break, // support for cross-filesystem copy added in Linux 5.3, use fallback
6386 .NOSYS => { // syscall added in Linux 4.5, use fallback
6387 has_copy_file_range_syscall.store(false, .Monotonic);
6388 break;
6389 },
6390 else => |err| return unexpectedErrno(err),
6391 }
6392 }
63806393 }
63816394 }
63826395
src/link.zig+1
......@@ -457,6 +457,7 @@ pub const File = struct {
457457 Unseekable,
458458 PermissionDenied,
459459 SwapFile,
460 CorruptedData,
460461 SystemResources,
461462 OperationAborted,
462463 BrokenPipe,