From: Bob Peterson <rpete...@redhat.com>

Before this patch, bad extended attributes were not properly removed
from a dinode, and blocks were not freed. This patch properly
removes them all.

rhbz#872564
---
 gfs2/fsck/pass1.c  | 12 ++++++++----
 gfs2/fsck/pass1c.c |  8 +++++++-
 gfs2/fsck/pass2.c  | 18 ++++++++++--------
 3 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index d678788..cf2bf99 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -493,6 +493,8 @@ static int remove_inode_eattr(struct gfs2_inode *ip, struct 
block_count *bc)
 static int ask_remove_inode_eattr(struct gfs2_inode *ip,
                                  struct block_count *bc)
 {
+       if (ip->i_di.di_eattr == 0)
+               return 0; /* eattr was removed prior to this call */
        log_err( _("Inode %lld (0x%llx) has unrecoverable Extended Attribute "
                   "errors.\n"), (unsigned long long)ip->i_di.di_num.no_addr,
                 (unsigned long long)ip->i_di.di_num.no_addr);
@@ -1080,11 +1082,13 @@ static int handle_ip(struct gfs2_sbd *sdp, struct 
gfs2_inode *ip)
        if (fsck_abort)
                return 0;
 
-       error = check_inode_eattr(ip, &pass1_fxns);
+       if (!error) {
+               error = check_inode_eattr(ip, &pass1_fxns);
 
-       if (error &&
-           !(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT))
-               ask_remove_inode_eattr(ip, &bc);
+               if (error &&
+                   !(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT))
+                       ask_remove_inode_eattr(ip, &bc);
+       }
 
        if (ip->i_di.di_blocks != 
                (1 + bc.indir_count + bc.data_count + bc.ea_count)) {
diff --git a/gfs2/fsck/pass1c.c b/gfs2/fsck/pass1c.c
index 26d47d5..b918de1 100644
--- a/gfs2/fsck/pass1c.c
+++ b/gfs2/fsck/pass1c.c
@@ -12,6 +12,12 @@
 #include "util.h"
 #include "metawalk.h"
 
+struct metawalk_fxns pass1c_fxns_delete = {
+       .private = NULL,
+       .check_eattr_indir = delete_eattr_indir,
+       .check_eattr_leaf = delete_eattr_leaf,
+};
+
 static int remove_eattr_entry(struct gfs2_sbd *sdp,
                              struct gfs2_buffer_head *leaf_bh,
                              struct gfs2_ea_header *curr,
@@ -62,7 +68,7 @@ static int ask_remove_eattr_entry(struct gfs2_sbd *sdp,
 static int ask_remove_eattr(struct gfs2_inode *ip)
 {
        if (query( _("Remove the bad Extended Attribute? (y/n) "))) {
-               ip->i_di.di_eattr = 0;
+               check_inode_eattr(ip, &pass1c_fxns_delete);
                bmodified(ip->i_bh);
                log_err( _("Bad Extended Attribute removed.\n"));
                return 1;
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 8b38b43..5c27a35 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -20,11 +20,13 @@
 
 #define MAX_FILENAME 256
 
-struct metawalk_fxns clear_eattrs = {
+struct metawalk_fxns pass2_fxns;
+
+struct metawalk_fxns delete_eattrs = {
        .check_eattr_indir = delete_eattr_indir,
        .check_eattr_leaf = delete_eattr_leaf,
-       .check_eattr_entry = clear_eattr_entry,
-       .check_eattr_extentry = clear_eattr_extentry,
+       .check_eattr_entry = delete_eattr_entry,
+       .check_eattr_extentry = delete_eattr_extentry,
 };
 
 /* Set children's parent inode in dir_info structure - ext2 does not set
@@ -599,7 +601,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, 
struct gfs2_dirent *dent,
                        entry_ip = ip;
                else
                        entry_ip = fsck_load_inode(sdp, entry->no_addr);
-               check_inode_eattr(entry_ip, &clear_eattrs);
+               check_inode_eattr(entry_ip, &delete_eattrs);
                if (entry_ip != ip)
                        fsck_inode_put(&entry_ip);
                return 1;
@@ -683,7 +685,7 @@ static int check_dentry(struct gfs2_inode *ip, struct 
gfs2_dirent *dent,
                                entry_ip = ip;
                        else
                                entry_ip = fsck_load_inode(sdp, entry.no_addr);
-                       check_inode_eattr(entry_ip, &clear_eattrs);
+                       check_inode_eattr(entry_ip, &delete_eattrs);
                        if (entry_ip != ip)
                                fsck_inode_put(&entry_ip);
                        goto nuke_dentry;
@@ -714,7 +716,7 @@ static int check_dentry(struct gfs2_inode *ip, struct 
gfs2_dirent *dent,
                                entry_ip = ip;
                        else
                                entry_ip = fsck_load_inode(sdp, entry.no_addr);
-                       check_inode_eattr(entry_ip, &clear_eattrs);
+                       check_inode_eattr(entry_ip, &delete_eattrs);
                        if (entry_ip != ip)
                                fsck_inode_put(&entry_ip);
                        goto nuke_dentry;
@@ -744,7 +746,7 @@ static int check_dentry(struct gfs2_inode *ip, struct 
gfs2_dirent *dent,
                                entry_ip = ip;
                        else
                                entry_ip = fsck_load_inode(sdp, entry.no_addr);
-                       check_inode_eattr(entry_ip, &clear_eattrs);
+                       check_inode_eattr(entry_ip, &delete_eattrs);
                        if (entry_ip != ip)
                                fsck_inode_put(&entry_ip);
 
@@ -764,7 +766,7 @@ static int check_dentry(struct gfs2_inode *ip, struct 
gfs2_dirent *dent,
                                entry_ip = ip;
                        else
                                entry_ip = fsck_load_inode(sdp, entry.no_addr);
-                       check_inode_eattr(entry_ip, &clear_eattrs);
+                       check_inode_eattr(entry_ip, &delete_eattrs);
                        if (entry_ip != ip)
                                fsck_inode_put(&entry_ip);
 
-- 
1.7.11.7

Reply via email to