From patchwork Thu Feb 16 20:40:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13143791 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 01823C61DA4 for ; Thu, 16 Feb 2023 20:40:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229475AbjBPUkQ (ORCPT ); Thu, 16 Feb 2023 15:40:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229492AbjBPUkP (ORCPT ); Thu, 16 Feb 2023 15:40:15 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 440161ADE1 for ; Thu, 16 Feb 2023 12:40:14 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id D3D5B60A65 for ; Thu, 16 Feb 2023 20:40:13 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 43E53C433EF; Thu, 16 Feb 2023 20:40:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1676580013; bh=xlH/6AtMMhy+NbcyAHu+BhDPGi0MOcdzdlgyIvQduQk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=EU9aIRojgiuBRpJ6ktkjCWCQnZi2oO+0L+qwGIk7bO1E7FyW761fMy6++XdZrpEUw smMRp6yJrfs7mcxtOqDWK63xlqwovaIubVfnnXw4s18JQxHU7g8Rc/LZTxdRv88nAZ 0fJTAaZKFaR1N9nO/fd11dR5cydzBj8k2Nn+c4NTya9yUXHoIPEZ61iyGJpRLcz+H6 nTfxK1MtMXnrOrtNN4cWjPM+eIiKygsvo+Vu5RS9U3O12vp0mvylinaK/6idTjI630 L0+laN29SNYz0V7mkCMysujt84BfIkR4iioVhUOkv0ONFeFVPy1NbpZcjjINbIhhp2 T49b9DfyWtJ1Q== Date: Thu, 16 Feb 2023 12:40:12 -0800 Subject: [PATCH 1/3] xfs: directory lookups should return diroffsets too From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <167657873107.3474076.14790811015593279205.stgit@magnolia> In-Reply-To: <167657873091.3474076.6801004934386808232.stgit@magnolia> References: <167657873091.3474076.6801004934386808232.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Teach the directory lookup functions to return the dir offset of the dirent that it finds. Online fsck will use this when checking and repairing filesystems. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_dir2_block.c | 2 ++ fs/xfs/libxfs/xfs_dir2_leaf.c | 2 ++ fs/xfs/libxfs/xfs_dir2_node.c | 2 ++ fs/xfs/libxfs/xfs_dir2_sf.c | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c index 0f3a03e87278..24467e1a0d6f 100644 --- a/fs/xfs/libxfs/xfs_dir2_block.c +++ b/fs/xfs/libxfs/xfs_dir2_block.c @@ -749,6 +749,8 @@ xfs_dir2_block_lookup_int( cmp = xfs_dir2_compname(args, dep->name, dep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { args->cmpresult = cmp; + args->offset = xfs_dir2_byte_to_dataptr( + (char *)dep - (char *)hdr); *bpp = bp; *entno = mid; if (cmp == XFS_CMP_EXACT) diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c index fe75ffadace9..b7ea73b4f592 100644 --- a/fs/xfs/libxfs/xfs_dir2_leaf.c +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c @@ -1300,6 +1300,8 @@ xfs_dir2_leaf_lookup_int( cmp = xfs_dir2_compname(args, dep->name, dep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { args->cmpresult = cmp; + args->offset = xfs_dir2_db_off_to_dataptr(args->geo, + newdb, (char *)dep - (char *)dbp->b_addr); *indexp = index; /* case exact match: return the current buffer. */ if (cmp == XFS_CMP_EXACT) { diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c index 53cd0d5d94f7..f8c01e8d885c 100644 --- a/fs/xfs/libxfs/xfs_dir2_node.c +++ b/fs/xfs/libxfs/xfs_dir2_node.c @@ -887,6 +887,8 @@ xfs_dir2_leafn_lookup_for_entry( args->cmpresult = cmp; args->inumber = be64_to_cpu(dep->inumber); args->filetype = xfs_dir2_data_get_ftype(mp, dep); + args->offset = xfs_dir2_db_off_to_dataptr(args->geo, ++ newdb, (char *)dep - (char *)curbp->b_addr); *indexp = index; state->extravalid = 1; state->extrablk.bp = curbp; diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c index 032c65804610..f8670c56c7a6 100644 --- a/fs/xfs/libxfs/xfs_dir2_sf.c +++ b/fs/xfs/libxfs/xfs_dir2_sf.c @@ -889,6 +889,7 @@ xfs_dir2_sf_lookup( args->inumber = dp->i_ino; args->cmpresult = XFS_CMP_EXACT; args->filetype = XFS_DIR3_FT_DIR; + args->offset = 1; return -EEXIST; } /* @@ -899,6 +900,7 @@ xfs_dir2_sf_lookup( args->inumber = xfs_dir2_sf_get_parent_ino(sfp); args->cmpresult = XFS_CMP_EXACT; args->filetype = XFS_DIR3_FT_DIR; + args->offset = 2; return -EEXIST; } /* @@ -917,6 +919,8 @@ xfs_dir2_sf_lookup( args->cmpresult = cmp; args->inumber = xfs_dir2_sf_get_ino(mp, sfp, sfep); args->filetype = xfs_dir2_sf_get_ftype(mp, sfep); + args->offset = xfs_dir2_byte_to_dataptr( + xfs_dir2_sf_get_offset(sfep)); if (cmp == XFS_CMP_EXACT) return -EEXIST; ci_sfep = sfep; From patchwork Thu Feb 16 20:40:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13143792 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 798B7C636CC for ; Thu, 16 Feb 2023 20:40:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229558AbjBPUkd (ORCPT ); Thu, 16 Feb 2023 15:40:33 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53656 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229492AbjBPUkc (ORCPT ); Thu, 16 Feb 2023 15:40:32 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6F2171CF49 for ; Thu, 16 Feb 2023 12:40:31 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 1A88FB829AB for ; Thu, 16 Feb 2023 20:40:30 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D58FDC433EF; Thu, 16 Feb 2023 20:40:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1676580028; bh=5DS0NDOe3iIG075TKvvXgdPOR5zw49ao6Smz0XB3UwY=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=akmveWpTTyqJ6wspB8kn/jd9tasMeFL3Ca2lp6EoSx/8s6A1su5geITu51yKA3ULn h0yShli7vK9HGd2ykOvW5kFsYEV48jPl61TNaOJ2Uj3KVPgPPJ8/rIvaCVaGjTjHhL iRKq9svJ+HVb+4qQmh8A4pVEUnLm/Utr8P6OLWWtTQKMWiyiqOES5rqYUmnhbm/Wnc X4GIGjBxjRhxYmW+kHjkHOOiFkTgYSHlXJmX13TptkoOrnBGz/Te5WBTzDlZDVPP1g xl13henXIbfaFzXti0FLszHPj+liHlt9sGZyq0svaDZUe9k6zFgTGOddG3GF65pXe+ uCGnupl3CG54w== Date: Thu, 16 Feb 2023 12:40:28 -0800 Subject: [PATCH 2/3] xfs: move/add parent pointer validators to xfs_parent From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <167657873121.3474076.2978424746322208247.stgit@magnolia> In-Reply-To: <167657873091.3474076.6801004934386808232.stgit@magnolia> References: <167657873091.3474076.6801004934386808232.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong Move the parent pointer xattr name validator to xfs_parent.c, and add a new function to check the xattr value. Signed-off-by: Darrick J. Wong --- fs/xfs/libxfs/xfs_attr.c | 61 +++++++++----------------------------------- fs/xfs/libxfs/xfs_attr.h | 2 + fs/xfs/libxfs/xfs_parent.c | 44 ++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_parent.h | 7 +++++ 4 files changed, 65 insertions(+), 49 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index 57080ea4c869..3065dd622102 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c @@ -26,6 +26,7 @@ #include "xfs_trace.h" #include "xfs_attr_item.h" #include "xfs_xattr.h" +#include "xfs_parent.h" struct kmem_cache *xfs_attr_intent_cache; @@ -1577,62 +1578,26 @@ xfs_attr_node_get( return error; } -/* - * Verify parent pointer attribute is valid. - * Return true on success or false on failure - */ -STATIC bool -xfs_verify_pptr( - struct xfs_mount *mp, - const struct xfs_parent_name_rec *rec) -{ - xfs_ino_t p_ino; - xfs_dir2_dataptr_t p_diroffset; - - p_ino = be64_to_cpu(rec->p_ino); - p_diroffset = be32_to_cpu(rec->p_diroffset); - - if (!xfs_verify_ino(mp, p_ino)) - return false; - - if (p_diroffset > XFS_DIR2_MAX_DATAPTR) - return false; - - return true; -} - -/* Returns true if the string attribute entry name is valid. */ -static bool -xfs_str_attr_namecheck( - const void *name, - size_t length) -{ - /* - * MAXNAMELEN includes the trailing null, but (name/length) leave it - * out, so use >= for the length check. - */ - if (length >= MAXNAMELEN) - return false; - - /* There shouldn't be any nulls here */ - return !memchr(name, 0, length); -} - /* Returns true if the attribute entry name is valid. */ bool xfs_attr_namecheck( struct xfs_mount *mp, const void *name, size_t length, - int flags) + unsigned int flags) { - if (flags & XFS_ATTR_PARENT) { - if (length != sizeof(struct xfs_parent_name_rec)) - return false; - return xfs_verify_pptr(mp, (struct xfs_parent_name_rec *)name); - } + if (flags & XFS_ATTR_PARENT) + return xfs_parent_namecheck(mp, name, length, flags); - return xfs_str_attr_namecheck(name, length); + /* + * MAXNAMELEN includes the trailing null, but (name/length) leave it + * out, so use >= for the length check. + */ + if (length >= MAXNAMELEN) + return false; + + /* There shouldn't be any nulls here */ + return !memchr(name, 0, length); } int __init diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 985761264d1f..d6d23cf19ade 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h @@ -551,7 +551,7 @@ int xfs_attr_set(struct xfs_da_args *args); int xfs_attr_set_iter(struct xfs_attr_intent *attr); int xfs_attr_remove_iter(struct xfs_attr_intent *attr); bool xfs_attr_namecheck(struct xfs_mount *mp, const void *name, size_t length, - int flags); + unsigned int flags); int xfs_attr_calc_size(struct xfs_da_args *args, int *local); void xfs_init_attr_trans(struct xfs_da_args *args, struct xfs_trans_res *tres, unsigned int *total); diff --git a/fs/xfs/libxfs/xfs_parent.c b/fs/xfs/libxfs/xfs_parent.c index 9176adfaa9e8..8cc264baf6c7 100644 --- a/fs/xfs/libxfs/xfs_parent.c +++ b/fs/xfs/libxfs/xfs_parent.c @@ -55,6 +55,50 @@ xfs_init_parent_ptr(struct xfs_parent_ptr *xpp, * occurring. */ +/* Return true if parent pointer EA name is valid. */ +bool +xfs_parent_namecheck( + struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, + size_t reclen, + unsigned int attr_flags) +{ + xfs_ino_t p_ino; + xfs_dir2_dataptr_t p_diroffset; + + if (reclen != sizeof(struct xfs_parent_name_rec)) + return false; + + /* Only one namespace bit allowed. */ + if (hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) > 1) + return false; + + p_ino = be64_to_cpu(rec->p_ino); + if (!xfs_verify_ino(mp, p_ino)) + return false; + + p_diroffset = be32_to_cpu(rec->p_diroffset); + if (p_diroffset > XFS_DIR2_MAX_DATAPTR) + return false; + + return true; +} + +/* Return true if parent pointer EA value is valid. */ +bool +xfs_parent_valuecheck( + struct xfs_mount *mp, + const void *value, + size_t valuelen) +{ + if (valuelen == 0 || valuelen >= MAXNAMELEN) + return false; + + if (value == NULL) + return false; + + return true; +} /* Initializes a xfs_parent_name_rec to be stored as an attribute name */ void diff --git a/fs/xfs/libxfs/xfs_parent.h b/fs/xfs/libxfs/xfs_parent.h index 13040b9d8b08..4ffcb81d399c 100644 --- a/fs/xfs/libxfs/xfs_parent.h +++ b/fs/xfs/libxfs/xfs_parent.h @@ -8,6 +8,13 @@ extern struct kmem_cache *xfs_parent_intent_cache; +/* Metadata validators */ +bool xfs_parent_namecheck(struct xfs_mount *mp, + const struct xfs_parent_name_rec *rec, size_t reclen, + unsigned int attr_flags); +bool xfs_parent_valuecheck(struct xfs_mount *mp, const void *value, + size_t valuelen); + /* * Dynamically allocd structure used to wrap the needed data to pass around * the defer ops machinery From patchwork Thu Feb 16 20:40:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13143793 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5771BC61DA4 for ; Thu, 16 Feb 2023 20:40:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229492AbjBPUkr (ORCPT ); Thu, 16 Feb 2023 15:40:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229508AbjBPUkq (ORCPT ); Thu, 16 Feb 2023 15:40:46 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7F31D1ADE1 for ; Thu, 16 Feb 2023 12:40:45 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 1C63960C1A for ; Thu, 16 Feb 2023 20:40:45 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 78AB2C433EF; Thu, 16 Feb 2023 20:40:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1676580044; bh=PrfV13CNEaBOsdBwLC5kZh+ukLsf81WYNp57jNOYIYo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=M2CPQ9YfQXZtiZ83AU91bMhYHdOhOutH3n92ZFvvl12vAEzFFaD9ByROA4O3GDGI6 V5I9MVb25dR+LdZQT4YA8nqnNdDDd7EW7Rq1pN/u1UMXye5/mKQeh/JORiR9+2ur3A peKfikG18bHbhuGvJ/QG3RBtRV8GbWoQLc/ONnV9IDOP34KrwxH2bjmJOuVz1fun7c 8FXKLaSXqQWM5NBhfobC09dudexHGJwIHQ7SiDbxKv2IIk5p/gFybG+i6DpqE2SZCT yqSofNlBEiSVfcWPiNSWB+JUzDj1PPdNK1k9ly6nNL9OKfeHnYXZl8g5mWfF/7airl 2g4KTZufzXIbQ== Date: Thu, 16 Feb 2023 12:40:44 -0800 Subject: [PATCH 3/3] xfs: don't remove the attr fork when parent pointers are enabled From: "Darrick J. Wong" To: djwong@kernel.org Cc: allison.henderson@oracle.com, linux-xfs@vger.kernel.org Message-ID: <167657873134.3474076.16426437706062736205.stgit@magnolia> In-Reply-To: <167657873091.3474076.6801004934386808232.stgit@magnolia> References: <167657873091.3474076.6801004934386808232.stgit@magnolia> User-Agent: StGit/0.19 MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org From: Darrick J. Wong 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 --- fs/xfs/libxfs/xfs_attr_leaf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index beee51ad75ce..e6c4c8b52a55 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -854,7 +854,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); @@ -863,7 +864,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); }