Skip to content

Commit f60b668

Browse files
sandeenBrian Maly
authored andcommitted
xfs: fix up xfs_swap_extent_forks inline extent handling
There have been several reports over the years of NULL pointer dereferences in xfs_trans_log_inode during xfs_fsr processes, when the process is doing an fput and tearing down extents on the temporary inode, something like: BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 PID: 29439 TASK: ffff880550584fa0 CPU: 6 COMMAND: "xfs_fsr" [exception RIP: xfs_trans_log_inode+0x10] #9 [ffff8800a57bbbe0] xfs_bunmapi at ffffffffa037398e [xfs] As it turns out, this is because the i_itemp pointer, along with the d_ops pointer, has been overwritten with zeros when we tear down the extents during truncate. When the in-core inode fork on the temporary inode used by xfs_fsr was originally set up during the extent swap, we mistakenly looked at di_nextents to determine whether all extents fit inline, but this misses extents generated by speculative preallocation; we should be using if_bytes instead. This mistake corrupts the in-memory inode, and code in xfs_iext_remove_inline eventually gets bad inputs, causing it to memmove and memset incorrect ranges; this became apparent because the two values in ifp->if_u2.if_inline_ext[1] contained what should have been in d_ops and i_itemp; they were memmoved due to incorrect array indexing and then the original locations were zeroed with memset, again due to an array overrun. Fix this by properly using i_df.if_bytes to determine the number of extents, not di_nextents. Thanks to dchinner for looking at this with me and spotting the root cause. Cc: [email protected] Signed-off-by: Eric Sandeen <[email protected]> Reviewed-by: Brian Foster <[email protected]> Signed-off-by: Dave Chinner <[email protected]> (cherry picked from commit 4dfce57) Orabug: 31032831 Signed-off-by: Junxiao Bi <[email protected]> Reviewed-by: Wengang Wang <[email protected]> Conflicts: fs/xfs/xfs_bmap_util.c Signed-off-by: Brian Maly <[email protected]>
1 parent 11d9104 commit f60b668

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

fs/xfs/xfs_bmap_util.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,7 @@ xfs_swap_extents(
17031703
int error = 0;
17041704
int aforkblks = 0;
17051705
int taforkblks = 0;
1706+
xfs_extnum_t nextents;
17061707
__uint64_t tmp;
17071708
int lock_flags;
17081709

@@ -1885,7 +1886,8 @@ xfs_swap_extents(
18851886
* pointer. Otherwise it's already NULL or
18861887
* pointing to the extent.
18871888
*/
1888-
if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) {
1889+
nextents = ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1890+
if (nextents <= XFS_INLINE_EXTS) {
18891891
ifp->if_u1.if_extents =
18901892
ifp->if_u2.if_inline_ext;
18911893
}
@@ -1904,7 +1906,8 @@ xfs_swap_extents(
19041906
* pointer. Otherwise it's already NULL or
19051907
* pointing to the extent.
19061908
*/
1907-
if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) {
1909+
nextents = tip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
1910+
if (nextents <= XFS_INLINE_EXTS) {
19081911
tifp->if_u1.if_extents =
19091912
tifp->if_u2.if_inline_ext;
19101913
}

0 commit comments

Comments
 (0)