((ext).fe_logical != 0) && \
((ext).fe_physical != (exp))
+/*
+ * Copy fields from fiemap_extent 'from' to the fiemap_extent
+ * pointed to by 'to'.
+ */
+#define ext_copy(to, from) \
+do { \
+ *(to) = *(from); \
+} while (0)
+
+static uint64_t _stats_map_extents(struct dm_pool *mem,
+ struct fiemap *fiemap,
+ struct fiemap_extent *fm_ext,
+ struct fiemap_extent *fm_last,
+ struct fiemap_extent *fm_pending,
+ uint64_t next_extent,
+ int *eof)
+{
+ uint64_t expected = 0, nr_extents = next_extent;
+ unsigned int i;
+
+ /*
+ * Loop over the returned extents adding the fm_pending extent
+ * to the table of extents each time a discontinuity (or eof)
+ * is detected.
+ *
+ * We use a pointer to fm_pending in the caller since it is
+ * possible that logical extents comprising a single physical
+ * extent are returned by successive FIEMAP calls.
+ */
+ for (i = 0; i < fiemap->fm_mapped_extents; i++) {
+ expected = fm_last->fe_physical + fm_last->fe_length;
+
+ if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
+ *eof = 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)) {
+ if (!_stats_add_extent(mem, fm_pending, nr_extents))
+ goto_bad;
+ nr_extents++;
+ /* Begin a new pending extent. */
+ ext_copy(fm_pending, fm_ext + i);
+ } else {
+ expected = 0;
+ /* Begin a new pending extent for extent 0. */
+ if (fm_ext[i].fe_logical == 0)
+ ext_copy(fm_pending, fm_ext + i);
+ else
+ /* accumulate this logical extent's length */
+ fm_pending->fe_length += fm_ext[i].fe_length;
+ }
+ *fm_last = fm_ext[i];
+ }
+
+ /*
+ * 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, nr_extents);
+
+ fiemap->fm_start = (fm_ext[i - 1].fe_logical +
+ fm_ext[i - 1].fe_length);
+
+ /* return the number of extents found in this call. */
+ return nr_extents - next_extent;
+bad:
+ /* signal mapping error to caller */
+ *eof = -1;
+ return 0;
+}
+
/*
* Read the extents of an open file descriptor into a table of struct _extent.
*
static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
uint64_t *count)
{
- uint64_t *buf;
+ struct fiemap_extent fm_last = {0}, fm_pending = {0}, *fm_ext = NULL;
struct fiemap *fiemap = NULL;
- struct fiemap_extent *fm_ext = NULL;
- struct fiemap_extent fm_last = {0}, fm_pending = {0};
+ int eof = 0, nr_extents = 0;
struct _extent *extents;
- unsigned long long expected = 0;
unsigned long flags = 0;
- unsigned int i, num = 0;
- int tot_extents = 0, n = 0;
- int last = 0;
+ uint64_t *buf;
int rc;
buf = dm_zalloc(STATS_FIE_BUF_LEN);
goto bad;
}
- /* If 0 extents are returned, then more ioctls are not needed */
+ /* If 0 extents are returned, more ioctls are not needed */
if (fiemap->fm_mapped_extents == 0)
break;
- for (i = 0; i < fiemap->fm_mapped_extents; i++) {
- expected = fm_last.fe_physical + fm_last.fe_length;
+ nr_extents += _stats_map_extents(mem, fiemap, fm_ext, &fm_last,
+ &fm_pending, nr_extents, &eof);
- 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_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;
- /* 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;
- 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);
+ /* check for extent mapping error */
+ if (eof < 0)
+ goto bad;
- fiemap->fm_start = (fm_ext[i - 1].fe_logical +
- fm_ext[i - 1].fe_length);
- } while (last == 0);
+ } while (eof == 0);
- if (!tot_extents) {
+ if (!nr_extents) {
log_error("Cannot map file: no allocated extents.");
goto bad;
}
/* return total number of extents */
- *count = tot_extents;
+ *count = nr_extents;
extents = dm_pool_end_object(mem);
/* free FIEMAP buffer. */