core/log: copy early logs with sendfile/readwrite again

copy_file_range does not work across devices and memfds count as a
separate device.
This commit is contained in:
outfoxxed 2026-01-08 02:35:08 -08:00
parent 6742148cf4
commit 8d19beb69e
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
2 changed files with 65 additions and 11 deletions

View file

@ -27,7 +27,10 @@
#include <qtmetamacros.h> #include <qtmetamacros.h>
#include <qtypes.h> #include <qtypes.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #ifdef __linux__
#include <sys/sendfile.h>
#include <sys/types.h>
#endif
#include "instanceinfo.hpp" #include "instanceinfo.hpp"
#include "logcat.hpp" #include "logcat.hpp"
@ -43,6 +46,57 @@ using namespace qt_logging_registry;
QS_LOGGING_CATEGORY(logLogging, "quickshell.logging", QtWarningMsg); QS_LOGGING_CATEGORY(logLogging, "quickshell.logging", QtWarningMsg);
namespace {
bool copyFileData(int sourceFd, int destFd, qint64 size) {
auto usize = static_cast<size_t>(size);
#ifdef __linux__
off_t offset = 0;
auto remaining = usize;
while (remaining > 0) {
auto r = sendfile(destFd, sourceFd, &offset, remaining);
if (r == -1) {
if (errno == EINTR) continue;
return false;
}
if (r == 0) break;
remaining -= static_cast<size_t>(r);
}
return true;
#else
std::array<char, 64 * 1024> buffer = {};
auto remaining = totalTarget;
while (remaining > 0) {
auto chunk = std::min(remaining, buffer.size());
auto r = ::read(sourceFd, buffer.data(), chunk);
if (r == -1) {
if (errno == EINTR) continue;
return false;
}
if (r == 0) break;
auto readBytes = static_cast<size_t>(r);
size_t written = 0;
while (written < readBytes) {
auto w = ::write(destFd, buffer.data() + written, readBytes - written);
if (w == -1) {
if (errno == EINTR) continue;
return false;
}
written += static_cast<size_t>(w);
}
remaining -= readBytes;
}
return true;
#endif
}
} // namespace
bool LogMessage::operator==(const LogMessage& other) const { bool LogMessage::operator==(const LogMessage& other) const {
// note: not including time // note: not including time
return this->type == other.type && this->category == other.category && this->body == other.body; return this->type == other.type && this->category == other.category && this->body == other.body;
@ -414,7 +468,11 @@ void ThreadLogging::initFs() {
auto* oldFile = this->file; auto* oldFile = this->file;
if (oldFile) { if (oldFile) {
oldFile->seek(0); oldFile->seek(0);
copy_file_range(oldFile->handle(), nullptr, file->handle(), nullptr, oldFile->size(), 0);
if (!copyFileData(oldFile->handle(), file->handle(), oldFile->size())) {
qCritical(logLogging) << "Failed to copy log from memfd with error code " << errno
<< qt_error_string(errno);
}
} }
this->file = file; this->file = file;
@ -426,14 +484,10 @@ void ThreadLogging::initFs() {
auto* oldFile = this->detailedFile; auto* oldFile = this->detailedFile;
if (oldFile) { if (oldFile) {
oldFile->seek(0); oldFile->seek(0);
copy_file_range( if (!copyFileData(oldFile->handle(), detailedFile->handle(), oldFile->size())) {
oldFile->handle(), qCritical(logLogging) << "Failed to copy detailed log from memfd with error code " << errno
nullptr, << qt_error_string(errno);
detailedFile->handle(), }
nullptr,
oldFile->size(),
0
);
} }
crash::CrashInfo::INSTANCE.logFd = detailedFile->handle(); crash::CrashInfo::INSTANCE.logFd = detailedFile->handle();

View file

@ -1,4 +1,5 @@
#include "conversation.hpp" #include "conversation.hpp"
#include <csignal>
#include <qlogging.h> #include <qlogging.h>
#include <qloggingcategory.h> #include <qloggingcategory.h>
@ -6,7 +7,6 @@
#include <qsocketnotifier.h> #include <qsocketnotifier.h>
#include <qstring.h> #include <qstring.h>
#include <qtmetamacros.h> #include <qtmetamacros.h>
#include <csignal>
#include <sys/signal.h> #include <sys/signal.h>
#include <sys/wait.h> #include <sys/wait.h>