[PATCH 2/4] xfs: don't propagate invalid extent size hints to new files

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

 



From: Darrick J. Wong <djwong@xxxxxxxxxx>

Under the current inode extent size hint validation rules, it's possible
to set extent size hints on directories along with an 'inherit' flag so
that the values will be propagated to newly created regular files.  (The
directories themselves do not care about the hint values.)

For these directories, the alignment of the hint is checked against the
data device even if the directory also has the rtinherit hint set, which
means that one can set a directory's hint value to something that isn't
an integer multiple of the realtime extent size.  This isn't a problem
for the directory itself, but the validation routines require rt extent
alignment for realtime files.

If the unaligned hint value and the realtime bit are both propagated
into a newly created regular realtime file, we end up writing out an
incorrect hint that trips the verifiers the next time we try to read the
inode buffer, and the fs shuts down.  Fix this by cancelling the hint
propagation if it would cause problems.

Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
---
 fs/xfs/xfs_inode.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)


diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 0369eb22c1bb..db81e8c22708 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -689,6 +689,7 @@ xfs_inode_inherit_flags(
 	struct xfs_inode	*ip,
 	const struct xfs_inode	*pip)
 {
+	xfs_failaddr_t		failaddr;
 	unsigned int		di_flags = 0;
 	umode_t			mode = VFS_I(ip)->i_mode;
 
@@ -728,6 +729,14 @@ xfs_inode_inherit_flags(
 	if (pip->i_diflags & XFS_DIFLAG_FILESTREAM)
 		di_flags |= XFS_DIFLAG_FILESTREAM;
 
+	/* Make sure the extsize actually validates properly. */
+	failaddr = xfs_inode_validate_extsize(ip->i_mount, ip->i_extsize,
+			VFS_I(ip)->i_mode, ip->i_diflags);
+	if (failaddr) {
+		di_flags &= ~(XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT);
+		ip->i_extsize = 0;
+	}
+
 	ip->i_diflags |= di_flags;
 }
 
@@ -737,12 +746,22 @@ xfs_inode_inherit_flags2(
 	struct xfs_inode	*ip,
 	const struct xfs_inode	*pip)
 {
+	xfs_failaddr_t		failaddr;
+
 	if (pip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) {
 		ip->i_diflags2 |= XFS_DIFLAG2_COWEXTSIZE;
 		ip->i_cowextsize = pip->i_cowextsize;
 	}
 	if (pip->i_diflags2 & XFS_DIFLAG2_DAX)
 		ip->i_diflags2 |= XFS_DIFLAG2_DAX;
+
+	/* Make sure the cowextsize actually validates properly. */
+	failaddr = xfs_inode_validate_cowextsize(ip->i_mount, ip->i_cowextsize,
+			VFS_I(ip)->i_mode, ip->i_diflags, ip->i_diflags2);
+	if (failaddr) {
+		ip->i_diflags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
+		ip->i_cowextsize = 0;
+	}
 }
 
 /*




[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