]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
UBIFS: add inode size debugging check
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Thu, 27 Aug 2009 13:34:19 +0000 (16:34 +0300)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Thu, 10 Sep 2009 06:58:11 +0000 (09:58 +0300)
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>
fs/ubifs/debug.h
fs/ubifs/key.h
fs/ubifs/super.c
fs/ubifs/tnc.c

index c1cd73b2e06e4ecc541ebf3b5f840572c8bfe282..fe2c9274c6a982e419c13d1f0f80a07861c3444d 100644 (file)
@@ -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
index 919af84b9e173aaee594271d6ba68ff0232f23ec..0f530c684f0ba13c99c1424c6614d54f0f3ae23b 100644 (file)
@@ -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__ */
index b541bd75bd1fe516d5142fc884b759662ed44692..7e2b3d4d487ad154900dbc8ad94f72ed54283e18 100644 (file)
@@ -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;
index f249f7b0d656930ff3c364f0579cf43f0fb0b926..e5b1a7d00fa018f732bcbd84c336a5ef7eaaeea8 100644 (file)
@@ -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 */