mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 11:16:11 +00:00
UBIFS: add inode size debugging check
Add one more check to UBIFS - a check that makes sure that there are no data nodes beyond inode size. And few commantaries fixes along the line. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Reviewed-by: Adrian Hunter <Adrian.Hunter@nokia.com>
This commit is contained in:
parent
8c6866b071
commit
e3c3efc243
4 changed files with 91 additions and 3 deletions
|
@ -321,6 +321,8 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
|
|||
int dbg_check_lprops(struct ubifs_info *c);
|
||||
int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
|
||||
int row, int col);
|
||||
int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
|
||||
loff_t size);
|
||||
|
||||
/* Force the use of in-the-gaps method for testing */
|
||||
|
||||
|
@ -460,6 +462,7 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
|
|||
#define dbg_check_heap(c, heap, cat, add_pos) ({})
|
||||
#define dbg_check_lprops(c) 0
|
||||
#define dbg_check_lpt_nodes(c, cnode, row, col) 0
|
||||
#define dbg_check_inode_size(c, inode, size) 0
|
||||
#define dbg_force_in_the_gaps_enabled 0
|
||||
#define dbg_force_in_the_gaps() 0
|
||||
#define dbg_failure_mode 0
|
||||
|
|
|
@ -277,6 +277,18 @@ static inline void data_key_init(const struct ubifs_info *c,
|
|||
key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* highest_data_key - get the highest possible data key for an inode.
|
||||
* @c: UBIFS file-system description object
|
||||
* @key: key to initialize
|
||||
* @inum: inode number
|
||||
*/
|
||||
static inline void highest_data_key(const struct ubifs_info *c,
|
||||
union ubifs_key *key, ino_t inum)
|
||||
{
|
||||
data_key_init(c, key, inum, UBIFS_S_KEY_BLOCK_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* trun_key_init - initialize truncation node key.
|
||||
* @c: UBIFS file-system description object
|
||||
|
@ -518,4 +530,5 @@ static inline unsigned long long key_max_inode_size(const struct ubifs_info *c)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !__UBIFS_KEY_H__ */
|
||||
|
|
|
@ -317,6 +317,8 @@ static int ubifs_write_inode(struct inode *inode, int wait)
|
|||
if (err)
|
||||
ubifs_err("can't write inode %lu, error %d",
|
||||
inode->i_ino, err);
|
||||
else
|
||||
err = dbg_check_inode_size(c, inode, ui->ui_size);
|
||||
}
|
||||
|
||||
ui->dirty = 0;
|
||||
|
|
|
@ -1159,8 +1159,8 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
|
|||
* o exact match, i.e. the found zero-level znode contains key @key, then %1
|
||||
* is returned and slot number of the matched branch is stored in @n;
|
||||
* o not exact match, which means that zero-level znode does not contain
|
||||
* @key, then %0 is returned and slot number of the closed branch is stored
|
||||
* in @n;
|
||||
* @key, then %0 is returned and slot number of the closest branch is stored
|
||||
* in @n;
|
||||
* o @key is so small that it is even less than the lowest key of the
|
||||
* leftmost zero-level node, then %0 is returned and %0 is stored in @n.
|
||||
*
|
||||
|
@ -1433,7 +1433,7 @@ static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1)
|
|||
* @lnum: LEB number is returned here
|
||||
* @offs: offset is returned here
|
||||
*
|
||||
* This function look up and reads node with key @key. The caller has to make
|
||||
* This function looks up and reads node with key @key. The caller has to make
|
||||
* sure the @node buffer is large enough to fit the node. Returns zero in case
|
||||
* of success, %-ENOENT if the node was not found, and a negative error code in
|
||||
* case of failure. The node location can be returned in @lnum and @offs.
|
||||
|
@ -3268,3 +3268,73 @@ out_unlock:
|
|||
mutex_unlock(&c->tnc_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UBIFS_FS_DEBUG
|
||||
|
||||
/**
|
||||
* dbg_check_inode_size - check if inode size is correct.
|
||||
* @c: UBIFS file-system description object
|
||||
* @inum: inode number
|
||||
* @size: inode size
|
||||
*
|
||||
* This function makes sure that the inode size (@size) is correct and it does
|
||||
* not have any pages beyond @size. Returns zero if the inode is OK, %-EINVAL
|
||||
* if it has a data page beyond @size, and other negative error code in case of
|
||||
* other errors.
|
||||
*/
|
||||
int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
|
||||
loff_t size)
|
||||
{
|
||||
int err, n;
|
||||
union ubifs_key from_key, to_key, *key;
|
||||
struct ubifs_znode *znode;
|
||||
unsigned int block;
|
||||
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
|
||||
return 0;
|
||||
|
||||
block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
|
||||
data_key_init(c, &from_key, inode->i_ino, block);
|
||||
highest_data_key(c, &to_key, inode->i_ino);
|
||||
|
||||
mutex_lock(&c->tnc_mutex);
|
||||
err = ubifs_lookup_level0(c, &from_key, &znode, &n);
|
||||
if (err < 0)
|
||||
goto out_unlock;
|
||||
|
||||
if (err) {
|
||||
err = -EINVAL;
|
||||
key = &from_key;
|
||||
goto out_dump;
|
||||
}
|
||||
|
||||
err = tnc_next(c, &znode, &n);
|
||||
if (err == -ENOENT) {
|
||||
err = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
if (err < 0)
|
||||
goto out_unlock;
|
||||
|
||||
ubifs_assert(err == 0);
|
||||
key = &znode->zbranch[n].key;
|
||||
if (!key_in_range(c, key, &from_key, &to_key))
|
||||
goto out_unlock;
|
||||
|
||||
out_dump:
|
||||
block = key_block(c, key);
|
||||
ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
|
||||
"(data key %s)", (unsigned long)inode->i_ino, size,
|
||||
((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
|
||||
dbg_dump_inode(c, inode);
|
||||
dbg_dump_stack();
|
||||
err = -EINVAL;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&c->tnc_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_UBIFS_FS_DEBUG */
|
||||
|
|
Loading…
Reference in a new issue