From: Darrick J. Wong <djwong@xxxxxxxxxx> When running generic/388, I observed the following .out.bad output: _check_xfs_filesystem: filesystem on /dev/sda4 is inconsistent (r) *** xfs_repair -n output *** Phase 1 - find and verify superblock... Phase 2 - using internal log - zero log... - scan filesystem freespace and inode maps... - found root inode chunk Phase 3 - for each AG... - scan (but don't clear) agi unlinked lists... - process known inodes and perform inode discovery... - agno = 0 - agno = 1 mismatch between format (2) and size (276) in symlink ino 37223730 bad data fork in symlink 37223730 would have cleared inode 37223730 - agno = 2 - agno = 3 mismatch between format (2) and size (276) in symlink ino 102725435 bad data fork in symlink 102725435 would have cleared inode 102725435 - process newly discovered inodes... Phase 4 - check for duplicate blocks... - setting up duplicate extent list... unknown block state, ag 1, blocks 458655-458655 unknown block state, ag 3, blocks 257772-257772 - check for inodes claiming duplicate blocks... - agno = 1 - agno = 2 - agno = 3 - agno = 0 mismatch between format (2) and size (276) in symlink ino 102725435 bad data fork in symlink 102725435 would have cleared inode 102725435 mismatch between format (2) and size (276) in symlink ino 37223730 bad data fork in symlink 37223730 would have cleared inode 37223730 No modify flag set, skipping phase 5 Phase 6 - check inode connectivity... - traversing filesystem ... - traversal finished ... - moving disconnected inodes to lost+found ... Phase 7 - verify link counts... user quota id 0 has bcount 1140448, expected 1140446 user quota id 0 has icount 39892, expected 39890 No modify flag set, skipping filesystem flush and exiting. Inode 37223730 is an unlinked remote-format symlink with no xattr fork. According to the inode verifier and xfs_repair, this symlink ought to have a local format data fork, since 276 bytes is small enough to fit in the immediate area. How did we get here? fsstress removed the symlink, which removed the last parent pointer xattr. There were no other xattrs, so that removal also removed the attr fork. This transaction got flushed to the log, but the system went down before we could inactivate the symlink. Log recovery tried to inactivate this inode (since it is on the unlinked list) but the verifier tripped over the remote value and leaked it. Hence we ended up with a file in this odd state on a "clean" mount. The "obvious" fix is to prohibit erasure of the attr fork to avoid tripping over the verifiers when pptrs are enabled. I wonder this could be reproduced with normal xattrs and (say) a directory? Maybe this fix should target /any/ symlink or directory? Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- libxfs/xfs_attr_leaf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c index 6cac2531..6391f6ab 100644 --- a/libxfs/xfs_attr_leaf.c +++ b/libxfs/xfs_attr_leaf.c @@ -851,7 +851,8 @@ xfs_attr_sf_removename( totsize -= size; if (totsize == sizeof(xfs_attr_sf_hdr_t) && xfs_has_attr2(mp) && (dp->i_df.if_format != XFS_DINODE_FMT_BTREE) && - !(args->op_flags & (XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE))) { + !(args->op_flags & (XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE)) && + !xfs_has_parent(mp)) { xfs_attr_fork_remove(dp, args->trans); } else { xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); @@ -860,7 +861,8 @@ xfs_attr_sf_removename( ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || (args->op_flags & XFS_DA_OP_ADDNAME) || !xfs_has_attr2(mp) || - dp->i_df.if_format == XFS_DINODE_FMT_BTREE); + dp->i_df.if_format == XFS_DINODE_FMT_BTREE || + xfs_has_parent(mp)); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); }