[PATCH 2/2] xfs: make sure link path does not go away at access

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When following a trailing symlink in rcu-walk mode it's possible to
succeed in getting the ->get_link() method pointer but the link path
string be deallocated while it's being used.

Utilize the rcu mechanism to mitigate this risk.

Suggested-by: Miklos Szeredi <miklos@xxxxxxxxxx>
Signed-off-by: Ian Kent <raven@xxxxxxxxxx>
---
 fs/xfs/kmem.h      |    4 ++++
 fs/xfs/xfs_inode.c |    4 ++--
 fs/xfs/xfs_iops.c  |   10 ++++++++--
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/kmem.h b/fs/xfs/kmem.h
index 54da6d717a06..c1bd1103b340 100644
--- a/fs/xfs/kmem.h
+++ b/fs/xfs/kmem.h
@@ -61,6 +61,10 @@ static inline void  kmem_free(const void *ptr)
 {
 	kvfree(ptr);
 }
+static inline void  kmem_free_rcu(const void *ptr)
+{
+	kvfree_rcu(ptr);
+}
 
 
 static inline void *
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a4f6f034fb81..aaa1911e61ed 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2650,8 +2650,8 @@ xfs_ifree(
 	 * already been freed by xfs_attr_inactive.
 	 */
 	if (ip->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
-		kmem_free(ip->i_df.if_u1.if_data);
-		ip->i_df.if_u1.if_data = NULL;
+		kmem_free_rcu(ip->i_df.if_u1.if_data);
+		RCU_INIT_POINTER(ip->i_df.if_u1.if_data, NULL);
 		ip->i_df.if_bytes = 0;
 	}
 
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index a607d6aca5c4..2977e19da7b7 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -524,11 +524,17 @@ xfs_vn_get_link_inline(
 
 	/*
 	 * The VFS crashes on a NULL pointer, so return -EFSCORRUPTED if
-	 * if_data is junk.
+	 * if_data is junk. Also, if the path walk is in rcu-walk mode
+	 * and the inode link path has gone away due inode re-use we have
+	 * no choice but to tell the VFS to redo the lookup.
 	 */
-	link = ip->i_df.if_u1.if_data;
+	link = rcu_dereference(ip->i_df.if_u1.if_data);
+	if (!dentry && !link)
+		return ERR_PTR(-ECHILD);
+
 	if (XFS_IS_CORRUPT(ip->i_mount, !link))
 		return ERR_PTR(-EFSCORRUPTED);
+
 	return link;
 }
 





[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux