]> sourceware.org Git - lvm2.git/commitdiff
libdm: fix _stats_get_extents_for_file()
authorBryn M. Reeves <bmr@redhat.com>
Mon, 12 Dec 2016 20:40:27 +0000 (20:40 +0000)
committerBryn M. Reeves <bmr@redhat.com>
Tue, 13 Dec 2016 09:09:25 +0000 (09:09 +0000)
Handle files that contain multiple logical extents in a single
physical extent properly:

  - In FIEMAP terms a logical extent is a contiguous range of
    sectors in the file's address space.

  - One or more physically adjacent logical extents comprise a
    physical extent: these are the disk areas that will be mapped
    to regions.

  - An extent boundary occurs when the start sector of extent
    n+1 is not equal to (n.start + n.length).

This requires that we accumulate the length values of extents
returned by FIEMAP until a discontinuity is found (since each
struct fiemap_extent returned by FIEMAP only represents a single
logical extent, which may be contiguous with other logical
extents on-disk).

This avoids creating large numbers of regions for physically
adjacent (logical) extents and fixes the earlier behaviour which
would only map the first logical extent of the physical extent,
leaving gaps in the region table for these files.

WHATS_NEW_DM
libdm/libdm-stats.c

index f402113c2901973548b8218883708b17fa8a1f8e..ab32bdba5f5664b7fd08b197a358f38b50b65ff1 100644 (file)
@@ -1,8 +1,9 @@
 Version 1.02.138 - 
 =====================================
+  Fix file mapping for extents with physically adjacent extents.
   Validation vsnprintf result in runtime translate of dm_log (1.02.136).
   Separate filemap extent allocation from region table.
-  Fix segmentation fault when filemap region creation fails
+  Fix segmentation fault when filemap region creation fails.
   Fix performance of region cleanup for failed filemap creation.
   Fix very slow region deletion with many regions.
 
index 850aa49126afda02b6e491fc5aa424528fee0e15..56a38f27efa566860964f31d759906442cac2101 100644 (file)
@@ -4194,10 +4194,9 @@ static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
 }
 
 /* test for the boundary of an extent */
-#define ext_boundary(ext, exp, exp_dense)      \
-(((ext).fe_logical != 0) &&                    \
-((ext).fe_physical != (exp)) &&                        \
-((ext).fe_physical != (exp_dense)))
+#define ext_boundary(ext, exp)         \
+((ext).fe_logical != 0) &&             \
+((ext).fe_physical != (exp))
 
 /*
  * Read the extents of an open file descriptor into a table of struct _extent.
@@ -4213,10 +4212,9 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
        uint64_t *buf;
        struct fiemap *fiemap = NULL;
        struct fiemap_extent *fm_ext = NULL;
-       struct fiemap_extent fm_last = {0};
+       struct fiemap_extent fm_last = {0}, fm_pending = {0};
        struct _extent *extents;
        unsigned long long expected = 0;
-       unsigned long long expected_dense = 0;
        unsigned long flags = 0;
        unsigned int i, num = 0;
        int tot_extents = 0, n = 0;
@@ -4264,31 +4262,51 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
                        break;
 
                for (i = 0; i < fiemap->fm_mapped_extents; i++) {
-                       expected_dense = fm_last.fe_physical +
-                                        fm_last.fe_length;
-                       expected = fm_last.fe_physical +
-                                  fm_ext[i].fe_logical - fm_last.fe_logical;
-                       if (ext_boundary(fm_ext[i], expected, expected_dense)) {
+                       expected = fm_last.fe_physical + fm_last.fe_length;
+
+                       if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
+                               last = 1;
+
+                       /* cannot map extents that are not yet allocated. */
+                       if (fm_ext[i].fe_flags
+                           & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC))
+                               continue;
+
+                       if (ext_boundary(fm_ext[i], expected)) {
                                tot_extents++;
-                               if (!_stats_add_extent(mem, fm_ext + i,
-                                                      tot_extents - 1))
+                               if (!_stats_add_extent(mem, &fm_pending,
+                                                      fm_pending.fe_flags))
                                        goto_bad;
+                               /* Begin a new pending extent. */
+                               fm_pending.fe_flags = tot_extents - 1;
+                               fm_pending.fe_physical = fm_ext[i].fe_physical;
+                               fm_pending.fe_logical = fm_ext[i].fe_logical;
+                               fm_pending.fe_length = fm_ext[i].fe_length;
                        } else {
                                expected = 0;
                                if (!tot_extents)
                                        tot_extents = 1;
-                               if (fm_ext[i].fe_logical == 0)
-                                       if (!_stats_add_extent(mem, fm_ext + i,
-                                                              tot_extents - 1))
-                                               goto_bad;
+                               /* Begin a new pending extent for extent 0. */
+                               if (fm_ext[i].fe_logical == 0) {
+                                       fm_pending.fe_flags = tot_extents - 1;
+                                       fm_pending.fe_physical = fm_ext[i].fe_physical;
+                                       fm_pending.fe_logical = fm_ext[i].fe_logical;
+                                       fm_pending.fe_length = fm_ext[i].fe_length;
+                               } else
+                                       fm_pending.fe_length += fm_ext[i].fe_length;
                        }
                        num += tot_extents;
-                       if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
-                               last = 1;
                        fm_last = fm_ext[i];
                        n++;
                }
 
+               /*
+                * If the file only has a single extent, no boundary is ever
+                * detected to trigger addition of the first extent.
+                */
+               if (fm_ext[i].fe_logical == 0)
+                       _stats_add_extent(mem, &fm_pending, fm_pending.fe_flags);
+
                fiemap->fm_start = (fm_ext[i - 1].fe_logical +
                                    fm_ext[i - 1].fe_length);
        } while (last == 0);
This page took 0.046489 seconds and 5 git commands to generate.