Handle second splice() failure gracefully

This commit is contained in:
LoveSy
2025-10-01 19:30:15 +08:00
committed by John Wu
parent 7270f5e413
commit c07fdc87e3

View File

@@ -10,7 +10,7 @@ use nix::{
}; };
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::mem::MaybeUninit; use std::mem::{ManuallyDrop, MaybeUninit};
use std::os::fd::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd}; use std::os::fd::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@@ -51,20 +51,24 @@ fn pump_via_copy(mut fd_in: &File, mut fd_out: &File) -> LoggedResult<()> {
} }
fn pump_via_splice(fd_in: &File, fd_out: &File, pipe: &(OwnedFd, OwnedFd)) -> LoggedResult<()> { fn pump_via_splice(fd_in: &File, fd_out: &File, pipe: &(OwnedFd, OwnedFd)) -> LoggedResult<()> {
if !SHOULD_USE_SPLICE.load(Ordering::Acquire) { if !SHOULD_USE_SPLICE.load(Ordering::Relaxed) {
return pump_via_copy(fd_in, fd_out); return pump_via_copy(fd_in, fd_out);
} }
// The pipe capacity is by default 16 pages, let's just use 65536 // The pipe capacity is by default 16 pages, let's just use 65536
let Ok(len) = splice(fd_in, &pipe.1, 65536) else { let Ok(len) = splice(fd_in, &pipe.1, 65536) else {
// If splice failed, stop using splice and fallback to userspace copy // If splice failed, stop using splice and fallback to userspace copy
SHOULD_USE_SPLICE.store(false, Ordering::Release); SHOULD_USE_SPLICE.store(false, Ordering::Relaxed);
return pump_via_copy(fd_in, fd_out); return pump_via_copy(fd_in, fd_out);
}; };
if len == 0 { if len == 0 {
return Ok(()); return Ok(());
} }
splice(&pipe.0, fd_out, len)?; if let Err(_) = splice(&pipe.0, fd_out, len) {
// If splice failed, stop using splice and fallback to userspace copy
SHOULD_USE_SPLICE.store(false, Ordering::Relaxed);
return pump_via_copy(&ManuallyDrop::new(unsafe { File::from_raw_fd(pipe.0.as_raw_fd()) }), fd_out);
}
Ok(()) Ok(())
} }