Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=efd9859b14…
Commit: efd9859b14143d5c124bba686a6bc19983d29e42
Parent: 506995267a25075634a1427ec5960b5b98f7556a
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Dec 19 09:09:27 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Dec 20 14:31:24 2012 -0600
fsck.gfs2: Detect and fix mismatch in GFS1 formal inode number
This patch adds code to fsck.gfs2 that checks and fixes
GFS1 formal inode numbers. In GFS1 only, the formal inode number
is supposed to match the block address. If it doesn't, it's a
problem that should be fixed. If the problem goes undetected,
further conversions to GFS2 via the gfs2_convert tool will treat
the dinode as not being GFS1, which, in turn, yields the wrong
type number in the dirent. This causes the file in question to
be improperly treated (by gfs2_convert) as a GFS2 fifo
(DT_FIFO==1) rather than a GFS1 file (GFS_FILE_REG==1). The end
result is something like this, from pass2 in fsck.gfs2, after
the gfs2_convert:
Type 'fifo' in dir entry (lost_file_20431, 20431/0x4fcf)
conflicts with type 'file' in dinode. (Dir entry is stale.)
rhbz#888053
---
gfs2/fsck/pass1.c | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 0f80f87..540f2a9 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1311,6 +1311,23 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
(unsigned long long)block,
(unsigned long long)block);
}
+ if (sdp->gfs1 && ip->i_di.di_num.no_formal_ino != block) {
+ log_err( _("Inode #%llu (0x%llx): GFS1 formal inode number "
+ "mismatch: was %llu (0x%llx)\n"),
+ (unsigned long long)block, (unsigned long long)block,
+ (unsigned long long)ip->i_di.di_num.no_formal_ino,
+ (unsigned long long)ip->i_di.di_num.no_formal_ino);
+ if (query( _("Fix formal inode number in inode #%llu"
+ " (0x%llx)? (y/n) "), (unsigned long long)block,
+ (unsigned long long)block)) {
+ ip->i_di.di_num.no_formal_ino = block;
+ bmodified(ip->i_bh);
+ } else
+ log_err( _("Inode number in inode at block #%lld "
+ "(0x%llx) not fixed\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ }
error = handle_ip(sdp, ip);
fsck_inode_put(&ip);
return error;
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=caeb3efcb3…
Commit: caeb3efcb35b19c2a251cece2e59e13774baa108
Parent: fd9ccf25cadd901079a6a801b098c606223375d2
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Dec 18 14:14:08 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Dec 20 14:31:11 2012 -0600
gfs2_convert: clear out old di_mode before setting it
This patch clears the dinode 'di_mode' inode type field before
setting it based on the GFS1 value. In rare circumstances
(e.g. fsck.gfs2 ran on a GFS1 file system and created lost+found
with both GFS1 and GFS2 data) di_mode might have an old value.
In these cases, simply doing a logical 'or' with the correct
value produces an invalid value. Zeroing it out beforehand ensures
it is set correctly based on the GFS1 type.
rhbz#888053
---
gfs2/convert/gfs2_convert.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index a38bbff..aa1d5aa 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -916,6 +916,7 @@ static int adjust_inode(struct gfs2_sbd *sbp, struct gfs2_buffer_head *bh)
inode->i_di.di_num.no_formal_ino = sbp->md.next_inum; ;
/* Fix the inode type: gfs1 uses di_type, gfs2 uses di_mode. */
+ inode->i_di.di_mode &= ~S_IFMT;
switch (inode->i_di.__pad1) { /* formerly di_type */
case GFS_FILE_DIR: /* directory */
inode->i_di.di_mode |= S_IFDIR;
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=fd9ccf25ca…
Commit: fd9ccf25cadd901079a6a801b098c606223375d2
Parent: e7820f91c1b5bf5dbe5966dcf0b982df0d3e4ba7
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Dec 17 15:11:34 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Dec 20 14:31:05 2012 -0600
gfs2_convert: calculate height 1 for small files that were once big
This patch changes function calc_gfs2_tree_height so that it gives
a height of 1 to small files that once were big. The problems here
is with files that were once big (needed two levels of indirection
(height 2)) and then are truncated to a tiny non-zero size
(ordinarily, they would be stuffed, but due to the growth followed
by truncate, they're still at height 2). The required GFS2 height is
zero, whereas the GFS1 height is 2. After the conversion the file
will not really be stuffed, because function fix_metatree will
unstuff the dinode as part of its conversion. So at least it will
be at height 1. The problem is that if we don't fix the 0 height to
its proper value of 1, fix_ind_reg_or_dir gets called with gfs2_hgt=0,
which then calls mp_gfs1_to_gfs2, which then tries to set:
gfs2factor[gfs2_h - 1] = 1ull. This results in a negative index of the
array.
rhbz#887374
---
gfs2/convert/gfs2_convert.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 36ca1a3..a38bbff 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -272,6 +272,12 @@ static unsigned int calc_gfs2_tree_height(struct gfs2_inode *ip, uint64_t size)
for (height = 0; height < max; height++)
if (arr[height] >= size)
break;
+ /* If calc_gfs2_tree_height was called, the dinode is not stuffed or
+ we would have returned before this point. After the call, a call is
+ made to fix_metatree, which unstuffs the dinode. Therefore, the
+ smallest height that can result after this call is 1. */
+ if (!height)
+ height = 1;
return height;
}
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=e7820f91c1…
Commit: e7820f91c1b5bf5dbe5966dcf0b982df0d3e4ba7
Parent: b180bc7302d47319674be977d1d621405eca406f
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Dec 17 15:01:02 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Dec 20 14:30:58 2012 -0600
gfs2_convert: Use proper header size when reordering meta pointers
This patch changes function fix_metatree to use a proper metadata
header size. Before, it was using sizeof(struct gfs2_meta_header).
That's correct in almost all cases. But if you make a big file,
such that it goes into height==2 (two levels of indirection), then
truncate the file back to where it only would normally only need
height==1, then run gfs2_convert, it gets into trouble. That's
because you have a small file size, which calculates a much smaller
number of GFS2 pointers needed, due to the truncation. Function
fix_metatree will ensure at least one level of indirection by
unstuffing the converted dinode, but we need to start pushing out
the pointers onto the dinode's buffer, and for that, we need to
calculate the right header size.
rhbz#887374
---
gfs2/convert/gfs2_convert.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 61d1504..36ca1a3 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -356,7 +356,8 @@ static void fix_metatree(struct gfs2_sbd *sbp, struct gfs2_inode *ip,
gfs2_meta_header_out(&mh, bh);
}
- hdrsize = sizeof(struct gfs2_meta_header);
+ hdrsize = blk->height ? sizeof(struct gfs2_meta_header) :
+ sizeof(struct gfs2_dinode);
if (amount > sbp->bsize - hdrsize - ptramt)
amount = sbp->bsize - hdrsize - ptramt;
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=b180bc7302…
Commit: b180bc7302d47319674be977d1d621405eca406f
Parent: 606330ca9fec696123c075da069b0790811aa58d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Dec 17 14:56:16 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Dec 20 14:30:52 2012 -0600
gfs2_convert: remember number of blocks when converting quotas
This patch changes function copy_quotas so that it properly copies
the di_blocks field from the GFS1 quotas file to its new GFS2 file.
If the quota file had a non-trivial size, gfs2_convert was copying
all the data and pointers, but not properly setting the di_blocks.
This ordinarily isn't tragic because the file is never deleted, but
it did flag fsck.gfs2 errors.
rhbz#887374
---
gfs2/convert/gfs2_convert.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index 095f4ed..61d1504 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -2084,6 +2084,7 @@ static void copy_quotas(struct gfs2_sbd *sdp)
nq_ip->i_di.di_height = oq_ip->i_di.di_height;
nq_ip->i_di.di_size = oq_ip->i_di.di_size;
+ nq_ip->i_di.di_blocks = oq_ip->i_di.di_blocks;
memcpy(nq_ip->i_bh->b_data + sizeof(struct gfs2_dinode),
oq_ip->i_bh->b_data + sizeof(struct gfs2_dinode),
sdp->bsize - sizeof(struct gfs2_dinode));
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=606330ca9f…
Commit: 606330ca9fec696123c075da069b0790811aa58d
Parent: e59fbaad61d1a2b8286fa6ea3d37975fa21de64a
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Dec 17 14:47:50 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Thu Dec 20 14:30:45 2012 -0600
gfs2_convert: mark buffer dirty when switching dirs from meta to data
This patch changes function inode_renumber so that it properly marks
the rgrp bitmap dirty after switching bits from "meta" to "data".
This happens when directory leaf, hash table, eattr, etc. blocks come
in from GFS1 as "meta" and need to be switched to GFS2 as "data".
In GFS2, only dinodes get the "meta" designation. This conversion was
taking place, but the code broke out of the loop before properly
marking the buffer as modified. So if no other modifications were
done to that bitmap, the bitmap change would be forgotten.
rhbz#887374
---
gfs2/convert/gfs2_convert.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index da5c7dd..095f4ed 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -1074,10 +1074,10 @@ static int inode_renumber(struct gfs2_sbd *sbp, uint64_t root_inode_addr, osi_li
~(0x03 << (GFS2_BIT_SIZE * byte_bit));
rgd->bh[blk]->b_data[buf_offset + bitmap_byte] |=
(0x01 << (GFS2_BIT_SIZE * byte_bit));
+ bmodified(rgd->bh[blk]);
break;
}
bitmap_byte -= (sbp->bsize - buf_offset);
- bmodified(rgd->bh[blk]);
}
}
brelse(bh);