Commit 59a7ac12 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6

* 'linux-next' of git://git.infradead.org/ubifs-2.6: (32 commits)
  MAINTAINERS: change e-mail of Adrian Hunter
  UBIFS: fix master node recovery
  UBIFS: improve power cut emulation testing
  UBIFS: rename recovery testing variables
  UBIFS: remove custom list of superblocks
  UBIFS: stop re-defining UBI operations
  UBIFS: switch to I/O helpers
  UBIFS: switch to ubifs_leb_write
  UBIFS: switch to ubifs_leb_read
  UBIFS: introduce more I/O helpers
  UBIFS: always print stacktrace when switching to R/O mode
  UBIFS: remove unused and unneeded debugging function
  UBIFS: add global debugfs knobs
  UBIFS: introduce debugfs helpers
  UBIFS: re-arrange debugging code a bit
  UBIFS: be more informative in failure mode
  UBIFS: switch self-check knobs to debugfs
  UBIFS: lessen amount of debugging check types
  UBIFS: introduce helper functions for debugging checks and tests
  UBIFS: amend debugging inode size check function prototype
  ...
parents f99b7880 cc8f9b99
......@@ -111,34 +111,6 @@ The following is an example of the kernel boot arguments to attach mtd0
to UBI and mount volume "rootfs":
ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs
Module Parameters for Debugging
===============================
When UBIFS has been compiled with debugging enabled, there are 2 module
parameters that are available to control aspects of testing and debugging.
debug_chks Selects extra checks that UBIFS can do while running:
Check Flag value
General checks 1
Check Tree Node Cache (TNC) 2
Check indexing tree size 4
Check orphan area 8
Check old indexing tree 16
Check LEB properties (lprops) 32
Check leaf nodes and inodes 64
debug_tsts Selects a mode of testing, as follows:
Test mode Flag value
Failure mode for recovery testing 4
For example, set debug_chks to 3 to enable general and TNC checks.
References
==========
......
List of maintainers and how to submit kernel changes
Please try to follow the guidelines below. This will make things
......@@ -6321,7 +6322,7 @@ F: drivers/scsi/u14-34f.c
UBI FILE SYSTEM (UBIFS)
M: Artem Bityutskiy <dedekind1@gmail.com>
M: Adrian Hunter <adrian.hunter@nokia.com>
M: Adrian Hunter <adrian.hunter@intel.com>
L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubifs-2.6.git
W: http://www.linux-mtd.infradead.org/doc/ubifs.html
......
......@@ -78,7 +78,7 @@ static int nothing_to_commit(struct ubifs_info *c)
* If the root TNC node is dirty, we definitely have something to
* commit.
*/
if (c->zroot.znode && test_bit(DIRTY_ZNODE, &c->zroot.znode->flags))
if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
return 0;
/*
......@@ -418,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c)
spin_lock(&c->cs_lock);
if (c->cmt_state == COMMIT_BROKEN) {
err = -EINVAL;
err = -EROFS;
goto out;
}
......@@ -444,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c)
* re-check it.
*/
if (c->cmt_state == COMMIT_BROKEN) {
err = -EINVAL;
err = -EROFS;
goto out_cmt_unlock;
}
......@@ -576,7 +576,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
struct idx_node *i;
size_t sz;
if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX))
if (!dbg_is_chk_index(c))
return 0;
INIT_LIST_HEAD(&list);
......
......@@ -27,13 +27,12 @@
* various local functions of those subsystems.
*/
#define UBIFS_DBG_PRESERVE_UBI
#include "ubifs.h"
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/debugfs.h>
#include <linux/math64.h>
#include <linux/uaccess.h>
#include <linux/random.h>
#include "ubifs.h"
#ifdef CONFIG_UBIFS_FS_DEBUG
......@@ -42,15 +41,6 @@ DEFINE_SPINLOCK(dbg_lock);
static char dbg_key_buf0[128];
static char dbg_key_buf1[128];
unsigned int ubifs_chk_flags;
unsigned int ubifs_tst_flags;
module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug_chks, "Debug check flags");
MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
static const char *get_key_fmt(int fmt)
{
switch (fmt) {
......@@ -91,6 +81,28 @@ static const char *get_key_type(int type)
}
}
static const char *get_dent_type(int type)
{
switch (type) {
case UBIFS_ITYPE_REG:
return "file";
case UBIFS_ITYPE_DIR:
return "dir";
case UBIFS_ITYPE_LNK:
return "symlink";
case UBIFS_ITYPE_BLK:
return "blkdev";
case UBIFS_ITYPE_CHR:
return "char dev";
case UBIFS_ITYPE_FIFO:
return "fifo";
case UBIFS_ITYPE_SOCK:
return "socket";
default:
return "unknown/invalid type";
}
}
static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
char *buffer)
{
......@@ -234,9 +246,13 @@ static void dump_ch(const struct ubifs_ch *ch)
printk(KERN_DEBUG "\tlen %u\n", le32_to_cpu(ch->len));
}
void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode)
void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
{
const struct ubifs_inode *ui = ubifs_inode(inode);
struct qstr nm = { .name = NULL };
union ubifs_key key;
struct ubifs_dent_node *dent, *pdent = NULL;
int count = 2;
printk(KERN_DEBUG "Dump in-memory inode:");
printk(KERN_DEBUG "\tinode %lu\n", inode->i_ino);
......@@ -270,6 +286,32 @@ void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode)
printk(KERN_DEBUG "\tlast_page_read %lu\n", ui->last_page_read);
printk(KERN_DEBUG "\tread_in_a_row %lu\n", ui->read_in_a_row);
printk(KERN_DEBUG "\tdata_len %d\n", ui->data_len);
if (!S_ISDIR(inode->i_mode))
return;
printk(KERN_DEBUG "List of directory entries:\n");
ubifs_assert(!mutex_is_locked(&c->tnc_mutex));
lowest_dent_key(c, &key, inode->i_ino);
while (1) {
dent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(dent)) {
if (PTR_ERR(dent) != -ENOENT)
printk(KERN_DEBUG "error %ld\n", PTR_ERR(dent));
break;
}
printk(KERN_DEBUG "\t%d: %s (%s)\n",
count++, dent->name, get_dent_type(dent->type));
nm.name = dent->name;
nm.len = le16_to_cpu(dent->nlen);
kfree(pdent);
pdent = dent;
key_read(c, &dent->key, &key);
}
kfree(pdent);
}
void dbg_dump_node(const struct ubifs_info *c, const void *node)
......@@ -278,7 +320,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
union ubifs_key key;
const struct ubifs_ch *ch = node;
if (dbg_failure_mode)
if (dbg_is_tst_rcvry(c))
return;
/* If the magic is incorrect, just hexdump the first bytes */
......@@ -834,7 +876,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
struct ubifs_scan_node *snod;
void *buf;
if (dbg_failure_mode)
if (dbg_is_tst_rcvry(c))
return;
printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
......@@ -1080,6 +1122,7 @@ int dbg_check_space_info(struct ubifs_info *c)
/**
* dbg_check_synced_i_size - check synchronized inode size.
* @c: UBIFS file-system description object
* @inode: inode to check
*
* If inode is clean, synchronized inode size has to be equivalent to current
......@@ -1087,12 +1130,12 @@ int dbg_check_space_info(struct ubifs_info *c)
* has to be locked). Returns %0 if synchronized inode size if correct, and
* %-EINVAL if not.
*/
int dbg_check_synced_i_size(struct inode *inode)
int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode)
{
int err = 0;
struct ubifs_inode *ui = ubifs_inode(inode);
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
if (!S_ISREG(inode->i_mode))
return 0;
......@@ -1125,7 +1168,7 @@ int dbg_check_synced_i_size(struct inode *inode)
* Note, it is good idea to make sure the @dir->i_mutex is locked before
* calling this function.
*/
int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
{
unsigned int nlink = 2;
union ubifs_key key;
......@@ -1133,7 +1176,7 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
struct qstr nm = { .name = NULL };
loff_t size = UBIFS_INO_NODE_SZ;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
if (!S_ISDIR(dir->i_mode))
......@@ -1167,12 +1210,14 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
"but calculated size is %llu", dir->i_ino,
(unsigned long long)i_size_read(dir),
(unsigned long long)size);
dbg_dump_inode(c, dir);
dump_stack();
return -EINVAL;
}
if (dir->i_nlink != nlink) {
ubifs_err("directory inode %lu has nlink %u, but calculated "
"nlink is %u", dir->i_ino, dir->i_nlink, nlink);
dbg_dump_inode(c, dir);
dump_stack();
return -EINVAL;
}
......@@ -1489,7 +1534,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra)
long clean_cnt = 0, dirty_cnt = 0;
int err, last;
if (!(ubifs_chk_flags & UBIFS_CHK_TNC))
if (!dbg_is_chk_index(c))
return 0;
ubifs_assert(mutex_is_locked(&c->tnc_mutex));
......@@ -1736,7 +1781,7 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
int err;
long long calc = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ))
if (!dbg_is_chk_index(c))
return 0;
err = dbg_walk_index(c, NULL, add_size, &calc);
......@@ -2312,7 +2357,7 @@ int dbg_check_filesystem(struct ubifs_info *c)
int err;
struct fsck_data fsckd;
if (!(ubifs_chk_flags & UBIFS_CHK_FS))
if (!dbg_is_chk_fs(c))
return 0;
fsckd.inodes = RB_ROOT;
......@@ -2347,7 +2392,7 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
struct list_head *cur;
struct ubifs_scan_node *sa, *sb;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
for (cur = head->next; cur->next != head; cur = cur->next) {
......@@ -2414,7 +2459,7 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
struct list_head *cur;
struct ubifs_scan_node *sa, *sb;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
for (cur = head->next; cur->next != head; cur = cur->next) {
......@@ -2491,214 +2536,141 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
return 0;
}
int dbg_force_in_the_gaps(void)
static inline int chance(unsigned int n, unsigned int out_of)
{
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
return 0;
return !!((random32() % out_of) + 1 <= n);
return !(random32() & 7);
}
/* Failure mode for recovery testing */
#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d))
struct failure_mode_info {
struct list_head list;
struct ubifs_info *c;
};
static LIST_HEAD(fmi_list);
static DEFINE_SPINLOCK(fmi_lock);
static unsigned int next;
static int simple_rand(void)
{
if (next == 0)
next = current->pid;
next = next * 1103515245 + 12345;
return (next >> 16) & 32767;
}
static void failure_mode_init(struct ubifs_info *c)
{
struct failure_mode_info *fmi;
fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
if (!fmi) {
ubifs_err("Failed to register failure mode - no memory");
return;
}
fmi->c = c;
spin_lock(&fmi_lock);
list_add_tail(&fmi->list, &fmi_list);
spin_unlock(&fmi_lock);
}
static void failure_mode_exit(struct ubifs_info *c)
static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
{
struct failure_mode_info *fmi, *tmp;
spin_lock(&fmi_lock);
list_for_each_entry_safe(fmi, tmp, &fmi_list, list)
if (fmi->c == c) {
list_del(&fmi->list);
kfree(fmi);
}
spin_unlock(&fmi_lock);
}
static struct ubifs_info *dbg_find_info(struct ubi_volume_desc *desc)
{
struct failure_mode_info *fmi;
spin_lock(&fmi_lock);
list_for_each_entry(fmi, &fmi_list, list)
if (fmi->c->ubi == desc) {
struct ubifs_info *c = fmi->c;
spin_unlock(&fmi_lock);
return c;
}
spin_unlock(&fmi_lock);
return NULL;
}
static int in_failure_mode(struct ubi_volume_desc *desc)
{
struct ubifs_info *c = dbg_find_info(desc);
if (c && dbg_failure_mode)
return c->dbg->failure_mode;
return 0;
}
struct ubifs_debug_info *d = c->dbg;
static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
{
struct ubifs_info *c = dbg_find_info(desc);
struct ubifs_debug_info *d;
ubifs_assert(dbg_is_tst_rcvry(c));
if (!c || !dbg_failure_mode)
return 0;
d = c->dbg;
if (d->failure_mode)
return 1;
if (!d->fail_cnt) {
/* First call - decide delay to failure */
if (!d->pc_cnt) {
/* First call - decide delay to the power cut */
if (chance(1, 2)) {
unsigned int delay = 1 << (simple_rand() >> 11);
unsigned long delay;
if (chance(1, 2)) {
d->fail_delay = 1;
d->fail_timeout = jiffies +
msecs_to_jiffies(delay);
dbg_rcvry("failing after %ums", delay);
d->pc_delay = 1;
/* Fail withing 1 minute */
delay = random32() % 60000;
d->pc_timeout = jiffies;
d->pc_timeout += msecs_to_jiffies(delay);
ubifs_warn("failing after %lums", delay);
} else {
d->fail_delay = 2;
d->fail_cnt_max = delay;
dbg_rcvry("failing after %u calls", delay);
d->pc_delay = 2;
delay = random32() % 10000;
/* Fail within 10000 operations */
d->pc_cnt_max = delay;
ubifs_warn("failing after %lu calls", delay);
}
}
d->fail_cnt += 1;
d->pc_cnt += 1;
}
/* Determine if failure delay has expired */
if (d->fail_delay == 1) {
if (time_before(jiffies, d->fail_timeout))
if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout))
return 0;
} else if (d->fail_delay == 2)
if (d->fail_cnt++ < d->fail_cnt_max)
if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max)
return 0;
if (lnum == UBIFS_SB_LNUM) {
if (write) {
if (chance(1, 2))
return 0;
} else if (chance(19, 20))
if (write && chance(1, 2))
return 0;
if (chance(19, 20))
return 0;
dbg_rcvry("failing in super block LEB %d", lnum);
ubifs_warn("failing in super block LEB %d", lnum);
} else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
if (chance(19, 20))
return 0;
dbg_rcvry("failing in master LEB %d", lnum);
ubifs_warn("failing in master LEB %d", lnum);
} else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
if (write) {
if (chance(99, 100))
return 0;
} else if (chance(399, 400))
if (write && chance(99, 100))
return 0;
dbg_rcvry("failing in log LEB %d", lnum);
if (chance(399, 400))
return 0;
ubifs_warn("failing in log LEB %d", lnum);
} else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
if (write) {
if (chance(7, 8))
return 0;
} else if (chance(19, 20))
if (write && chance(7, 8))
return 0;
dbg_rcvry("failing in LPT LEB %d", lnum);
if (chance(19, 20))
return 0;
ubifs_warn("failing in LPT LEB %d", lnum);
} else if (lnum >= c->orph_first && lnum <= c->orph_last) {
if (write) {
if (chance(1, 2))
return 0;
} else if (chance(9, 10))
if (write && chance(1, 2))
return 0;
if (chance(9, 10))
return 0;
dbg_rcvry("failing in orphan LEB %d", lnum);
ubifs_warn("failing in orphan LEB %d", lnum);
} else if (lnum == c->ihead_lnum) {
if (chance(99, 100))
return 0;
dbg_rcvry("failing in index head LEB %d", lnum);
ubifs_warn("failing in index head LEB %d", lnum);
} else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
if (chance(9, 10))
return 0;
dbg_rcvry("failing in GC head LEB %d", lnum);
ubifs_warn("failing in GC head LEB %d", lnum);
} else if (write && !RB_EMPTY_ROOT(&c->buds) &&
!ubifs_search_bud(c, lnum)) {
if (chance(19, 20))
return 0;
dbg_rcvry("failing in non-bud LEB %d", lnum);
ubifs_warn("failing in non-bud LEB %d", lnum);
} else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND ||
c->cmt_state == COMMIT_RUNNING_REQUIRED) {
if (chance(999, 1000))
return 0;
dbg_rcvry("failing in bud LEB %d commit running", lnum);
ubifs_warn("failing in bud LEB %d commit running", lnum);
} else {
if (chance(9999, 10000))
return 0;
dbg_rcvry("failing in bud LEB %d commit not running", lnum);
ubifs_warn("failing in bud LEB %d commit not running", lnum);
}
ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum);
d->failure_mode = 1;
d->pc_happened = 1;
ubifs_warn("========== Power cut emulated ==========");
dump_stack();
return 1;
}
static void cut_data(const void *buf, int len)
static void cut_data(const void *buf, unsigned int len)
{
int flen, i;
unsigned int from, to, i, ffs = chance(1, 2);
unsigned char *p = (void *)buf;
flen = (len * (long long)simple_rand()) >> 15;
for (i = flen; i < len; i++)
p[i] = 0xff;
}
from = random32() % (len + 1);
if (chance(1, 2))
to = random32() % (len - from + 1);
else
to = len;
int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
int len, int check)
{
if (in_failure_mode(desc))
return -EROFS;
return ubi_leb_read(desc, lnum, buf, offset, len, check);
if (from < to)
ubifs_warn("filled bytes %u-%u with %s", from, to - 1,
ffs ? "0xFFs" : "random data");
if (ffs)
for (i = from; i < to; i++)
p[i] = 0xFF;
else
for (i = from; i < to; i++)
p[i] = random32() % 0x100;
}
int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
int offset, int len, int dtype)
int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
int offs, int len, int dtype)
{
int err, failing;
if (in_failure_mode(desc))
if (c->dbg->pc_happened)
return -EROFS;
failing = do_fail(desc, lnum, 1);
failing = power_cut_emulated(c, lnum, 1);
if (failing)
cut_data(buf, len);
err = ubi_leb_write(desc, lnum, buf, offset, len, dtype);
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
if (err)
return err;
if (failing)
......@@ -2706,162 +2678,207 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
return 0;
}
int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
int len, int dtype)
{
int err;
if (do_fail(desc, lnum, 1))
if (c->dbg->pc_happened)
return -EROFS;
err = ubi_leb_change(desc, lnum, buf, len, dtype);
if (power_cut_emulated(c, lnum, 1))
return -EROFS;
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
if (err)
return err;
if (do_fail(desc, lnum, 1))
if (power_cut_emulated(c, lnum, 1))
return -EROFS;
return 0;
}
int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum)
int dbg_leb_unmap(struct ubifs_info *c, int lnum)
{
int err;
if (do_fail(desc, lnum, 0))
if (c->dbg->pc_happened)
return -EROFS;
if (power_cut_emulated(c, lnum, 0))
return -EROFS;
err = ubi_leb_erase(desc, lnum);
err = ubi_leb_unmap(c->ubi, lnum);
if (err)
return err;
if (do_fail(desc, lnum, 0))
if (power_cut_emulated(c, lnum, 0))
return -EROFS;
return 0;
}
int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)
int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype)
{
int err;
if (do_fail(desc, lnum, 0))
if (c->dbg->pc_happened)
return -EROFS;
err = ubi_leb_unmap(desc, lnum);
if (power_cut_emulated(c, lnum, 0))
return -EROFS;
err = ubi_leb_map(c->ubi, lnum, dtype);
if (err)
return err;
if (do_fail(desc, lnum, 0))
if (power_cut_emulated(c, lnum, 0))
return -EROFS;
return 0;
}
int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum)
{
if (in_failure_mode(desc))
return -EROFS;
return ubi_is_mapped(desc, lnum);
}
/*
* Root directory for UBIFS stuff in debugfs. Contains sub-directories which
* contain the stuff specific to particular file-system mounts.
*/
static struct dentry *dfs_rootdir;
int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
static int dfs_file_open(struct inode *inode, struct file *file)
{
int err;
if (do_fail(desc, lnum, 0))
return -EROFS;
err = ubi_leb_map(desc, lnum, dtype);
if (err)
return err;
if (do_fail(desc, lnum, 0))
return -EROFS;
return 0;
file->private_data = inode->i_private;
return nonseekable_open(inode, file);
}
/**
* ubifs_debugging_init - initialize UBIFS debugging.
* @c: UBIFS file-system description object
* provide_user_output - provide output to the user reading a debugfs file.
* @val: boolean value for the answer
* @u: the buffer to store the answer at
* @count: size of the buffer
* @ppos: position in the @u output buffer
*
* This function initializes debugging-related data for the file system.
* Returns zero in case of success and a negative error code in case of
* This is a simple helper function which stores @val boolean value in the user
* buffer when the user reads one of UBIFS debugfs files. Returns amount of
* bytes written to @u in case of success and a negative error code in case of
* failure.
*/
int ubifs_debugging_init(struct ubifs_info *c)
static int provide_user_output(int val, char __user *u, size_t count,
loff_t *ppos)
{
c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
if (!c->dbg)
return -ENOMEM;
char buf[3];
failure_mode_init(c);
return 0;
if (val)
buf[0] = '1';
else
buf[0] = '0';
buf[1] = '\n';
buf[2] = 0x00;
return simple_read_from_buffer(u, count, ppos, buf, 2);
}
/**
* ubifs_debugging_exit - free debugging data.
* @c: UBIFS file-system description object
*/
void ubifs_debugging_exit(struct ubifs_info *c)
static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count,
loff_t *ppos)
{
failure_mode_exit(c);
kfree(c->dbg);
}
struct dentry *dent = file->f_path.dentry;
struct ubifs_info *c = file->private_data;
struct ubifs_debug_info *d = c->dbg;
int val;
if (dent == d->dfs_chk_gen)
val = d->chk_gen;
else if (dent == d->dfs_chk_index)
val = d->chk_index;
else if (dent == d->dfs_chk_orph)
val = d->chk_orph;
else if (dent == d->dfs_chk_lprops)
val = d->chk_lprops;
else if (dent == d->dfs_chk_fs)
val = d->chk_fs;
else if (dent == d->dfs_tst_rcvry)
val = d->tst_rcvry;
else
return -EINVAL;
/*
* Root directory for UBIFS stuff in debugfs. Contains sub-directories which
* contain the stuff specific to particular file-system mounts.
*/
static struct dentry *dfs_rootdir;
return provide_user_output(val, u, count, ppos);
}
/**
* dbg_debugfs_init - initialize debugfs file-system.
* interpret_user_input - interpret user debugfs file input.
* @u: user-provided buffer with the input
* @count: buffer size
*
* UBIFS uses debugfs file-system to expose various debugging knobs to
* user-space. This function creates "ubifs" directory in the debugfs
* file-system. Returns zero in case of success and a negative error code in
* case of failure.
* This is a helper function which interpret user input to a boolean UBIFS
* debugfs file. Returns %0 or %1 in case of success and a negative error code
* in case of failure.
*/
int dbg_debugfs_init(void)
static int interpret_user_input(const char __user *u, size_t count)
{
dfs_rootdir = debugfs_create_dir("ubifs", NULL);
if (IS_ERR(dfs_rootdir)) {
int err = PTR_ERR(dfs_rootdir);
ubifs_err("cannot create \"ubifs\" debugfs directory, "
"error %d\n", err);
return err;
}
size_t buf_size;
char buf[8];
return 0;
}
buf_size = min_t(size_t, count, (sizeof(buf) - 1));
if (copy_from_user(buf, u, buf_size))
return -EFAULT;
/**
* dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
*/
void dbg_debugfs_exit(void)
{
debugfs_remove(dfs_rootdir);
}
if (buf[0] == '1')
return 1;
else if (buf[0] == '0')
return 0;
static int open_debugfs_file(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return nonseekable_open(inode, file);
return -EINVAL;
}
static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
static ssize_t dfs_file_write(struct file *file, const char __user *u,
size_t count, loff_t *ppos)
{
struct ubifs_info *c = file->private_data;
struct ubifs_debug_info *d = c->dbg;
struct dentry *dent = file->f_path.dentry;
int val;
if (file->f_path.dentry == d->dfs_dump_lprops)
/*
* TODO: this is racy - the file-system might have already been
* unmounted and we'd oops in this case. The plan is to fix it with
* help of 'iterate_supers_type()' which we should have in v3.0: when
* a debugfs opened, we rember FS's UUID in file->private_data. Then
* whenever we access the FS via a debugfs file, we iterate all UBIFS
* superblocks and fine the one with the same UUID, and take the
* locking right.
*
* The other way to go suggested by Al Viro is to create a separate
* 'ubifs-debug' file-system instead.
*/
if (file->f_path.dentry == d->dfs_dump_lprops) {
dbg_dump_lprops(c);
else if (file->f_path.dentry == d->dfs_dump_budg)
return count;
}
if (file->f_path.dentry == d->dfs_dump_budg) {
dbg_dump_budg(c, &c->bi);
else if (file->f_path.dentry == d->dfs_dump_tnc) {
return count;
}
if (file->f_path.dentry == d->dfs_dump_tnc) {
mutex_lock(&c->tnc_mutex);
dbg_dump_tnc(c);
mutex_unlock(&c->tnc_mutex);
} else
return count;
}
val = interpret_user_input(u, count);
if (val < 0)
return val;
if (dent == d->dfs_chk_gen)
d->chk_gen = val;
else if (dent == d->dfs_chk_index)
d->chk_index = val;
else if (dent == d->dfs_chk_orph)
d->chk_orph = val;
else if (dent == d->dfs_chk_lprops)
d->chk_lprops = val;
else if (dent == d->dfs_chk_fs)
d->chk_fs = val;
else if (dent == d->dfs_tst_rcvry)
d->tst_rcvry = val;
else
return -EINVAL;
return count;
}
static const struct file_operations dfs_fops = {
.open = open_debugfs_file,
.write = write_debugfs_file,
.open = dfs_file_open,
.read = dfs_file_read,
.write = dfs_file_write,
.owner = THIS_MODULE,
.llseek = no_llseek,
};
......@@ -2880,12 +2897,20 @@ static const struct file_operations dfs_fops = {
*/
int dbg_debugfs_init_fs(struct ubifs_info *c)
{
int err;
int err, n;
const char *fname;
struct dentry *dent;
struct ubifs_debug_info *d = c->dbg;
sprintf(d->dfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
c->vi.ubi_num, c->vi.vol_id);
if (n == UBIFS_DFS_DIR_LEN) {
/* The array size is too small */
fname = UBIFS_DFS_DIR_NAME;
dent = ERR_PTR(-EINVAL);
goto out;
}
fname = d->dfs_dir_name;
dent = debugfs_create_dir(fname, dfs_rootdir);
if (IS_ERR_OR_NULL(dent))
......@@ -2910,13 +2935,55 @@ int dbg_debugfs_init_fs(struct ubifs_info *c)
goto out_remove;
d->dfs_dump_tnc = dent;
fname = "chk_general";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
&dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
d->dfs_chk_gen = dent;
fname = "chk_index";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
&dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
d->dfs_chk_index = dent;
fname = "chk_orphans";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
&dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
d->dfs_chk_orph = dent;
fname = "chk_lprops";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
&dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
d->dfs_chk_lprops = dent;
fname = "chk_fs";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
&dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
d->dfs_chk_fs = dent;
fname = "tst_recovery";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
&dfs_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
d->dfs_tst_rcvry = dent;
return 0;
out_remove:
debugfs_remove_recursive(d->dfs_dir);
out:
err = dent ? PTR_ERR(dent) : -ENODEV;
ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
fname, err);
return err;
}
......@@ -2930,4 +2997,179 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c)
debugfs_remove_recursive(c->dbg->dfs_dir);
}
struct ubifs_global_debug_info ubifs_dbg;
static struct dentry *dfs_chk_gen;
static struct dentry *dfs_chk_index;
static struct dentry *dfs_chk_orph;
static struct dentry *dfs_chk_lprops;
static struct dentry *dfs_chk_fs;
static struct dentry *dfs_tst_rcvry;
static ssize_t dfs_global_file_read(struct file *file, char __user *u,
size_t count, loff_t *ppos)
{
struct dentry *dent = file->f_path.dentry;
int val;
if (dent == dfs_chk_gen)
val = ubifs_dbg.chk_gen;
else if (dent == dfs_chk_index)
val = ubifs_dbg.chk_index;
else if (dent == dfs_chk_orph)
val = ubifs_dbg.chk_orph;
else if (dent == dfs_chk_lprops)
val = ubifs_dbg.chk_lprops;
else if (dent == dfs_chk_fs)
val = ubifs_dbg.chk_fs;
else if (dent == dfs_tst_rcvry)
val = ubifs_dbg.tst_rcvry;
else
return -EINVAL;
return provide_user_output(val, u, count, ppos);
}
static ssize_t dfs_global_file_write(struct file *file, const char __user *u,
size_t count, loff_t *ppos)
{
struct dentry *dent = file->f_path.dentry;
int val;
val = interpret_user_input(u, count);
if (val < 0)
return val;
if (dent == dfs_chk_gen)
ubifs_dbg.chk_gen = val;
else if (dent == dfs_chk_index)
ubifs_dbg.chk_index = val;
else if (dent == dfs_chk_orph)
ubifs_dbg.chk_orph = val;
else if (dent == dfs_chk_lprops)
ubifs_dbg.chk_lprops = val;
else if (dent == dfs_chk_fs)
ubifs_dbg.chk_fs = val;
else if (dent == dfs_tst_rcvry)
ubifs_dbg.tst_rcvry = val;
else
return -EINVAL;
return count;
}
static const struct file_operations dfs_global_fops = {
.read = dfs_global_file_read,
.write = dfs_global_file_write,
.owner = THIS_MODULE,
.llseek = no_llseek,
};
/**
* dbg_debugfs_init - initialize debugfs file-system.
*
* UBIFS uses debugfs file-system to expose various debugging knobs to
* user-space. This function creates "ubifs" directory in the debugfs
* file-system. Returns zero in case of success and a negative error code in
* case of failure.
*/
int dbg_debugfs_init(void)
{
int err;
const char *fname;
struct dentry *dent;
fname = "ubifs";
dent = debugfs_create_dir(fname, NULL);
if (IS_ERR_OR_NULL(dent))
goto out;
dfs_rootdir = dent;
fname = "chk_general";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
&dfs_global_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
dfs_chk_gen = dent;
fname = "chk_index";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
&dfs_global_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
dfs_chk_index = dent;
fname = "chk_orphans";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
&dfs_global_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
dfs_chk_orph = dent;
fname = "chk_lprops";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
&dfs_global_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
dfs_chk_lprops = dent;
fname = "chk_fs";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
&dfs_global_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
dfs_chk_fs = dent;
fname = "tst_recovery";
dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
&dfs_global_fops);
if (IS_ERR_OR_NULL(dent))
goto out_remove;
dfs_tst_rcvry = dent;
return 0;
out_remove:
debugfs_remove_recursive(dfs_rootdir);
out:
err = dent ? PTR_ERR(dent) : -ENODEV;
ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
fname, err);
return err;
}
/**
* dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
*/
void dbg_debugfs_exit(void)
{
debugfs_remove_recursive(dfs_rootdir);
}
/**
* ubifs_debugging_init - initialize UBIFS debugging.
* @c: UBIFS file-system description object
*
* This function initializes debugging-related data for the file system.
* Returns zero in case of success and a negative error code in case of
* failure.
*/
int ubifs_debugging_init(struct ubifs_info *c)
{
c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
if (!c->dbg)
return -ENOMEM;
return 0;
}
/**
* ubifs_debugging_exit - free debugging data.
* @c: UBIFS file-system description object
*/
void ubifs_debugging_exit(struct ubifs_info *c)
{
kfree(c->dbg);
}
#endif /* CONFIG_UBIFS_FS_DEBUG */
......@@ -31,18 +31,25 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
#ifdef CONFIG_UBIFS_FS_DEBUG
#include <linux/random.h>
/*
* The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi"
* + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
*/
#define UBIFS_DFS_DIR_NAME "ubi%d_%d"
#define UBIFS_DFS_DIR_LEN (3 + 1 + 2*2 + 1)
/**
* ubifs_debug_info - per-FS debugging information.
* @old_zroot: old index root - used by 'dbg_check_old_index()'
* @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
* @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
* @failure_mode: failure mode for recovery testing
* @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
* @fail_timeout: time in jiffies when delay of failure mode expires
* @fail_cnt: current number of calls to failure mode I/O functions
* @fail_cnt_max: number of calls by which to delay failure mode
*
* @pc_happened: non-zero if an emulated power cut happened
* @pc_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
* @pc_timeout: time in jiffies when delay of failure mode expires
* @pc_cnt: current number of calls to failure mode I/O functions
* @pc_cnt_max: number of calls by which to delay failure mode
*
* @chk_lpt_sz: used by LPT tree size checker
* @chk_lpt_sz2: used by LPT tree size checker
* @chk_lpt_wastage: used by LPT tree size checker
......@@ -56,21 +63,36 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
* @saved_free: saved amount of free space
* @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt
*
* @chk_gen: if general extra checks are enabled
* @chk_index: if index xtra checks are enabled
* @chk_orph: if orphans extra checks are enabled
* @chk_lprops: if lprops extra checks are enabled
* @chk_fs: if UBIFS contents extra checks are enabled
* @tst_rcvry: if UBIFS recovery testing mode enabled
*
* @dfs_dir_name: name of debugfs directory containing this file-system's files
* @dfs_dir: direntry object of the file-system debugfs directory
* @dfs_dump_lprops: "dump lprops" debugfs knob
* @dfs_dump_budg: "dump budgeting information" debugfs knob
* @dfs_dump_tnc: "dump TNC" debugfs knob
* @dfs_chk_gen: debugfs knob to enable UBIFS general extra checks
* @dfs_chk_index: debugfs knob to enable UBIFS index extra checks
* @dfs_chk_orph: debugfs knob to enable UBIFS orphans extra checks
* @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks
* @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks
* @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing
*/
struct ubifs_debug_info {
struct ubifs_zbranch old_zroot;
int old_zroot_level;
unsigned long long old_zroot_sqnum;
int failure_mode;
int fail_delay;
unsigned long fail_timeout;
unsigned int fail_cnt;
unsigned int fail_cnt_max;
int pc_happened;
int pc_delay;
unsigned long pc_timeout;
unsigned int pc_cnt;
unsigned int pc_cnt_max;
long long chk_lpt_sz;
long long chk_lpt_sz2;
long long chk_lpt_wastage;
......@@ -84,11 +106,43 @@ struct ubifs_debug_info {
long long saved_free;
int saved_idx_gc_cnt;
char dfs_dir_name[100];
unsigned int chk_gen:1;
unsigned int chk_index:1;
unsigned int chk_orph:1;
unsigned int chk_lprops:1;
unsigned int chk_fs:1;
unsigned int tst_rcvry:1;
char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1];
struct dentry *dfs_dir;
struct dentry *dfs_dump_lprops;
struct dentry *dfs_dump_budg;
struct dentry *dfs_dump_tnc;
struct dentry *dfs_chk_gen;
struct dentry *dfs_chk_index;
struct dentry *dfs_chk_orph;
struct dentry *dfs_chk_lprops;
struct dentry *dfs_chk_fs;
struct dentry *dfs_tst_rcvry;
};
/**
* ubifs_global_debug_info - global (not per-FS) UBIFS debugging information.
*
* @chk_gen: if general extra checks are enabled
* @chk_index: if index xtra checks are enabled
* @chk_orph: if orphans extra checks are enabled
* @chk_lprops: if lprops extra checks are enabled
* @chk_fs: if UBIFS contents extra checks are enabled
* @tst_rcvry: if UBIFS recovery testing mode enabled
*/
struct ubifs_global_debug_info {
unsigned int chk_gen:1;
unsigned int chk_index:1;
unsigned int chk_orph:1;
unsigned int chk_lprops:1;
unsigned int chk_fs:1;
unsigned int tst_rcvry:1;
};
#define ubifs_assert(expr) do { \
......@@ -127,6 +181,8 @@ const char *dbg_key_str1(const struct ubifs_info *c,
#define DBGKEY(key) dbg_key_str0(c, (key))
#define DBGKEY1(key) dbg_key_str1(c, (key))
extern spinlock_t dbg_lock;
#define ubifs_dbg_msg(type, fmt, ...) do { \
spin_lock(&dbg_lock); \
pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
......@@ -162,41 +218,36 @@ const char *dbg_key_str1(const struct ubifs_info *c,
/* Additional recovery messages */
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
/*
* Debugging check flags.
*
* UBIFS_CHK_GEN: general checks
* UBIFS_CHK_TNC: check TNC
* UBIFS_CHK_IDX_SZ: check index size
* 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,
UBIFS_CHK_TNC = 0x2,
UBIFS_CHK_IDX_SZ = 0x4,
UBIFS_CHK_ORPH = 0x8,
UBIFS_CHK_OLD_IDX = 0x10,
UBIFS_CHK_LPROPS = 0x20,
UBIFS_CHK_FS = 0x40,
};
/*
* Special testing flags.
*
* UBIFS_TST_RCVRY: failure mode for recovery testing
*/
enum {
UBIFS_TST_RCVRY = 0x4,
};
extern spinlock_t dbg_lock;
extern struct ubifs_global_debug_info ubifs_dbg;
extern unsigned int ubifs_msg_flags;
extern unsigned int ubifs_chk_flags;
extern unsigned int ubifs_tst_flags;
static inline int dbg_is_chk_gen(const struct ubifs_info *c)
{
return !!(ubifs_dbg.chk_gen || c->dbg->chk_gen);
}
static inline int dbg_is_chk_index(const struct ubifs_info *c)
{
return !!(ubifs_dbg.chk_index || c->dbg->chk_index);
}
static inline int dbg_is_chk_orph(const struct ubifs_info *c)
{
return !!(ubifs_dbg.chk_orph || c->dbg->chk_orph);
}
static inline int dbg_is_chk_lprops(const struct ubifs_info *c)
{
return !!(ubifs_dbg.chk_lprops || c->dbg->chk_lprops);
}
static inline int dbg_is_chk_fs(const struct ubifs_info *c)
{
return !!(ubifs_dbg.chk_fs || c->dbg->chk_fs);
}
static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)
{
return !!(ubifs_dbg.tst_rcvry || c->dbg->tst_rcvry);
}
static inline int dbg_is_power_cut(const struct ubifs_info *c)
{
return !!c->dbg->pc_happened;
}
int ubifs_debugging_init(struct ubifs_info *c);
void ubifs_debugging_exit(struct ubifs_info *c);
......@@ -207,7 +258,7 @@ const char *dbg_cstate(int cmt_state);
const char *dbg_jhead(int jhead);
const char *dbg_get_key_dump(const struct ubifs_info *c,
const union ubifs_key *key);
void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode);
void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
void dbg_dump_node(const struct ubifs_info *c, const void *node);
void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
int offs);
......@@ -240,8 +291,8 @@ int dbg_check_cats(struct ubifs_info *c);
int dbg_check_ltab(struct ubifs_info *c);
int dbg_chk_lpt_free_spc(struct ubifs_info *c);
int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len);
int dbg_check_synced_i_size(struct inode *inode);
int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir);
int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode);
int dbg_check_dir(struct ubifs_info *c, const struct inode *dir);
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);
......@@ -254,54 +305,12 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
/* Force the use of in-the-gaps method for testing */
static inline int dbg_force_in_the_gaps_enabled(void)
{
return ubifs_chk_flags & UBIFS_CHK_GEN;
}
int dbg_force_in_the_gaps(void);
/* Failure mode for recovery testing */
#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
#ifndef UBIFS_DBG_PRESERVE_UBI
#define ubi_leb_read dbg_leb_read
#define ubi_leb_write dbg_leb_write
#define ubi_leb_change dbg_leb_change
#define ubi_leb_erase dbg_leb_erase
#define ubi_leb_unmap dbg_leb_unmap
#define ubi_is_mapped dbg_is_mapped
#define ubi_leb_map dbg_leb_map
#endif
int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
int len, int check);
int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
int offset, int len, int dtype);
int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
int len, int dtype);
int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum);
int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum);
int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum);
int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf,
int offset, int len)
{
return dbg_leb_read(desc, lnum, buf, offset, len, 0);
}
static inline int dbg_write(struct ubi_volume_desc *desc, int lnum,
const void *buf, int offset, int len)
{
return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
}
static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
const void *buf, int len)
{
return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
}
int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
int len, int dtype);
int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
int dtype);
int dbg_leb_unmap(struct ubifs_info *c, int lnum);
int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
/* Debugfs-related stuff */
int dbg_debugfs_init(void);
......@@ -313,7 +322,7 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
/* Use "if (0)" to make compiler check arguments even if debugging is off */
#define ubifs_assert(expr) do { \
if (0 && (expr)) \
if (0) \
printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
__func__, __LINE__, current->pid); \
} while (0)
......@@ -323,6 +332,9 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
ubifs_err(fmt, ##__VA_ARGS__); \
} while (0)
#define DBGKEY(key) ((char *)(key))
#define DBGKEY1(key) ((char *)(key))
#define ubifs_dbg_msg(fmt, ...) do { \
if (0) \
pr_debug(fmt "\n", ##__VA_ARGS__); \
......@@ -346,9 +358,6 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
#define dbg_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
#define DBGKEY(key) ((char *)(key))
#define DBGKEY1(key) ((char *)(key))
static inline int ubifs_debugging_init(struct ubifs_info *c) { return 0; }
static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; }
static inline const char *dbg_ntype(int type) { return ""; }
......@@ -357,7 +366,7 @@ static inline const char *dbg_jhead(int jhead) { return ""; }
static inline const char *
dbg_get_key_dump(const struct ubifs_info *c,
const union ubifs_key *key) { return ""; }
static inline void dbg_dump_inode(const struct ubifs_info *c,
static inline void dbg_dump_inode(struct ubifs_info *c,
const struct inode *inode) { return; }
static inline void dbg_dump_node(const struct ubifs_info *c,
const void *node) { return; }
......@@ -409,9 +418,11 @@ static inline int dbg_check_ltab(struct ubifs_info *c) { return 0; }
static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c) { return 0; }
static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
int action, int len) { return 0; }
static inline int dbg_check_synced_i_size(struct inode *inode) { return 0; }
static inline int dbg_check_dir_size(struct ubifs_info *c,
const struct inode *dir) { return 0; }
static inline int
dbg_check_synced_i_size(const struct ubifs_info *c,
struct inode *inode) { return 0; }
static inline int dbg_check_dir(struct ubifs_info *c,
const struct inode *dir) { return 0; }
static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; }
static inline int dbg_check_idx_size(struct ubifs_info *c,
long long idx_size) { return 0; }
......@@ -431,9 +442,23 @@ static inline int
dbg_check_nondata_nodes_order(struct ubifs_info *c,
struct list_head *head) { return 0; }
static inline int dbg_force_in_the_gaps(void) { return 0; }
#define dbg_force_in_the_gaps_enabled() 0
#define dbg_failure_mode 0
static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
const void *buf, int offset,
int len, int dtype) { return 0; }
static inline int dbg_leb_change(struct ubifs_info *c, int lnum,
const void *buf, int len,
int dtype) { return 0; }
static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum) { return 0; }
static inline int dbg_leb_map(struct ubifs_info *c, int lnum,
int dtype) { return 0; }
static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_chk_index(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_chk_orph(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_chk_lprops(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_chk_fs(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_power_cut(const struct ubifs_info *c) { return 0; }
static inline int dbg_debugfs_init(void) { return 0; }
static inline void dbg_debugfs_exit(void) { return; }
......
......@@ -102,7 +102,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
* UBIFS has to fully control "clean <-> dirty" transitions of inodes
* to make budgeting work.
*/
inode->i_flags |= (S_NOCMTIME);
inode->i_flags |= S_NOCMTIME;
inode_init_owner(inode, dir, mode);
inode->i_mtime = inode->i_atime = inode->i_ctime =
......@@ -172,9 +172,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
#ifdef CONFIG_UBIFS_FS_DEBUG
static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
static int dbg_check_name(const struct ubifs_info *c,
const struct ubifs_dent_node *dent,
const struct qstr *nm)
{
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
if (le16_to_cpu(dent->nlen) != nm->len)
return -EINVAL;
......@@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
#else
#define dbg_check_name(dent, nm) 0
#define dbg_check_name(c, dent, nm) 0
#endif
......@@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
goto out;
}
if (dbg_check_name(dent, &dentry->d_name)) {
if (dbg_check_name(c, dent, &dentry->d_name)) {
err = -EINVAL;
goto out;
}
......@@ -522,7 +524,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex));
err = dbg_check_synced_i_size(inode);
err = dbg_check_synced_i_size(c, inode);
if (err)
return err;
......@@ -577,7 +579,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
inode->i_nlink, dir->i_ino);
ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex));
err = dbg_check_synced_i_size(inode);
err = dbg_check_synced_i_size(c, inode);
if (err)
return err;
......
......@@ -1263,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
return err;
err = dbg_check_synced_i_size(inode);
err = dbg_check_synced_i_size(c, inode);
if (err)
return err;
......
......@@ -86,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
c->no_chk_data_crc = 0;
c->vfs_sb->s_flags |= MS_RDONLY;
ubifs_warn("switched to read-only mode, error %d", err);
dump_stack();
}
}
/*
* Below are simple wrappers over UBI I/O functions which include some
* additional checks and UBIFS debugging stuff. See corresponding UBI function
* for more information.
*/
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
int len, int even_ebadmsg)
{
int err;
err = ubi_read(c->ubi, lnum, buf, offs, len);
/*
* In case of %-EBADMSG print the error message only if the
* @even_ebadmsg is true.
*/
if (err && (err != -EBADMSG || even_ebadmsg)) {
ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
len, lnum, offs, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
else
err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
if (err) {
ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
len, lnum, offs, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
else
err = dbg_leb_change(c, lnum, buf, len, dtype);
if (err) {
ubifs_err("changing %d bytes in LEB %d failed, error %d",
len, lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_unmap(c->ubi, lnum);
else
err = dbg_leb_unmap(c, lnum);
if (err) {
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_map(c->ubi, lnum, dtype);
else
err = dbg_leb_map(c, lnum, dtype);
if (err) {
ubifs_err("mapping LEB %d failed, error %d", lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
{
int err;
err = ubi_is_mapped(c->ubi, lnum);
if (err < 0) {
ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
lnum, err);
dbg_dump_stack();
}
return err;
}
/**
......@@ -406,14 +523,10 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
dirt = sync_len - wbuf->used;
if (dirt)
ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
sync_len, wbuf->dtype);
if (err) {
ubifs_err("cannot write %d bytes to LEB %d:%d",
sync_len, wbuf->lnum, wbuf->offs);
dbg_dump_stack();
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
wbuf->dtype);
if (err)
return err;
}
spin_lock(&wbuf->lock);
wbuf->offs += sync_len;
......@@ -605,9 +718,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
if (aligned_len == wbuf->avail) {
dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
wbuf->offs, wbuf->size,
wbuf->dtype);
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
wbuf->offs, wbuf->size,
wbuf->dtype);
if (err)
goto out;
......@@ -642,8 +755,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
wbuf->size, wbuf->dtype);
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
wbuf->size, wbuf->dtype);
if (err)
goto out;
......@@ -661,8 +774,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
*/
dbg_io("write %d bytes to LEB %d:%d",
wbuf->size, wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf, wbuf->offs,
wbuf->size, wbuf->dtype);
err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
wbuf->size, wbuf->dtype);
if (err)
goto out;
......@@ -683,8 +796,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
n <<= c->max_write_shift;
dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written,
wbuf->offs, n, wbuf->dtype);
err = ubifs_leb_write(c, wbuf->lnum, buf + written,
wbuf->offs, n, wbuf->dtype);
if (err)
goto out;
wbuf->offs += n;
......@@ -766,13 +879,9 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
return -EROFS;
ubifs_prepare_node(c, buf, len, 1);
err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype);
if (err) {
ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
buf_len, lnum, offs, err);
err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
if (err)
dbg_dump_node(c, buf);
dbg_dump_stack();
}
return err;
}
......@@ -824,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
if (rlen > 0) {
/* Read everything that goes before write-buffer */
err = ubi_read(c->ubi, lnum, buf, offs, rlen);
if (err && err != -EBADMSG) {
ubifs_err("failed to read node %d from LEB %d:%d, "
"error %d", type, lnum, offs, err);
dbg_dump_stack();
err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
if (err && err != -EBADMSG)
return err;
}
}
if (type != ch->node_type) {
......@@ -885,12 +990,9 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
ubifs_assert(!(offs & 7) && offs < c->leb_size);
ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
err = ubi_read(c->ubi, lnum, buf, offs, len);
if (err && err != -EBADMSG) {
ubifs_err("cannot read node %d from LEB %d:%d, error %d",
type, lnum, offs, err);
err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
if (err && err != -EBADMSG)
return err;
}
if (type != ch->node_type) {
ubifs_err("bad node type (%d but expected %d)",
......
......@@ -262,7 +262,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
* an unclean reboot, because the target LEB might have been
* unmapped, but not yet physically erased.
*/
err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM);
err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
if (err)
goto out_unlock;
}
......@@ -283,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
return 0;
out_unlock:
if (err != -EAGAIN)
ubifs_ro_mode(c, err);
mutex_unlock(&c->log_mutex);
kfree(ref);
kfree(bud);
......@@ -752,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
struct ubifs_bud *bud;
long long bud_bytes = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
spin_lock(&c->buds_lock);
......
......@@ -504,7 +504,7 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
pnode = (struct ubifs_pnode *)container_of(lprops - pos,
struct ubifs_pnode,
lprops[0]);
return !test_bit(COW_ZNODE, &pnode->flags) &&
return !test_bit(COW_CNODE, &pnode->flags) &&
test_bit(DIRTY_CNODE, &pnode->flags);
}
......@@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c)
struct list_head *pos;
int i, cat;
if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
return 0;
list_for_each_entry(lprops, &c->empty_list, list) {
......@@ -958,7 +958,7 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
{
int i = 0, j, err = 0;
if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
return;
for (i = 0; i < heap->cnt; i++) {
......@@ -1262,7 +1262,7 @@ int dbg_check_lprops(struct ubifs_info *c)
int i, err;
struct ubifs_lp_stats lst;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
/*
......
......@@ -701,8 +701,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM);
if (err)
goto out;
p = buf;
......@@ -732,8 +732,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
set_ltab(c, lnum, c->leb_size - alen,
alen - len);
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM);
if (err)
goto out;
p = buf;
......@@ -780,8 +780,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM);
if (err)
goto out;
p = buf;
......@@ -806,7 +806,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
if (err)
goto out;
p = buf;
......@@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
/* Write remaining buffer */
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
if (err)
goto out;
......@@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
if (c->big_lpt)
nnode->num = calc_nnode_num_from_parent(c, parent, iip);
} else {
err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
if (err)
goto out;
err = ubifs_unpack_nnode(c, buf, nnode);
......@@ -1247,6 +1247,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out:
ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
dbg_dump_stack();
kfree(nnode);
return err;
}
......@@ -1290,7 +1291,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
lprops->flags = ubifs_categorize_lprops(c, lprops);
}
} else {
err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
if (err)
goto out;
err = unpack_pnode(c, buf, pnode);
......@@ -1312,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out:
ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
dbg_dump_pnode(c, pnode, parent, iip);
dbg_dump_stack();
dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
kfree(pnode);
return err;
......@@ -1331,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c)
buf = vmalloc(c->ltab_sz);
if (!buf)
return -ENOMEM;
err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
if (err)
goto out;
err = unpack_ltab(c, buf);
......@@ -1354,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c)
buf = vmalloc(c->lsave_sz);
if (!buf)
return -ENOMEM;
err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz);
err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
c->lsave_sz, 1);
if (err)
goto out;
err = unpack_lsave(c, buf);
......@@ -1814,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
if (c->big_lpt)
nnode->num = calc_nnode_num_from_parent(c, parent, iip);
} else {
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
c->nnode_sz);
err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
c->nnode_sz, 1);
if (err)
return ERR_PTR(err);
err = ubifs_unpack_nnode(c, buf, nnode);
......@@ -1883,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
ubifs_assert(branch->lnum >= c->lpt_first &&
branch->lnum <= c->lpt_last);
ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
c->pnode_sz);
err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
c->pnode_sz, 1);
if (err)
return ERR_PTR(err);
err = unpack_pnode(c, buf, pnode);
......@@ -2224,7 +2227,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
struct ubifs_cnode *cn;
int num, iip = 0, err;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
while (cnode) {
......
......@@ -27,6 +27,7 @@
#include <linux/crc16.h>
#include <linux/slab.h>
#include <linux/random.h>
#include "ubifs.h"
#ifdef CONFIG_UBIFS_FS_DEBUG
......@@ -116,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)
return 0;
cnt += 1;
while (1) {
ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags));
__set_bit(COW_ZNODE, &cnode->flags);
ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
__set_bit(COW_CNODE, &cnode->flags);
cnext = next_dirty_cnode(cnode);
if (!cnext) {
cnode->cnext = c->lpt_cnext;
......@@ -465,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c)
*/
clear_bit(DIRTY_CNODE, &cnode->flags);
smp_mb__before_clear_bit();
clear_bit(COW_ZNODE, &cnode->flags);
clear_bit(COW_CNODE, &cnode->flags);
smp_mb__after_clear_bit();
offs += len;
dbg_chk_lpt_sz(c, 1, len);
......@@ -1160,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
void *buf = c->lpt_buf;
dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
ubifs_err("cannot read LEB %d, error %d", lnum, err);
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
if (err)
return err;
}
while (1) {
if (!is_a_node(c, buf, len)) {
int pad_len;
......@@ -1640,7 +1641,7 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
int ret;
void *buf, *p;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
......@@ -1650,11 +1651,11 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
}
dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err);
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
if (err)
goto out;
}
while (1) {
if (!is_a_node(c, p, len)) {
int i, pad_len;
......@@ -1711,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c)
{
int lnum, err, i, cnt;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
/* Bring the entire tree into memory */
......@@ -1754,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
long long free = 0;
int i;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
for (i = 0; i < c->lpt_lebs; i++) {
......@@ -1796,7 +1797,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
long long chk_lpt_sz, lpt_sz;
int err = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
switch (action) {
......@@ -1901,11 +1902,10 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
return;
}
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
ubifs_err("cannot read LEB %d, error %d", lnum, err);
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
if (err)
goto out;
}
while (1) {
offs = c->leb_size - len;
if (!is_a_node(c, p, len)) {
......@@ -2019,7 +2019,7 @@ static int dbg_populate_lsave(struct ubifs_info *c)
struct ubifs_lpt_heap *heap;
int i;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
if (random32() & 3)
return 0;
......
......@@ -38,6 +38,29 @@ static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
return !!test_bit(DIRTY_ZNODE, &znode->flags);
}
/**
* ubifs_zn_obsolete - check if znode is obsolete.
* @znode: znode to check
*
* This helper function returns %1 if @znode is obsolete and %0 otherwise.
*/
static inline int ubifs_zn_obsolete(const struct ubifs_znode *znode)
{
return !!test_bit(OBSOLETE_ZNODE, &znode->flags);
}
/**
* ubifs_zn_cow - check if znode has to be copied on write.
* @znode: znode to check
*
* This helper function returns %1 if @znode is has COW flag set and %0
* otherwise.
*/
static inline int ubifs_zn_cow(const struct ubifs_znode *znode)
{
return !!test_bit(COW_ZNODE, &znode->flags);
}
/**
* ubifs_wake_up_bgt - wake up background thread.
* @c: UBIFS file-system description object
......@@ -121,86 +144,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
return err;
}
/**
* ubifs_leb_unmap - unmap an LEB.
* @c: UBIFS file-system description object
* @lnum: LEB number to unmap
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_unmap(c->ubi, lnum);
if (err) {
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
return err;
}
return 0;
}
/**
* ubifs_leb_write - write to a LEB.
* @c: UBIFS file-system description object
* @lnum: LEB number to write
* @buf: buffer to write from
* @offs: offset within LEB to write to
* @len: length to write
* @dtype: data type
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
const void *buf, int offs, int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
if (err) {
ubifs_err("writing %d bytes at %d:%d, error %d",
len, lnum, offs, err);
return err;
}
return 0;
}
/**
* ubifs_leb_change - atomic LEB change.
* @c: UBIFS file-system description object
* @lnum: LEB number to write
* @buf: buffer to write from
* @len: length to write
* @dtype: data type
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
const void *buf, int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
if (err) {
ubifs_err("changing %d bytes in LEB %d, error %d",
len, lnum, err);
return err;
}
return 0;
}
/**
* ubifs_encode_dev - encode device node IDs.
* @dev: UBIFS device node information
......
......@@ -929,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c)
struct check_info ci;
int err;
if (!(ubifs_chk_flags & UBIFS_CHK_ORPH))
if (!dbg_is_chk_orph(c))
return 0;
ci.last_ino = 0;
......
......@@ -117,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
if (!sbuf)
return -ENOMEM;
err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
err = ubifs_leb_read(c, lnum, sbuf, 0, c->leb_size, 0);
if (err && err != -EBADMSG)
goto out_free;
......@@ -213,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
if (err)
goto out;
err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
if (err)
goto out;
out:
......@@ -274,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c)
if (cor1)
goto out_err;
mst = mst1;
} else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
} else if (offs1 == 0 &&
c->leb_size - offs2 - sz < sz) {
/* 1st LEB was unmapped and written, 2nd not */
if (cor1)
goto out_err;
......@@ -539,8 +540,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
int len = ALIGN(endpt, c->min_io_size);
if (start) {
err = ubi_read(c->ubi, lnum, sleb->buf, 0,
start);
err = ubifs_leb_read(c, lnum, sleb->buf, 0,
start, 1);
if (err)
return err;
}
......@@ -554,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ubifs_pad(c, buf, pad_len);
}
}
err = ubi_leb_change(c->ubi, lnum, sleb->buf, len,
UBI_UNKNOWN);
err = ubifs_leb_change(c, lnum, sleb->buf, len,
UBI_UNKNOWN);
if (err)
return err;
}
......@@ -819,7 +820,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
return -ENOMEM;
if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
goto out_err;
err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
err = ubifs_leb_read(c, lnum, (void *)cs_node, offs,
UBIFS_CS_NODE_SZ, 0);
if (err && err != -EBADMSG)
goto out_free;
ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
......@@ -919,8 +921,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
*
* This function returns %0 on success and a negative error code on failure.
*/
static int recover_head(const struct ubifs_info *c, int lnum, int offs,
void *sbuf)
static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
{
int len = c->max_write_size, err;
......@@ -931,15 +932,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
return 0;
/* Read at the head location and check it is empty flash */
err = ubi_read(c->ubi, lnum, sbuf, offs, len);
err = ubifs_leb_read(c, lnum, sbuf, offs, len, 1);
if (err || !is_empty(sbuf, len)) {
dbg_rcvry("cleaning head at %d:%d", lnum, offs);
if (offs == 0)
return ubifs_leb_unmap(c, lnum);
err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
if (err)
return err;
return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
}
return 0;
......@@ -962,7 +963,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
*
* This function returns %0 on success and a negative error code on failure.
*/
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
{
int err;
......@@ -993,7 +994,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
*
* This function returns %0 on success and a negative error code on failure.
*/
static int clean_an_unclean_leb(const struct ubifs_info *c,
static int clean_an_unclean_leb(struct ubifs_info *c,
struct ubifs_unclean_leb *ucleb, void *sbuf)
{
int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
......@@ -1009,7 +1010,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
return 0;
}
err = ubi_read(c->ubi, lnum, buf, offs, len);
err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
if (err && err != -EBADMSG)
return err;
......@@ -1069,7 +1070,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
}
/* Write back the LEB atomically */
err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
if (err)
return err;
......@@ -1089,7 +1090,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
*
* This function returns %0 on success and a negative error code on failure.
*/
int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
{
dbg_rcvry("recovery");
while (!list_empty(&c->unclean_leb_list)) {
......@@ -1454,7 +1455,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
if (i_size >= e->d_size)
return 0;
/* Read the LEB */
err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size);
err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1);
if (err)
goto out;
/* Change the size field and recalculate the CRC */
......@@ -1470,7 +1471,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
len -= 1;
len = ALIGN(len + 1, c->min_io_size);
/* Atomically write the fixed LEB back again */
err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
if (err)
goto out;
dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
......
......@@ -523,8 +523,7 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
if (!list_is_last(&next->list, &jh->buds_list))
return 0;
err = ubi_read(c->ubi, next->lnum, (char *)&data,
next->start, 4);
err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
if (err)
return 0;
......
......@@ -674,15 +674,15 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int len)
if (len == 0) {
dbg_mnt("unmap empty LEB %d", lnum);
return ubi_leb_unmap(c->ubi, lnum);
return ubifs_leb_unmap(c, lnum);
}
dbg_mnt("fixup LEB %d, data len %d", lnum, len);
err = ubi_read(c->ubi, lnum, c->sbuf, 0, len);
err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 1);
if (err)
return err;
return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
}
/**
......
......@@ -148,7 +148,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
INIT_LIST_HEAD(&sleb->nodes);
sleb->buf = sbuf;
err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs, 0);
if (err && err != -EBADMSG) {
ubifs_err("cannot read %d bytes from LEB %d:%d,"
" error %d", c->leb_size - offs, lnum, offs, err);
......@@ -240,7 +240,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
int len;
ubifs_err("corruption at LEB %d:%d", lnum, offs);
if (dbg_failure_mode)
if (dbg_is_tst_rcvry(c))
return;
len = c->leb_size - offs;
if (len > 8192)
......
......@@ -85,7 +85,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
return 4;
if (ui->xattr && (inode->i_mode & S_IFMT) != S_IFREG)
if (ui->xattr && !S_ISREG(inode->i_mode))
return 5;
if (!ubifs_compr_present(ui->compr_type)) {
......@@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
ubifs_compr_name(ui->compr_type));
}
err = dbg_check_dir_size(c, inode);
err = dbg_check_dir(c, inode);
return err;
}
......@@ -914,7 +914,7 @@ static int check_volume_empty(struct ubifs_info *c)
c->empty = 1;
for (lnum = 0; lnum < c->leb_cnt; lnum++) {
err = ubi_is_mapped(c->ubi, lnum);
err = ubifs_is_mapped(c, lnum);
if (unlikely(err < 0))
return err;
if (err == 1) {
......
......@@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
__set_bit(DIRTY_ZNODE, &zn->flags);
__clear_bit(COW_ZNODE, &zn->flags);
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
ubifs_assert(!ubifs_zn_obsolete(znode));
__set_bit(OBSOLETE_ZNODE, &znode->flags);
if (znode->level != 0) {
......@@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
struct ubifs_znode *zn;
int err;
if (!test_bit(COW_ZNODE, &znode->flags)) {
if (!ubifs_zn_cow(znode)) {
/* znode is not being committed */
if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
atomic_long_inc(&c->dirty_zn_cnt);
......@@ -462,7 +462,7 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
err = ubi_read(c->ubi, lnum, buf, offs, len);
err = ubifs_leb_read(c, lnum, buf, offs, len, 1);
if (err) {
ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
type, lnum, offs, err);
......@@ -1666,7 +1666,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
if (!overlap) {
/* We may safely unlock the write-buffer and read the data */
spin_unlock(&wbuf->lock);
return ubi_read(c->ubi, lnum, buf, offs, len);
return ubifs_leb_read(c, lnum, buf, offs, len, 0);
}
/* Don't read under wbuf */
......@@ -1680,7 +1680,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
if (rlen > 0)
/* Read everything that goes before write-buffer */
return ubi_read(c->ubi, lnum, buf, offs, rlen);
return ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
return 0;
}
......@@ -1767,7 +1767,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
if (wbuf)
err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
else
err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
err = ubifs_leb_read(c, lnum, bu->buf, offs, len, 0);
/* Check for a race with GC */
if (maybe_leb_gced(c, lnum, bu->gc_seq))
......@@ -2423,7 +2423,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
*/
do {
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
ubifs_assert(!ubifs_zn_obsolete(znode));
ubifs_assert(ubifs_zn_dirty(znode));
zp = znode->parent;
......@@ -2479,9 +2479,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(!test_bit(OBSOLETE_ZNODE,
&zp->flags));
ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
ubifs_assert(!ubifs_zn_obsolete(zp));
ubifs_assert(ubifs_zn_dirty(zp));
atomic_long_dec(&c->dirty_zn_cnt);
if (zp->cnext) {
......@@ -2865,7 +2864,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
struct ubifs_znode *znode = cnext;
cnext = cnext->cnext;
if (test_bit(OBSOLETE_ZNODE, &znode->flags))
if (ubifs_zn_obsolete(znode))
kfree(znode);
} while (cnext && cnext != c->cnext);
}
......@@ -3301,7 +3300,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
if (!S_ISREG(inode->i_mode))
return 0;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
......@@ -3337,9 +3336,10 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
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));
mutex_unlock(&c->tnc_mutex);
dbg_dump_inode(c, inode);
dbg_dump_stack();
err = -EINVAL;
return -EINVAL;
out_unlock:
mutex_unlock(&c->tnc_mutex);
......
......@@ -22,6 +22,7 @@
/* This file implements TNC functions for committing */
#include <linux/random.h>
#include "ubifs.h"
/**
......@@ -87,8 +88,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
atomic_long_dec(&c->dirty_zn_cnt);
ubifs_assert(ubifs_zn_dirty(znode));
ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
ubifs_assert(ubifs_zn_cow(znode));
/*
* Note, unlike 'write_index()' we do not add memory barriers here
* because this function is called with @c->tnc_mutex locked.
*/
__clear_bit(DIRTY_ZNODE, &znode->flags);
__clear_bit(COW_ZNODE, &znode->flags);
......@@ -377,7 +382,7 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
c->gap_lebs = NULL;
return err;
}
if (dbg_force_in_the_gaps_enabled()) {
if (!dbg_is_chk_index(c)) {
/*
* Do not print scary warnings if the debugging
* option which forces in-the-gaps is enabled.
......@@ -491,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c)
else
next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
if (c->min_io_size == 1) {
buf_offs += ALIGN(len, 8);
if (next_len) {
if (buf_offs + next_len <= c->leb_size)
continue;
err = ubifs_update_one_lp(c, lnum, 0,
c->leb_size - buf_offs, 0, 0);
if (err)
return err;
lnum = -1;
continue;
}
err = ubifs_update_one_lp(c, lnum,
c->leb_size - buf_offs, 0, 0, 0);
if (err)
return err;
break;
}
/* Update buffer positions */
wlen = used + len;
used += ALIGN(len, 8);
......@@ -658,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c)
}
cnt += 1;
while (1) {
ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
ubifs_assert(!ubifs_zn_cow(znode));
__set_bit(COW_ZNODE, &znode->flags);
znode->alt = 0;
cnext = find_next_dirty(znode);
......@@ -704,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
c->ilebs[c->ileb_cnt++] = lnum;
dbg_cmt("LEB %d", lnum);
}
if (dbg_force_in_the_gaps())
if (dbg_is_chk_index(c) && !(random32() & 7))
return -ENOSPC;
return 0;
}
......@@ -830,7 +816,7 @@ static int write_index(struct ubifs_info *c)
struct ubifs_idx_node *idx;
struct ubifs_znode *znode, *cnext;
int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
int avail, wlen, err, lnum_pos = 0;
int avail, wlen, err, lnum_pos = 0, blen, nxt_offs;
cnext = c->enext;
if (!cnext)
......@@ -907,7 +893,7 @@ static int write_index(struct ubifs_info *c)
cnext = znode->cnext;
ubifs_assert(ubifs_zn_dirty(znode));
ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
ubifs_assert(ubifs_zn_cow(znode));
/*
* It is important that other threads should see %DIRTY_ZNODE
......@@ -922,6 +908,28 @@ static int write_index(struct ubifs_info *c)
clear_bit(COW_ZNODE, &znode->flags);
smp_mb__after_clear_bit();
/*
* We have marked the znode as clean but have not updated the
* @c->clean_zn_cnt counter. If this znode becomes dirty again
* before 'free_obsolete_znodes()' is called, then
* @c->clean_zn_cnt will be decremented before it gets
* incremented (resulting in 2 decrements for the same znode).
* This means that @c->clean_zn_cnt may become negative for a
* while.
*
* Q: why we cannot increment @c->clean_zn_cnt?
* A: because we do not have the @c->tnc_mutex locked, and the
* following code would be racy and buggy:
*
* if (!ubifs_zn_obsolete(znode)) {
* atomic_long_inc(&c->clean_zn_cnt);
* atomic_long_inc(&ubifs_clean_zn_cnt);
* }
*
* Thus, we just delay the @c->clean_zn_cnt update until we
* have the mutex locked.
*/
/* Do not access znode from this point on */
/* Update buffer positions */
......@@ -938,65 +946,38 @@ static int write_index(struct ubifs_info *c)
else
next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
if (c->min_io_size == 1) {
/*
* Write the prepared index node immediately if there is
* no minimum IO size
*/
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
wlen, UBI_SHORTTERM);
if (err)
return err;
buf_offs += ALIGN(wlen, 8);
if (next_len) {
used = 0;
avail = buf_len;
if (buf_offs + next_len > c->leb_size) {
err = ubifs_update_one_lp(c, lnum,
LPROPS_NC, 0, 0, LPROPS_TAKEN);
if (err)
return err;
lnum = -1;
}
nxt_offs = buf_offs + used + next_len;
if (next_len && nxt_offs <= c->leb_size) {
if (avail > 0)
continue;
}
else
blen = buf_len;
} else {
int blen, nxt_offs = buf_offs + used + next_len;
if (next_len && nxt_offs <= c->leb_size) {
if (avail > 0)
continue;
else
blen = buf_len;
} else {
wlen = ALIGN(wlen, 8);
blen = ALIGN(wlen, c->min_io_size);
ubifs_pad(c, c->cbuf + wlen, blen - wlen);
}
/*
* The buffer is full or there are no more znodes
* to do
*/
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
blen, UBI_SHORTTERM);
if (err)
return err;
buf_offs += blen;
if (next_len) {
if (nxt_offs > c->leb_size) {
err = ubifs_update_one_lp(c, lnum,
LPROPS_NC, 0, 0, LPROPS_TAKEN);
if (err)
return err;
lnum = -1;
}
used -= blen;
if (used < 0)
used = 0;
avail = buf_len - used;
memmove(c->cbuf, c->cbuf + blen, used);
continue;
wlen = ALIGN(wlen, 8);
blen = ALIGN(wlen, c->min_io_size);
ubifs_pad(c, c->cbuf + wlen, blen - wlen);
}
/* The buffer is full or there are no more znodes to do */
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
UBI_SHORTTERM);
if (err)
return err;
buf_offs += blen;
if (next_len) {
if (nxt_offs > c->leb_size) {
err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
0, LPROPS_TAKEN);
if (err)
return err;
lnum = -1;
}
used -= blen;
if (used < 0)
used = 0;
avail = buf_len - used;
memmove(c->cbuf, c->cbuf + blen, used);
continue;
}
break;
}
......@@ -1029,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c)
do {
znode = cnext;
cnext = znode->cnext;
if (test_bit(OBSOLETE_ZNODE, &znode->flags))
if (ubifs_zn_obsolete(znode))
kfree(znode);
else {
znode->cnext = NULL;
......
......@@ -230,14 +230,14 @@ enum {
* LPT cnode flag bits.
*
* DIRTY_CNODE: cnode is dirty
* COW_CNODE: cnode is being committed and must be copied before writing
* OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
* so it can (and must) be freed when the commit is finished
* so it can (and must) be freed when the commit is finished
* COW_CNODE: cnode is being committed and must be copied before writing
*/
enum {
DIRTY_CNODE = 0,
COW_CNODE = 1,
OBSOLETE_CNODE = 2,
OBSOLETE_CNODE = 1,
COW_CNODE = 2,
};
/*
......@@ -1468,6 +1468,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
/* io.c */
void ubifs_ro_mode(struct ubifs_info *c, int err);
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
int len, int even_ebadmsg);
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
int len, int dtype);
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
int dtype);
int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
int dtype);
......@@ -1747,8 +1756,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
int offs, void *sbuf, int jhead);
struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
int offs, void *sbuf);
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
int ubifs_rcvry_gc_commit(struct ubifs_info *c);
int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
int deletion, loff_t new_size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment