Commit 33a86cfa authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba
Browse files

btrfs: properly flush delalloc when entering fiemap



If the flag FIEMAP_FLAG_SYNC is passed to fiemap, it means all delalloc
should be flushed and writeback complete. We call the generic helper
fiemap_prep() which does a filemap_write_and_wait() in case that flag is
given, however that is not enough if we have compression. Because a
single filemap_fdatawrite_range() only starts compression (in an async
thread) and therefore returns before the compression is done and writeback
is started.

So make btrfs_fiemap(), actually wait for all writeback to start and
complete if FIEMAP_FLAG_SYNC is set. We start and wait for writeback
on the whole possible file range, from 0 to LLONG_MAX, because that is
what the generic code at fiemap_prep() does.

Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Reviewed-by: default avatarQu Wenruo <wqu@suse.com>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 9a42bbae
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -8252,6 +8252,26 @@ static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
	if (ret)
		return ret;

	/*
	 * fiemap_prep() called filemap_write_and_wait() for the whole possible
	 * file range (0 to LLONG_MAX), but that is not enough if we have
	 * compression enabled. The first filemap_fdatawrite_range() only kicks
	 * in the compression of data (in an async thread) and will return
	 * before the compression is done and writeback is started. A second
	 * filemap_fdatawrite_range() is needed to wait for the compression to
	 * complete and writeback to start. Without this, our user is very
	 * likely to get stale results, because the extents and extent maps for
	 * delalloc regions are only allocated when writeback starts.
	 */
	if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC) {
		ret = btrfs_fdatawrite_range(inode, 0, LLONG_MAX);
		if (ret)
			return ret;
		ret = filemap_fdatawait_range(inode->i_mapping, 0, LLONG_MAX);
		if (ret)
			return ret;
	}

	return extent_fiemap(BTRFS_I(inode), fieinfo, start, len);
}