From: Zygo Blaxell Date: Sun, 24 May 2026 19:09:18 +0000 (-0400) Subject: fs: make FILE_EXTENT_SAME failures self-describing X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fnext;p=bees fs: make FILE_EXTENT_SAME failures self-describing The old error dumped the raw btrfs_ioctl_same_args struct after the source path. With long backup-snapshot pathnames the line was truncated before the destination offset, so the log rarely contained enough to understand or reproduce the failure. Emit the parameters of dedupe_file_range directly: the src file and offset, the length, and every dst file and offset. That is the full set of inputs needed to replay the ioctl by hand. Assisted-by: Claude-Code:claude-opus-4-7 Signed-off-by: Zygo Blaxell --- diff --git a/lib/fs.cc b/lib/fs.cc index ee7d9b68..45c0d841 100644 --- a/lib/fs.cc +++ b/lib/fs.cc @@ -145,7 +145,24 @@ namespace crucible { } int rv = ioctl(m_fd, BTRFS_IOC_FILE_EXTENT_SAME, ioctl_ptr); if (rv) { - THROW_ERRNO("After FILE_EXTENT_SAME (fd = " << m_fd << " '" << name_fd(m_fd) << "') : " << ioctl_ptr); + // Build a self-contained description of the failed + // request: the src file/offset, the length, and every + // dst file/offset. That is exactly the set of + // parameters needed to replay the dedupe_file_range + // ioctl by hand. (name_fd() preserves errno across its + // readlink(), so THROW_ERRNO still reports the ioctl's.) + ostringstream oss; + oss << "FILE_EXTENT_SAME failed:" + << " src fd " << m_fd << " '" << name_fd(m_fd) << "'" + << " offset " << to_hex(m_logical_offset) + << " length " << to_hex(m_length); + for (size_t i = 0; i < m_info.size(); ++i) { + const auto &info = m_info[i]; + oss << " -> dst[" << i << "] fd " << info.fd + << " '" << name_fd(info.fd) << "'" + << " offset " << to_hex(info.logical_offset); + } + THROW_ERRNO(oss.str()); } count = 0; for (auto i = m_info.cbegin(); i != m_info.cend(); ++i) {