mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 19:01:56 -04:00
Reinstate the splice read/write/move paths removed in 84592a9f, now
gated behind runtime options with negotiated pipe sizing and fallback
logging.
- Transport: msgbuf-piped splice receive, fd-referenced splice reply
(vmsplice + splice), splice-move pipe-bounce, and restored
fuse_buf_copy/fuse_buf_flags plumbing for copy fallbacks
- Negotiation: new pipe-max-size option (auto-raised at INIT when
possible; the sysctl read/write is factored into src/pipe_max_size.cpp
so fuse_init.cpp and option_parser.cpp share one implementation);
fuse-msg-size clamped to what the pipe can hold; splice is disabled
at INIT with a warning if the sysctl can't fit even the minimum,
retracting the FUSE_CAP_SPLICE_* bits already advertised to the
kernel in that case
- Read replies and splice-move are gated at 128 KiB (below that the
syscalls cost more than the copy they avoid); every fallback path
degrades to the copy path and logs once per process via SysLog
- msgbuf pipe cache is process-global and mutex-guarded (mutex_lockguard)
so pipes can move between read and worker threads under
process-thread mode
- API simplified after review: collapsed the three per-axis options
(splice-read/write/move) into a single splice boolean (default on);
no-splice-read/write/move and the bare splice-read/write/move
spellings stay registered as accepted no-ops so existing mount
options don't fail the mount, but they do NOT alter the splice
knob - upgraders with no-splice-* in their config get splice
enabled and must set splice=false explicitly (see
deprecated_options.md)
- Fixed several correctness issues found in parallel review: a
dropped write_buf registration that silently corrupted writes, a
dirty-pipe reuse bug in msgbuf_free, an iov double-send in
fuse_reply_data's splice-move fallback, and pipe-capacity math that
assumed a 4096-byte page size
- Modernized the transport/negotiation code to this codebase's C++
style: RAII (unique_ptr/DEFER) instead of malloc/free and manual fd
close(), std::from_chars/to_chars instead of stoul/snprintf,
_ReplyPipe's pipe ops as methods instead of free functions closing
over a thread_local global, and vendored/libfuse/lib/buffer.cpp (a
near-verbatim port of upstream's buffer.c) brought in line with the
rest of the fork
- Documented splice and pipe-max-size options (mkdocs, FAQ,
deprecated-options list); added tools/bench-splice.sh
- Benchmarked on tmpfs: seq_write +21%, seq_read +52%, small_write
+5%, small_read +12%; validated with a 1h soak (~271 GiB
hash-verified I/O, zero integrity failures), a live-mount round-trip
of I/O above the splice threshold, and the existing unit/smoke
suites at their pre-existing baseline
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
120 lines
3.1 KiB
C++
120 lines
3.1 KiB
C++
/*
|
|
ISC License
|
|
|
|
Copyright (c) 2025, Antonio SJ Musumeci <trapexit@spawn.link>
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "fmt/core.h"
|
|
#include "fmt/format.h"
|
|
|
|
#include <syslog.h>
|
|
|
|
namespace SysLog
|
|
{
|
|
static
|
|
inline
|
|
void
|
|
open()
|
|
{
|
|
const char *ident = "mergerfs";
|
|
/* Deliberately NOT LOG_PERROR: that would echo every SysLog call
|
|
in the whole process (not just the splice fallback warnings) to
|
|
stderr, doubling log volume under systemd/journald setups where
|
|
stderr is also journal-captured. The splice fallback loggers
|
|
(fuse_splice_fallback_log / msgbuf_splice_fallback_log) print to
|
|
stderr themselves instead, scoping the "visible in foreground
|
|
runs" behavior to the messages that actually need it. */
|
|
const int option = (LOG_CONS|LOG_PID);
|
|
const int facility = LOG_USER;
|
|
|
|
openlog(ident,option,facility);
|
|
}
|
|
|
|
static
|
|
inline
|
|
void
|
|
close()
|
|
{
|
|
closelog();
|
|
}
|
|
|
|
template<typename... Args>
|
|
void
|
|
log(int priority_,
|
|
fmt::format_string<Args...> format_,
|
|
Args&&... args)
|
|
{
|
|
auto msg = fmt::format(format_,std::forward<Args>(args)...);
|
|
::syslog(priority_,"%s",msg.c_str());
|
|
}
|
|
|
|
template<typename... Args>
|
|
void
|
|
info(fmt::format_string<Args...> format_,
|
|
Args&&... args)
|
|
{
|
|
SysLog::log(LOG_INFO,format_,std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<typename... Args>
|
|
void
|
|
debug(fmt::format_string<Args...> format_,
|
|
Args&&... args)
|
|
{
|
|
SysLog::log(LOG_DEBUG,format_,std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<typename... Args>
|
|
void
|
|
notice(fmt::format_string<Args...> format_,
|
|
Args&&... args)
|
|
{
|
|
SysLog::log(LOG_NOTICE,format_,std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<typename... Args>
|
|
void
|
|
warning(fmt::format_string<Args...> format_,
|
|
Args&&... args)
|
|
{
|
|
SysLog::log(LOG_WARNING,format_,std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<typename... Args>
|
|
void
|
|
error(fmt::format_string<Args...> format_,
|
|
Args&&... args)
|
|
{
|
|
SysLog::log(LOG_ERR,format_,std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<typename... Args>
|
|
void
|
|
alert(fmt::format_string<Args...> format_,
|
|
Args&&... args)
|
|
{
|
|
SysLog::log(LOG_ALERT,format_,std::forward<Args>(args)...);
|
|
}
|
|
|
|
template<typename... Args>
|
|
void
|
|
crit(fmt::format_string<Args...> format_,
|
|
Args&&... args)
|
|
{
|
|
SysLog::log(LOG_CRIT,format_,std::forward<Args>(args)...);
|
|
}
|
|
}
|