summaryrefslogtreecommitdiff
path: root/fs/ubifs
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-06-03 15:18:07 +0300
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-06-06 18:50:40 +0300
commit2e107a27f5f0c2aa484b821d8504c3575467b95a (patch)
treeb88125bb14a088a1b4352b1cce5de39943363ab4 /fs/ubifs
parent6370a704b36adbb15d0004615d2febce96be650d (diff)
UBIFS: add file-system checking function
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'fs/ubifs')
-rw-r--r--fs/ubifs/debug.c565
-rw-r--r--fs/ubifs/debug.h5
-rw-r--r--fs/ubifs/key.h13
-rw-r--r--fs/ubifs/super.c8
-rw-r--r--fs/ubifs/tnc.c24
-rw-r--r--fs/ubifs/ubifs.h9
-rw-r--r--fs/ubifs/xattr.c3
7 files changed, 600 insertions, 27 deletions
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 7c351d08eea6..595243b06b07 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -777,7 +777,7 @@ static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
* dbg_dump_index - dump the on-flash index.
* @c: UBIFS file-system description object
*
- * This function dumps whold UBIFS indexing B-tree, unlike 'dbg_dump_tnc()'
+ * This function dumps whole UBIFS indexing B-tree, unlike 'dbg_dump_tnc()'
* which dumps only in-memory znodes and does not read znodes which from flash.
*/
void dbg_dump_index(struct ubifs_info *c)
@@ -1288,14 +1288,24 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
if (znode_cb) {
err = znode_cb(c, znode, priv);
- if (err)
- goto out_unlock;
+ if (err) {
+ ubifs_err("znode checking function returned "
+ "error %d", err);
+ dbg_dump_znode(c, znode);
+ goto out_dump;
+ }
}
if (leaf_cb && znode->level == 0) {
for (idx = 0; idx < znode->child_cnt; idx++) {
- err = leaf_cb(c, &znode->zbranch[idx], priv);
- if (err)
- goto out_unlock;
+ zbr = &znode->zbranch[idx];
+ err = leaf_cb(c, zbr, priv);
+ if (err) {
+ ubifs_err("leaf checking function "
+ "returned error %d, for leaf "
+ "at LEB %d:%d",
+ err, zbr->lnum, zbr->offs);
+ goto out_dump;
+ }
}
}
@@ -1340,12 +1350,31 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
}
}
- err = 0;
+ mutex_unlock(&c->tnc_mutex);
+ return 0;
+
+out_dump:
+ if (znode->parent)
+ zbr = &znode->parent->zbranch[znode->iip];
+ else
+ zbr = &c->zroot;
+ ubifs_msg("dump of znode at LEB %d:%d", zbr->lnum, zbr->offs);
+ dbg_dump_znode(c, znode);
out_unlock:
mutex_unlock(&c->tnc_mutex);
return err;
}
+/**
+ * add_size - add znode size to partially calculated index size.
+ * @c: UBIFS file-system description object
+ * @znode: znode to add size for
+ * @priv: partially calculated index size
+ *
+ * This is a helper function for 'dbg_check_idx_size()' which is called for
+ * every indexing node and adds its size to the 'long long' variable pointed to
+ * by @priv.
+ */
static int add_size(struct ubifs_info *c, struct ubifs_znode *znode, void *priv)
{
long long *idx_size = priv;
@@ -1357,6 +1386,15 @@ static int add_size(struct ubifs_info *c, struct ubifs_znode *znode, void *priv)
return 0;
}
+/**
+ * dbg_check_idx_size - check index size.
+ * @c: UBIFS file-system description object
+ * @idx_size: size to check
+ *
+ * This function walks the UBIFS index, calculates its size and checks that the
+ * size is equivalent to @idx_size. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
{
int err;
@@ -1372,9 +1410,8 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
}
if (calc != idx_size) {
- ubifs_err("index size check failed");
- ubifs_err("calculated size is %lld, should be %lld",
- calc, idx_size);
+ ubifs_err("index size check failed: calculated size is %lld, "
+ "should be %lld", calc, idx_size);
dump_stack();
return -EINVAL;
}
@@ -1382,6 +1419,514 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
return 0;
}
+/**
+ * fsck_inode - information about an inode used when checking the file-system.
+ * @rb: link in the RB-tree of inodes
+ * @inum: inode number
+ * @mode: inode type, permissions, etc
+ * @nlink: inode link count
+ * @xatt_cnt: count of extended attributes
+ * @references: how many directory/xattr entries refer this inode (calculated
+ * while walking the index)
+ * @calc_cnt: for directory inode count of child directories, for regular files
+ * count of extended attributes
+ * @size: inode size (read from on-flash inode)
+ * @xattr_sz: summary size of all extended attributes (read from on-flash
+ * inode)
+ * @calc_sz: for directories calculated directory size, for regular files
+ * calculated summary size of all extended attributes
+ */
+struct fsck_inode {
+ struct rb_node rb;
+ ino_t inum;
+ umode_t mode;
+ int nlink;
+ int xattr_cnt;
+ int references;
+ int calc_cnt;
+ long long size;
+ long long xattr_sz;
+ long long calc_sz;
+};
+
+/**
+ * fsck_data - private FS checking information.
+ * @inodes: RB-tree of all inodes (contains @struct fsck_inode objects)
+ */
+struct fsck_data {
+ struct rb_root inodes;
+};
+
+/**
+ * add_inode - add inode information to RB-tree of inodes.
+ * @c: UBIFS file-system description object
+ * @fsckd: FS checking information
+ * @ino: raw UBIFS inode to add
+ *
+ * This is a helper function for 'check_leaf()' which adds information about
+ * inode @ino to the RB-tree of inodes. Returns inode information pointer in
+ * case of success and a negative error code in case of failure.
+ */
+static struct fsck_inode *add_inode(struct ubifs_info *c,
+ struct fsck_data *fsckd,
+ struct ubifs_ino_node *ino)
+{
+ struct rb_node **p, *parent = NULL;
+ struct fsck_inode *fscki;
+ ino_t inum = key_ino_flash(c, &ino->key);
+
+ p = &fsckd->inodes.rb_node;
+ while (*p) {
+ parent = *p;
+ fscki = rb_entry(parent, struct fsck_inode, rb);
+ if (inum < fscki->inum)
+ p = &(*p)->rb_left;
+ else if (inum > fscki->inum)
+ p = &(*p)->rb_right;
+ else
+ return fscki;
+ }
+
+ fscki = kzalloc(sizeof(struct fsck_inode), GFP_NOFS);
+ if (!fscki)
+ return ERR_PTR(-ENOMEM);
+
+ 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 = le64_to_cpu(ino->xattr_size);
+ fscki->mode = le32_to_cpu(ino->mode);
+ 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;
+}
+
+/**
+ * search_inode - search inode in the RB-tree of inodes.
+ * @fsckd: FS checking information
+ * @inum: inode number to search
+ *
+ * This is a helper function for 'check_leaf()' which searches inode @inum in
+ * the RB-tree of inodes and returns an inode information pointer or %NULL if
+ * the inode was not found.
+ */
+static struct fsck_inode *search_inode(struct fsck_data *fsckd, ino_t inum)
+{
+ struct rb_node *p;
+ struct fsck_inode *fscki;
+
+ p = fsckd->inodes.rb_node;
+ while (p) {
+ fscki = rb_entry(p, struct fsck_inode, rb);
+ if (inum < fscki->inum)
+ p = p->rb_left;
+ else if (inum > fscki->inum)
+ p = p->rb_right;
+ else
+ return fscki;
+ }
+ return NULL;
+}
+
+/**
+ * read_add_inode - read inode node and add it to RB-tree of inodes.
+ * @c: UBIFS file-system description object
+ * @fsckd: FS checking information
+ * @inum: inode number to read
+ *
+ * This is a helper function for 'check_leaf()' which finds inode node @inum in
+ * the index, reads it, and adds it to the RB-tree of inodes. Returns inode
+ * information pointer in case of success and a negative error code in case of
+ * failure.
+ */
+static struct fsck_inode *read_add_inode(struct ubifs_info *c,
+ struct fsck_data *fsckd, ino_t inum)
+{
+ int n, err;
+ union ubifs_key key;
+ struct ubifs_znode *znode;
+ struct ubifs_zbranch *zbr;
+ struct ubifs_ino_node *ino;
+ struct fsck_inode *fscki;
+
+ fscki = search_inode(fsckd, inum);
+ if (fscki)
+ return fscki;
+
+ ino_key_init(c, &key, inum);
+ err = ubifs_lookup_level0(c, &key, &znode, &n);
+ if (!err) {
+ ubifs_err("inode %lu not found in index", inum);
+ return ERR_PTR(-ENOENT);
+ } else if (err < 0) {
+ ubifs_err("error %d while looking up inode %lu", err, inum);
+ return ERR_PTR(err);
+ }
+
+ zbr = &znode->zbranch[n];
+ if (zbr->len < UBIFS_INO_NODE_SZ) {
+ ubifs_err("bad node %lu node length %d", inum, zbr->len);
+ return ERR_PTR(-EINVAL);
+ }
+
+ ino = kmalloc(zbr->len, GFP_NOFS);
+ if (!ino)
+ return ERR_PTR(-ENOMEM);
+
+ err = ubifs_tnc_read_node(c, zbr, ino);
+ if (err) {
+ ubifs_err("cannot read inode node at LEB %d:%d, error %d",
+ zbr->lnum, zbr->offs, err);
+ kfree(ino);
+ return ERR_PTR(err);
+ }
+
+ fscki = add_inode(c, fsckd, ino);
+ kfree(ino);
+ if (IS_ERR(fscki)) {
+ ubifs_err("error %ld while adding inode %lu node",
+ PTR_ERR(fscki), inum);
+ return fscki;
+ }
+
+ return fscki;
+}
+
+/**
+ * check_leaf - check leaf node.
+ * @c: UBIFS file-system description object
+ * @zbr: zbranch of the leaf node to check
+ * @priv: FS checking information
+ *
+ * This is a helper function for 'dbg_check_filesystem()' which is called for
+ * every single leaf node while walking the indexing tree. It checks that the
+ * leaf node referred from the indexing tree exists, has correct CRC, and does
+ * some other basic validation. This function is also responsible for building
+ * an RB-tree of inodes - it adds all inodes into the RB-tree. It also
+ * calculates reference count, size, etc for each inode in order to later
+ * compare them to the information stored inside the inodes and detect possible
+ * inconsistencies. Returns zero in case of success and a negative error code
+ * in case of failure.
+ */
+static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ void *priv)
+{
+ ino_t inum;
+ void *node;
+ int err, type = key_type(c, &zbr->key);
+ struct fsck_inode *fscki;
+
+ if (zbr->len < UBIFS_CH_SZ) {
+ ubifs_err("bad leaf length %d (LEB %d:%d)",
+ zbr->len, zbr->lnum, zbr->offs);
+ return -EINVAL;
+ }
+
+ node = kmalloc(zbr->len, GFP_NOFS);
+ if (!node)
+ return -ENOMEM;
+
+ err = ubifs_tnc_read_node(c, zbr, node);
+ if (err) {
+ ubifs_err("cannot read leaf node at LEB %d:%d, error %d",
+ zbr->lnum, zbr->offs, err);
+ goto out_free;
+ }
+
+ /* If this is an inode node, add it to RB-tree of inodes */
+ if (type == UBIFS_INO_KEY) {
+ fscki = add_inode(c, priv, node);
+ if (IS_ERR(fscki)) {
+ err = PTR_ERR(fscki);
+ ubifs_err("error %d while adding inode node", err);
+ goto out_dump;
+ }
+ goto out;
+ }
+
+ if (type != UBIFS_DENT_KEY && type != UBIFS_XENT_KEY &&
+ type != UBIFS_DATA_KEY) {
+ ubifs_err("unexpected node type %d at LEB %d:%d",
+ type, zbr->lnum, zbr->offs);
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ if (type == UBIFS_DATA_KEY) {
+ long long blk_offs;
+ struct ubifs_data_node *dn = node;
+
+ /*
+ * Search the inode node this data node belongs to and insert
+ * it to the RB-tree of inodes.
+ */
+ inum = key_ino_flash(c, &dn->key);
+ fscki = read_add_inode(c, priv, inum);
+ if (IS_ERR(fscki)) {
+ err = PTR_ERR(fscki);
+ ubifs_err("error %d while processing data node and "
+ "trying to find inode node %lu", err, inum);
+ goto out_dump;
+ }
+
+ /* Make sure the data node is within inode size */
+ blk_offs = (key_block_flash(c, &dn->key) << UBIFS_BLOCK_SHIFT);
+ blk_offs += le32_to_cpu(dn->size);
+ if (blk_offs > fscki->size) {
+ ubifs_err("data node at LEB %d:%d is not within inode "
+ "size %lld", zbr->lnum, zbr->offs, fscki->size);
+ err = -EINVAL;
+ goto out_dump;
+ }
+ } else {
+ int nlen;
+ struct ubifs_dent_node *dent = node;
+ struct fsck_inode *fscki1;
+
+ err = ubifs_validate_entry(c, dent);
+ if (err)
+ goto out_dump;
+
+ /*
+ * Search the inode node this entry refers to and the parent
+ * inode node and insert them to the RB-tree of inodes.
+ */
+ inum = le64_to_cpu(dent->inum);
+ fscki = read_add_inode(c, priv, inum);
+ if (IS_ERR(fscki)) {
+ err = PTR_ERR(fscki);
+ ubifs_err("error %d while processing entry node and "
+ "trying to find inode node %lu", err, inum);
+ goto out_dump;
+ }
+
+ /* Count how many direntries or xentries refers this inode */
+ fscki->references += 1;
+
+ inum = key_ino_flash(c, &dent->key);
+ fscki1 = read_add_inode(c, priv, inum);
+ if (IS_ERR(fscki1)) {
+ err = PTR_ERR(fscki);
+ ubifs_err("error %d while processing entry node and "
+ "trying to find parent inode node %lu",
+ err, inum);
+ goto out_dump;
+ }
+
+ nlen = le16_to_cpu(dent->nlen);
+ if (type == UBIFS_XENT_KEY) {
+ fscki1->calc_cnt += 1;
+ fscki1->calc_sz += CALC_DENT_SIZE(nlen);
+ fscki1->calc_sz += CALC_XATTR_BYTES(fscki->size);
+ } else {
+ fscki1->calc_sz += CALC_DENT_SIZE(nlen);
+ if (dent->type == UBIFS_ITYPE_DIR)
+ fscki1->calc_cnt += 1;
+ }
+ }
+
+out:
+ kfree(node);
+ return 0;
+
+out_dump:
+ ubifs_msg("dump of node at LEB %d:%d", zbr->lnum, zbr->offs);
+ dbg_dump_node(c, node);
+out_free:
+ kfree(node);
+ return err;
+}
+
+/**
+ * free_inodes - free RB-tree of inodes.
+ * @fsckd: FS checking information
+ */
+static void free_inodes(struct fsck_data *fsckd)
+{
+ struct rb_node *this = fsckd->inodes.rb_node;
+ struct fsck_inode *fscki;
+
+ while (this) {
+ if (this->rb_left)
+ this = this->rb_left;
+ else if (this->rb_right)
+ this = this->rb_right;
+ else {
+ fscki = rb_entry(this, struct fsck_inode, rb);
+ this = rb_parent(this);
+ if (this) {
+ if (this->rb_left == &fscki->rb)
+ this->rb_left = NULL;
+ else
+ this->rb_right = NULL;
+ }
+ kfree(fscki);
+ }
+ }
+}
+
+/**
+ * check_inodes - checks all inodes.
+ * @c: UBIFS file-system description object
+ * @fsckd: FS checking information
+ *
+ * This is a helper function for 'dbg_check_filesystem()' which walks the
+ * RB-tree of inodes after the index scan has been finished, and checks that
+ * inode nlink, size, etc are correct. Returns zero if inodes are fine,
+ * %-EINVAL if not, and a negative error code in case of failure.
+ */
+static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd)
+{
+ int n, err;
+ union ubifs_key key;
+ struct ubifs_znode *znode;
+ struct ubifs_zbranch *zbr;
+ struct ubifs_ino_node *ino;
+ struct fsck_inode *fscki;
+ struct rb_node *this = rb_first(&fsckd->inodes);
+
+ while (this) {
+ fscki = rb_entry(this, struct fsck_inode, rb);
+ this = rb_next(this);
+
+ if (S_ISDIR(fscki->mode)) {
+ /*
+ * Directories have to have exactly one reference (they
+ * cannot have hardlinks), although root inode is an
+ * exception.
+ */
+ if (fscki->inum != UBIFS_ROOT_INO &&
+ fscki->references != 1) {
+ ubifs_err("directory inode %lu has %d "
+ "direntries which refer it, but "
+ "should be 1", fscki->inum,
+ fscki->references);
+ goto out_dump;
+ }
+ if (fscki->inum == UBIFS_ROOT_INO &&
+ fscki->references != 0) {
+ ubifs_err("root inode %lu has non-zero (%d) "
+ "direntries which refer it",
+ fscki->inum, fscki->references);
+ goto out_dump;
+ }
+ if (fscki->calc_sz != fscki->size) {
+ ubifs_err("directory inode %lu size is %lld, "
+ "but calculated size is %lld",
+ fscki->inum, fscki->size,
+ fscki->calc_sz);
+ goto out_dump;
+ }
+ if (fscki->calc_cnt != fscki->nlink) {
+ ubifs_err("directory inode %lu nlink is %d, "
+ "but calculated nlink is %d",
+ fscki->inum, fscki->nlink,
+ fscki->calc_cnt);
+ goto out_dump;
+ }
+ } else {
+ if (fscki->references != fscki->nlink) {
+ ubifs_err("inode %lu nlink is %d, but "
+ "calculated nlink is %d", fscki->inum,
+ fscki->nlink, fscki->references);
+ goto out_dump;
+ }
+ if (fscki->xattr_sz != fscki->calc_sz) {
+ ubifs_err("inode %lu has xattr size %lld, but "
+ "calculated size is %lld",
+ fscki->inum, fscki->xattr_sz,
+ fscki->calc_sz);
+ goto out_dump;
+ }
+ if (fscki->xattr_cnt != fscki->calc_cnt) {
+ ubifs_err("inode %lu has %d xattrs, but "
+ "calculated count is %d", fscki->inum,
+ fscki->xattr_cnt, fscki->calc_cnt);
+ goto out_dump;
+ }
+ }
+ }
+
+ return 0;
+
+out_dump:
+ /* Read the bad inode and dump it */
+ ino_key_init(c, &key, fscki->inum);
+ err = ubifs_lookup_level0(c, &key, &znode, &n);
+ if (!err) {
+ ubifs_err("inode %lu not found in index", fscki->inum);
+ return -ENOENT;
+ } else if (err < 0) {
+ ubifs_err("error %d while looking up inode %lu",
+ err, fscki->inum);
+ return err;
+ }
+
+ zbr = &znode->zbranch[n];
+ ino = kmalloc(zbr->len, GFP_NOFS);
+ if (!ino)
+ return -ENOMEM;
+
+ err = ubifs_tnc_read_node(c, zbr, ino);
+ if (err) {
+ ubifs_err("cannot read inode node at LEB %d:%d, error %d",
+ zbr->lnum, zbr->offs, err);
+ kfree(ino);
+ return err;
+ }
+
+ ubifs_msg("dump of the inode %lu sitting in LEB %d:%d",
+ fscki->inum, zbr->lnum, zbr->offs);
+ dbg_dump_node(c, ino);
+ kfree(ino);
+ return -EINVAL;
+}
+
+/**
+ * dbg_check_filesystem - check the file-system.
+ * @c: UBIFS file-system description object
+ *
+ * This function checks the file system, namely:
+ * o makes sure that all leaf nodes exist and their CRCs are correct;
+ * o makes sure inode nlink, size, xattr size/count are correct (for all
+ * inodes).
+ *
+ * The function reads whole indexing tree and all nodes, so it is pretty
+ * heavy-weight. Returns zero if the file-system is consistent, %-EINVAL if
+ * not, and a negative error code in case of failure.
+ */
+int dbg_check_filesystem(struct ubifs_info *c)
+{
+ int err;
+ struct fsck_data fsckd;
+
+ if (!(ubifs_chk_flags & UBIFS_CHK_FS))
+ return 0;
+
+ fsckd.inodes = RB_ROOT;
+ err = dbg_walk_index(c, check_leaf, NULL, &fsckd);
+ if (err)
+ goto out_free;
+
+ err = check_inodes(c, &fsckd);
+ if (err)
+ goto out_free;
+
+ free_inodes(&fsckd);
+ return 0;
+
+out_free:
+ ubifs_err("file-system check failed with error %d", err);
+ dump_stack();
+ free_inodes(&fsckd);
+ return err;
+}
+
static int invocation_cnt;
int dbg_force_in_the_gaps(void)
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index a0be60002a0f..a6b669110f5d 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -166,6 +166,7 @@ enum {
* UBIFS_CHK_ORPH: check orphans
* UBIFS_CHK_OLD_IDX: check the old index
* UBIFS_CHK_LPROPS: check lprops
+ * UBIFS_CHK_FS: check the file-system
*/
enum {
UBIFS_CHK_GEN = 0x1,
@@ -174,6 +175,7 @@ enum {
UBIFS_CHK_ORPH = 0x8,
UBIFS_CHK_OLD_IDX = 0x10,
UBIFS_CHK_LPROPS = 0x20,
+ UBIFS_CHK_FS = 0x40,
};
/*
@@ -258,6 +260,8 @@ int dbg_check_tnc(struct ubifs_info *c, int extra);
int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
+int dbg_check_filesystem(struct ubifs_info *c);
+
void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
int add_pos);
@@ -373,6 +377,7 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
#define dbg_check_tnc(c, x) 0
#define dbg_check_idx_size(c, idx_size) 0
+#define dbg_check_filesystem(c) 0
#define dbg_check_heap(c, heap, cat, add_pos) ({})
diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
index 2dfc32d36e60..5a919d0ad853 100644
--- a/fs/ubifs/key.h
+++ b/fs/ubifs/key.h
@@ -453,6 +453,19 @@ static inline unsigned int key_block(const struct ubifs_info *c,
}
/**
+ * key_block_flash - get data block number from an on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: the key to get the block number from
+ */
+static inline unsigned int key_block_flash(const struct ubifs_info *c,
+ const void *k)
+{
+ const union ubifs_key *key = k;
+
+ return le32_to_cpu(key->u32[1]) & UBIFS_S_KEY_BLOCK_MASK;
+}
+
+/**
* key_read - transform a key to in-memory format.
* @c: UBIFS file-system description object
* @from: the key to transform
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 50146e2555df..fedf2e8620b0 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1142,6 +1142,10 @@ static int mount_ubifs(struct ubifs_info *c)
}
}
+ err = dbg_check_filesystem(c);
+ if (err)
+ goto out_infos;
+
ubifs_msg("mounted UBI device %d, volume %d", c->vi.ubi_num,
c->vi.vol_id);
if (mounted_read_only)
@@ -1199,6 +1203,10 @@ static int mount_ubifs(struct ubifs_info *c)
return 0;
+out_infos:
+ spin_lock(&ubifs_infos_lock);
+ list_del(&c->infos_list);
+ spin_unlock(&ubifs_infos_lock);
out_orphans:
free_orphans(c);
out_journal:
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index d9aabb6cca08..9b8d986b6ae4 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -1140,7 +1140,7 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
}
/**
- * lookup_level0 - search for zero-level znode.
+ * ubifs_lookup_level0 - search for zero-level znode.
* @c: UBIFS file-system description object
* @key: key to lookup
* @zn: znode is returned here
@@ -1161,8 +1161,8 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
* function reads corresponding indexing nodes and inserts them to TNC. In
* case of failure, a negative error code is returned.
*/
-static int lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
- struct ubifs_znode **zn, int *n)
+int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n)
{
int err, exact;
struct ubifs_znode *znode;
@@ -1401,7 +1401,7 @@ int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_zbranch zbr, *zt;
mutex_lock(&c->tnc_mutex);
- found = lookup_level0(c, key, &znode, &n);
+ found = ubifs_lookup_level0(c, key, &znode, &n);
if (!found) {
err = -ENOENT;
goto out;
@@ -1448,7 +1448,7 @@ int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_zbranch zbr, *zt;
mutex_lock(&c->tnc_mutex);
- found = lookup_level0(c, key, &znode, &n);
+ found = ubifs_lookup_level0(c, key, &znode, &n);
if (!found) {
err = -ENOENT;
goto out;
@@ -1504,7 +1504,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
mutex_lock(&c->tnc_mutex);
- found = lookup_level0(c, key, &znode, &n);
+ found = ubifs_lookup_level0(c, key, &znode, &n);
if (!found) {
err = -ENOENT;
goto out_unlock;
@@ -2299,7 +2299,7 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
mutex_lock(&c->tnc_mutex);
while (1) {
/* Find first level 0 znode that contains keys to remove */
- err = lookup_level0(c, from_key, &znode, &n);
+ err = ubifs_lookup_level0(c, from_key, &znode, &n);
if (err < 0)
goto out_unlock;
@@ -2464,7 +2464,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
ubifs_assert(is_hash_key(c, key));
mutex_lock(&c->tnc_mutex);
- err = lookup_level0(c, key, &znode, &n);
+ err = ubifs_lookup_level0(c, key, &znode, &n);
if (unlikely(err < 0))
goto out_unlock;
@@ -2705,9 +2705,9 @@ static struct ubifs_znode *lookup_znode(struct ubifs_info *c,
* We reached a znode where the leftmost key is greater
* than the key we are searching for. This is the same
* situation as the one described in a huge comment at
- * the end of the 'lookup_level0()' function. And for
- * exactly the same reasons we have to try to look left
- * before giving up.
+ * the end of the 'ubifs_lookup_level0()' function. And
+ * for exactly the same reasons we have to try to look
+ * left before giving up.
*/
znode = left_znode(c, znode);
if (!znode)
@@ -2833,7 +2833,7 @@ static int is_leaf_node_in_tnc(struct ubifs_info *c, union ubifs_key *key,
int n, found, err, nn;
const int unique = !is_hash_key(c, key);
- found = lookup_level0(c, key, &znode, &n);
+ found = ubifs_lookup_level0(c, key, &znode, &n);
if (found < 0)
return found; /* Error code */
if (!found)
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 61e06581d94e..2e6f293df404 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -114,6 +114,9 @@
*/
#define CALC_DENT_SIZE(name_len) ALIGN(UBIFS_DENT_NODE_SZ + (name_len) + 1, 8)
+/* How much an extended attribute adds to the host inode */
+#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8)
+
/*
* Znodes which were not touched for 'OLD_ZNODE_AGE' seconds are considered
* "old", and znode which were touched last 'YOUNG_ZNODE_AGE' seconds ago are
@@ -1381,12 +1384,14 @@ int ubifs_find_dirty_idx_leb(struct ubifs_info *c);
int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
/* tnc.c */
+int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n);
int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key,
void *node);
-int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
- void *node, int *lnum, int *offs);
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
void *node, const struct qstr *nm);
+int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, int *lnum, int *offs);
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
int offs, int len);
int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 5d1b03da6cd0..05f1ab5392ad 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -59,9 +59,6 @@
#include <linux/posix_acl_xattr.h>
#include "ubifs.h"
-/* How many bytes an extended attribute adds to the host inode */
-#define CALC_XATTR_BYTES(data_len) ALIGN(UBIFS_INO_NODE_SZ + (data_len) + 1, 8)
-
/*
* Extended attribute type constants.
*