linux_dsm_epyc7002/fs/xfs/libxfs
Brian Foster 7df1c170b9 xfs: swap leaf buffer into path struct atomically during path shift
The node directory lookup code uses a state structure that tracks the
path of buffers used to search for the hash of a filename through the
leaf blocks. When the lookup encounters a block that ends with the
requested hash, but the entry has not yet been found, it must shift over
to the next block and continue looking for the entry (i.e., duplicate
hashes could continue over into the next block). This shift mechanism
involves walking back up and down the state structure, replacing buffers
at the appropriate btree levels as necessary.

When a buffer is replaced, the old buffer is released and the new buffer
read into the active slot in the path structure. Because the buffer is
read directly into the path slot, a buffer read failure can result in
setting a NULL buffer pointer in an active slot. This throws off the
state cleanup code in xfs_dir2_node_lookup(), which expects to release a
buffer from each active slot. Instead, a BUG occurs due to a NULL
pointer dereference:

  BUG: unable to handle kernel NULL pointer dereference at 00000000000001e8
  IP: [<ffffffffa0585063>] xfs_trans_brelse+0x2a3/0x3c0 [xfs]
  ...
  RIP: 0010:[<ffffffffa0585063>]  [<ffffffffa0585063>] xfs_trans_brelse+0x2a3/0x3c0 [xfs]
  ...
  Call Trace:
   [<ffffffffa05250c6>] xfs_dir2_node_lookup+0xa6/0x2c0 [xfs]
   [<ffffffffa0519f7c>] xfs_dir_lookup+0x1ac/0x1c0 [xfs]
   [<ffffffffa055d0e1>] xfs_lookup+0x91/0x290 [xfs]
   [<ffffffffa05580b3>] xfs_vn_lookup+0x73/0xb0 [xfs]
   [<ffffffff8122de8d>] lookup_real+0x1d/0x50
   [<ffffffff8123330e>] path_openat+0x91e/0x1490
   [<ffffffff81235079>] do_filp_open+0x89/0x100
   ...

This has been reproduced via a parallel fsstress and filesystem shutdown
workload in a loop. The shutdown triggers the read error in the
aforementioned codepath and causes the BUG in xfs_dir2_node_lookup().

Update xfs_da3_path_shift() to update the active path slot atomically
with respect to the caller when a buffer is replaced. This ensures that
the caller always sees the old or new buffer in the slot and prevents
the NULL pointer dereference.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
2015-08-19 10:32:33 +10:00
..
xfs_alloc_btree.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_alloc_btree.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_alloc.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_alloc.h Merge branch 'xfs-freelist-cleanup' into for-next 2015-06-23 08:48:43 +10:00
xfs_attr_leaf.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_attr_leaf.h xfs: xfs_attr_inactive leaves inconsistent attr fork state behind 2015-05-29 07:40:08 +10:00
xfs_attr_remote.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_attr_remote.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_attr_sf.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_attr.c xfs: set XFS_DA_OP_OKNOENT in xfs_attr_get 2015-08-19 10:30:48 +10:00
xfs_bit.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_bmap_btree.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_bmap_btree.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_bmap.c Merge branch 'xfs-freelist-cleanup' into for-next 2015-06-23 08:48:43 +10:00
xfs_bmap.h xfs: Add support FALLOC_FL_INSERT_RANGE for fallocate 2015-03-25 15:08:56 +11:00
xfs_btree.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_btree.h xfs: require 64-bit sector_t 2014-07-30 09:12:05 +10:00
xfs_cksum.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_da_btree.c xfs: swap leaf buffer into path struct atomically during path shift 2015-08-19 10:32:33 +10:00
xfs_da_btree.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_da_format.c xfs: move most of xfs_sb.h to xfs_format.h 2014-11-28 14:27:09 +11:00
xfs_da_format.h xfs: use larger in-core attr firstused field and detect overflow 2015-04-13 11:27:10 +10:00
xfs_dir2_block.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_dir2_data.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_dir2_leaf.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_dir2_node.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_dir2_priv.h xfs: move type conversion functions to xfs_dir.h 2014-12-04 09:43:17 +11:00
xfs_dir2_sf.c Merge branch 'xfs-misc-fixes-for-3.19-2' into for-next 2014-12-04 09:46:17 +11:00
xfs_dir2.c Merge branch 'xfs-misc-fixes-for-3.19-2' into for-next 2014-12-04 09:46:17 +11:00
xfs_dir2.h xfs: move type conversion functions to xfs_dir.h 2014-12-04 09:43:17 +11:00
xfs_dquot_buf.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_format.h xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_fs.h xfs: add fs geometry bit for sparse inode chunks 2015-05-29 08:58:32 +10:00
xfs_ialloc_btree.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_ialloc_btree.h xfs: allocate sparse inode chunks on full chunk allocation failure 2015-05-29 09:18:32 +10:00
xfs_ialloc.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_ialloc.h Merge branch 'xfs-misc-fixes-for-4.2-3' into for-next 2015-06-23 08:49:01 +10:00
xfs_inode_buf.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_inode_buf.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_inode_fork.c xfs: merge xfs_inum.h into xfs_format.h 2014-11-28 14:27:10 +11:00
xfs_inode_fork.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_log_format.h xfs: merge xfs_dinode.h into xfs_format.h 2014-11-28 14:24:06 +11:00
xfs_log_recover.h libxfs: move header files 2014-06-25 14:57:36 +10:00
xfs_log_rlimit.c xfs: move most of xfs_sb.h to xfs_format.h 2014-11-28 14:27:09 +11:00
xfs_quota_defs.h xfs: remove XFS_IS_OQUOTA_ON macros 2014-07-24 21:27:16 +10:00
xfs_rtbitmap.c xfs: move most of xfs_sb.h to xfs_format.h 2014-11-28 14:27:09 +11:00
xfs_sb.c xfs: relocate sparse inode mount warning 2015-08-19 10:32:14 +10:00
xfs_sb.h xfs: consolidate superblock logging functions 2015-01-22 09:10:31 +11:00
xfs_shared.h xfs: saner xfs_trans_commit interface 2015-06-04 13:48:08 +10:00
xfs_symlink_remote.c xfs: create new metadata UUID field and incompat flag 2015-07-29 11:53:31 +10:00
xfs_trans_resv.c xfs: consolidate superblock logging functions 2015-01-22 09:10:31 +11:00
xfs_trans_resv.h xfs: clean up XFS_MIN_FREELIST macros 2015-06-22 10:13:30 +10:00
xfs_trans_space.h xfs: clean up XFS_MIN_FREELIST macros 2015-06-22 10:13:30 +10:00
xfs_types.h xfs: move xfs_types.h to libxfs 2015-01-09 10:46:31 +11:00