summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap_util.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-01-27 12:44:32 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2017-01-27 12:44:32 -0800
commit3365135d43f861003555c963b309672d053a2228 (patch)
treebfef4adec5da118bf1b3df7e5cff74f45af9e02d /fs/xfs/xfs_bmap_util.c
parent5906374446386fd16fe562b042429d905d231ec3 (diff)
parente0d76fa4475ef2cf4b52d18588b8ce95153d021b (diff)
downloadlinux-3365135d43f861003555c963b309672d053a2228.tar.bz2
Merge tag 'xfs-for-linus-4.10-rc6-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull xfs uodates from Darrick Wong: "I have some more fixes this week: better input validation, corruption avoidance, build fixes, memory leak fixes, and a couple from Christoph to avoid an ENOSPC failure. Summary: - Fix race conditions in the CoW code - Fix some incorrect input validation checks - Avoid crashing fs by running out of space when freeing inodes - Fix toctou race wrt whether or not an inode has an attr - Fix build error on arm - Fix page refcount corruption when readahead fails - Don't corrupt userspace in the bmap ioctl" * tag 'xfs-for-linus-4.10-rc6-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: xfs: prevent quotacheck from overloading inode lru xfs: fix bmv_count confusion w/ shared extents xfs: clear _XBF_PAGES from buffers when readahead page xfs: extsize hints are not unlikely in xfs_bmap_btalloc xfs: remove racy hasattr check from attr ops xfs: use per-AG reservations for the finobt xfs: only update mount/resv fields on success in __xfs_ag_resv_init xfs: verify dirblocklog correctly xfs: fix COW writeback race
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r--fs/xfs/xfs_bmap_util.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index b9abce524c33..c1417919ab0a 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -528,7 +528,6 @@ xfs_getbmap(
xfs_bmbt_irec_t *map; /* buffer for user's data */
xfs_mount_t *mp; /* file system mount point */
int nex; /* # of user extents can do */
- int nexleft; /* # of user extents left */
int subnex; /* # of bmapi's can do */
int nmap; /* number of map entries */
struct getbmapx *out; /* output structure */
@@ -686,10 +685,8 @@ xfs_getbmap(
goto out_free_map;
}
- nexleft = nex;
-
do {
- nmap = (nexleft > subnex) ? subnex : nexleft;
+ nmap = (nex> subnex) ? subnex : nex;
error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
XFS_BB_TO_FSB(mp, bmv->bmv_length),
map, &nmap, bmapi_flags);
@@ -697,8 +694,8 @@ xfs_getbmap(
goto out_free_map;
ASSERT(nmap <= subnex);
- for (i = 0; i < nmap && nexleft && bmv->bmv_length &&
- cur_ext < bmv->bmv_count; i++) {
+ for (i = 0; i < nmap && bmv->bmv_length &&
+ cur_ext < bmv->bmv_count - 1; i++) {
out[cur_ext].bmv_oflags = 0;
if (map[i].br_state == XFS_EXT_UNWRITTEN)
out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC;
@@ -760,16 +757,27 @@ xfs_getbmap(
continue;
}
+ /*
+ * In order to report shared extents accurately,
+ * we report each distinct shared/unshared part
+ * of a single bmbt record using multiple bmap
+ * extents. To make that happen, we iterate the
+ * same map array item multiple times, each
+ * time trimming out the subextent that we just
+ * reported.
+ *
+ * Because of this, we must check the out array
+ * index (cur_ext) directly against bmv_count-1
+ * to avoid overflows.
+ */
if (inject_map.br_startblock != NULLFSBLOCK) {
map[i] = inject_map;
i--;
- } else
- nexleft--;
+ }
bmv->bmv_entries++;
cur_ext++;
}
- } while (nmap && nexleft && bmv->bmv_length &&
- cur_ext < bmv->bmv_count);
+ } while (nmap && bmv->bmv_length && cur_ext < bmv->bmv_count - 1);
out_free_map:
kmem_free(map);