gfs2-utils: master - fsck.gfs2: Don't traverse EAs that belong to another inode

Bob Peterson rpeterso at fedoraproject.org
Tue Sep 29 18:38:04 UTC 2015


Gitweb:        http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=bce4edab765816449c1b26379c7163ffea1a87da
Commit:        bce4edab765816449c1b26379c7163ffea1a87da
Parent:        29c87d36a746016cb7f60dc1dd8a78b82fa0e0bf
Author:        Bob Peterson <rpeterso at redhat.com>
AuthorDate:    Wed Sep 23 13:46:59 2015 -0500
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Tue Sep 29 13:23:17 2015 -0500

fsck.gfs2: Don't traverse EAs that belong to another inode

Before this patch, pass1b would find a duplicate reference to
extended attributes, which may be an entire tree structure. After
deciding which inode gets to keep the extended attributes, it
removes the extended attributes from other dinodes with another
pointer to it. However, if the EAs are big, and there's a whole
list of them as indirect blocks, we only want to traverse the
indirect list if that list is owned by the second (bad) reference.

If we do traverse the tree, we're basically freeing EA blocks
belonging to the only remaining valid reference, and that's wrong.

This patch adds a check to function resolve_dup_references that
avoids a whole EA tree traversal if the duplicate EA reference is
the root of the EAs (not an indirect list of blocks). Instead,
the reference to the block is just removed from the inode.
---
 gfs2/fsck/pass1b.c |   23 +++++++++++++++++++++--
 1 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 382d5e9..4c41fef 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -198,8 +198,27 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
 		   it again. That could free blocks that used to be duplicate
 		   references that are now resolved (and gone). */
 		if (q != GFS2_BLKST_FREE) {
-			/* Clear the EAs for the inode first */
-			check_inode_eattr(ip, &pass1b_fxns_delete);
+			/* If the inode's eattr pointer is to the duplicate
+			   ref block, we don't want to call check_inode_eattr
+			   because that would traverse the structure, and it's
+			   not ours to do anymore; it rightly belongs to a
+			   different dinode. On the other hand, if the dup
+			   block is buried deep within the eattr structure
+			   of this dinode, we need to traverse the structure
+			   because it IS ours, and we need to remove all the
+			   eattr leaf blocks: they do belong to us (except for
+			   the duplicate referenced one, which is handled). */
+			if (ip->i_di.di_eattr == dt->block) {
+				ip->i_di.di_eattr = 0;
+				if (ip->i_di.di_blocks > 0)
+					ip->i_di.di_blocks--;
+				ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
+				bmodified(ip->i_bh);
+				dup_listent_delete(dt, id);
+			} else {
+				/* Clear the EAs for the inode first */
+				check_inode_eattr(ip, &pass1b_fxns_delete);
+			}
 			/* If the reference was as metadata or data, we've got
 			   a corrupt dinode that will be deleted. */
 			if ((this_ref != ref_as_ea) &&


More information about the cluster-commits mailing list