summaryrefslogtreecommitdiff
path: root/fs/ubifs/tnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ubifs/tnc.c')
-rw-r--r--fs/ubifs/tnc.c394
1 files changed, 223 insertions, 171 deletions
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 0a213dcba2a1..33946b518148 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -1,21 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* This file is part of UBIFS.
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
* Authors: Adrian Hunter
* Artem Bityutskiy (Битюцкий Артём)
*/
@@ -35,7 +23,7 @@
#include "ubifs.h"
static int try_read_node(const struct ubifs_info *c, void *buf, int type,
- int len, int lnum, int offs);
+ struct ubifs_zbranch *zbr);
static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_zbranch *zbr, void *node);
@@ -56,6 +44,34 @@ enum {
NOT_ON_MEDIA = 3,
};
+static void do_insert_old_idx(struct ubifs_info *c,
+ struct ubifs_old_idx *old_idx)
+{
+ struct ubifs_old_idx *o;
+ struct rb_node **p, *parent = NULL;
+
+ p = &c->old_idx.rb_node;
+ while (*p) {
+ parent = *p;
+ o = rb_entry(parent, struct ubifs_old_idx, rb);
+ if (old_idx->lnum < o->lnum)
+ p = &(*p)->rb_left;
+ else if (old_idx->lnum > o->lnum)
+ p = &(*p)->rb_right;
+ else if (old_idx->offs < o->offs)
+ p = &(*p)->rb_left;
+ else if (old_idx->offs > o->offs)
+ p = &(*p)->rb_right;
+ else {
+ ubifs_err(c, "old idx added twice!");
+ kfree(old_idx);
+ return;
+ }
+ }
+ rb_link_node(&old_idx->rb, parent, p);
+ rb_insert_color(&old_idx->rb, &c->old_idx);
+}
+
/**
* insert_old_idx - record an index node obsoleted since the last commit start.
* @c: UBIFS file-system description object
@@ -81,35 +97,15 @@ enum {
*/
static int insert_old_idx(struct ubifs_info *c, int lnum, int offs)
{
- struct ubifs_old_idx *old_idx, *o;
- struct rb_node **p, *parent = NULL;
+ struct ubifs_old_idx *old_idx;
old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS);
if (unlikely(!old_idx))
return -ENOMEM;
old_idx->lnum = lnum;
old_idx->offs = offs;
+ do_insert_old_idx(c, old_idx);
- p = &c->old_idx.rb_node;
- while (*p) {
- parent = *p;
- o = rb_entry(parent, struct ubifs_old_idx, rb);
- if (lnum < o->lnum)
- p = &(*p)->rb_left;
- else if (lnum > o->lnum)
- p = &(*p)->rb_right;
- else if (offs < o->offs)
- p = &(*p)->rb_left;
- else if (offs > o->offs)
- p = &(*p)->rb_right;
- else {
- ubifs_err(c, "old idx added twice!");
- kfree(old_idx);
- return 0;
- }
- }
- rb_link_node(&old_idx->rb, parent, p);
- rb_insert_color(&old_idx->rb, &c->old_idx);
return 0;
}
@@ -211,23 +207,6 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
__set_bit(DIRTY_ZNODE, &zn->flags);
__clear_bit(COW_ZNODE, &zn->flags);
- ubifs_assert(!ubifs_zn_obsolete(znode));
- __set_bit(OBSOLETE_ZNODE, &znode->flags);
-
- if (znode->level != 0) {
- int i;
- const int n = zn->child_cnt;
-
- /* The children now have new parent */
- for (i = 0; i < n; i++) {
- struct ubifs_zbranch *zbr = &zn->zbranch[i];
-
- if (zbr->znode)
- zbr->znode->parent = zn;
- }
- }
-
- atomic_long_inc(&c->dirty_zn_cnt);
return zn;
}
@@ -246,6 +225,42 @@ static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt)
}
/**
+ * replace_znode - replace old znode with new znode.
+ * @c: UBIFS file-system description object
+ * @new_zn: new znode
+ * @old_zn: old znode
+ * @zbr: the branch of parent znode
+ *
+ * Replace old znode with new znode in TNC.
+ */
+static void replace_znode(struct ubifs_info *c, struct ubifs_znode *new_zn,
+ struct ubifs_znode *old_zn, struct ubifs_zbranch *zbr)
+{
+ ubifs_assert(c, !ubifs_zn_obsolete(old_zn));
+ __set_bit(OBSOLETE_ZNODE, &old_zn->flags);
+
+ if (old_zn->level != 0) {
+ int i;
+ const int n = new_zn->child_cnt;
+
+ /* The children now have new parent */
+ for (i = 0; i < n; i++) {
+ struct ubifs_zbranch *child = &new_zn->zbranch[i];
+
+ if (child->znode)
+ child->znode->parent = new_zn;
+ }
+ }
+
+ zbr->znode = new_zn;
+ zbr->lnum = 0;
+ zbr->offs = 0;
+ zbr->len = 0;
+
+ atomic_long_inc(&c->dirty_zn_cnt);
+}
+
+/**
* dirty_cow_znode - ensure a znode is not being committed.
* @c: UBIFS file-system description object
* @zbr: branch of znode to check
@@ -277,21 +292,32 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
return zn;
if (zbr->len) {
- err = insert_old_idx(c, zbr->lnum, zbr->offs);
- if (unlikely(err))
- return ERR_PTR(err);
+ struct ubifs_old_idx *old_idx;
+
+ old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS);
+ if (unlikely(!old_idx)) {
+ err = -ENOMEM;
+ goto out;
+ }
+ old_idx->lnum = zbr->lnum;
+ old_idx->offs = zbr->offs;
+
err = add_idx_dirt(c, zbr->lnum, zbr->len);
- } else
- err = 0;
+ if (err) {
+ kfree(old_idx);
+ goto out;
+ }
- zbr->znode = zn;
- zbr->lnum = 0;
- zbr->offs = 0;
- zbr->len = 0;
+ do_insert_old_idx(c, old_idx);
+ }
+
+ replace_znode(c, zn, znode, zbr);
- if (unlikely(err))
- return ERR_PTR(err);
return zn;
+
+out:
+ kfree(zn);
+ return ERR_PTR(err);
}
/**
@@ -321,14 +347,14 @@ static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
void *lnc_node;
const struct ubifs_dent_node *dent = node;
- ubifs_assert(!zbr->leaf);
- ubifs_assert(zbr->len != 0);
- ubifs_assert(is_hash_key(c, &zbr->key));
+ ubifs_assert(c, !zbr->leaf);
+ ubifs_assert(c, zbr->len != 0);
+ ubifs_assert(c, is_hash_key(c, &zbr->key));
err = ubifs_validate_entry(c, dent);
if (err) {
dump_stack();
- ubifs_dump_node(c, dent);
+ ubifs_dump_node(c, dent, zbr->len);
return err;
}
@@ -355,13 +381,13 @@ static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr,
{
int err;
- ubifs_assert(!zbr->leaf);
- ubifs_assert(zbr->len != 0);
+ ubifs_assert(c, !zbr->leaf);
+ ubifs_assert(c, zbr->len != 0);
err = ubifs_validate_entry(c, node);
if (err) {
dump_stack();
- ubifs_dump_node(c, node);
+ ubifs_dump_node(c, node, zbr->len);
return err;
}
@@ -372,7 +398,6 @@ static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr,
/**
* lnc_free - remove a leaf node from the leaf node cache.
* @zbr: zbranch of leaf node
- * @node: leaf node
*/
static void lnc_free(struct ubifs_zbranch *zbr)
{
@@ -390,7 +415,7 @@ static void lnc_free(struct ubifs_zbranch *zbr)
*
* This function reads a "hashed" node defined by @zbr from the leaf node cache
* (in it is there) or from the hash media, in which case the node is also
- * added to LNC. Returns zero in case of success or a negative negative error
+ * added to LNC. Returns zero in case of success or a negative error
* code in case of failure.
*/
static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
@@ -398,11 +423,11 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
{
int err;
- ubifs_assert(is_hash_key(c, &zbr->key));
+ ubifs_assert(c, is_hash_key(c, &zbr->key));
if (zbr->leaf) {
/* Read from the leaf node cache */
- ubifs_assert(zbr->len != 0);
+ ubifs_assert(c, zbr->len != 0);
memcpy(node, zbr->leaf, zbr->len);
return 0;
}
@@ -433,9 +458,7 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
* @c: UBIFS file-system description object
* @buf: buffer to read to
* @type: node type
- * @len: node length (not aligned)
- * @lnum: LEB number of node to read
- * @offs: offset of node to read
+ * @zbr: the zbranch describing the node to read
*
* This function tries to read a node of known type and length, checks it and
* stores it in @buf. This function returns %1 if a node is present and %0 if
@@ -453,8 +476,11 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
* journal nodes may potentially be corrupted, so checking is required.
*/
static int try_read_node(const struct ubifs_info *c, void *buf, int type,
- int len, int lnum, int offs)
+ struct ubifs_zbranch *zbr)
{
+ int len = zbr->len;
+ int lnum = zbr->lnum;
+ int offs = zbr->offs;
int err, node_len;
struct ubifs_ch *ch = buf;
uint32_t crc, node_crc;
@@ -478,14 +504,19 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
if (node_len != len)
return 0;
- if (type == UBIFS_DATA_NODE && c->no_chk_data_crc && !c->mounting &&
- !c->remounting_rw)
- return 1;
+ if (type != UBIFS_DATA_NODE || !c->no_chk_data_crc || c->mounting ||
+ c->remounting_rw) {
+ crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+ node_crc = le32_to_cpu(ch->crc);
+ if (crc != node_crc)
+ return 0;
+ }
- crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
- node_crc = le32_to_cpu(ch->crc);
- if (crc != node_crc)
+ err = ubifs_node_check_hash(c, buf, zbr->hash);
+ if (err) {
+ ubifs_bad_hash(c, buf, zbr->hash, lnum, offs);
return 0;
+ }
return 1;
}
@@ -507,8 +538,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs);
- ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
- zbr->offs);
+ ret = try_read_node(c, node, key_type(c, key), zbr);
if (ret == 1) {
union ubifs_key node_key;
struct ubifs_dent_node *dent = node;
@@ -721,7 +751,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
while (1) {
err = tnc_prev(c, zn, n);
if (err == -ENOENT) {
- ubifs_assert(*n == 0);
+ ubifs_assert(c, *n == 0);
*n = -1;
return 0;
}
@@ -761,12 +791,12 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
err = tnc_next(c, zn, n);
if (err) {
/* Should be impossible */
- ubifs_assert(0);
+ ubifs_assert(c, 0);
if (err == -ENOENT)
err = -EINVAL;
return err;
}
- ubifs_assert(*n == 0);
+ ubifs_assert(c, *n == 0);
*n = -1;
}
return 0;
@@ -778,7 +808,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
return 0;
if (err == NAME_MATCHES)
return 1;
- ubifs_assert(err == NAME_GREATER);
+ ubifs_assert(c, err == NAME_GREATER);
}
} else {
int nn = *n;
@@ -802,7 +832,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
*n = nn;
if (err == NAME_MATCHES)
return 1;
- ubifs_assert(err == NAME_LESS);
+ ubifs_assert(c, err == NAME_LESS);
}
}
}
@@ -843,7 +873,7 @@ static int fallible_matches_name(struct ubifs_info *c,
err = NOT_ON_MEDIA;
goto out_free;
}
- ubifs_assert(err == 1);
+ ubifs_assert(c, err == 1);
err = lnc_add_directly(c, zbr, dent);
if (err)
@@ -899,7 +929,7 @@ static int fallible_resolve_collision(struct ubifs_info *c,
int adding)
{
struct ubifs_znode *o_znode = NULL, *znode = *zn;
- int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
+ int o_n, err, cmp, unsure = 0, nn = *n;
cmp = fallible_matches_name(c, &znode->zbranch[nn], nm);
if (unlikely(cmp < 0))
@@ -923,7 +953,7 @@ static int fallible_resolve_collision(struct ubifs_info *c,
while (1) {
err = tnc_prev(c, zn, n);
if (err == -ENOENT) {
- ubifs_assert(*n == 0);
+ ubifs_assert(c, *n == 0);
*n = -1;
break;
}
@@ -935,12 +965,12 @@ static int fallible_resolve_collision(struct ubifs_info *c,
err = tnc_next(c, zn, n);
if (err) {
/* Should be impossible */
- ubifs_assert(0);
+ ubifs_assert(c, 0);
if (err == -ENOENT)
err = -EINVAL;
return err;
}
- ubifs_assert(*n == 0);
+ ubifs_assert(c, *n == 0);
*n = -1;
}
break;
@@ -1100,12 +1130,13 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
struct ubifs_znode *zp;
int *path = c->bottom_up_buf, p = 0;
- ubifs_assert(c->zroot.znode);
- ubifs_assert(znode);
+ ubifs_assert(c, c->zroot.znode);
+ ubifs_assert(c, znode);
if (c->zroot.znode->level > BOTTOM_UP_HEIGHT) {
kfree(c->bottom_up_buf);
- c->bottom_up_buf = kmalloc(c->zroot.znode->level * sizeof(int),
- GFP_NOFS);
+ c->bottom_up_buf = kmalloc_array(c->zroot.znode->level,
+ sizeof(int),
+ GFP_NOFS);
if (!c->bottom_up_buf)
return ERR_PTR(-ENOMEM);
path = c->bottom_up_buf;
@@ -1119,7 +1150,7 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
if (!zp)
break;
n = znode->iip;
- ubifs_assert(p < c->zroot.znode->level);
+ ubifs_assert(c, p < c->zroot.znode->level);
path[p++] = n;
if (!zp->cnext && ubifs_zn_dirty(znode))
break;
@@ -1133,18 +1164,18 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
zp = znode->parent;
if (zp) {
- ubifs_assert(path[p - 1] >= 0);
- ubifs_assert(path[p - 1] < zp->child_cnt);
+ ubifs_assert(c, path[p - 1] >= 0);
+ ubifs_assert(c, path[p - 1] < zp->child_cnt);
zbr = &zp->zbranch[path[--p]];
znode = dirty_cow_znode(c, zbr);
} else {
- ubifs_assert(znode == c->zroot.znode);
+ ubifs_assert(c, znode == c->zroot.znode);
znode = dirty_cow_znode(c, &c->zroot);
}
if (IS_ERR(znode) || !p)
break;
- ubifs_assert(path[p - 1] >= 0);
- ubifs_assert(path[p - 1] < znode->child_cnt);
+ ubifs_assert(c, path[p - 1] >= 0);
+ ubifs_assert(c, path[p - 1] < znode->child_cnt);
znode = znode->zbranch[path[p - 1]].znode;
}
@@ -1164,8 +1195,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 closest branch is stored
- * in @n;
+ * @key, then %0 is returned and slot number of the closest branch or %-1
+ * is stored in @n; In this case calling tnc_next() is mandatory.
* 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.
*
@@ -1178,10 +1209,10 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
{
int err, exact;
struct ubifs_znode *znode;
- unsigned long time = get_seconds();
+ time64_t time = ktime_get_seconds();
dbg_tnck(key, "search key ");
- ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
+ ubifs_assert(c, key_type(c, key) < UBIFS_INVALID_KEY);
znode = c->zroot.znode;
if (unlikely(!znode)) {
@@ -1314,7 +1345,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
{
int err, exact;
struct ubifs_znode *znode;
- unsigned long time = get_seconds();
+ time64_t time = ktime_get_seconds();
dbg_tnck(key, "search and dirty key ");
@@ -1520,8 +1551,8 @@ out:
*/
int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
{
- int n, err = 0, lnum = -1, uninitialized_var(offs);
- int uninitialized_var(len);
+ int n, err = 0, lnum = -1, offs;
+ int len;
unsigned int block = key_block(c, &bu->key);
struct ubifs_znode *znode;
@@ -1657,9 +1688,9 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
int rlen, overlap;
dbg_io("LEB %d:%d, length %d", lnum, offs, len);
- ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
- ubifs_assert(!(offs & 7) && offs < c->leb_size);
- ubifs_assert(offs + len <= c->leb_size);
+ ubifs_assert(c, wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+ ubifs_assert(c, !(offs & 7) && offs < c->leb_size);
+ ubifs_assert(c, offs + len <= c->leb_size);
spin_lock(&wbuf->lock);
overlap = (lnum == wbuf->lnum && offs + len > wbuf->offs);
@@ -1706,12 +1737,18 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
goto out_err;
}
- err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0, 0);
+ err = ubifs_check_node(c, buf, zbr->len, zbr->lnum, zbr->offs, 0, 0);
if (err) {
ubifs_err(c, "expected node type %d", UBIFS_DATA_NODE);
goto out;
}
+ err = ubifs_node_check_hash(c, buf, zbr->hash);
+ if (err) {
+ ubifs_bad_hash(c, buf, zbr->hash, zbr->lnum, zbr->offs);
+ return err;
+ }
+
len = le32_to_cpu(ch->len);
if (len != zbr->len) {
ubifs_err(c, "bad node length %d, expected %d", len, zbr->len);
@@ -1734,7 +1771,7 @@ out_err:
err = -EINVAL;
out:
ubifs_err(c, "bad node at LEB %d:%d", zbr->lnum, zbr->offs);
- ubifs_dump_node(c, buf);
+ ubifs_dump_node(c, buf, zbr->len);
dump_stack();
return err;
}
@@ -1823,7 +1860,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
goto out_unlock;
}
- ubifs_assert(n >= 0);
+ ubifs_assert(c, n >= 0);
err = resolve_collision(c, key, &znode, &n, nm);
dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
@@ -1882,43 +1919,42 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
static int search_dh_cookie(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_dent_node *dent, uint32_t cookie,
- struct ubifs_znode **zn, int *n)
+ struct ubifs_znode **zn, int *n, int exact)
{
int err;
struct ubifs_znode *znode = *zn;
struct ubifs_zbranch *zbr;
union ubifs_key *dkey;
- for (;;) {
- if (!err) {
- err = tnc_next(c, &znode, n);
- if (err)
- goto out;
- }
+ if (!exact) {
+ err = tnc_next(c, &znode, n);
+ if (err)
+ return err;
+ }
+ for (;;) {
zbr = &znode->zbranch[*n];
dkey = &zbr->key;
if (key_inum(c, dkey) != key_inum(c, key) ||
key_type(c, dkey) != key_type(c, key)) {
- err = -ENOENT;
- goto out;
+ return -ENOENT;
}
err = tnc_read_hashed_node(c, zbr, dent);
if (err)
- goto out;
+ return err;
if (key_hash(c, key) == key_hash(c, dkey) &&
le32_to_cpu(dent->cookie) == cookie) {
*zn = znode;
- goto out;
+ return 0;
}
- }
-
-out:
- return err;
+ err = tnc_next(c, &znode, n);
+ if (err)
+ return err;
+ }
}
static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
@@ -1928,7 +1964,7 @@ static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_znode *znode;
union ubifs_key start_key;
- ubifs_assert(is_hash_key(c, key));
+ ubifs_assert(c, is_hash_key(c, key));
lowest_dent_key(c, &start_key, key_inum(c, key));
@@ -1937,7 +1973,7 @@ static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
if (unlikely(err < 0))
goto out_unlock;
- err = search_dh_cookie(c, key, dent, cookie, &znode, &n);
+ err = search_dh_cookie(c, key, dent, cookie, &znode, &n, err);
out_unlock:
mutex_unlock(&c->tnc_mutex);
@@ -1999,8 +2035,8 @@ static void correct_parent_keys(const struct ubifs_info *c,
{
union ubifs_key *key, *key1;
- ubifs_assert(znode->parent);
- ubifs_assert(znode->iip == 0);
+ ubifs_assert(c, znode->parent);
+ ubifs_assert(c, znode->iip == 0);
key = &znode->zbranch[0].key;
key1 = &znode->parent->zbranch[0].key;
@@ -2017,6 +2053,7 @@ static void correct_parent_keys(const struct ubifs_info *c,
/**
* insert_zbranch - insert a zbranch into a znode.
+ * @c: UBIFS file-system description object
* @znode: znode into which to insert
* @zbr: zbranch to insert
* @n: slot number to insert to
@@ -2026,12 +2063,12 @@ static void correct_parent_keys(const struct ubifs_info *c,
* zbranch has to be inserted to the @znode->zbranches[]' array at the @n-th
* slot, zbranches starting from @n have to be moved right.
*/
-static void insert_zbranch(struct ubifs_znode *znode,
+static void insert_zbranch(struct ubifs_info *c, struct ubifs_znode *znode,
const struct ubifs_zbranch *zbr, int n)
{
int i;
- ubifs_assert(ubifs_zn_dirty(znode));
+ ubifs_assert(c, ubifs_zn_dirty(znode));
if (znode->level) {
for (i = znode->child_cnt; i > n; i--) {
@@ -2085,16 +2122,16 @@ static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode,
int i, keep, move, appending = 0;
union ubifs_key *key = &zbr->key, *key1;
- ubifs_assert(n >= 0 && n <= c->fanout);
+ ubifs_assert(c, n >= 0 && n <= c->fanout);
/* Implement naive insert for now */
again:
zp = znode->parent;
if (znode->child_cnt < c->fanout) {
- ubifs_assert(n != c->fanout);
+ ubifs_assert(c, n != c->fanout);
dbg_tnck(key, "inserted at %d level %d, key ", n, znode->level);
- insert_zbranch(znode, zbr, n);
+ insert_zbranch(c, znode, zbr, n);
/* Ensure parent's key is correct */
if (n == 0 && zp && znode->iip == 0)
@@ -2203,7 +2240,7 @@ do_split:
/* Insert new key and branch */
dbg_tnck(key, "inserting at %d level %d, key ", n, zn->level);
- insert_zbranch(zi, zbr, n);
+ insert_zbranch(c, zi, zbr, n);
/* Insert new znode (produced by spitting) into the parent */
if (zp) {
@@ -2265,13 +2302,14 @@ do_split:
* @lnum: LEB number of node
* @offs: node offset
* @len: node length
+ * @hash: The hash over the node
*
* This function adds a node with key @key to TNC. The node may be new or it may
* obsolete some existing one. Returns %0 on success or negative error code on
* failure.
*/
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
- int offs, int len)
+ int offs, int len, const u8 *hash)
{
int found, n, err = 0;
struct ubifs_znode *znode;
@@ -2286,6 +2324,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
zbr.lnum = lnum;
zbr.offs = offs;
zbr.len = len;
+ ubifs_copy_hash(c, hash, zbr.hash);
key_copy(c, key, &zbr.key);
err = tnc_insert(c, znode, &zbr, n + 1);
} else if (found == 1) {
@@ -2296,6 +2335,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
zbr->lnum = lnum;
zbr->offs = offs;
zbr->len = len;
+ ubifs_copy_hash(c, hash, zbr->hash);
} else
err = found;
if (!err)
@@ -2397,13 +2437,14 @@ out_unlock:
* @lnum: LEB number of node
* @offs: node offset
* @len: node length
+ * @hash: The hash over the node
* @nm: node name
*
* This is the same as 'ubifs_tnc_add()' but it should be used with keys which
* may have collisions, like directory entry keys.
*/
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
- int lnum, int offs, int len,
+ int lnum, int offs, int len, const u8 *hash,
const struct fscrypt_name *nm)
{
int found, n, err = 0;
@@ -2446,6 +2487,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
zbr->lnum = lnum;
zbr->offs = offs;
zbr->len = len;
+ ubifs_copy_hash(c, hash, zbr->hash);
goto out_unlock;
}
}
@@ -2457,6 +2499,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
zbr.lnum = lnum;
zbr.offs = offs;
zbr.len = len;
+ ubifs_copy_hash(c, hash, zbr.hash);
key_copy(c, key, &zbr.key);
err = tnc_insert(c, znode, &zbr, n + 1);
if (err)
@@ -2501,8 +2544,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
int i, err;
/* Delete without merge for now */
- ubifs_assert(znode->level == 0);
- ubifs_assert(n >= 0 && n < c->fanout);
+ ubifs_assert(c, znode->level == 0);
+ ubifs_assert(c, n >= 0 && n < c->fanout);
dbg_tnck(&znode->zbranch[n].key, "deleting key ");
zbr = &znode->zbranch[n];
@@ -2528,8 +2571,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
*/
do {
- ubifs_assert(!ubifs_zn_obsolete(znode));
- ubifs_assert(ubifs_zn_dirty(znode));
+ ubifs_assert(c, !ubifs_zn_obsolete(znode));
+ ubifs_assert(c, ubifs_zn_dirty(znode));
zp = znode->parent;
n = znode->iip;
@@ -2551,7 +2594,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
/* Remove from znode, entry n - 1 */
znode->child_cnt -= 1;
- ubifs_assert(znode->level != 0);
+ ubifs_assert(c, znode->level != 0);
for (i = n; i < znode->child_cnt; i++) {
znode->zbranch[i] = znode->zbranch[i + 1];
if (znode->zbranch[i].znode)
@@ -2584,8 +2627,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
c->zroot.offs = zbr->offs;
c->zroot.len = zbr->len;
c->zroot.znode = znode;
- ubifs_assert(!ubifs_zn_obsolete(zp));
- ubifs_assert(ubifs_zn_dirty(zp));
+ ubifs_assert(c, !ubifs_zn_obsolete(zp));
+ ubifs_assert(c, ubifs_zn_dirty(zp));
atomic_long_dec(&c->dirty_zn_cnt);
if (zp->cnext) {
@@ -2723,7 +2766,7 @@ int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
if (unlikely(err < 0))
goto out_free;
- err = search_dh_cookie(c, key, dent, cookie, &znode, &n);
+ err = search_dh_cookie(c, key, dent, cookie, &znode, &n, err);
if (err)
goto out_free;
}
@@ -2879,6 +2922,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
err = PTR_ERR(xent);
if (err == -ENOENT)
break;
+ kfree(pxent);
return err;
}
@@ -2886,12 +2930,11 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
dbg_tnc("xent '%s', ino %lu", xent->name,
(unsigned long)xattr_inum);
- ubifs_evict_xattr_inode(c, xattr_inum);
-
fname_name(&nm) = xent->name;
fname_len(&nm) = le16_to_cpu(xent->nlen);
err = ubifs_tnc_remove_nm(c, &key1, &nm);
if (err) {
+ kfree(pxent);
kfree(xent);
return err;
}
@@ -2900,6 +2943,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
highest_ino_key(c, &key2, xattr_inum);
err = ubifs_tnc_remove_range(c, &key1, &key2);
if (err) {
+ kfree(pxent);
kfree(xent);
return err;
}
@@ -2950,7 +2994,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
union ubifs_key *dkey;
dbg_tnck(key, "key ");
- ubifs_assert(is_hash_key(c, key));
+ ubifs_assert(c, is_hash_key(c, key));
mutex_lock(&c->tnc_mutex);
err = ubifs_lookup_level0(c, key, &znode, &n);
@@ -3037,7 +3081,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
if (!c->cnext)
return;
- ubifs_assert(c->cmt_state == COMMIT_BROKEN);
+ ubifs_assert(c, c->cmt_state == COMMIT_BROKEN);
cnext = c->cnext;
do {
struct ubifs_znode *znode = cnext;
@@ -3045,6 +3089,21 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
cnext = cnext->cnext;
if (ubifs_zn_obsolete(znode))
kfree(znode);
+ else if (!ubifs_zn_cow(znode)) {
+ /*
+ * Don't forget to update clean znode count after
+ * committing failed, because ubifs will check this
+ * count while closing tnc. Non-obsolete znode could
+ * be re-dirtied during committing process, so dirty
+ * flag is untrustable. The flag 'COW_ZNODE' is set
+ * for each dirty znode before committing, and it is
+ * cleared as long as the znode become clean, so we
+ * can statistic clean znode count according to this
+ * flag.
+ */
+ atomic_long_inc(&c->clean_zn_cnt);
+ atomic_long_inc(&ubifs_clean_zn_cnt);
+ }
} while (cnext && cnext != c->cnext);
}
@@ -3055,14 +3114,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
void ubifs_tnc_close(struct ubifs_info *c)
{
tnc_destroy_cnext(c);
- if (c->zroot.znode) {
- long n, freed;
-
- n = atomic_long_read(&c->clean_zn_cnt);
- freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
- ubifs_assert(freed == n);
- atomic_long_sub(n, &ubifs_clean_zn_cnt);
- }
+ ubifs_destroy_tnc_tree(c);
kfree(c->gap_lebs);
kfree(c->ilebs);
destroy_old_idx(c);
@@ -3173,7 +3225,7 @@ static struct ubifs_znode *lookup_znode(struct ubifs_info *c,
struct ubifs_znode *znode, *zn;
int n, nn;
- ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
+ ubifs_assert(c, key_type(c, key) < UBIFS_INVALID_KEY);
/*
* The arguments have probably been read off flash, so don't assume
@@ -3212,7 +3264,7 @@ static struct ubifs_znode *lookup_znode(struct ubifs_info *c,
if (IS_ERR(znode))
return znode;
ubifs_search_zbranch(c, znode, key, &n);
- ubifs_assert(n >= 0);
+ ubifs_assert(c, n >= 0);
}
if (znode->level == level + 1)
break;
@@ -3460,7 +3512,7 @@ out_unlock:
/**
* dbg_check_inode_size - check if inode size is correct.
* @c: UBIFS file-system description object
- * @inum: inode number
+ * @inode: inode to check
* @size: inode size
*
* This function makes sure that the inode size (@size) is correct and it does
@@ -3503,7 +3555,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
if (err < 0)
goto out_unlock;
- ubifs_assert(err == 0);
+ ubifs_assert(c, err == 0);
key = &znode->zbranch[n].key;
if (!key_in_range(c, key, &from_key, &to_key))
goto out_unlock;