From: Darrick J. Wong <djwong@xxxxxxxxxx> The RTINHERIT bit can be set on a directory so that newly created regular files will have the REALTIME bit set to store their data on the realtime volume. If an extent size hint (and EXTSZINHERIT) are set on the directory, the hint will also be copied into the new file. As pointed out in previous patches, for realtime files we require the extent size hint be an integer multiple of the realtime extent, but we don't perform the same validation on a directory with both RTINHERIT and EXTSZINHERIT set, even though the only use-case of that combination is to propagate extent size hints into new realtime files. This leads to inode corruption errors when the bad values are propagated. Strengthen the validation routine to avoid this situation and fix the open-coded unit conversion while we're at it. Note that this is technically a breaking change to the ondisk format, but the risk should be minimal because (a) most vendors disable realtime, (b) letting unaligned hints propagate to new files would immediately crash the filesystem, and (c) xfs_repair flags such filesystems as corrupt, so anyone with such a configuration is broken already anyway. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_inode_buf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c index 5c9a7440d9e4..25261dd73290 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.c +++ b/fs/xfs/libxfs/xfs_inode_buf.c @@ -569,19 +569,20 @@ xfs_inode_validate_extsize( uint16_t mode, uint16_t flags) { - bool rt_flag; + bool rt_flag, rtinherit_flag; bool hint_flag; bool inherit_flag; uint32_t extsize_bytes; uint32_t blocksize_bytes; rt_flag = (flags & XFS_DIFLAG_REALTIME); + rtinherit_flag = (flags & XFS_DIFLAG_RTINHERIT); hint_flag = (flags & XFS_DIFLAG_EXTSIZE); inherit_flag = (flags & XFS_DIFLAG_EXTSZINHERIT); extsize_bytes = XFS_FSB_TO_B(mp, extsize); - if (rt_flag) - blocksize_bytes = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog; + if (rt_flag || (rtinherit_flag && inherit_flag)) + blocksize_bytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_rextsize); else blocksize_bytes = mp->m_sb.sb_blocksize;