From: Jeff Mahoney <jeffm@suse.com>
Subject: xfs/dmapi: Obtain vfsmount for use in xfs_dm_rdwr
Patch-mainline: Never, I'll disavow all knowledge of this patch

 XFS's DMAPI implementation needs a vfsmount to do internal file opens.
 Older kernels passed the vfsmount in with the get_sb call but that has
 since been removed. This patch adds a lookup before the actual use of
 the vfsmount and caches it.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 fs/xfs/dmapi/xfs_dm.c        |   20 ++++++++++++++++++++
 fs/xfs/linux-2.6/xfs_super.c |   15 +++++----------
 fs/xfs/xfs_mount.h           |    2 ++
 3 files changed, 27 insertions(+), 10 deletions(-)

--- a/fs/xfs/dmapi/xfs_dm.c
+++ b/fs/xfs/dmapi/xfs_dm.c
@@ -52,6 +52,7 @@
 #include "xfs_dm.h"
 
 #include <linux/mount.h>
+#include <linux/namei.h>
 
 #define MAXNAMLEN MAXNAMELEN
 
@@ -853,6 +854,8 @@ xfs_dm_rdwr(
 	ssize_t		xfer;
 	struct file	*file;
 	struct dentry	*dentry;
+	struct path	path;
+	struct xfs_mount *mp = ip->i_mount;
 
 	if ((off < 0) || (off > i_size_read(inode)) || !S_ISREG(inode->i_mode))
 		return EINVAL;
@@ -889,6 +892,23 @@ xfs_dm_rdwr(
 		return ENOMEM;
 	}
 
+	/*
+	 * Ugh. This is not ideal, but we can't even keep a private vfsmount
+	 * for this. We'd run into problems with freeing the superblock as
+	 * well as AppArmor refusing access due to the pathnames not matching.
+	 */
+	if (!mp->m_vfsmount) {
+		error = kern_path(mp->m_mtpt, 0, &path);
+		if (error)
+			return -error;
+
+		spin_lock(&mp->m_vfsmount_lock);
+		if (!mp->m_vfsmount)
+			mp->m_vfsmount = path.mnt;
+		spin_unlock(&mp->m_vfsmount_lock);
+		path_put(&path);
+	}
+
 	file = dentry_open(dentry, mntget(ip->i_mount->m_vfsmount), oflags,
 			   cred);
 	if (IS_ERR(file)) {
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1088,6 +1088,7 @@ xfs_fs_put_super(
 	xfs_close_devices(mp);
 	xfs_dmops_put(mp);
 	xfs_free_fsname(mp);
+	kfree(mp->m_mtpt);
 	kfree(mp);
 }
 
@@ -1405,6 +1406,8 @@ xfs_fs_fill_super(
 	if (error)
 		goto out_free_fsname;
 
+	mp->m_mtpt = mtpt;
+
 	sb_min_blocksize(sb, BBSIZE);
 	sb->s_xattr = xfs_xattr_handlers;
 	sb->s_export_op = &xfs_export_operations;
@@ -1481,13 +1484,13 @@ xfs_fs_fill_super(
 		error = EINVAL;
 		goto out_syncd_stop;
 	}
+
 	sb->s_root = d_alloc_root(root);
 	if (!sb->s_root) {
 		error = ENOMEM;
 		goto out_iput;
 	}
 
-	kfree(mtpt);
 	return 0;
 
  out_filestream_unmount:
@@ -1535,15 +1538,7 @@ xfs_fs_mount(
 	const char		*dev_name,
 	void			*data)
 {
-	int error;
-
-	error = mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
-	if (!error) {
-		xfs_mount_t *mp = XFS_M(mnt->mnt_sb);
-		mp->m_vfsmount = mnt;
-	}
-
-	return error;
+	return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
 }
 
 static const struct super_operations xfs_super_operations = {
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -215,6 +215,8 @@ typedef struct xfs_mount {
 	int64_t			m_low_space[XFS_LOWSP_MAX];
 						/* low free space thresholds */
 	struct vfsmount         *m_vfsmount;
+	spinlock_t		m_vfsmount_lock;
+	const char		*m_mtpt;
 } xfs_mount_t;
 
 /*
