We use di_format and if_flags to decide whether we're grabbing the ilock in btree mode (btree extents not loaded) or shared mode (anything else), but the state of those fields can be changed by other threads that are also trying to load the btree extents -- IFEXTENTS gets set before the _bmap_read_extents call and cleared if it fails. Therefore, once we've grabbed the shared ilock we have to re-check the fields to see if we actually need to upgrade to the exclusive ilock in order to try loading the extents. Without this patch, we trigger ilock assert failures when a bunch of threads try to access a btree format directory with a corrupt bmbt root and corrupt the incore data structures, leading to a crash. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- fs/xfs/xfs_inode.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index b955779..b04bda8 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -125,6 +125,18 @@ xfs_ilock_data_map_shared( (ip->i_df.if_flags & XFS_IFEXTENTS) == 0) lock_mode = XFS_ILOCK_EXCL; xfs_ilock(ip, lock_mode); + /* + * We can change if_flags under ilock if we try to read the + * extents and fail. Since we hadn't grabbed the ilock at check + * time, we have to re-check and upgrade the lock now. + */ + if (lock_mode == XFS_ILOCK_SHARED && + ip->i_d.di_format == XFS_DINODE_FMT_BTREE && + (ip->i_df.if_flags & XFS_IFEXTENTS) == 0) { + xfs_iunlock(ip, lock_mode); + lock_mode = XFS_ILOCK_EXCL; + xfs_ilock(ip, lock_mode); + } return lock_mode; } -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html