Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitdiff... Commit: 7b21b2ceb7716e8c746f4ae4eb10dc7bcf6768a3 Parent: d87cae562082f880678866df795e6fef5daf465a Author: Bob Peterson rpeterso@redhat.com AuthorDate: Fri Aug 19 08:50:48 2011 -0500 Committer: Bob Peterson rpeterso@redhat.com CommitterDate: Mon Aug 29 12:55:37 2011 -0500
fsck.gfs2: Bad extended attributes not deleted properly
This patch fixes a couple of problems fsck.gfs2 when it discovered corrupt extended attributes and tried to delete them. First, in check_eattr_entries it wasn't reporting the corruption. Second, when the EA block was freed, it wasn't returning a proper return code which caused fsck to not update the inode accordingly. Third, it wasn't zeroing out the EA block address properly. Fourth, I did a small amount of reformatting.
rhbz#675723 --- gfs2/fsck/metawalk.c | 57 +++++++++++++++++++++++++++++++++++++++---------- gfs2/fsck/pass1.c | 4 +-- gfs2/fsck/pass1c.c | 7 +++-- gfs2/fsck/pass2.c | 9 +++++-- 4 files changed, 56 insertions(+), 21 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c index 3fc9e70..9feaa8a 100644 --- a/gfs2/fsck/metawalk.c +++ b/gfs2/fsck/metawalk.c @@ -754,6 +754,13 @@ static int check_eattr_entries(struct gfs2_inode *ip, bh, ea_hdr, ea_hdr_prev, pass->private)) { + log_err(_("Bad extended attribute " + "found at block %lld " + "(0x%llx)"), + (unsigned long long) + be64_to_cpu(*ea_data_ptr), + (unsigned long long) + be64_to_cpu(*ea_data_ptr)); if (query( _("Repair the bad Extended " "Attribute? (y/n) "))) { ea_hdr->ea_num_ptrs = i; @@ -806,13 +813,14 @@ static int check_leaf_eattr(struct gfs2_inode *ip, uint64_t block, uint64_t parent, struct metawalk_fxns *pass) { struct gfs2_buffer_head *bh = NULL; - int error = 0; - - log_debug( _("Checking EA leaf block #%llu (0x%llx).\n"), - (unsigned long long)block, - (unsigned long long)block);
if (pass->check_eattr_leaf) { + int error = 0; + + log_debug( _("Checking EA leaf block #%llu (0x%llx).\n"), + (unsigned long long)block, + (unsigned long long)block); + error = pass->check_eattr_leaf(ip, block, parent, &bh, pass->private); if (error < 0) { @@ -886,13 +894,18 @@ int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype) /** * free_block_if_notdup - free blocks associated with an inode, but if it's a * duplicate, just remove that designation instead. - * Returns: 0 if the block was freed, 1 if a duplicate reference was removed + * Returns: 1 if the block was freed, 0 if a duplicate reference was removed + * Note: The return code is handled this way because there are places in + * metawalk.c that assume "1" means "change was made" and "0" means + * change was not made. */ int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block, const char *btype) { - if (!find_remove_dup(ip, block, btype)) + if (!find_remove_dup(ip, block, btype)) { /* not a dup */ fsck_blockmap_set(ip, block, btype, gfs2_block_free); + return 1; + } return 0; }
@@ -1447,16 +1460,36 @@ int delete_data(struct gfs2_inode *ip, uint64_t block, void *private) int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent, struct gfs2_buffer_head **bh, void *private) { - return delete_block_if_notdup(ip, block, NULL, - _("indirect extended attribute"), - private); + int ret; + + ret = delete_block_if_notdup(ip, block, NULL, + _("indirect extended attribute"), + private); + /* Even if it's a duplicate reference, we want to eliminate the + reference itself, and adjust di_blocks accordingly. */ + if (ip->i_di.di_eattr) { + ip->i_di.di_blocks--; + if (block == ip->i_di.di_eattr) + ip->i_di.di_eattr = 0; + bmodified(ip->i_bh); + } + return ret; }
int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent, struct gfs2_buffer_head **bh, void *private) { - return delete_block_if_notdup(ip, block, NULL, _("extended attribute"), - private); + int ret; + + ret = delete_block_if_notdup(ip, block, NULL, _("extended attribute"), + private); + if (ip->i_di.di_eattr) { + ip->i_di.di_blocks--; + if (block == ip->i_di.di_eattr) + ip->i_di.di_eattr = 0; + bmodified(ip->i_bh); + } + return ret; }
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block, diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c index 56f003b..8db8579 100644 --- a/gfs2/fsck/pass1.c +++ b/gfs2/fsck/pass1.c @@ -1181,9 +1181,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip) (unsigned long long)ip->i_di.di_num.no_addr, (unsigned long long)ip->i_di.di_num.no_addr); check_metatree(ip, &invalidate_fxns); - if (fsck_blockmap_set(ip, block, _("invalid mode"), - gfs2_inode_invalid)) - goto bad_dinode; + check_inode_eattr(ip, &invalidate_fxns); return 0; } else if (error) goto bad_dinode; diff --git a/gfs2/fsck/pass1c.c b/gfs2/fsck/pass1c.c index 209c32d..26d47d5 100644 --- a/gfs2/fsck/pass1c.c +++ b/gfs2/fsck/pass1c.c @@ -65,9 +65,10 @@ static int ask_remove_eattr(struct gfs2_inode *ip) ip->i_di.di_eattr = 0; bmodified(ip->i_bh); log_err( _("Bad Extended Attribute removed.\n")); - } else - log_err( _("Bad Extended Attribute not removed.\n")); - return 1; + return 1; + } + log_err( _("Bad Extended Attribute not removed.\n")); + return 0; }
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block, diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c index 52763a2..e017448 100644 --- a/gfs2/fsck/pass2.c +++ b/gfs2/fsck/pass2.c @@ -207,9 +207,9 @@ static int delete_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr, struct gfs2_ea_header *ea_hdr_prev, void *private) { - uint64_t block = be64_to_cpu(*ea_data_ptr); + uint64_t block = be64_to_cpu(*ea_data_ptr);
- return delete_metadata(ip, block, NULL, 0, private); + return delete_metadata(ip, block, NULL, 0, private); }
struct metawalk_fxns pass2_fxns_delete = { @@ -347,7 +347,10 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, entry_ip = ip; else entry_ip = fsck_load_inode(sdp, entryblock); - check_inode_eattr(entry_ip, &pass2_fxns_delete); + if (ip->i_di.di_eattr) { + check_inode_eattr(entry_ip, + &pass2_fxns_delete); + } check_metatree(entry_ip, &pass2_fxns_delete); if (entry_ip != ip) fsck_inode_put(&entry_ip);