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 ...@@ -111,34 +111,6 @@ The following is an example of the kernel boot arguments to attach mtd0
to UBI and mount volume "rootfs": to UBI and mount volume "rootfs":
ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs 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 References
========== ==========
......
List of maintainers and how to submit kernel changes List of maintainers and how to submit kernel changes
Please try to follow the guidelines below. This will make things Please try to follow the guidelines below. This will make things
...@@ -6321,7 +6322,7 @@ F: drivers/scsi/u14-34f.c ...@@ -6321,7 +6322,7 @@ F: drivers/scsi/u14-34f.c
UBI FILE SYSTEM (UBIFS) UBI FILE SYSTEM (UBIFS)
M: Artem Bityutskiy <dedekind1@gmail.com> 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 L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubifs-2.6.git T: git git://git.infradead.org/ubifs-2.6.git
W: http://www.linux-mtd.infradead.org/doc/ubifs.html W: http://www.linux-mtd.infradead.org/doc/ubifs.html
......
...@@ -78,7 +78,7 @@ static int nothing_to_commit(struct ubifs_info *c) ...@@ -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 * If the root TNC node is dirty, we definitely have something to
* commit. * 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; return 0;
/* /*
...@@ -418,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c) ...@@ -418,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c)
spin_lock(&c->cs_lock); spin_lock(&c->cs_lock);
if (c->cmt_state == COMMIT_BROKEN) { if (c->cmt_state == COMMIT_BROKEN) {
err = -EINVAL; err = -EROFS;
goto out; goto out;
} }
...@@ -444,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c) ...@@ -444,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c)
* re-check it. * re-check it.
*/ */
if (c->cmt_state == COMMIT_BROKEN) { if (c->cmt_state == COMMIT_BROKEN) {
err = -EINVAL; err = -EROFS;
goto out_cmt_unlock; goto out_cmt_unlock;
} }
...@@ -576,7 +576,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot) ...@@ -576,7 +576,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
struct idx_node *i; struct idx_node *i;
size_t sz; size_t sz;
if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX)) if (!dbg_is_chk_index(c))
return 0; return 0;
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
......
...@@ -27,13 +27,12 @@ ...@@ -27,13 +27,12 @@
* various local functions of those subsystems. * various local functions of those subsystems.
*/ */
#define UBIFS_DBG_PRESERVE_UBI
#include "ubifs.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/uaccess.h>
#include <linux/random.h>
#include "ubifs.h"
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
...@@ -42,15 +41,6 @@ DEFINE_SPINLOCK(dbg_lock); ...@@ -42,15 +41,6 @@ DEFINE_SPINLOCK(dbg_lock);
static char dbg_key_buf0[128]; static char dbg_key_buf0[128];
static char dbg_key_buf1[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) static const char *get_key_fmt(int fmt)
{ {
switch (fmt) { switch (fmt) {
...@@ -91,6 +81,28 @@ static const char *get_key_type(int type) ...@@ -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, static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
char *buffer) char *buffer)
{ {
...@@ -234,9 +246,13 @@ static void dump_ch(const struct ubifs_ch *ch) ...@@ -234,9 +246,13 @@ static void dump_ch(const struct ubifs_ch *ch)
printk(KERN_DEBUG "\tlen %u\n", le32_to_cpu(ch->len)); 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); 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 "Dump in-memory inode:");
printk(KERN_DEBUG "\tinode %lu\n", inode->i_ino); 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) ...@@ -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 "\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 "\tread_in_a_row %lu\n", ui->read_in_a_row);
printk(KERN_DEBUG "\tdata_len %d\n", ui->data_len); 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) 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) ...@@ -278,7 +320,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
union ubifs_key key; union ubifs_key key;
const struct ubifs_ch *ch = node; const struct ubifs_ch *ch = node;
if (dbg_failure_mode) if (dbg_is_tst_rcvry(c))
return; return;
/* If the magic is incorrect, just hexdump the first bytes */ /* 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) ...@@ -834,7 +876,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
struct ubifs_scan_node *snod; struct ubifs_scan_node *snod;
void *buf; void *buf;
if (dbg_failure_mode) if (dbg_is_tst_rcvry(c))
return; return;
printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n", printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
...@@ -1080,6 +1122,7 @@ int dbg_check_space_info(struct ubifs_info *c) ...@@ -1080,6 +1122,7 @@ int dbg_check_space_info(struct ubifs_info *c)
/** /**
* dbg_check_synced_i_size - check synchronized inode size. * dbg_check_synced_i_size - check synchronized inode size.
* @c: UBIFS file-system description object
* @inode: inode to check * @inode: inode to check
* *
* If inode is clean, synchronized inode size has to be equivalent to current * 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) ...@@ -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 * has to be locked). Returns %0 if synchronized inode size if correct, and
* %-EINVAL if not. * %-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; int err = 0;
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return 0; return 0;
...@@ -1125,7 +1168,7 @@ int dbg_check_synced_i_size(struct inode *inode) ...@@ -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 * Note, it is good idea to make sure the @dir->i_mutex is locked before
* calling this function. * 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; unsigned int nlink = 2;
union ubifs_key key; union ubifs_key key;
...@@ -1133,7 +1176,7 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir) ...@@ -1133,7 +1176,7 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
struct qstr nm = { .name = NULL }; struct qstr nm = { .name = NULL };
loff_t size = UBIFS_INO_NODE_SZ; loff_t size = UBIFS_INO_NODE_SZ;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
if (!S_ISDIR(dir->i_mode)) if (!S_ISDIR(dir->i_mode))
...@@ -1167,12 +1210,14 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir) ...@@ -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, "but calculated size is %llu", dir->i_ino,
(unsigned long long)i_size_read(dir), (unsigned long long)i_size_read(dir),
(unsigned long long)size); (unsigned long long)size);
dbg_dump_inode(c, dir);
dump_stack(); dump_stack();
return -EINVAL; return -EINVAL;
} }
if (dir->i_nlink != nlink) { if (dir->i_nlink != nlink) {
ubifs_err("directory inode %lu has nlink %u, but calculated " ubifs_err("directory inode %lu has nlink %u, but calculated "
"nlink is %u", dir->i_ino, dir->i_nlink, nlink); "nlink is %u", dir->i_ino, dir->i_nlink, nlink);
dbg_dump_inode(c, dir);
dump_stack(); dump_stack();
return -EINVAL; return -EINVAL;
} }
...@@ -1489,7 +1534,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra) ...@@ -1489,7 +1534,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra)
long clean_cnt = 0, dirty_cnt = 0; long clean_cnt = 0, dirty_cnt = 0;
int err, last; int err, last;
if (!(ubifs_chk_flags & UBIFS_CHK_TNC)) if (!dbg_is_chk_index(c))
return 0; return 0;
ubifs_assert(mutex_is_locked(&c->tnc_mutex)); 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) ...@@ -1736,7 +1781,7 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
int err; int err;
long long calc = 0; long long calc = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ)) if (!dbg_is_chk_index(c))
return 0; return 0;
err = dbg_walk_index(c, NULL, add_size, &calc); err = dbg_walk_index(c, NULL, add_size, &calc);
...@@ -2312,7 +2357,7 @@ int dbg_check_filesystem(struct ubifs_info *c) ...@@ -2312,7 +2357,7 @@ int dbg_check_filesystem(struct ubifs_info *c)
int err; int err;
struct fsck_data fsckd; struct fsck_data fsckd;
if (!(ubifs_chk_flags & UBIFS_CHK_FS)) if (!dbg_is_chk_fs(c))
return 0; return 0;
fsckd.inodes = RB_ROOT; fsckd.inodes = RB_ROOT;
...@@ -2347,7 +2392,7 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head) ...@@ -2347,7 +2392,7 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
struct list_head *cur; struct list_head *cur;
struct ubifs_scan_node *sa, *sb; struct ubifs_scan_node *sa, *sb;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
for (cur = head->next; cur->next != head; cur = cur->next) { 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) ...@@ -2414,7 +2459,7 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
struct list_head *cur; struct list_head *cur;
struct ubifs_scan_node *sa, *sb; struct ubifs_scan_node *sa, *sb;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
for (cur = head->next; cur->next != head; cur = cur->next) { 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) ...@@ -2491,214 +2536,141 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
return 0; 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 !!((random32() % out_of) + 1 <= n);
return 0;
return !(random32() & 7);
} }
/* Failure mode for recovery testing */ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
#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)
{ {
struct failure_mode_info *fmi, *tmp; struct ubifs_debug_info *d = c->dbg;
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;
}
static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) ubifs_assert(dbg_is_tst_rcvry(c));
{
struct ubifs_info *c = dbg_find_info(desc);
struct ubifs_debug_info *d;
if (!c || !dbg_failure_mode) if (!d->pc_cnt) {
return 0; /* First call - decide delay to the power cut */
d = c->dbg;
if (d->failure_mode)
return 1;
if (!d->fail_cnt) {
/* First call - decide delay to failure */
if (chance(1, 2)) { if (chance(1, 2)) {
unsigned int delay = 1 << (simple_rand() >> 11); unsigned long delay;
if (chance(1, 2)) { if (chance(1, 2)) {
d->fail_delay = 1; d->pc_delay = 1;
d->fail_timeout = jiffies + /* Fail withing 1 minute */
msecs_to_jiffies(delay); delay = random32() % 60000;
dbg_rcvry("failing after %ums", delay); d->pc_timeout = jiffies;
d->pc_timeout += msecs_to_jiffies(delay);
ubifs_warn("failing after %lums", delay);
} else { } else {
d->fail_delay = 2; d->pc_delay = 2;
d->fail_cnt_max = delay; delay = random32() % 10000;
dbg_rcvry("failing after %u calls", delay); /* 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 */ /* Determine if failure delay has expired */
if (d->fail_delay == 1) { if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout))
if (time_before(jiffies, d->fail_timeout))
return 0; return 0;
} else if (d->fail_delay == 2) if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max)
if (d->fail_cnt++ < d->fail_cnt_max)
return 0; return 0;
if (lnum == UBIFS_SB_LNUM) { if (lnum == UBIFS_SB_LNUM) {
if (write) { if (write && chance(1, 2))
if (chance(1, 2)) return 0;
return 0; if (chance(19, 20))
} else if (chance(19, 20))
return 0; 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) { } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
if (chance(19, 20)) if (chance(19, 20))
return 0; 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) { } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
if (write) { if (write && chance(99, 100))
if (chance(99, 100))
return 0;
} else if (chance(399, 400))
return 0; 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) { } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
if (write) { if (write && chance(7, 8))
if (chance(7, 8))
return 0;
} else if (chance(19, 20))
return 0; 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) { } else if (lnum >= c->orph_first && lnum <= c->orph_last) {
if (write) { if (write && chance(1, 2))
if (chance(1, 2)) return 0;
return 0; if (chance(9, 10))
} else if (chance(9, 10))
return 0; return 0;
dbg_rcvry("failing in orphan LEB %d", lnum); ubifs_warn("failing in orphan LEB %d", lnum);
} else if (lnum == c->ihead_lnum) { } else if (lnum == c->ihead_lnum) {
if (chance(99, 100)) if (chance(99, 100))
return 0; 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) { } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
if (chance(9, 10)) if (chance(9, 10))
return 0; 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) && } else if (write && !RB_EMPTY_ROOT(&c->buds) &&
!ubifs_search_bud(c, lnum)) { !ubifs_search_bud(c, lnum)) {
if (chance(19, 20)) if (chance(19, 20))
return 0; 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 || } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND ||
c->cmt_state == COMMIT_RUNNING_REQUIRED) { c->cmt_state == COMMIT_RUNNING_REQUIRED) {
if (chance(999, 1000)) if (chance(999, 1000))
return 0; return 0;
dbg_rcvry("failing in bud LEB %d commit running", lnum); ubifs_warn("failing in bud LEB %d commit running", lnum);
} else { } else {
if (chance(9999, 10000)) if (chance(9999, 10000))
return 0; 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(); dump_stack();
return 1; 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; unsigned char *p = (void *)buf;
flen = (len * (long long)simple_rand()) >> 15; from = random32() % (len + 1);
for (i = flen; i < len; i++) if (chance(1, 2))
p[i] = 0xff; to = random32() % (len - from + 1);
} else
to = len;
int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, if (from < to)
int len, int check) ubifs_warn("filled bytes %u-%u with %s", from, to - 1,
{ ffs ? "0xFFs" : "random data");
if (in_failure_mode(desc))
return -EROFS; if (ffs)
return ubi_leb_read(desc, lnum, buf, offset, len, check); 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 dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
int offset, int len, int dtype) int offs, int len, int dtype)
{ {
int err, failing; int err, failing;
if (in_failure_mode(desc)) if (c->dbg->pc_happened)
return -EROFS; return -EROFS;
failing = do_fail(desc, lnum, 1);
failing = power_cut_emulated(c, lnum, 1);
if (failing) if (failing)
cut_data(buf, len); 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) if (err)
return err; return err;
if (failing) if (failing)
...@@ -2706,162 +2678,207 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, ...@@ -2706,162 +2678,207 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
return 0; 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 len, int dtype)
{ {
int err; int err;
if (do_fail(desc, lnum, 1)) if (c->dbg->pc_happened)
return -EROFS; 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) if (err)
return err; return err;
if (do_fail(desc, lnum, 1)) if (power_cut_emulated(c, lnum, 1))
return -EROFS; return -EROFS;
return 0; 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; int err;
if (do_fail(desc, lnum, 0)) if (c->dbg->pc_happened)
return -EROFS;
if (power_cut_emulated(c, lnum, 0))
return -EROFS; return -EROFS;
err = ubi_leb_erase(desc, lnum); err = ubi_leb_unmap(c->ubi, lnum);
if (err) if (err)
return err; return err;
if (do_fail(desc, lnum, 0)) if (power_cut_emulated(c, lnum, 0))
return -EROFS; return -EROFS;
return 0; 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; int err;
if (do_fail(desc, lnum, 0)) if (c->dbg->pc_happened)
return -EROFS; 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) if (err)
return err; return err;
if (do_fail(desc, lnum, 0)) if (power_cut_emulated(c, lnum, 0))
return -EROFS; return -EROFS;
return 0; return 0;
} }
int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum) /*
{ * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
if (in_failure_mode(desc)) * contain the stuff specific to particular file-system mounts.
return -EROFS; */
return ubi_is_mapped(desc, lnum); 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; file->private_data = inode->i_private;
return nonseekable_open(inode, file);
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;
} }
/** /**
* ubifs_debugging_init - initialize UBIFS debugging. * provide_user_output - provide output to the user reading a debugfs file.
* @c: UBIFS file-system description object * @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. * This is a simple helper function which stores @val boolean value in the user
* Returns zero in case of success and a negative error code in case of * 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. * 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); char buf[3];
if (!c->dbg)
return -ENOMEM;
failure_mode_init(c); if (val)
return 0; buf[0] = '1';
else
buf[0] = '0';
buf[1] = '\n';
buf[2] = 0x00;
return simple_read_from_buffer(u, count, ppos, buf, 2);
} }
/** static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count,
* ubifs_debugging_exit - free debugging data. loff_t *ppos)
* @c: UBIFS file-system description object
*/
void ubifs_debugging_exit(struct ubifs_info *c)
{ {
failure_mode_exit(c); struct dentry *dent = file->f_path.dentry;
kfree(c->dbg); 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;
/* return provide_user_output(val, u, count, ppos);
* 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;
/** /**
* 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 * This is a helper function which interpret user input to a boolean UBIFS
* user-space. This function creates "ubifs" directory in the debugfs * debugfs file. Returns %0 or %1 in case of success and a negative error code
* file-system. Returns zero in case of success and a negative error code in * in case of failure.
* 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); size_t buf_size;
if (IS_ERR(dfs_rootdir)) { char buf[8];
int err = PTR_ERR(dfs_rootdir);
ubifs_err("cannot create \"ubifs\" debugfs directory, "
"error %d\n", err);
return err;
}
return 0; buf_size = min_t(size_t, count, (sizeof(buf) - 1));
} if (copy_from_user(buf, u, buf_size))
return -EFAULT;
/** if (buf[0] == '1')
* dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system. return 1;
*/ else if (buf[0] == '0')
void dbg_debugfs_exit(void) return 0;
{
debugfs_remove(dfs_rootdir);
}
static int open_debugfs_file(struct inode *inode, struct file *file) return -EINVAL;
{
file->private_data = inode->i_private;
return nonseekable_open(inode, file);
} }
static ssize_t write_debugfs_file(struct file *file, const char __user *buf, static ssize_t dfs_file_write(struct file *file, const char __user *u,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ubifs_info *c = file->private_data; struct ubifs_info *c = file->private_data;
struct ubifs_debug_info *d = c->dbg; 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); 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); 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); mutex_lock(&c->tnc_mutex);
dbg_dump_tnc(c); dbg_dump_tnc(c);
mutex_unlock(&c->tnc_mutex); 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 -EINVAL;
return count; return count;
} }
static const struct file_operations dfs_fops = { static const struct file_operations dfs_fops = {
.open = open_debugfs_file, .open = dfs_file_open,
.write = write_debugfs_file, .read = dfs_file_read,
.write = dfs_file_write,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
}; };
...@@ -2880,12 +2897,20 @@ static const struct file_operations dfs_fops = { ...@@ -2880,12 +2897,20 @@ static const struct file_operations dfs_fops = {
*/ */
int dbg_debugfs_init_fs(struct ubifs_info *c) int dbg_debugfs_init_fs(struct ubifs_info *c)
{ {
int err; int err, n;
const char *fname; const char *fname;
struct dentry *dent; struct dentry *dent;
struct ubifs_debug_info *d = c->dbg; 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; fname = d->dfs_dir_name;
dent = debugfs_create_dir(fname, dfs_rootdir); dent = debugfs_create_dir(fname, dfs_rootdir);
if (IS_ERR_OR_NULL(dent)) if (IS_ERR_OR_NULL(dent))
...@@ -2910,13 +2935,55 @@ int dbg_debugfs_init_fs(struct ubifs_info *c) ...@@ -2910,13 +2935,55 @@ int dbg_debugfs_init_fs(struct ubifs_info *c)
goto out_remove; goto out_remove;
d->dfs_dump_tnc = dent; 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; return 0;
out_remove: out_remove:
debugfs_remove_recursive(d->dfs_dir); debugfs_remove_recursive(d->dfs_dir);
out: out:
err = dent ? PTR_ERR(dent) : -ENODEV; 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); fname, err);
return err; return err;
} }
...@@ -2930,4 +2997,179 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c) ...@@ -2930,4 +2997,179 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c)
debugfs_remove_recursive(c->dbg->dfs_dir); 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 */ #endif /* CONFIG_UBIFS_FS_DEBUG */
...@@ -31,18 +31,25 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c, ...@@ -31,18 +31,25 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
#ifdef CONFIG_UBIFS_FS_DEBUG #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. * ubifs_debug_info - per-FS debugging information.
* @old_zroot: old index root - used by 'dbg_check_old_index()' * @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_level: old index root level - used by 'dbg_check_old_index()'
* @old_zroot_sqnum: old index root sqnum - 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 * @pc_happened: non-zero if an emulated power cut happened
* @fail_timeout: time in jiffies when delay of failure mode expires * @pc_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
* @fail_cnt: current number of calls to failure mode I/O functions * @pc_timeout: time in jiffies when delay of failure mode expires
* @fail_cnt_max: number of calls by which to delay failure mode * @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_sz: used by LPT tree size checker
* @chk_lpt_sz2: used by LPT tree size checker * @chk_lpt_sz2: used by LPT tree size checker
* @chk_lpt_wastage: 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, ...@@ -56,21 +63,36 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
* @saved_free: saved amount of free space * @saved_free: saved amount of free space
* @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt * @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_name: name of debugfs directory containing this file-system's files
* @dfs_dir: direntry object of the file-system debugfs directory * @dfs_dir: direntry object of the file-system debugfs directory
* @dfs_dump_lprops: "dump lprops" debugfs knob * @dfs_dump_lprops: "dump lprops" debugfs knob
* @dfs_dump_budg: "dump budgeting information" debugfs knob * @dfs_dump_budg: "dump budgeting information" debugfs knob
* @dfs_dump_tnc: "dump TNC" 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_debug_info {
struct ubifs_zbranch old_zroot; struct ubifs_zbranch old_zroot;
int old_zroot_level; int old_zroot_level;
unsigned long long old_zroot_sqnum; unsigned long long old_zroot_sqnum;
int failure_mode;
int fail_delay; int pc_happened;
unsigned long fail_timeout; int pc_delay;
unsigned int fail_cnt; unsigned long pc_timeout;
unsigned int fail_cnt_max; unsigned int pc_cnt;
unsigned int pc_cnt_max;
long long chk_lpt_sz; long long chk_lpt_sz;
long long chk_lpt_sz2; long long chk_lpt_sz2;
long long chk_lpt_wastage; long long chk_lpt_wastage;
...@@ -84,11 +106,43 @@ struct ubifs_debug_info { ...@@ -84,11 +106,43 @@ struct ubifs_debug_info {
long long saved_free; long long saved_free;
int saved_idx_gc_cnt; 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_dir;
struct dentry *dfs_dump_lprops; struct dentry *dfs_dump_lprops;
struct dentry *dfs_dump_budg; struct dentry *dfs_dump_budg;
struct dentry *dfs_dump_tnc; 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 { \ #define ubifs_assert(expr) do { \
...@@ -127,6 +181,8 @@ const char *dbg_key_str1(const struct ubifs_info *c, ...@@ -127,6 +181,8 @@ const char *dbg_key_str1(const struct ubifs_info *c,
#define DBGKEY(key) dbg_key_str0(c, (key)) #define DBGKEY(key) dbg_key_str0(c, (key))
#define DBGKEY1(key) dbg_key_str1(c, (key)) #define DBGKEY1(key) dbg_key_str1(c, (key))
extern spinlock_t dbg_lock;
#define ubifs_dbg_msg(type, fmt, ...) do { \ #define ubifs_dbg_msg(type, fmt, ...) do { \
spin_lock(&dbg_lock); \ spin_lock(&dbg_lock); \
pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \ pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
...@@ -162,41 +218,36 @@ const char *dbg_key_str1(const struct ubifs_info *c, ...@@ -162,41 +218,36 @@ const char *dbg_key_str1(const struct ubifs_info *c,
/* Additional recovery messages */ /* Additional recovery messages */
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__) #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
/* extern struct ubifs_global_debug_info ubifs_dbg;
* 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 unsigned int ubifs_msg_flags; static inline int dbg_is_chk_gen(const struct ubifs_info *c)
extern unsigned int ubifs_chk_flags; {
extern unsigned int ubifs_tst_flags; 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); int ubifs_debugging_init(struct ubifs_info *c);
void ubifs_debugging_exit(struct ubifs_info *c); void ubifs_debugging_exit(struct ubifs_info *c);
...@@ -207,7 +258,7 @@ const char *dbg_cstate(int cmt_state); ...@@ -207,7 +258,7 @@ const char *dbg_cstate(int cmt_state);
const char *dbg_jhead(int jhead); const char *dbg_jhead(int jhead);
const char *dbg_get_key_dump(const struct ubifs_info *c, const char *dbg_get_key_dump(const struct ubifs_info *c,
const union ubifs_key *key); 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_node(const struct ubifs_info *c, const void *node);
void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum, void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
int offs); int offs);
...@@ -240,8 +291,8 @@ int dbg_check_cats(struct ubifs_info *c); ...@@ -240,8 +291,8 @@ int dbg_check_cats(struct ubifs_info *c);
int dbg_check_ltab(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_free_spc(struct ubifs_info *c);
int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len); 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_synced_i_size(const struct ubifs_info *c, struct inode *inode);
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);
int dbg_check_tnc(struct ubifs_info *c, int extra); 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_idx_size(struct ubifs_info *c, long long idx_size);
int dbg_check_filesystem(struct ubifs_info *c); 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, ...@@ -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_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); int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
/* Force the use of in-the-gaps method for testing */ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
static inline int dbg_force_in_the_gaps_enabled(void) int len, int dtype);
{ int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
return ubifs_chk_flags & UBIFS_CHK_GEN; int dtype);
} int dbg_leb_unmap(struct ubifs_info *c, int lnum);
int dbg_force_in_the_gaps(void); int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
/* 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);
}
/* Debugfs-related stuff */ /* Debugfs-related stuff */
int dbg_debugfs_init(void); int dbg_debugfs_init(void);
...@@ -313,7 +322,7 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); ...@@ -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 */ /* Use "if (0)" to make compiler check arguments even if debugging is off */
#define ubifs_assert(expr) do { \ #define ubifs_assert(expr) do { \
if (0 && (expr)) \ if (0) \
printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
__func__, __LINE__, current->pid); \ __func__, __LINE__, current->pid); \
} while (0) } while (0)
...@@ -323,6 +332,9 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); ...@@ -323,6 +332,9 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
ubifs_err(fmt, ##__VA_ARGS__); \ ubifs_err(fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#define DBGKEY(key) ((char *)(key))
#define DBGKEY1(key) ((char *)(key))
#define ubifs_dbg_msg(fmt, ...) do { \ #define ubifs_dbg_msg(fmt, ...) do { \
if (0) \ if (0) \
pr_debug(fmt "\n", ##__VA_ARGS__); \ pr_debug(fmt "\n", ##__VA_ARGS__); \
...@@ -346,9 +358,6 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); ...@@ -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_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
#define dbg_rcvry(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 int ubifs_debugging_init(struct ubifs_info *c) { return 0; }
static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; } static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; }
static inline const char *dbg_ntype(int type) { return ""; } static inline const char *dbg_ntype(int type) { return ""; }
...@@ -357,7 +366,7 @@ static inline const char *dbg_jhead(int jhead) { return ""; } ...@@ -357,7 +366,7 @@ static inline const char *dbg_jhead(int jhead) { return ""; }
static inline const char * static inline const char *
dbg_get_key_dump(const struct ubifs_info *c, dbg_get_key_dump(const struct ubifs_info *c,
const union ubifs_key *key) { return ""; } 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; } const struct inode *inode) { return; }
static inline void dbg_dump_node(const struct ubifs_info *c, static inline void dbg_dump_node(const struct ubifs_info *c,
const void *node) { return; } const void *node) { return; }
...@@ -409,9 +418,11 @@ static inline int dbg_check_ltab(struct ubifs_info *c) { return 0; } ...@@ -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_free_spc(struct ubifs_info *c) { return 0; }
static inline int dbg_chk_lpt_sz(struct ubifs_info *c, static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
int action, int len) { return 0; } int action, int len) { return 0; }
static inline int dbg_check_synced_i_size(struct inode *inode) { return 0; } static inline int
static inline int dbg_check_dir_size(struct ubifs_info *c, dbg_check_synced_i_size(const struct ubifs_info *c,
const struct inode *dir) { return 0; } 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_tnc(struct ubifs_info *c, int extra) { return 0; }
static inline int dbg_check_idx_size(struct ubifs_info *c, static inline int dbg_check_idx_size(struct ubifs_info *c,
long long idx_size) { return 0; } long long idx_size) { return 0; }
...@@ -431,9 +442,23 @@ static inline int ...@@ -431,9 +442,23 @@ static inline int
dbg_check_nondata_nodes_order(struct ubifs_info *c, dbg_check_nondata_nodes_order(struct ubifs_info *c,
struct list_head *head) { return 0; } struct list_head *head) { return 0; }
static inline int dbg_force_in_the_gaps(void) { return 0; } static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
#define dbg_force_in_the_gaps_enabled() 0 const void *buf, int offset,
#define dbg_failure_mode 0 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 int dbg_debugfs_init(void) { return 0; }
static inline void dbg_debugfs_exit(void) { return; } 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, ...@@ -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 * UBIFS has to fully control "clean <-> dirty" transitions of inodes
* to make budgeting work. * to make budgeting work.
*/ */
inode->i_flags |= (S_NOCMTIME); inode->i_flags |= S_NOCMTIME;
inode_init_owner(inode, dir, mode); inode_init_owner(inode, dir, mode);
inode->i_mtime = inode->i_atime = inode->i_ctime = 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, ...@@ -172,9 +172,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
#ifdef CONFIG_UBIFS_FS_DEBUG #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; return 0;
if (le16_to_cpu(dent->nlen) != nm->len) if (le16_to_cpu(dent->nlen) != nm->len)
return -EINVAL; return -EINVAL;
...@@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm) ...@@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
#else #else
#define dbg_check_name(dent, nm) 0 #define dbg_check_name(c, dent, nm) 0
#endif #endif
...@@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
goto out; goto out;
} }
if (dbg_check_name(dent, &dentry->d_name)) { if (dbg_check_name(c, dent, &dentry->d_name)) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
...@@ -522,7 +524,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -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(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->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) if (err)
return err; return err;
...@@ -577,7 +579,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -577,7 +579,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
inode->i_nlink, dir->i_ino); inode->i_nlink, dir->i_ino);
ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->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) if (err)
return err; return err;
......
...@@ -1263,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1263,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
if (err) if (err)
return err; return err;
err = dbg_check_synced_i_size(inode); err = dbg_check_synced_i_size(c, inode);
if (err) if (err)
return err; return err;
......
...@@ -86,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err) ...@@ -86,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
c->no_chk_data_crc = 0; c->no_chk_data_crc = 0;
c->vfs_sb->s_flags |= MS_RDONLY; c->vfs_sb->s_flags |= MS_RDONLY;
ubifs_warn("switched to read-only mode, error %d", err); 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(); dbg_dump_stack();
} }
return err;
} }
/** /**
...@@ -406,14 +523,10 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) ...@@ -406,14 +523,10 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
dirt = sync_len - wbuf->used; dirt = sync_len - wbuf->used;
if (dirt) if (dirt)
ubifs_pad(c, wbuf->buf + wbuf->used, dirt); ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
sync_len, wbuf->dtype); wbuf->dtype);
if (err) { if (err)
ubifs_err("cannot write %d bytes to LEB %d:%d",
sync_len, wbuf->lnum, wbuf->offs);
dbg_dump_stack();
return err; return err;
}
spin_lock(&wbuf->lock); spin_lock(&wbuf->lock);
wbuf->offs += sync_len; wbuf->offs += sync_len;
...@@ -605,9 +718,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) ...@@ -605,9 +718,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
if (aligned_len == wbuf->avail) { if (aligned_len == wbuf->avail) {
dbg_io("flush jhead %s wbuf to LEB %d:%d", dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs); dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
wbuf->offs, wbuf->size, wbuf->offs, wbuf->size,
wbuf->dtype); wbuf->dtype);
if (err) if (err)
goto out; goto out;
...@@ -642,8 +755,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) ...@@ -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_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs); dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail); memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
wbuf->size, wbuf->dtype); wbuf->size, wbuf->dtype);
if (err) if (err)
goto out; goto out;
...@@ -661,8 +774,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) ...@@ -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", dbg_io("write %d bytes to LEB %d:%d",
wbuf->size, wbuf->lnum, wbuf->offs); wbuf->size, wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf, wbuf->offs, err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
wbuf->size, wbuf->dtype); wbuf->size, wbuf->dtype);
if (err) if (err)
goto out; goto out;
...@@ -683,8 +796,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) ...@@ -683,8 +796,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
n <<= c->max_write_shift; n <<= c->max_write_shift;
dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
wbuf->offs); wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, err = ubifs_leb_write(c, wbuf->lnum, buf + written,
wbuf->offs, n, wbuf->dtype); wbuf->offs, n, wbuf->dtype);
if (err) if (err)
goto out; goto out;
wbuf->offs += n; wbuf->offs += n;
...@@ -766,13 +879,9 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, ...@@ -766,13 +879,9 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
return -EROFS; return -EROFS;
ubifs_prepare_node(c, buf, len, 1); ubifs_prepare_node(c, buf, len, 1);
err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype); err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
if (err) { if (err)
ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
buf_len, lnum, offs, err);
dbg_dump_node(c, buf); dbg_dump_node(c, buf);
dbg_dump_stack();
}
return err; return err;
} }
...@@ -824,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, ...@@ -824,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
if (rlen > 0) { if (rlen > 0) {
/* Read everything that goes before write-buffer */ /* Read everything that goes before write-buffer */
err = ubi_read(c->ubi, lnum, buf, offs, rlen); err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
if (err && err != -EBADMSG) { if (err && err != -EBADMSG)
ubifs_err("failed to read node %d from LEB %d:%d, "
"error %d", type, lnum, offs, err);
dbg_dump_stack();
return err; return err;
}
} }
if (type != ch->node_type) { if (type != ch->node_type) {
...@@ -885,12 +990,9 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len, ...@@ -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(!(offs & 7) && offs < c->leb_size);
ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
err = ubi_read(c->ubi, lnum, buf, offs, len); err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
if (err && err != -EBADMSG) { if (err && err != -EBADMSG)
ubifs_err("cannot read node %d from LEB %d:%d, error %d",
type, lnum, offs, err);
return err; return err;
}
if (type != ch->node_type) { if (type != ch->node_type) {
ubifs_err("bad node type (%d but expected %d)", 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) ...@@ -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 * an unclean reboot, because the target LEB might have been
* unmapped, but not yet physically erased. * 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) if (err)
goto out_unlock; goto out_unlock;
} }
...@@ -283,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) ...@@ -283,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
return 0; return 0;
out_unlock: out_unlock:
if (err != -EAGAIN)
ubifs_ro_mode(c, err);
mutex_unlock(&c->log_mutex); mutex_unlock(&c->log_mutex);
kfree(ref); kfree(ref);
kfree(bud); kfree(bud);
...@@ -752,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c) ...@@ -752,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
struct ubifs_bud *bud; struct ubifs_bud *bud;
long long bud_bytes = 0; long long bud_bytes = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
spin_lock(&c->buds_lock); spin_lock(&c->buds_lock);
......
...@@ -504,7 +504,7 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops) ...@@ -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, pnode = (struct ubifs_pnode *)container_of(lprops - pos,
struct ubifs_pnode, struct ubifs_pnode,
lprops[0]); lprops[0]);
return !test_bit(COW_ZNODE, &pnode->flags) && return !test_bit(COW_CNODE, &pnode->flags) &&
test_bit(DIRTY_CNODE, &pnode->flags); test_bit(DIRTY_CNODE, &pnode->flags);
} }
...@@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c) ...@@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c)
struct list_head *pos; struct list_head *pos;
int i, cat; 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; return 0;
list_for_each_entry(lprops, &c->empty_list, list) { 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, ...@@ -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; 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; return;
for (i = 0; i < heap->cnt; i++) { for (i = 0; i < heap->cnt; i++) {
...@@ -1262,7 +1262,7 @@ int dbg_check_lprops(struct ubifs_info *c) ...@@ -1262,7 +1262,7 @@ int dbg_check_lprops(struct ubifs_info *c)
int i, err; int i, err;
struct ubifs_lp_stats lst; struct ubifs_lp_stats lst;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
/* /*
......
...@@ -701,8 +701,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -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); alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len); set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len); memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM); UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
p = buf; p = buf;
...@@ -732,8 +732,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -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, set_ltab(c, lnum, c->leb_size - alen,
alen - len); alen - len);
memset(p, 0xff, alen - len); memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM); UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
p = buf; p = buf;
...@@ -780,8 +780,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -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); alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len); set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len); memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM); UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
p = buf; p = buf;
...@@ -806,7 +806,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -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); alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len); set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, 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) if (err)
goto out; goto out;
p = buf; p = buf;
...@@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
/* Write remaining buffer */ /* Write remaining buffer */
memset(p, 0xff, 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) if (err)
goto out; goto out;
...@@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip) ...@@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
if (c->big_lpt) if (c->big_lpt)
nnode->num = calc_nnode_num_from_parent(c, parent, iip); nnode->num = calc_nnode_num_from_parent(c, parent, iip);
} else { } 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) if (err)
goto out; goto out;
err = ubifs_unpack_nnode(c, buf, nnode); 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) ...@@ -1247,6 +1247,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out: out:
ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs); ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
dbg_dump_stack();
kfree(nnode); kfree(nnode);
return err; return err;
} }
...@@ -1290,7 +1291,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip) ...@@ -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); lprops->flags = ubifs_categorize_lprops(c, lprops);
} }
} else { } 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) if (err)
goto out; goto out;
err = unpack_pnode(c, buf, pnode); err = unpack_pnode(c, buf, pnode);
...@@ -1312,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip) ...@@ -1312,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out: out:
ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs); ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
dbg_dump_pnode(c, pnode, parent, iip); dbg_dump_pnode(c, pnode, parent, iip);
dbg_dump_stack();
dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip)); dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
kfree(pnode); kfree(pnode);
return err; return err;
...@@ -1331,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c) ...@@ -1331,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c)
buf = vmalloc(c->ltab_sz); buf = vmalloc(c->ltab_sz);
if (!buf) if (!buf)
return -ENOMEM; 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) if (err)
goto out; goto out;
err = unpack_ltab(c, buf); err = unpack_ltab(c, buf);
...@@ -1354,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c) ...@@ -1354,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c)
buf = vmalloc(c->lsave_sz); buf = vmalloc(c->lsave_sz);
if (!buf) if (!buf)
return -ENOMEM; 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) if (err)
goto out; goto out;
err = unpack_lsave(c, buf); err = unpack_lsave(c, buf);
...@@ -1814,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c, ...@@ -1814,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
if (c->big_lpt) if (c->big_lpt)
nnode->num = calc_nnode_num_from_parent(c, parent, iip); nnode->num = calc_nnode_num_from_parent(c, parent, iip);
} else { } else {
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs, err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
c->nnode_sz); c->nnode_sz, 1);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
err = ubifs_unpack_nnode(c, buf, nnode); err = ubifs_unpack_nnode(c, buf, nnode);
...@@ -1883,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c, ...@@ -1883,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
ubifs_assert(branch->lnum >= c->lpt_first && ubifs_assert(branch->lnum >= c->lpt_first &&
branch->lnum <= c->lpt_last); branch->lnum <= c->lpt_last);
ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size); ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs, err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
c->pnode_sz); c->pnode_sz, 1);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
err = unpack_pnode(c, buf, pnode); err = unpack_pnode(c, buf, pnode);
...@@ -2224,7 +2227,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, ...@@ -2224,7 +2227,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
struct ubifs_cnode *cn; struct ubifs_cnode *cn;
int num, iip = 0, err; int num, iip = 0, err;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
while (cnode) { while (cnode) {
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/crc16.h> #include <linux/crc16.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/random.h>
#include "ubifs.h" #include "ubifs.h"
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
...@@ -116,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c) ...@@ -116,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)
return 0; return 0;
cnt += 1; cnt += 1;
while (1) { while (1) {
ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags)); ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
__set_bit(COW_ZNODE, &cnode->flags); __set_bit(COW_CNODE, &cnode->flags);
cnext = next_dirty_cnode(cnode); cnext = next_dirty_cnode(cnode);
if (!cnext) { if (!cnext) {
cnode->cnext = c->lpt_cnext; cnode->cnext = c->lpt_cnext;
...@@ -465,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c) ...@@ -465,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c)
*/ */
clear_bit(DIRTY_CNODE, &cnode->flags); clear_bit(DIRTY_CNODE, &cnode->flags);
smp_mb__before_clear_bit(); smp_mb__before_clear_bit();
clear_bit(COW_ZNODE, &cnode->flags); clear_bit(COW_CNODE, &cnode->flags);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
offs += len; offs += len;
dbg_chk_lpt_sz(c, 1, len); dbg_chk_lpt_sz(c, 1, len);
...@@ -1160,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum) ...@@ -1160,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
void *buf = c->lpt_buf; void *buf = c->lpt_buf;
dbg_lp("LEB %d", lnum); dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) { err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
ubifs_err("cannot read LEB %d, error %d", lnum, err); if (err)
return err; return err;
}
while (1) { while (1) {
if (!is_a_node(c, buf, len)) { if (!is_a_node(c, buf, len)) {
int pad_len; int pad_len;
...@@ -1640,7 +1641,7 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum) ...@@ -1640,7 +1641,7 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
int ret; int ret;
void *buf, *p; void *buf, *p;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL); 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) ...@@ -1650,11 +1651,11 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
} }
dbg_lp("LEB %d", lnum); dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) { err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err); if (err)
goto out; goto out;
}
while (1) { while (1) {
if (!is_a_node(c, p, len)) { if (!is_a_node(c, p, len)) {
int i, pad_len; int i, pad_len;
...@@ -1711,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c) ...@@ -1711,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c)
{ {
int lnum, err, i, cnt; int lnum, err, i, cnt;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
/* Bring the entire tree into memory */ /* Bring the entire tree into memory */
...@@ -1754,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c) ...@@ -1754,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
long long free = 0; long long free = 0;
int i; int i;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
for (i = 0; i < c->lpt_lebs; i++) { 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) ...@@ -1796,7 +1797,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
long long chk_lpt_sz, lpt_sz; long long chk_lpt_sz, lpt_sz;
int err = 0; int err = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
switch (action) { switch (action) {
...@@ -1901,11 +1902,10 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum) ...@@ -1901,11 +1902,10 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
return; return;
} }
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
if (err) { if (err)
ubifs_err("cannot read LEB %d, error %d", lnum, err);
goto out; goto out;
}
while (1) { while (1) {
offs = c->leb_size - len; offs = c->leb_size - len;
if (!is_a_node(c, p, len)) { if (!is_a_node(c, p, len)) {
...@@ -2019,7 +2019,7 @@ static int dbg_populate_lsave(struct ubifs_info *c) ...@@ -2019,7 +2019,7 @@ static int dbg_populate_lsave(struct ubifs_info *c)
struct ubifs_lpt_heap *heap; struct ubifs_lpt_heap *heap;
int i; int i;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
if (random32() & 3) if (random32() & 3)
return 0; return 0;
......
...@@ -38,6 +38,29 @@ static inline int ubifs_zn_dirty(const struct ubifs_znode *znode) ...@@ -38,6 +38,29 @@ static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
return !!test_bit(DIRTY_ZNODE, &znode->flags); 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. * ubifs_wake_up_bgt - wake up background thread.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -121,86 +144,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf) ...@@ -121,86 +144,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
return err; 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. * ubifs_encode_dev - encode device node IDs.
* @dev: UBIFS device node information * @dev: UBIFS device node information
......
...@@ -929,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c) ...@@ -929,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c)
struct check_info ci; struct check_info ci;
int err; int err;
if (!(ubifs_chk_flags & UBIFS_CHK_ORPH)) if (!dbg_is_chk_orph(c))
return 0; return 0;
ci.last_ino = 0; ci.last_ino = 0;
......
...@@ -117,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf, ...@@ -117,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
if (!sbuf) if (!sbuf)
return -ENOMEM; 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) if (err && err != -EBADMSG)
goto out_free; goto out_free;
...@@ -213,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c, ...@@ -213,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY); mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1); 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) if (err)
goto out; 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) if (err)
goto out; goto out;
out: out:
...@@ -274,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c) ...@@ -274,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c)
if (cor1) if (cor1)
goto out_err; goto out_err;
mst = mst1; 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 */ /* 1st LEB was unmapped and written, 2nd not */
if (cor1) if (cor1)
goto out_err; goto out_err;
...@@ -539,8 +540,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -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); int len = ALIGN(endpt, c->min_io_size);
if (start) { if (start) {
err = ubi_read(c->ubi, lnum, sleb->buf, 0, err = ubifs_leb_read(c, lnum, sleb->buf, 0,
start); start, 1);
if (err) if (err)
return err; return err;
} }
...@@ -554,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -554,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ubifs_pad(c, buf, pad_len); ubifs_pad(c, buf, pad_len);
} }
} }
err = ubi_leb_change(c->ubi, lnum, sleb->buf, len, err = ubifs_leb_change(c, lnum, sleb->buf, len,
UBI_UNKNOWN); UBI_UNKNOWN);
if (err) if (err)
return err; return err;
} }
...@@ -819,7 +820,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs, ...@@ -819,7 +820,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
return -ENOMEM; return -ENOMEM;
if (c->leb_size - offs < UBIFS_CS_NODE_SZ) if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
goto out_err; 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) if (err && err != -EBADMSG)
goto out_free; goto out_free;
ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0); 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, ...@@ -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. * 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, static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
void *sbuf)
{ {
int len = c->max_write_size, err; int len = c->max_write_size, err;
...@@ -931,15 +932,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs, ...@@ -931,15 +932,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
return 0; return 0;
/* Read at the head location and check it is empty flash */ /* 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)) { if (err || !is_empty(sbuf, len)) {
dbg_rcvry("cleaning head at %d:%d", lnum, offs); dbg_rcvry("cleaning head at %d:%d", lnum, offs);
if (offs == 0) if (offs == 0)
return ubifs_leb_unmap(c, lnum); 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) if (err)
return 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; return 0;
...@@ -962,7 +963,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs, ...@@ -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. * 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; int err;
...@@ -993,7 +994,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf) ...@@ -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. * 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) struct ubifs_unclean_leb *ucleb, void *sbuf)
{ {
int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1; 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, ...@@ -1009,7 +1010,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
return 0; 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) if (err && err != -EBADMSG)
return err; return err;
...@@ -1069,7 +1070,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c, ...@@ -1069,7 +1070,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
} }
/* Write back the LEB atomically */ /* 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) if (err)
return err; return err;
...@@ -1089,7 +1090,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c, ...@@ -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. * 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"); dbg_rcvry("recovery");
while (!list_empty(&c->unclean_leb_list)) { 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) ...@@ -1454,7 +1455,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
if (i_size >= e->d_size) if (i_size >= e->d_size)
return 0; return 0;
/* Read the LEB */ /* 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) if (err)
goto out; goto out;
/* Change the size field and recalculate the CRC */ /* 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) ...@@ -1470,7 +1471,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
len -= 1; len -= 1;
len = ALIGN(len + 1, c->min_io_size); len = ALIGN(len + 1, c->min_io_size);
/* Atomically write the fixed LEB back again */ /* 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) if (err)
goto out; goto out;
dbg_rcvry("inode %lu at %d:%d size %lld -> %lld", 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) ...@@ -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)) if (!list_is_last(&next->list, &jh->buds_list))
return 0; return 0;
err = ubi_read(c->ubi, next->lnum, (char *)&data, err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
next->start, 4);
if (err) if (err)
return 0; return 0;
......
...@@ -674,15 +674,15 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int len) ...@@ -674,15 +674,15 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int len)
if (len == 0) { if (len == 0) {
dbg_mnt("unmap empty LEB %d", lnum); 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); 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) if (err)
return 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, ...@@ -148,7 +148,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
INIT_LIST_HEAD(&sleb->nodes); INIT_LIST_HEAD(&sleb->nodes);
sleb->buf = sbuf; 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) { if (err && err != -EBADMSG) {
ubifs_err("cannot read %d bytes from LEB %d:%d," ubifs_err("cannot read %d bytes from LEB %d:%d,"
" error %d", c->leb_size - offs, lnum, offs, err); " 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, ...@@ -240,7 +240,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
int len; int len;
ubifs_err("corruption at LEB %d:%d", lnum, offs); ubifs_err("corruption at LEB %d:%d", lnum, offs);
if (dbg_failure_mode) if (dbg_is_tst_rcvry(c))
return; return;
len = c->leb_size - offs; len = c->leb_size - offs;
if (len > 8192) if (len > 8192)
......
...@@ -85,7 +85,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -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) if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
return 4; return 4;
if (ui->xattr && (inode->i_mode & S_IFMT) != S_IFREG) if (ui->xattr && !S_ISREG(inode->i_mode))
return 5; return 5;
if (!ubifs_compr_present(ui->compr_type)) { if (!ubifs_compr_present(ui->compr_type)) {
...@@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
ubifs_compr_name(ui->compr_type)); ubifs_compr_name(ui->compr_type));
} }
err = dbg_check_dir_size(c, inode); err = dbg_check_dir(c, inode);
return err; return err;
} }
...@@ -914,7 +914,7 @@ static int check_volume_empty(struct ubifs_info *c) ...@@ -914,7 +914,7 @@ static int check_volume_empty(struct ubifs_info *c)
c->empty = 1; c->empty = 1;
for (lnum = 0; lnum < c->leb_cnt; lnum++) { 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)) if (unlikely(err < 0))
return err; return err;
if (err == 1) { if (err == 1) {
......
...@@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c, ...@@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
__set_bit(DIRTY_ZNODE, &zn->flags); __set_bit(DIRTY_ZNODE, &zn->flags);
__clear_bit(COW_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); __set_bit(OBSOLETE_ZNODE, &znode->flags);
if (znode->level != 0) { if (znode->level != 0) {
...@@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c, ...@@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
struct ubifs_znode *zn; struct ubifs_znode *zn;
int err; int err;
if (!test_bit(COW_ZNODE, &znode->flags)) { if (!ubifs_zn_cow(znode)) {
/* znode is not being committed */ /* znode is not being committed */
if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) { if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
atomic_long_inc(&c->dirty_zn_cnt); 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, ...@@ -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); 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) { if (err) {
ubifs_err("cannot read node type %d from LEB %d:%d, error %d", ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
type, lnum, offs, err); type, lnum, offs, err);
...@@ -1666,7 +1666,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum, ...@@ -1666,7 +1666,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
if (!overlap) { if (!overlap) {
/* We may safely unlock the write-buffer and read the data */ /* We may safely unlock the write-buffer and read the data */
spin_unlock(&wbuf->lock); 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 */ /* Don't read under wbuf */
...@@ -1680,7 +1680,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum, ...@@ -1680,7 +1680,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
if (rlen > 0) if (rlen > 0)
/* Read everything that goes before write-buffer */ /* 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; return 0;
} }
...@@ -1767,7 +1767,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu) ...@@ -1767,7 +1767,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
if (wbuf) if (wbuf)
err = read_wbuf(wbuf, bu->buf, len, lnum, offs); err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
else 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 */ /* Check for a race with GC */
if (maybe_leb_gced(c, lnum, bu->gc_seq)) 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) ...@@ -2423,7 +2423,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
*/ */
do { do {
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags)); ubifs_assert(!ubifs_zn_obsolete(znode));
ubifs_assert(ubifs_zn_dirty(znode)); ubifs_assert(ubifs_zn_dirty(znode));
zp = znode->parent; zp = znode->parent;
...@@ -2479,9 +2479,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n) ...@@ -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.offs = zbr->offs;
c->zroot.len = zbr->len; c->zroot.len = zbr->len;
c->zroot.znode = znode; c->zroot.znode = znode;
ubifs_assert(!test_bit(OBSOLETE_ZNODE, ubifs_assert(!ubifs_zn_obsolete(zp));
&zp->flags)); ubifs_assert(ubifs_zn_dirty(zp));
ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
atomic_long_dec(&c->dirty_zn_cnt); atomic_long_dec(&c->dirty_zn_cnt);
if (zp->cnext) { if (zp->cnext) {
...@@ -2865,7 +2864,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c) ...@@ -2865,7 +2864,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
struct ubifs_znode *znode = cnext; struct ubifs_znode *znode = cnext;
cnext = cnext->cnext; cnext = cnext->cnext;
if (test_bit(OBSOLETE_ZNODE, &znode->flags)) if (ubifs_zn_obsolete(znode))
kfree(znode); kfree(znode);
} while (cnext && cnext != c->cnext); } while (cnext && cnext != c->cnext);
} }
...@@ -3301,7 +3300,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode, ...@@ -3301,7 +3300,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return 0; return 0;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT; 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, ...@@ -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 " ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
"(data key %s)", (unsigned long)inode->i_ino, size, "(data key %s)", (unsigned long)inode->i_ino, size,
((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key)); ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
mutex_unlock(&c->tnc_mutex);
dbg_dump_inode(c, inode); dbg_dump_inode(c, inode);
dbg_dump_stack(); dbg_dump_stack();
err = -EINVAL; return -EINVAL;
out_unlock: out_unlock:
mutex_unlock(&c->tnc_mutex); mutex_unlock(&c->tnc_mutex);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
/* This file implements TNC functions for committing */ /* This file implements TNC functions for committing */
#include <linux/random.h>
#include "ubifs.h" #include "ubifs.h"
/** /**
...@@ -87,8 +88,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, ...@@ -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); atomic_long_dec(&c->dirty_zn_cnt);
ubifs_assert(ubifs_zn_dirty(znode)); 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(DIRTY_ZNODE, &znode->flags);
__clear_bit(COW_ZNODE, &znode->flags); __clear_bit(COW_ZNODE, &znode->flags);
...@@ -377,7 +382,7 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt) ...@@ -377,7 +382,7 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
c->gap_lebs = NULL; c->gap_lebs = NULL;
return err; return err;
} }
if (dbg_force_in_the_gaps_enabled()) { if (!dbg_is_chk_index(c)) {
/* /*
* Do not print scary warnings if the debugging * Do not print scary warnings if the debugging
* option which forces in-the-gaps is enabled. * option which forces in-the-gaps is enabled.
...@@ -491,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c) ...@@ -491,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c)
else else
next_len = ubifs_idx_node_sz(c, cnext->child_cnt); 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 */ /* Update buffer positions */
wlen = used + len; wlen = used + len;
used += ALIGN(len, 8); used += ALIGN(len, 8);
...@@ -658,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c) ...@@ -658,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c)
} }
cnt += 1; cnt += 1;
while (1) { while (1) {
ubifs_assert(!test_bit(COW_ZNODE, &znode->flags)); ubifs_assert(!ubifs_zn_cow(znode));
__set_bit(COW_ZNODE, &znode->flags); __set_bit(COW_ZNODE, &znode->flags);
znode->alt = 0; znode->alt = 0;
cnext = find_next_dirty(znode); cnext = find_next_dirty(znode);
...@@ -704,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt) ...@@ -704,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
c->ilebs[c->ileb_cnt++] = lnum; c->ilebs[c->ileb_cnt++] = lnum;
dbg_cmt("LEB %d", lnum); dbg_cmt("LEB %d", lnum);
} }
if (dbg_force_in_the_gaps()) if (dbg_is_chk_index(c) && !(random32() & 7))
return -ENOSPC; return -ENOSPC;
return 0; return 0;
} }
...@@ -830,7 +816,7 @@ static int write_index(struct ubifs_info *c) ...@@ -830,7 +816,7 @@ static int write_index(struct ubifs_info *c)
struct ubifs_idx_node *idx; struct ubifs_idx_node *idx;
struct ubifs_znode *znode, *cnext; struct ubifs_znode *znode, *cnext;
int i, lnum, offs, len, next_len, buf_len, buf_offs, used; 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; cnext = c->enext;
if (!cnext) if (!cnext)
...@@ -907,7 +893,7 @@ static int write_index(struct ubifs_info *c) ...@@ -907,7 +893,7 @@ static int write_index(struct ubifs_info *c)
cnext = znode->cnext; cnext = znode->cnext;
ubifs_assert(ubifs_zn_dirty(znode)); 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 * It is important that other threads should see %DIRTY_ZNODE
...@@ -922,6 +908,28 @@ static int write_index(struct ubifs_info *c) ...@@ -922,6 +908,28 @@ static int write_index(struct ubifs_info *c)
clear_bit(COW_ZNODE, &znode->flags); clear_bit(COW_ZNODE, &znode->flags);
smp_mb__after_clear_bit(); 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 */ /* Do not access znode from this point on */
/* Update buffer positions */ /* Update buffer positions */
...@@ -938,65 +946,38 @@ static int write_index(struct ubifs_info *c) ...@@ -938,65 +946,38 @@ static int write_index(struct ubifs_info *c)
else else
next_len = ubifs_idx_node_sz(c, cnext->child_cnt); next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
if (c->min_io_size == 1) { nxt_offs = buf_offs + used + next_len;
/* if (next_len && nxt_offs <= c->leb_size) {
* Write the prepared index node immediately if there is if (avail > 0)
* 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;
}
continue; continue;
} else
blen = buf_len;
} else { } else {
int blen, nxt_offs = buf_offs + used + next_len; wlen = ALIGN(wlen, 8);
blen = ALIGN(wlen, c->min_io_size);
if (next_len && nxt_offs <= c->leb_size) { ubifs_pad(c, c->cbuf + wlen, blen - wlen);
if (avail > 0) }
continue;
else /* The buffer is full or there are no more znodes to do */
blen = buf_len; err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
} else { UBI_SHORTTERM);
wlen = ALIGN(wlen, 8); if (err)
blen = ALIGN(wlen, c->min_io_size); return err;
ubifs_pad(c, c->cbuf + wlen, blen - wlen); buf_offs += blen;
} if (next_len) {
/* if (nxt_offs > c->leb_size) {
* The buffer is full or there are no more znodes err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
* to do 0, LPROPS_TAKEN);
*/ if (err)
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, return err;
blen, UBI_SHORTTERM); lnum = -1;
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;
} }
used -= blen;
if (used < 0)
used = 0;
avail = buf_len - used;
memmove(c->cbuf, c->cbuf + blen, used);
continue;
} }
break; break;
} }
...@@ -1029,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c) ...@@ -1029,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c)
do { do {
znode = cnext; znode = cnext;
cnext = znode->cnext; cnext = znode->cnext;
if (test_bit(OBSOLETE_ZNODE, &znode->flags)) if (ubifs_zn_obsolete(znode))
kfree(znode); kfree(znode);
else { else {
znode->cnext = NULL; znode->cnext = NULL;
......
...@@ -230,14 +230,14 @@ enum { ...@@ -230,14 +230,14 @@ enum {
* LPT cnode flag bits. * LPT cnode flag bits.
* *
* DIRTY_CNODE: cnode is dirty * 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), * 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 { enum {
DIRTY_CNODE = 0, DIRTY_CNODE = 0,
COW_CNODE = 1, OBSOLETE_CNODE = 1,
OBSOLETE_CNODE = 2, COW_CNODE = 2,
}; };
/* /*
...@@ -1468,6 +1468,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; ...@@ -1468,6 +1468,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
/* io.c */ /* io.c */
void ubifs_ro_mode(struct ubifs_info *c, int err); 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_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
int dtype); int dtype);
...@@ -1747,8 +1756,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, ...@@ -1747,8 +1756,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
int offs, void *sbuf, int jhead); int offs, void *sbuf, int jhead);
struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
int offs, void *sbuf); int offs, void *sbuf);
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf); int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
int ubifs_clean_lebs(const 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_rcvry_gc_commit(struct ubifs_info *c);
int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
int deletion, loff_t new_size); 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