diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 2d2a03216..d9f0427a0 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4225,6 +4225,82 @@ static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
 ((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.
  *
@@ -4236,16 +4312,12 @@ static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
 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);
@@ -4284,67 +4356,26 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
 			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;
+		/* check for extent mapping error */
+		if (eof < 0)
+			goto bad;
 
-			/* cannot map extents that are not yet allocated. */
-			if (fm_ext[i].fe_flags
-			    & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC))
-				continue;
+	} while (eof == 0);
 
-			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);
-
-		fiemap->fm_start = (fm_ext[i - 1].fe_logical +
-				    fm_ext[i - 1].fe_length);
-	} while (last == 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. */