Commit e411d74c authored by Andreas Gruenbacher's avatar Andreas Gruenbacher
Browse files

gfs2: fiemap page fault fix



In gfs2_fiemap(), we are calling iomap_fiemap() while holding the inode
glock.  This can lead to recursive glock taking if the fiemap buffer is
memory mapped to the same inode and accessing it triggers a page fault.

Fix by disabling page faults for iomap_fiemap() and faulting in the
buffer by hand if necessary.

Fixes xfstest generic/742.

Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parent da6f5bbc
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -2192,6 +2192,14 @@ static int gfs2_getattr(struct mnt_idmap *idmap,
	return 0;
}

static bool fault_in_fiemap(struct fiemap_extent_info *fi)
{
	struct fiemap_extent __user *dest = fi->fi_extents_start;
	size_t size = sizeof(*dest) * fi->fi_extents_max;

	return fault_in_safe_writeable((char __user *)dest, size) == 0;
}

static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
		       u64 start, u64 len)
{
@@ -2201,14 +2209,22 @@ static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,

	inode_lock_shared(inode);

retry:
	ret = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
	if (ret)
		goto out;

	pagefault_disable();
	ret = iomap_fiemap(inode, fieinfo, start, len, &gfs2_iomap_ops);
	pagefault_enable();

	gfs2_glock_dq_uninit(&gh);

	if (ret == -EFAULT && fault_in_fiemap(fieinfo)) {
		fieinfo->fi_extents_mapped = 0;
		goto retry;
	}

out:
	inode_unlock_shared(inode);
	return ret;