summaryrefslogtreecommitdiffstats
path: root/fs/ubifs/tnc_misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ubifs/tnc_misc.c')
-rw-r--r--fs/ubifs/tnc_misc.c124
1 files changed, 88 insertions, 36 deletions
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
index 955219fa01..81bdad9203 100644
--- a/fs/ubifs/tnc_misc.c
+++ b/fs/ubifs/tnc_misc.c
@@ -3,18 +3,7 @@
*
* 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
+ * SPDX-License-Identifier: GPL-2.0+
*
* Authors: Adrian Hunter
* Artem Bityutskiy (Битюцкий Артём)
@@ -27,6 +16,10 @@
* putting it all in one file would make that file too big and unreadable.
*/
+#define __UBOOT__
+#ifdef __UBOOT__
+#include <linux/err.h>
+#endif
#include "ubifs.h"
/**
@@ -219,6 +212,44 @@ struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode)
}
/**
+ * ubifs_destroy_tnc_subtree - destroy all znodes connected to a subtree.
+ * @znode: znode defining subtree to destroy
+ *
+ * This function destroys subtree of the TNC tree. Returns number of clean
+ * znodes in the subtree.
+ */
+long ubifs_destroy_tnc_subtree(struct ubifs_znode *znode)
+{
+ struct ubifs_znode *zn = ubifs_tnc_postorder_first(znode);
+ long clean_freed = 0;
+ int n;
+
+ ubifs_assert(zn);
+ while (1) {
+ for (n = 0; n < zn->child_cnt; n++) {
+ if (!zn->zbranch[n].znode)
+ continue;
+
+ if (zn->level > 0 &&
+ !ubifs_zn_dirty(zn->zbranch[n].znode))
+ clean_freed += 1;
+
+ cond_resched();
+ kfree(zn->zbranch[n].znode);
+ }
+
+ if (zn == znode) {
+ if (!ubifs_zn_dirty(zn))
+ clean_freed += 1;
+ kfree(zn);
+ return clean_freed;
+ }
+
+ zn = ubifs_tnc_postorder_next(zn);
+ }
+}
+
+/**
* read_znode - read an indexing node from flash and fill znode.
* @c: UBIFS file-system description object
* @lnum: LEB of the indexing node to read
@@ -255,10 +286,10 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
lnum, offs, znode->level, znode->child_cnt);
if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
- dbg_err("current fanout %d, branch count %d",
- c->fanout, znode->child_cnt);
- dbg_err("max levels %d, znode level %d",
- UBIFS_MAX_LEVELS, znode->level);
+ ubifs_err("current fanout %d, branch count %d",
+ c->fanout, znode->child_cnt);
+ ubifs_err("max levels %d, znode level %d",
+ UBIFS_MAX_LEVELS, znode->level);
err = 1;
goto out_dump;
}
@@ -278,7 +309,7 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
if (zbr->lnum < c->main_first ||
zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
- dbg_err("bad branch %d", i);
+ ubifs_err("bad branch %d", i);
err = 2;
goto out_dump;
}
@@ -290,8 +321,8 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
case UBIFS_XENT_KEY:
break;
default:
- dbg_msg("bad key type at slot %d: %s", i,
- DBGKEY(&zbr->key));
+ ubifs_err("bad key type at slot %d: %d",
+ i, key_type(c, &zbr->key));
err = 3;
goto out_dump;
}
@@ -302,19 +333,19 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
type = key_type(c, &zbr->key);
if (c->ranges[type].max_len == 0) {
if (zbr->len != c->ranges[type].len) {
- dbg_err("bad target node (type %d) length (%d)",
- type, zbr->len);
- dbg_err("have to be %d", c->ranges[type].len);
+ ubifs_err("bad target node (type %d) length (%d)",
+ type, zbr->len);
+ ubifs_err("have to be %d", c->ranges[type].len);
err = 4;
goto out_dump;
}
} else if (zbr->len < c->ranges[type].min_len ||
zbr->len > c->ranges[type].max_len) {
- dbg_err("bad target node (type %d) length (%d)",
- type, zbr->len);
- dbg_err("have to be in range of %d-%d",
- c->ranges[type].min_len,
- c->ranges[type].max_len);
+ ubifs_err("bad target node (type %d) length (%d)",
+ type, zbr->len);
+ ubifs_err("have to be in range of %d-%d",
+ c->ranges[type].min_len,
+ c->ranges[type].max_len);
err = 5;
goto out_dump;
}
@@ -332,13 +363,13 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
cmp = keys_cmp(c, key1, key2);
if (cmp > 0) {
- dbg_err("bad key order (keys %d and %d)", i, i + 1);
+ ubifs_err("bad key order (keys %d and %d)", i, i + 1);
err = 6;
goto out_dump;
} else if (cmp == 0 && !is_hash_key(c, key1)) {
/* These can only be keys with colliding hash */
- dbg_err("keys %d and %d are not hashed but equivalent",
- i, i + 1);
+ ubifs_err("keys %d and %d are not hashed but equivalent",
+ i, i + 1);
err = 7;
goto out_dump;
}
@@ -349,7 +380,7 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
out_dump:
ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
- dbg_dump_node(c, idx);
+ ubifs_dump_node(c, idx);
kfree(idx);
return -EINVAL;
}
@@ -385,6 +416,16 @@ struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
if (err)
goto out;
+ atomic_long_inc(&c->clean_zn_cnt);
+
+ /*
+ * Increment the global clean znode counter as well. It is OK that
+ * global and per-FS clean znode counters may be inconsistent for some
+ * short time (because we might be preempted at this point), the global
+ * one is only used in shrinker.
+ */
+ atomic_long_inc(&ubifs_clean_zn_cnt);
+
zbr->znode = znode;
znode->parent = parent;
znode->time = get_seconds();
@@ -412,11 +453,22 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
{
union ubifs_key key1, *key = &zbr->key;
int err, type = key_type(c, key);
+ struct ubifs_wbuf *wbuf;
- err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum, zbr->offs);
+ /*
+ * 'zbr' has to point to on-flash node. The node may sit in a bud and
+ * may even be in a write buffer, so we have to take care about this.
+ */
+ wbuf = ubifs_get_wbuf(c, zbr->lnum);
+ if (wbuf)
+ err = ubifs_read_node_wbuf(wbuf, node, type, zbr->len,
+ zbr->lnum, zbr->offs);
+ else
+ err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum,
+ zbr->offs);
if (err) {
- dbg_tnc("key %s", DBGKEY(key));
+ dbg_tnck(key, "key ");
return err;
}
@@ -425,9 +477,9 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
if (!keys_eq(c, key, &key1)) {
ubifs_err("bad key in node at LEB %d:%d",
zbr->lnum, zbr->offs);
- dbg_tnc("looked for key %s found node's key %s",
- DBGKEY(key), DBGKEY1(&key1));
- dbg_dump_node(c, node);
+ dbg_tnck(key, "looked for key ");
+ dbg_tnck(&key1, "but found node's key ");
+ ubifs_dump_node(c, node);
return -EINVAL;
}
OpenPOWER on IntegriCloud