two patches merged here http://bugs.gentoo.org/353907 From f69876e558782eb770955aa0b1344a5a8262548b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draig=20Brady?= Date: Wed, 30 Mar 2011 22:50:05 +0100 Subject: [PATCH] copy: with fiemap copy, only sync when needed * src/extent-scan.h (struct extent_scan): Add the fm_flags member to pass to the fiemap scan. * src/extent-scan.c (extent_need_sync): A new function used to detect Linux kernels before 2.6.38. (extent_scan_init): Add FIEMAP_FLAG_SYNC when needed. * tests/cp/sparse-fiemap: Adjust comment. * NEWS: Mention the change in behavior. Indirectly suggested by Mike Frysinger --- NEWS | 4 ++++ src/extent-scan.c | 34 +++++++++++++++++++++++++++++++++- src/extent-scan.h | 3 +++ tests/cp/sparse-fiemap | 4 ++-- 4 files changed, 42 insertions(+), 3 deletions(-) From 1c3654cb1fb0d8f3c422c766028d0783a40f4a42 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Sat, 2 Apr 2011 19:59:30 +0200 Subject: [PATCH] copy: require fiemap sync also for 2.6.38 kernels * src/extent-scan.c (extent_need_sync): Require sync also for 2.6.38. Without this, part of the cp/fiemap-empty test would fail both on F15-to-be (2.6.38.1-6.fc15.x86_64) and rawhide. For details, see http://thread.gmane.org/gmane.comp.gnu.coreutils.bugs/22190 --- src/extent-scan.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extent-scan.c b/src/extent-scan.c index b9520b7..f10d8e0 100644 --- a/src/extent-scan.c +++ b/src/extent-scan.c @@ -20,15 +20,46 @@ #include #include #include +#include #include #include "system.h" #include "extent-scan.h" +#include "xstrtol.h" #ifndef HAVE_FIEMAP # include "fiemap.h" #endif +/* Work around Linux kernel issues on BTRFS and EXT4 before 2.6.39. + FIXME: remove in 2013, or whenever we're pretty confident + that the offending, unpatched kernels are no longer in use. */ +static bool +extent_need_sync (void) +{ + static int need_sync = -1; + + if (need_sync == -1) + { + struct utsname name; + need_sync = 0; /* No workaround by default. */ + +#ifdef __linux__ + if (uname (&name) != -1 && strncmp (name.release, "2.6.", 4) == 0) + { + unsigned long val; + if (xstrtoul (name.release + 4, NULL, 10, &val, NULL) == LONGINT_OK) + { + if (val < 39) + need_sync = 1; + } + } +#endif + } + + return need_sync; +} + /* Allocate space for struct extent_scan, initialize the entries if necessary and return it as the input argument of extent_scan_read(). */ extern void @@ -39,6 +70,7 @@ extent_scan_init (int src_fd, struct extent_scan *scan) scan->scan_start = 0; scan->initial_scan_failed = false; scan->hit_final_extent = false; + scan->fm_flags = extent_need_sync () ? FIEMAP_FLAG_SYNC : 0; } #ifdef __linux__ @@ -62,7 +94,7 @@ extent_scan_read (struct extent_scan *scan) memset (&fiemap_buf, 0, sizeof fiemap_buf); fiemap->fm_start = scan->scan_start; - fiemap->fm_flags = FIEMAP_FLAG_SYNC; + fiemap->fm_flags = scan->fm_flags; fiemap->fm_extent_count = count; fiemap->fm_length = FIEMAP_MAX_OFFSET - scan->scan_start; diff --git a/src/extent-scan.h b/src/extent-scan.h index 4724b25..8728515 100644 --- a/src/extent-scan.h +++ b/src/extent-scan.h @@ -41,6 +41,9 @@ struct extent_scan /* Next scan start offset. */ off_t scan_start; + /* Flags to use for scan. */ + uint32_t fm_flags; + /* How many extent info returned for a scan. */ uint32_t ei_count;