1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

libdm: fix _stats_get_extents_for_file()

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.
This commit is contained in:
Bryn M. Reeves 2016-12-12 20:40:27 +00:00
parent 87117c2b25
commit 93f420caf4
2 changed files with 39 additions and 20 deletions

View 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.

View 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);