]> git.hungrycats.org Git - bees/commitdiff
fs: make FILE_EXTENT_SAME failures self-describing next
authorZygo Blaxell <bees@furryterror.org>
Sun, 24 May 2026 19:09:18 +0000 (15:09 -0400)
committerZygo Blaxell <bees@furryterror.org>
Sat, 5 Sep 2026 04:03:59 +0000 (00:03 -0400)
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 <bees@furryterror.org>
lib/fs.cc

index ee7d9b68167ca406b95d345b98b60d5e877e01d0..45c0d8413331cdfba3e2a480443e70484bb146e0 100644 (file)
--- 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) {