Skip to content

Commit

Permalink
UBIFS: fix debugging FS checking failure
Browse files Browse the repository at this point in the history
When the debugging self-checks are enabled, we go trough whole file-system
after mount and check/validate every single node referred to by the index.
This is implemented by the 'dbg_check_filesystem()' function. However, this
function fails if we mount "unclean" file-system, i.e., if we mount the
file-system after a power cut. It fails with the following symptoms:

UBIFS DBG (pid 8171): ubifs_recover_size: ino 937 size 3309925 -> 3317760
UBIFS: recovery deferred
UBIFS error (pid 8171): check_leaf: data node at LEB 1000:0 is not within inode size 3309925

The reason of failure is that recovery fixed up the inode size in memory, but
not on the flash so far. So the value on the flash is incorrect so far,
and would be corrected when we re-mount R/W. But 'check_leaf()' ignores
this fact and tries to validate the size of the on-flash inode, which is
incorrect, so it fails.

This patch teaches the checking code to look at the VFS inode cache first,
and if there is the inode in question, use that inode instead of the inode
on the flash media. This fixes the issue.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
  • Loading branch information
Artem Bityutskiy authored and Artem Bityutskiy committed May 13, 2011
1 parent 69f8a75 commit 45cd5cd
Showing 1 changed file with 35 additions and 6 deletions.
41 changes: 35 additions & 6 deletions fs/ubifs/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,8 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
struct rb_node **p, *parent = NULL;
struct fsck_inode *fscki;
ino_t inum = key_inum_flash(c, &ino->key);
struct inode *inode;
struct ubifs_inode *ui;

p = &fsckd->inodes.rb_node;
while (*p) {
Expand All @@ -1841,19 +1843,46 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
if (!fscki)
return ERR_PTR(-ENOMEM);

inode = ilookup(c->vfs_sb, inum);

fscki->inum = inum;
fscki->nlink = le32_to_cpu(ino->nlink);
fscki->size = le64_to_cpu(ino->size);
fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
fscki->mode = le32_to_cpu(ino->mode);
/*
* If the inode is present in the VFS inode cache, use it instead of
* the on-flash inode which might be out-of-date. E.g., the size might
* be out-of-date. If we do not do this, the following may happen, for
* example:
* 1. A power cut happens
* 2. We mount the file-system R/O, the replay process fixes up the
* inode size in the VFS cache, but on on-flash.
* 3. 'check_leaf()' fails because it hits a data node beyond inode
* size.
*/
if (!inode) {
fscki->nlink = le32_to_cpu(ino->nlink);
fscki->size = le64_to_cpu(ino->size);
fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
fscki->mode = le32_to_cpu(ino->mode);
} else {
ui = ubifs_inode(inode);
fscki->nlink = inode->i_nlink;
fscki->size = inode->i_size;
fscki->xattr_cnt = ui->xattr_cnt;
fscki->xattr_sz = ui->xattr_size;
fscki->xattr_nms = ui->xattr_names;
fscki->mode = inode->i_mode;
iput(inode);
}

if (S_ISDIR(fscki->mode)) {
fscki->calc_sz = UBIFS_INO_NODE_SZ;
fscki->calc_cnt = 2;
}

rb_link_node(&fscki->rb, parent, p);
rb_insert_color(&fscki->rb, &fsckd->inodes);

return fscki;
}

Expand Down

0 comments on commit 45cd5cd

Please sign in to comment.