aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-08-27 09:34:19 -0400
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-09-10 02:58:11 -0400
commite3c3efc243462d67ba9fa7f67620dcbc4597bf0a (patch)
treeae29cf8fade7c9bfac77f7ceff0381e775d80c0d
parent8c6866b071cb242584df287dbd342e5815e8407f (diff)
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>
-rw-r--r--fs/ubifs/debug.h3
-rw-r--r--fs/ubifs/key.h13
-rw-r--r--fs/ubifs/super.c2
-rw-r--r--fs/ubifs/tnc.c76
4 files changed, 91 insertions, 3 deletions
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index c1cd73b2e06e..fe2c9274c6a9 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -321,6 +321,8 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
321int dbg_check_lprops(struct ubifs_info *c); 321int dbg_check_lprops(struct ubifs_info *c);
322int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, 322int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
323 int row, int col); 323 int row, int col);
324int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
325 loff_t size);
324 326
325/* Force the use of in-the-gaps method for testing */ 327/* Force the use of in-the-gaps method for testing */
326 328
@@ -460,6 +462,7 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
460#define dbg_check_heap(c, heap, cat, add_pos) ({}) 462#define dbg_check_heap(c, heap, cat, add_pos) ({})
461#define dbg_check_lprops(c) 0 463#define dbg_check_lprops(c) 0
462#define dbg_check_lpt_nodes(c, cnode, row, col) 0 464#define dbg_check_lpt_nodes(c, cnode, row, col) 0
465#define dbg_check_inode_size(c, inode, size) 0
463#define dbg_force_in_the_gaps_enabled 0 466#define dbg_force_in_the_gaps_enabled 0
464#define dbg_force_in_the_gaps() 0 467#define dbg_force_in_the_gaps() 0
465#define dbg_failure_mode 0 468#define dbg_failure_mode 0
diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
index 919af84b9e17..0f530c684f0b 100644
--- a/fs/ubifs/key.h
+++ b/fs/ubifs/key.h
@@ -278,6 +278,18 @@ static inline void data_key_init(const struct ubifs_info *c,
278} 278}
279 279
280/** 280/**
281 * highest_data_key - get the highest possible data key for an inode.
282 * @c: UBIFS file-system description object
283 * @key: key to initialize
284 * @inum: inode number
285 */
286static inline void highest_data_key(const struct ubifs_info *c,
287 union ubifs_key *key, ino_t inum)
288{
289 data_key_init(c, key, inum, UBIFS_S_KEY_BLOCK_MASK);
290}
291
292/**
281 * trun_key_init - initialize truncation node key. 293 * trun_key_init - initialize truncation node key.
282 * @c: UBIFS file-system description object 294 * @c: UBIFS file-system description object
283 * @key: key to initialize 295 * @key: key to initialize
@@ -518,4 +530,5 @@ static inline unsigned long long key_max_inode_size(const struct ubifs_info *c)
518 return 0; 530 return 0;
519 } 531 }
520} 532}
533
521#endif /* !__UBIFS_KEY_H__ */ 534#endif /* !__UBIFS_KEY_H__ */
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index b541bd75bd1f..7e2b3d4d487a 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -317,6 +317,8 @@ static int ubifs_write_inode(struct inode *inode, int wait)
317 if (err) 317 if (err)
318 ubifs_err("can't write inode %lu, error %d", 318 ubifs_err("can't write inode %lu, error %d",
319 inode->i_ino, err); 319 inode->i_ino, err);
320 else
321 err = dbg_check_inode_size(c, inode, ui->ui_size);
320 } 322 }
321 323
322 ui->dirty = 0; 324 ui->dirty = 0;
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index f249f7b0d656..e5b1a7d00fa0 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -1159,8 +1159,8 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
1159 * o exact match, i.e. the found zero-level znode contains key @key, then %1 1159 * o exact match, i.e. the found zero-level znode contains key @key, then %1
1160 * is returned and slot number of the matched branch is stored in @n; 1160 * is returned and slot number of the matched branch is stored in @n;
1161 * o not exact match, which means that zero-level znode does not contain 1161 * o not exact match, which means that zero-level znode does not contain
1162 * @key, then %0 is returned and slot number of the closed branch is stored 1162 * @key, then %0 is returned and slot number of the closest branch is stored
1163 * in @n; 1163 * in @n;
1164 * o @key is so small that it is even less than the lowest key of the 1164 * o @key is so small that it is even less than the lowest key of the
1165 * leftmost zero-level node, then %0 is returned and %0 is stored in @n. 1165 * leftmost zero-level node, then %0 is returned and %0 is stored in @n.
1166 * 1166 *
@@ -1433,7 +1433,7 @@ static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1)
1433 * @lnum: LEB number is returned here 1433 * @lnum: LEB number is returned here
1434 * @offs: offset is returned here 1434 * @offs: offset is returned here
1435 * 1435 *
1436 * This function look up and reads node with key @key. The caller has to make 1436 * This function looks up and reads node with key @key. The caller has to make
1437 * sure the @node buffer is large enough to fit the node. Returns zero in case 1437 * sure the @node buffer is large enough to fit the node. Returns zero in case
1438 * of success, %-ENOENT if the node was not found, and a negative error code in 1438 * of success, %-ENOENT if the node was not found, and a negative error code in
1439 * case of failure. The node location can be returned in @lnum and @offs. 1439 * case of failure. The node location can be returned in @lnum and @offs.
@@ -3268,3 +3268,73 @@ out_unlock:
3268 mutex_unlock(&c->tnc_mutex); 3268 mutex_unlock(&c->tnc_mutex);
3269 return err; 3269 return err;
3270} 3270}
3271
3272#ifdef CONFIG_UBIFS_FS_DEBUG
3273
3274/**
3275 * dbg_check_inode_size - check if inode size is correct.
3276 * @c: UBIFS file-system description object
3277 * @inum: inode number
3278 * @size: inode size
3279 *
3280 * This function makes sure that the inode size (@size) is correct and it does
3281 * not have any pages beyond @size. Returns zero if the inode is OK, %-EINVAL
3282 * if it has a data page beyond @size, and other negative error code in case of
3283 * other errors.
3284 */
3285int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
3286 loff_t size)
3287{
3288 int err, n;
3289 union ubifs_key from_key, to_key, *key;
3290 struct ubifs_znode *znode;
3291 unsigned int block;
3292
3293 if (!S_ISREG(inode->i_mode))
3294 return 0;
3295 if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
3296 return 0;
3297
3298 block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
3299 data_key_init(c, &from_key, inode->i_ino, block);
3300 highest_data_key(c, &to_key, inode->i_ino);
3301
3302 mutex_lock(&c->tnc_mutex);
3303 err = ubifs_lookup_level0(c, &from_key, &znode, &n);
3304 if (err < 0)
3305 goto out_unlock;
3306
3307 if (err) {
3308 err = -EINVAL;
3309 key = &from_key;
3310 goto out_dump;
3311 }
3312
3313 err = tnc_next(c, &znode, &n);
3314 if (err == -ENOENT) {
3315 err = 0;
3316 goto out_unlock;
3317 }
3318 if (err < 0)
3319 goto out_unlock;
3320
3321 ubifs_assert(err == 0);
3322 key = &znode->zbranch[n].key;
3323 if (!key_in_range(c, key, &from_key, &to_key))
3324 goto out_unlock;
3325
3326out_dump:
3327 block = key_block(c, key);
3328 ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
3329 "(data key %s)", (unsigned long)inode->i_ino, size,
3330 ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
3331 dbg_dump_inode(c, inode);
3332 dbg_dump_stack();
3333 err = -EINVAL;
3334
3335out_unlock:
3336 mutex_unlock(&c->tnc_mutex);
3337 return err;
3338}
3339
3340#endif /* CONFIG_UBIFS_FS_DEBUG */