7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Darrick J. Wong commit 73b7276b8a4b5eb272f3c3b36ea3042e786f4741 upstream. LOLLM noticed xchk_btree()'s odd habit of passing cur->bc_nlevels to xchk_btree_ptr_ok when we're checking the pointer to the root block at the start of the btree scan. This enables us to skip checking the pointer for an inode btree's root (since it doesn't have one) but doesn't handle per-AG btrees quite correctly. There isn't a problem for __xfs_btree_check_ptr itself, but the corruption tracepoint naively walks off the end of bc_level[]. Fix that by adding a helper to do an implicit range check. Cc: stable@vger.kernel.org # v5.16 Fixes: 6ca444cfd66354 ("xfs: prepare xfs_btree_cur for dynamic cursor heights") Signed-off-by: Darrick J. Wong Assisted-by: LOLLM # finding obvious bugs Reviewed-by: Christoph Hellwig Signed-off-by: Carlos Maiolino Signed-off-by: Greg Kroah-Hartman --- fs/xfs/scrub/trace.c | 13 +++++++++++++ fs/xfs/scrub/trace.h | 10 +++++----- 2 files changed, 18 insertions(+), 5 deletions(-) --- a/fs/xfs/scrub/trace.c +++ b/fs/xfs/scrub/trace.c @@ -42,6 +42,9 @@ xchk_btree_cur_fsbno( struct xfs_btree_cur *cur, int level) { + if (level < 0) + return NULLFSBLOCK; + if (level < cur->bc_nlevels && cur->bc_levels[level].bp) return XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(cur->bc_levels[level].bp)); @@ -53,6 +56,16 @@ xchk_btree_cur_fsbno( return NULLFSBLOCK; } +static inline int +xchk_btree_cur_ptr( + const struct xfs_btree_cur *cur, + int level) +{ + if (level >= 0 && level < cur->bc_nlevels) + return cur->bc_levels[level].ptr; + return -1; +} + /* * We include this last to have the helpers above available for the trace * event implementations. --- a/fs/xfs/scrub/trace.h +++ b/fs/xfs/scrub/trace.h @@ -577,7 +577,7 @@ TRACE_EVENT(xchk_btree_op_error, __entry->level = level; __entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsbno); __entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno); - __entry->ptr = cur->bc_levels[level].ptr; + __entry->ptr = xchk_btree_cur_ptr(cur, level); __entry->error = error; __entry->ret_ip = ret_ip; ), @@ -618,7 +618,7 @@ TRACE_EVENT(xchk_ifork_btree_op_error, __entry->type = sc->sm->sm_type; __assign_str(name); __entry->level = level; - __entry->ptr = cur->bc_levels[level].ptr; + __entry->ptr = xchk_btree_cur_ptr(cur, level); __entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsbno); __entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno); __entry->error = error; @@ -660,7 +660,7 @@ TRACE_EVENT(xchk_btree_error, __entry->level = level; __entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsbno); __entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno); - __entry->ptr = cur->bc_levels[level].ptr; + __entry->ptr = xchk_btree_cur_ptr(cur, level); __entry->ret_ip = ret_ip; ), TP_printk("dev %d:%d type %s %sbt level %d ptr %d agno 0x%x agbno 0x%x ret_ip %pS", @@ -700,7 +700,7 @@ TRACE_EVENT(xchk_ifork_btree_error, __entry->level = level; __entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsbno); __entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno); - __entry->ptr = cur->bc_levels[level].ptr; + __entry->ptr = xchk_btree_cur_ptr(cur, level); __entry->ret_ip = ret_ip; ), TP_printk("dev %d:%d ino 0x%llx fork %s type %s %sbt level %d ptr %d agno 0x%x agbno 0x%x ret_ip %pS", @@ -740,7 +740,7 @@ DECLARE_EVENT_CLASS(xchk_sbtree_class, __entry->bno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno); __entry->level = level; __entry->nlevels = cur->bc_nlevels; - __entry->ptr = cur->bc_levels[level].ptr; + __entry->ptr = xchk_btree_cur_ptr(cur, level); ), TP_printk("dev %d:%d type %s %sbt agno 0x%x agbno 0x%x level %d nlevels %d ptr %d", MAJOR(__entry->dev), MINOR(__entry->dev),