From: Andrew Price <anprice@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [gfs2-utils PATCH 7/7] fsck.gfs2: Detect and fix duplicate references in hash tables
Date: Tue, 16 Jul 2013 17:52:34 +0100 [thread overview]
Message-ID: <51E57A52.8030103@redhat.com> (raw)
In-Reply-To: <67014263a531655f54e1b40b0058a93c42790e01.1373979296.git.rpeterso@redhat.com>
Hi Bob,
A couple of comments below...
On 16/07/13 13:56, Bob Peterson wrote:
> This patch checks directory hash tables for multiple occurrences
> of the same leaf block. When duplicates are encountered, it checks
> to see which reference is appropriate for the hash table location
> based on the leaf block's hash value. The appropriate reference is
> kept and all duplicates are replaced by newly created leaf blocks.
>
> rhbz#984085
> ---
> gfs2/fsck/pass2.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 108 insertions(+)
>
> diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
> index a40a4a7..9f3e5c1 100644
> --- a/gfs2/fsck/pass2.c
> +++ b/gfs2/fsck/pass2.c
> @@ -1278,6 +1278,110 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
> return changes;
> }
>
> +/* check_hash_tbl_dups - check for the same leaf in multiple places */
> +static int check_hash_tbl_dups(struct gfs2_inode *ip, uint64_t *tbl,
> + unsigned hsize, int lindex, int len)
> +{
> + int l, len2;
> + uint64_t leafblk, leaf_no;
> + struct gfs2_buffer_head *lbh;
> + struct gfs2_leaf leaf;
> + struct gfs2_dirent dentry, *de;
> + int hash_index; /* index into the hash table based on the hash */
> +
> + leafblk = be64_to_cpu(tbl[lindex]);
> + for (l = 0; l < hsize; l++) {
> + if (l == lindex) { /* skip the valid reference */
> + l += len - 1;
> + continue;
> + }
> + if (be64_to_cpu(tbl[l]) != leafblk)
> + continue;
> +
> + for (len2 = 0; l + len2 < hsize; len2++) {
> + if (l + len2 == lindex)
> + break;
> + if (be64_to_cpu(tbl[l + len2]) != leafblk)
> + break;
> + }
> + log_err(_("Dinode %llu (0x%llx) has duplicate leaf pointers "
> + "to block %llu (0x%llx) at offsets %u (0x%x) "
> + "(for 0x%x) and %u (0x%x) (for 0x%x)\n"),
> + (unsigned long long)ip->i_di.di_num.no_addr,
> + (unsigned long long)ip->i_di.di_num.no_addr,
> + (unsigned long long)leafblk,
> + (unsigned long long)leafblk, lindex, lindex, len,
> + l, l, len2);
> +
> + /* See which set of references is valid: the one passed in
> + or the duplicate we found. */
> + memset(&leaf, 0, sizeof(leaf));
> + leaf_no = leafblk;
> + if (!valid_block(ip->i_sbd, leaf_no)) /* Checked later */
> + continue;
> +
> + lbh = bread(ip->i_sbd, leafblk);
> + if (gfs2_check_meta(lbh, GFS2_METATYPE_LF)) { /* Chked later */
> + brelse(lbh);
> + continue;
> + }
> +
> + memset(&dentry, 0, sizeof(struct gfs2_dirent));
> + de = (struct gfs2_dirent *)(lbh->b_data +
> + sizeof(struct gfs2_leaf));
> + gfs2_dirent_in(&dentry, (char *)de);
> + hash_index = hash_table_index(dentry.de_hash, ip);
> + brelse(lbh);
Unconditionally releasing lbh here ...
> + /* check the duplicate ref first */
> + if (hash_index < l || hash_index > l + len2) {
> + log_err(_("This leaf block has hash index %d, which "
> + "is out of bounds for lindex (%d - %d)\n"),
> + hash_index, l, l + len2);
> + if (!query( _("Fix the hash table? (y/n) "))) {
> + log_err(_("Hash table not fixed.\n"));
> + brelse(lbh);
so shouldn't need to here...
> + return 0;
> + }
> + /* Adjust the ondisk block count. The original value
> + may have been correct without the duplicates but
> + pass1 would have counted them and adjusted the
> + count to include them. So we must subtract them. */
> + ip->i_di.di_blocks--;
> + bmodified(ip->i_bh);
> + pad_with_leafblks(ip, tbl, l, len2);
> + } else {
> + log_debug(_("Hash index 0x%x is the proper "
> + "reference to leaf 0x%llx.\n"),
> + l, (unsigned long long)leafblk);
> + }
> + /* Check the original ref: both references might be bad.
> + If both were bad, just return and if we encounter it
> + again, we'll treat it as new. If the original ref is not
> + bad, keep looking for (and fixing) other instances. */
> + if (hash_index < lindex || hash_index > lindex + len) {
> + log_err(_("This leaf block has hash index %d, which "
> + "is out of bounds for lindex (%d - %d).\n"),
> + hash_index, lindex, lindex + len);
> + if (!query( _("Fix the hash table? (y/n) "))) {
> + log_err(_("Hash table not fixed.\n"));
> + brelse(lbh);
and here.
The rest looks good to me.
Cheers,
Andy
> + return 0;
> + }
> + ip->i_di.di_blocks--;
> + bmodified(ip->i_bh);
> + pad_with_leafblks(ip, tbl, lindex, len);
> + /* At this point we know both copies are bad, so we
> + return to start fresh */
> + return -EFAULT;
> + } else {
> + log_debug(_("Hash index 0x%x is the proper "
> + "reference to leaf 0x%llx.\n"),
> + lindex, (unsigned long long)leafblk);
> + }
> + }
> + return 0;
> +}
> +
> /* check_hash_tbl - check that the hash table is sane
> *
> * We've got to make sure the hash table is sane. Each leaf needs to
> @@ -1372,6 +1476,10 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
> lindex += proper_len;
> continue;
> }
> +
> + if (check_hash_tbl_dups(ip, tbl, hsize, lindex, len))
> + continue;
> +
> /* Make sure they call on proper leaf-split boundaries. This
> is the calculation used by the kernel, and dir_split_leaf */
> proper_start = (lindex & ~(proper_len - 1));
>
next prev parent reply other threads:[~2013-07-16 16:52 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-16 12:56 [Cluster-devel] [gfs2-utils PATCH 1/7] fsck.gfs2: Fix reference to uninitialized variable Bob Peterson
2013-07-16 12:56 ` [Cluster-devel] [gfs2-utils PATCH 2/7] fsck.gfs2: fix some log messages Bob Peterson
2013-07-16 12:56 ` [Cluster-devel] [gfs2-utils PATCH 3/7] fsck.gfs2: Fix directory link on relocated directory dirents Bob Peterson
2013-07-16 12:56 ` [Cluster-devel] [gfs2-utils PATCH 4/7] fsck.gfs2: Fix infinite loop in pass1b caused by duplicates in hash table Bob Peterson
2013-07-16 12:56 ` [Cluster-devel] [gfs2-utils PATCH 5/7] fsck.gfs2: don't check newly created lost+found in pass2 Bob Peterson
2013-07-16 16:52 ` Andrew Price
2013-07-16 17:14 ` Bob Peterson
2013-07-16 12:56 ` [Cluster-devel] [gfs2-utils PATCH 6/7] fsck.gfs2: avoid negative number in leaf depth Bob Peterson
2013-07-16 12:56 ` [Cluster-devel] [gfs2-utils PATCH 7/7] fsck.gfs2: Detect and fix duplicate references in hash tables Bob Peterson
2013-07-16 16:52 ` Andrew Price [this message]
2013-07-16 17:16 ` Bob Peterson
2013-07-17 5:30 ` [Cluster-devel] [gfs2-utils PATCH 1/7] fsck.gfs2: Fix reference to uninitialized variable Fabio M. Di Nitto
2013-07-17 7:53 ` Steven Whitehouse
2013-07-17 11:51 ` [Cluster-devel] [PATCH] fsck.gfs2: Don't rely on cluster.conf when rebuilding sb Andrew Price
2013-07-17 11:52 ` Steven Whitehouse
2013-07-17 12:27 ` Bob Peterson
2013-07-17 18:13 ` Fabio M. Di Nitto
2013-07-17 18:26 ` Bob Peterson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51E57A52.8030103@redhat.com \
--to=anprice@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).