public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Eric Sandeen <sandeen@redhat.com>
To: xfs-oss <xfs@oss.sgi.com>
Subject: [PATCH] xfs_repair: fix process_leaf_node_dir2() for fragmented multiblock dirs
Date: Wed, 02 May 2012 14:40:36 -0500	[thread overview]
Message-ID: <4FA18DB4.6050901@redhat.com> (raw)

Consider a filesystem with 4k fs blocks and 16k dir blocks, with
extremely fragmented freespace so that a 2 block (32k) directory
ends up with these extents, covering 2 multiblock dir blocks:

index:	phys	len
-----------------
0	10	1
1	12	1
2	14	1
3	16	1
-----------------
4	18	1
5	20	1
6	22	1
7	24	1

The loop in process_leaf_node_dir2() would obtain the first 4 just
fine:

-----------------
0	10	1
1	12	1
2	14	1
3	16	1
-----------------

But then although it advanced ndbno (next block nr) by
an amount relative to mp->m_dirfsbs, it left "t" (the starting
extent number for the search) untouched.

blkmap_next_off() is really designed to be iterated block by block,
as far as I can tell, and if you pass in a block nr which is at
an offset beyond that when extent "t" covers, it will simply return
you the first logical block in extent "t".

So, we advanced the requested block nr by 4, but left t untouched
at 1, and at the top of the loop next time, we get this for the
next 16k "dir block:"

1	12	1
2	14	1
3	16	1
-----------------
4	18	1

This isn't properly aligned with the dir block; the magic for the next
dir block is in phys block 18, not 12, so repair thinks things are 
corrupted and it gets worse from there.

To fix this, just call blkmap_next_off() a few more times in a loop
until we reach the last fs block in our dir block.  Then the outer
loop will find the next block after THAT, and process the next multiblock
dir block properly.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---

diff --git a/repair/dir2.c b/repair/dir2.c
index f9562d7..7a614a8 100644
--- a/repair/dir2.c
+++ b/repair/dir2.c
@@ -2003,7 +2003,11 @@ process_leaf_node_dir2(
 	ndbno = NULLDFILOFF;
 	while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dirleafblk) {
 		nex = blkmap_getn(blkmap, dbno, mp->m_dirblkfsbs, &bmp, &lbmp);
-		ndbno = dbno + mp->m_dirblkfsbs - 1;
+		/* Advance through map to last fs block in this dir block */
+		ndbno = dbno;
+		while (ndbno < dbno + mp->m_dirblkfsbs - 1) {
+			ndbno = blkmap_next_off(blkmap, ndbno, &t);
+		}
 		if (nex == 0) {
 			do_warn(
 _("block %" PRIu64 " for directory inode %" PRIu64 " is missing\n"),


_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

                 reply	other threads:[~2012-05-02 19:40 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=4FA18DB4.6050901@redhat.com \
    --to=sandeen@redhat.com \
    --cc=xfs@oss.sgi.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