Skip to content

Commit fadc23a

Browse files
committed
std.os: take advantage of the freebsd's copy_file_range
1 parent cae76d8 commit fadc23a

File tree

4 files changed

+64
-35
lines changed

4 files changed

+64
-35
lines changed

lib/std/c/freebsd.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,7 @@ pub const E = enum(u16) {
14491449
CAPMODE = 94, // Not permitted in capability mode
14501450
NOTRECOVERABLE = 95, // State not recoverable
14511451
OWNERDEAD = 96, // Previous owner died
1452+
INTEGRITY = 97, // Integrity check failed
14521453
_,
14531454
};
14541455

@@ -1884,3 +1885,4 @@ pub const MFD = struct {
18841885
};
18851886

18861887
pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
1888+
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;

lib/std/fs/file.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,8 +1235,7 @@ pub const File = struct {
12351235

12361236
pub fn copyRange(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 {
12371237
const adjusted_len = math.cast(usize, len) orelse math.maxInt(usize);
1238-
const result = try os.copy_file_range(in.handle, in_offset, out.handle, out_offset, adjusted_len, 0);
1239-
return result;
1238+
return os.copy_file_range(in.handle, in_offset, out.handle, out_offset, adjusted_len, 0);
12401239
}
12411240

12421241
/// Returns the number of bytes copied. If the number read is smaller than `buffer.len`, it

lib/std/os.zig

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6256,6 +6256,8 @@ pub const CopyFileRangeError = error{
62566256
Unseekable,
62576257
PermissionDenied,
62586258
SwapFile,
6259+
CorruptedData,
6260+
RangeOverlap,
62596261
} || PReadError || PWriteError || UnexpectedError;
62606262

62616263
var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);
@@ -6281,44 +6283,68 @@ var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);
62816283
///
62826284
/// These systems support in-kernel data copying:
62836285
/// * Linux 4.5 (cross-filesystem 5.3)
6286+
/// * FreeBSD 13.0
62846287
///
62856288
/// Other systems fall back to calling `pread` / `pwrite`.
62866289
///
6287-
/// Maximum offsets on Linux are `math.maxInt(i64)`.
6290+
/// Maximum offsets on Linux and FreeBSD are `math.maxInt(i64)`.
62886291
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 {
6289-
const call_cfr = comptime if (builtin.os.tag == .wasi)
6290-
// WASI-libc doesn't have copy_file_range.
6291-
false
6292-
else if (builtin.link_libc)
6293-
std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok
6294-
else
6295-
builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true;
6296-
6297-
if (call_cfr and has_copy_file_range_syscall.load(.Monotonic)) {
6298-
var off_in_copy = @bitCast(i64, off_in);
6299-
var off_out_copy = @bitCast(i64, off_out);
6300-
6301-
const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
6302-
switch (system.getErrno(rc)) {
6303-
.SUCCESS => return @intCast(usize, rc),
6304-
.BADF => return error.FilesOpenedWithWrongFlags,
6305-
.FBIG => return error.FileTooBig,
6306-
.IO => return error.InputOutput,
6307-
.ISDIR => return error.IsDir,
6308-
.NOMEM => return error.OutOfMemory,
6309-
.NOSPC => return error.NoSpaceLeft,
6310-
.OVERFLOW => return error.Unseekable,
6311-
.PERM => return error.PermissionDenied,
6312-
.TXTBSY => return error.SwapFile,
6313-
// these may not be regular files, try fallback
6314-
.INVAL => {},
6315-
// support for cross-filesystem copy added in Linux 5.3, use fallback
6316-
.XDEV => {},
6317-
// syscall added in Linux 4.5, use fallback
6318-
.NOSYS => {
6319-
has_copy_file_range_syscall.store(false, .Monotonic);
6292+
// WASI-libc doesn't have copy_file_range.
6293+
if (builtin.os.tag != .wasi) {
6294+
switch (builtin.os.tag) {
6295+
.linux => {
6296+
if (std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok and
6297+
builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true and
6298+
has_copy_file_range_syscall.load(.Monotonic))
6299+
{
6300+
var off_in_copy = @bitCast(i64, off_in);
6301+
var off_out_copy = @bitCast(i64, off_out);
6302+
6303+
const rc = system.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
6304+
switch (system.getErrno(rc)) {
6305+
.SUCCESS => return @intCast(usize, rc),
6306+
.BADF => return error.FilesOpenedWithWrongFlags,
6307+
.FBIG => return error.FileTooBig,
6308+
.IO => return error.InputOutput,
6309+
.ISDIR => return error.IsDir,
6310+
.NOMEM => return error.OutOfMemory,
6311+
.NOSPC => return error.NoSpaceLeft,
6312+
.OVERFLOW => return error.Unseekable,
6313+
.PERM => return error.PermissionDenied,
6314+
.TXTBSY => return error.SwapFile,
6315+
// these may not be regular files, try fallback
6316+
.INVAL => {},
6317+
// support for cross-filesystem copy added in Linux 5.3, use fallback
6318+
.XDEV => {},
6319+
// syscall added in Linux 4.5, use fallback
6320+
.NOSYS => {
6321+
has_copy_file_range_syscall.store(false, .Monotonic);
6322+
},
6323+
else => |err| return unexpectedErrno(err),
6324+
}
6325+
}
63206326
},
6321-
else => |err| return unexpectedErrno(err),
6327+
.freebsd => {
6328+
if (builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0 }) orelse true) {
6329+
var off_in_copy = @bitCast(i64, off_in);
6330+
var off_out_copy = @bitCast(i64, off_out);
6331+
const rc = freebsd.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags);
6332+
switch (system.getErrno(rc)) {
6333+
.SUCCESS => return @intCast(usize, rc),
6334+
.BADF => return error.FilesOpenedWithWrongFlags,
6335+
.FBIG => return error.FileTooBig,
6336+
.INVAL => return error.RangeOverlap,
6337+
.IO => return error.InputOutput,
6338+
.INTEGRITY => return error.CorruptedData,
6339+
.ISDIR => return error.IsDir,
6340+
.NOSPC => return error.NoSpaceLeft,
6341+
.INTR => unreachable,
6342+
else => |err| return unexpectedErrno(err),
6343+
}
6344+
}
6345+
},
6346+
// unsupported OS, use fallback
6347+
else => {},
63226348
}
63236349
}
63246350

src/link.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ pub const File = struct {
433433
Unseekable,
434434
PermissionDenied,
435435
SwapFile,
436+
CorruptedData,
437+
RangeOverlap,
436438
SystemResources,
437439
OperationAborted,
438440
BrokenPipe,

0 commit comments

Comments
 (0)