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

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

* 'linux-next' of git://git.infradead.org/ubifs-2.6: (32 commits)
  MAINTAINERS: change e-mail of Adrian Hunter
  UBIFS: fix master node recovery
  UBIFS: improve power cut emulation testing
  UBIFS: rename recovery testing variables
  UBIFS: remove custom list of superblocks
  UBIFS: stop re-defining UBI operations
  UBIFS: switch to I/O helpers
  UBIFS: switch to ubifs_leb_write
  UBIFS: switch to ubifs_leb_read
  UBIFS: introduce more I/O helpers
  UBIFS: always print stacktrace when switching to R/O mode
  UBIFS: remove unused and unneeded debugging function
  UBIFS: add global debugfs knobs
  UBIFS: introduce debugfs helpers
  UBIFS: re-arrange debugging code a bit
  UBIFS: be more informative in failure mode
  UBIFS: switch self-check knobs to debugfs
  UBIFS: lessen amount of debugging check types
  UBIFS: introduce helper functions for debugging checks and tests
  UBIFS: amend debugging inode size check function prototype
  ...
parents f99b7880 cc8f9b99
......@@ -111,34 +111,6 @@ The following is an example of the kernel boot arguments to attach mtd0
to UBI and mount volume "rootfs":
ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs
Module Parameters for Debugging
===============================
When UBIFS has been compiled with debugging enabled, there are 2 module
parameters that are available to control aspects of testing and debugging.
debug_chks Selects extra checks that UBIFS can do while running:
Check Flag value
General checks 1
Check Tree Node Cache (TNC) 2
Check indexing tree size 4
Check orphan area 8
Check old indexing tree 16
Check LEB properties (lprops) 32
Check leaf nodes and inodes 64
debug_tsts Selects a mode of testing, as follows:
Test mode Flag value
Failure mode for recovery testing 4
For example, set debug_chks to 3 to enable general and TNC checks.
References
==========
......
List of maintainers and how to submit kernel changes
Please try to follow the guidelines below. This will make things
......@@ -6321,7 +6322,7 @@ F: drivers/scsi/u14-34f.c
UBI FILE SYSTEM (UBIFS)
M: Artem Bityutskiy <dedekind1@gmail.com>
M: Adrian Hunter <adrian.hunter@nokia.com>
M: Adrian Hunter <adrian.hunter@intel.com>
L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubifs-2.6.git
W: http://www.linux-mtd.infradead.org/doc/ubifs.html
......
......@@ -78,7 +78,7 @@ static int nothing_to_commit(struct ubifs_info *c)
* If the root TNC node is dirty, we definitely have something to
* commit.
*/
if (c->zroot.znode && test_bit(DIRTY_ZNODE, &c->zroot.znode->flags))
if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
return 0;
/*
......@@ -418,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c)
spin_lock(&c->cs_lock);
if (c->cmt_state == COMMIT_BROKEN) {
err = -EINVAL;
err = -EROFS;
goto out;
}
......@@ -444,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c)
* re-check it.
*/
if (c->cmt_state == COMMIT_BROKEN) {
err = -EINVAL;
err = -EROFS;
goto out_cmt_unlock;
}
......@@ -576,7 +576,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
struct idx_node *i;
size_t sz;
if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX))
if (!dbg_is_chk_index(c))
return 0;
INIT_LIST_HEAD(&list);
......
This diff is collapsed.
This diff is collapsed.
......@@ -102,7 +102,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
* UBIFS has to fully control "clean <-> dirty" transitions of inodes
* to make budgeting work.
*/
inode->i_flags |= (S_NOCMTIME);
inode->i_flags |= S_NOCMTIME;
inode_init_owner(inode, dir, mode);
inode->i_mtime = inode->i_atime = inode->i_ctime =
......@@ -172,9 +172,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
#ifdef CONFIG_UBIFS_FS_DEBUG
static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
static int dbg_check_name(const struct ubifs_info *c,
const struct ubifs_dent_node *dent,
const struct qstr *nm)
{
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
if (le16_to_cpu(dent->nlen) != nm->len)
return -EINVAL;
......@@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
#else
#define dbg_check_name(dent, nm) 0
#define dbg_check_name(c, dent, nm) 0
#endif
......@@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
goto out;
}
if (dbg_check_name(dent, &dentry->d_name)) {
if (dbg_check_name(c, dent, &dentry->d_name)) {
err = -EINVAL;
goto out;
}
......@@ -522,7 +524,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex));
err = dbg_check_synced_i_size(inode);
err = dbg_check_synced_i_size(c, inode);
if (err)
return err;
......@@ -577,7 +579,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
inode->i_nlink, dir->i_ino);
ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex));
err = dbg_check_synced_i_size(inode);
err = dbg_check_synced_i_size(c, inode);
if (err)
return err;
......
......@@ -1263,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
return err;
err = dbg_check_synced_i_size(inode);
err = dbg_check_synced_i_size(c, inode);
if (err)
return err;
......
......@@ -86,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
c->no_chk_data_crc = 0;
c->vfs_sb->s_flags |= MS_RDONLY;
ubifs_warn("switched to read-only mode, error %d", err);
dump_stack();
}
}
/*
* Below are simple wrappers over UBI I/O functions which include some
* additional checks and UBIFS debugging stuff. See corresponding UBI function
* for more information.
*/
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
int len, int even_ebadmsg)
{
int err;
err = ubi_read(c->ubi, lnum, buf, offs, len);
/*
* In case of %-EBADMSG print the error message only if the
* @even_ebadmsg is true.
*/
if (err && (err != -EBADMSG || even_ebadmsg)) {
ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
len, lnum, offs, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
else
err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
if (err) {
ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
len, lnum, offs, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
else
err = dbg_leb_change(c, lnum, buf, len, dtype);
if (err) {
ubifs_err("changing %d bytes in LEB %d failed, error %d",
len, lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_unmap(c->ubi, lnum);
else
err = dbg_leb_unmap(c, lnum);
if (err) {
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_map(c->ubi, lnum, dtype);
else
err = dbg_leb_map(c, lnum, dtype);
if (err) {
ubifs_err("mapping LEB %d failed, error %d", lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
{
int err;
err = ubi_is_mapped(c->ubi, lnum);
if (err < 0) {
ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
lnum, err);
dbg_dump_stack();
}
return err;
}
/**
......@@ -406,14 +523,10 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
dirt = sync_len - wbuf->used;
if (dirt)
ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
sync_len, wbuf->dtype);
if (err) {
ubifs_err("cannot write %d bytes to LEB %d:%d",
sync_len, wbuf->lnum, wbuf->offs);
dbg_dump_stack();
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
wbuf->dtype);
if (err)
return err;
}
spin_lock(&wbuf->lock);
wbuf->offs += sync_len;
......@@ -605,9 +718,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
if (aligned_len == wbuf->avail) {
dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
wbuf->offs, wbuf->size,
wbuf->dtype);
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
wbuf->offs, wbuf->size,
wbuf->dtype);
if (err)
goto out;
......@@ -642,8 +755,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
wbuf->size, wbuf->dtype);
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
wbuf->size, wbuf->dtype);
if (err)
goto out;
......@@ -661,8 +774,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
*/
dbg_io("write %d bytes to LEB %d:%d",
wbuf->size, wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf, wbuf->offs,
wbuf->size, wbuf->dtype);
err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
wbuf->size, wbuf->dtype);
if (err)
goto out;
......@@ -683,8 +796,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
n <<= c->max_write_shift;
dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written,
wbuf->offs, n, wbuf->dtype);
err = ubifs_leb_write(c, wbuf->lnum, buf + written,
wbuf->offs, n, wbuf->dtype);
if (err)
goto out;
wbuf->offs += n;
......@@ -766,13 +879,9 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
return -EROFS;
ubifs_prepare_node(c, buf, len, 1);
err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype);
if (err) {
ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
buf_len, lnum, offs, err);
err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
if (err)
dbg_dump_node(c, buf);
dbg_dump_stack();
}
return err;
}
......@@ -824,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
if (rlen > 0) {
/* Read everything that goes before write-buffer */
err = ubi_read(c->ubi, lnum, buf, offs, rlen);
if (err && err != -EBADMSG) {
ubifs_err("failed to read node %d from LEB %d:%d, "
"error %d", type, lnum, offs, err);
dbg_dump_stack();
err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
if (err && err != -EBADMSG)
return err;
}
}
if (type != ch->node_type) {
......@@ -885,12 +990,9 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
ubifs_assert(!(offs & 7) && offs < c->leb_size);
ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
err = ubi_read(c->ubi, lnum, buf, offs, len);
if (err && err != -EBADMSG) {
ubifs_err("cannot read node %d from LEB %d:%d, error %d",
type, lnum, offs, err);
err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
if (err && err != -EBADMSG)
return err;
}
if (type != ch->node_type) {
ubifs_err("bad node type (%d but expected %d)",
......
......@@ -262,7 +262,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
* an unclean reboot, because the target LEB might have been
* unmapped, but not yet physically erased.
*/
err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM);
err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
if (err)
goto out_unlock;
}
......@@ -283,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
return 0;
out_unlock:
if (err != -EAGAIN)
ubifs_ro_mode(c, err);
mutex_unlock(&c->log_mutex);
kfree(ref);
kfree(bud);
......@@ -752,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
struct ubifs_bud *bud;
long long bud_bytes = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
spin_lock(&c->buds_lock);
......
......@@ -504,7 +504,7 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
pnode = (struct ubifs_pnode *)container_of(lprops - pos,
struct ubifs_pnode,
lprops[0]);
return !test_bit(COW_ZNODE, &pnode->flags) &&
return !test_bit(COW_CNODE, &pnode->flags) &&
test_bit(DIRTY_CNODE, &pnode->flags);
}
......@@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c)
struct list_head *pos;
int i, cat;
if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
return 0;
list_for_each_entry(lprops, &c->empty_list, list) {
......@@ -958,7 +958,7 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
{
int i = 0, j, err = 0;
if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
return;
for (i = 0; i < heap->cnt; i++) {
......@@ -1262,7 +1262,7 @@ int dbg_check_lprops(struct ubifs_info *c)
int i, err;
struct ubifs_lp_stats lst;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
/*
......
......@@ -701,8 +701,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM);
if (err)
goto out;
p = buf;
......@@ -732,8 +732,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
set_ltab(c, lnum, c->leb_size - alen,
alen - len);
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM);
if (err)
goto out;
p = buf;
......@@ -780,8 +780,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM);
if (err)
goto out;
p = buf;
......@@ -806,7 +806,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
if (err)
goto out;
p = buf;
......@@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
/* Write remaining buffer */
memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
if (err)
goto out;
......@@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
if (c->big_lpt)
nnode->num = calc_nnode_num_from_parent(c, parent, iip);
} else {
err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
if (err)
goto out;
err = ubifs_unpack_nnode(c, buf, nnode);
......@@ -1247,6 +1247,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out:
ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
dbg_dump_stack();
kfree(nnode);
return err;
}
......@@ -1290,7 +1291,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
lprops->flags = ubifs_categorize_lprops(c, lprops);
}
} else {
err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
if (err)
goto out;
err = unpack_pnode(c, buf, pnode);
......@@ -1312,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out:
ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
dbg_dump_pnode(c, pnode, parent, iip);
dbg_dump_stack();
dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
kfree(pnode);
return err;
......@@ -1331,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c)
buf = vmalloc(c->ltab_sz);
if (!buf)
return -ENOMEM;
err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
if (err)
goto out;
err = unpack_ltab(c, buf);
......@@ -1354,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c)
buf = vmalloc(c->lsave_sz);
if (!buf)
return -ENOMEM;
err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz);
err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
c->lsave_sz, 1);
if (err)
goto out;
err = unpack_lsave(c, buf);
......@@ -1814,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
if (c->big_lpt)
nnode->num = calc_nnode_num_from_parent(c, parent, iip);
} else {
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
c->nnode_sz);
err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
c->nnode_sz, 1);
if (err)
return ERR_PTR(err);
err = ubifs_unpack_nnode(c, buf, nnode);
......@@ -1883,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
ubifs_assert(branch->lnum >= c->lpt_first &&
branch->lnum <= c->lpt_last);
ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
c->pnode_sz);
err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
c->pnode_sz, 1);
if (err)
return ERR_PTR(err);
err = unpack_pnode(c, buf, pnode);
......@@ -2224,7 +2227,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
struct ubifs_cnode *cn;
int num, iip = 0, err;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
while (cnode) {
......
......@@ -27,6 +27,7 @@
#include <linux/crc16.h>
#include <linux/slab.h>
#include <linux/random.h>
#include "ubifs.h"
#ifdef CONFIG_UBIFS_FS_DEBUG
......@@ -116,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)
return 0;
cnt += 1;
while (1) {
ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags));
__set_bit(COW_ZNODE, &cnode->flags);
ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
__set_bit(COW_CNODE, &cnode->flags);
cnext = next_dirty_cnode(cnode);
if (!cnext) {
cnode->cnext = c->lpt_cnext;
......@@ -465,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c)
*/
clear_bit(DIRTY_CNODE, &cnode->flags);
smp_mb__before_clear_bit();
clear_bit(COW_ZNODE, &cnode->flags);
clear_bit(COW_CNODE, &cnode->flags);
smp_mb__after_clear_bit();
offs += len;
dbg_chk_lpt_sz(c, 1, len);
......@@ -1160,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
void *buf = c->lpt_buf;
dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
ubifs_err("cannot read LEB %d, error %d", lnum, err);
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
if (err)
return err;
}
while (1) {
if (!is_a_node(c, buf, len)) {
int pad_len;
......@@ -1640,7 +1641,7 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
int ret;
void *buf, *p;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
......@@ -1650,11 +1651,11 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
}
dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err);
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
if (err)
goto out;
}
while (1) {
if (!is_a_node(c, p, len)) {
int i, pad_len;
......@@ -1711,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c)
{
int lnum, err, i, cnt;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
/* Bring the entire tree into memory */
......@@ -1754,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
long long free = 0;
int i;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
for (i = 0; i < c->lpt_lebs; i++) {
......@@ -1796,7 +1797,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
long long chk_lpt_sz, lpt_sz;
int err = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
if (!dbg_is_chk_lprops(c))
return 0;
switch (action) {
......@@ -1901,11 +1902,10 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
return;
}
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) {
ubifs_err("cannot read LEB %d, error %d", lnum, err);
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
if (err)
goto out;
}
while (1) {
offs = c->leb_size - len;
if (!is_a_node(c, p, len)) {
......@@ -2019,7 +2019,7 @@ static int dbg_populate_lsave(struct ubifs_info *c)
struct ubifs_lpt_heap *heap;
int i;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
if (random32() & 3)
return 0;
......
......@@ -38,6 +38,29 @@ static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
return !!test_bit(DIRTY_ZNODE, &znode->flags);
}
/**
* ubifs_zn_obsolete - check if znode is obsolete.
* @znode: znode to check
*
* This helper function returns %1 if @znode is obsolete and %0 otherwise.
*/
static inline int ubifs_zn_obsolete(const struct ubifs_znode *znode)
{
return !!test_bit(OBSOLETE_ZNODE, &znode->flags);
}
/**
* ubifs_zn_cow - check if znode has to be copied on write.
* @znode: znode to check
*
* This helper function returns %1 if @znode is has COW flag set and %0
* otherwise.
*/
static inline int ubifs_zn_cow(const struct ubifs_znode *znode)
{
return !!test_bit(COW_ZNODE, &znode->flags);
}
/**
* ubifs_wake_up_bgt - wake up background thread.
* @c: UBIFS file-system description object
......@@ -121,86 +144,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
return err;
}
/**
* ubifs_leb_unmap - unmap an LEB.
* @c: UBIFS file-system description object
* @lnum: LEB number to unmap
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_unmap(c->ubi, lnum);
if (err) {
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
return err;
}
return 0;
}
/**
* ubifs_leb_write - write to a LEB.
* @c: UBIFS file-system description object
* @lnum: LEB number to write
* @buf: buffer to write from
* @offs: offset within LEB to write to
* @len: length to write
* @dtype: data type
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
const void *buf, int offs, int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
if (err) {
ubifs_err("writing %d bytes at %d:%d, error %d",
len, lnum, offs, err);
return err;
}
return 0;
}
/**
* ubifs_leb_change - atomic LEB change.
* @c: UBIFS file-system description object
* @lnum: LEB number to write
* @buf: buffer to write from
* @len: length to write
* @dtype: data type
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
const void *buf, int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
if (err) {
ubifs_err("changing %d bytes in LEB %d, error %d",
len, lnum, err);
return err;
}
return 0;
}
/**
* ubifs_encode_dev - encode device node IDs.
* @dev: UBIFS device node information
......
......@@ -929,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c)
struct check_info ci;
int err;
if (!(ubifs_chk_flags & UBIFS_CHK_ORPH))
if (!dbg_is_chk_orph(c))
return 0;
ci.last_ino = 0;
......
......@@ -117,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
if (!sbuf)
return -ENOMEM;
err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
err = ubifs_leb_read(c, lnum, sbuf, 0, c->leb_size, 0);
if (err && err != -EBADMSG)
goto out_free;
......@@ -213,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
if (err)
goto out;
err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
if (err)
goto out;
out:
......@@ -274,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c)
if (cor1)
goto out_err;
mst = mst1;
} else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
} else if (offs1 == 0 &&
c->leb_size - offs2 - sz < sz) {
/* 1st LEB was unmapped and written, 2nd not */
if (cor1)
goto out_err;
......@@ -539,8 +540,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
int len = ALIGN(endpt, c->min_io_size);
if (start) {
err = ubi_read(c->ubi, lnum, sleb->buf, 0,
start);
err = ubifs_leb_read(c, lnum, sleb->buf, 0,
start, 1);
if (err)
return err;
}
......@@ -554,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ubifs_pad(c, buf, pad_len);
}
}
err = ubi_leb_change(c->ubi, lnum, sleb->buf, len,
UBI_UNKNOWN);
err = ubifs_leb_change(c, lnum, sleb->buf, len,
UBI_UNKNOWN);
if (err)
return err;
}
......@@ -819,7 +820,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
return -ENOMEM;
if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
goto out_err;
err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
err = ubifs_leb_read(c, lnum, (void *)cs_node, offs,
UBIFS_CS_NODE_SZ, 0);
if (err && err != -EBADMSG)
goto out_free;
ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
......@@ -919,8 +921,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
*
* This function returns %0 on success and a negative error code on failure.
*/
static int recover_head(const struct ubifs_info *c, int lnum, int offs,
void *sbuf)
static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
{
int len = c->max_write_size, err;
......@@ -931,15 +932,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
return 0;
/* Read at the head location and check it is empty flash */
err = ubi_read(c->ubi, lnum, sbuf, offs, len);
err = ubifs_leb_read(c, lnum, sbuf, offs, len, 1);
if (err || !is_empty(sbuf, len)) {
dbg_rcvry("cleaning head at %d:%d", lnum, offs);
if (offs == 0)
return ubifs_leb_unmap(c, lnum);
err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
if (err)
return err;
return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
}
return 0;
......@@ -962,7 +963,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
*
* This function returns %0 on success and a negative error code on failure.
*/
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
{
int err;
......@@ -993,7 +994,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
*
* This function returns %0 on success and a negative error code on failure.
*/
static int clean_an_unclean_leb(const struct ubifs_info *c,
static int clean_an_unclean_leb(struct ubifs_info *c,
struct ubifs_unclean_leb *ucleb, void *sbuf)
{
int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
......@@ -1009,7 +1010,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
return 0;
}
err = ubi_read(c->ubi, lnum, buf, offs, len);
err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
if (err && err != -EBADMSG)
return err;
......@@ -1069,7 +1070,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
}
/* Write back the LEB atomically */
err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
if (err)
return err;
......@@ -1089,7 +1090,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
*
* This function returns %0 on success and a negative error code on failure.
*/
int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
{
dbg_rcvry("recovery");
while (!list_empty(&c->unclean_leb_list)) {
......@@ -1454,7 +1455,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
if (i_size >= e->d_size)
return 0;
/* Read the LEB */
err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size);
err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1);
if (err)
goto out;
/* Change the size field and recalculate the CRC */
......@@ -1470,7 +1471,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
len -= 1;
len = ALIGN(len + 1, c->min_io_size);
/* Atomically write the fixed LEB back again */
err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
if (err)
goto out;
dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
......
......@@ -523,8 +523,7 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
if (!list_is_last(&next->list, &jh->buds_list))
return 0;
err = ubi_read(c->ubi, next->lnum, (char *)&data,
next->start, 4);
err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
if (err)
return 0;
......
......@@ -674,15 +674,15 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int len)
if (len == 0) {
dbg_mnt("unmap empty LEB %d", lnum);
return ubi_leb_unmap(c->ubi, lnum);
return ubifs_leb_unmap(c, lnum);
}
dbg_mnt("fixup LEB %d, data len %d", lnum, len);
err = ubi_read(c->ubi, lnum, c->sbuf, 0, len);
err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 1);
if (err)
return err;
return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
}
/**
......
......@@ -148,7 +148,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
INIT_LIST_HEAD(&sleb->nodes);
sleb->buf = sbuf;
err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs, 0);
if (err && err != -EBADMSG) {
ubifs_err("cannot read %d bytes from LEB %d:%d,"
" error %d", c->leb_size - offs, lnum, offs, err);
......@@ -240,7 +240,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
int len;
ubifs_err("corruption at LEB %d:%d", lnum, offs);
if (dbg_failure_mode)
if (dbg_is_tst_rcvry(c))
return;
len = c->leb_size - offs;
if (len > 8192)
......
......@@ -85,7 +85,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
return 4;
if (ui->xattr && (inode->i_mode & S_IFMT) != S_IFREG)
if (ui->xattr && !S_ISREG(inode->i_mode))
return 5;
if (!ubifs_compr_present(ui->compr_type)) {
......@@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
ubifs_compr_name(ui->compr_type));
}
err = dbg_check_dir_size(c, inode);
err = dbg_check_dir(c, inode);
return err;
}
......@@ -914,7 +914,7 @@ static int check_volume_empty(struct ubifs_info *c)
c->empty = 1;
for (lnum = 0; lnum < c->leb_cnt; lnum++) {
err = ubi_is_mapped(c->ubi, lnum);
err = ubifs_is_mapped(c, lnum);
if (unlikely(err < 0))
return err;
if (err == 1) {
......
......@@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
__set_bit(DIRTY_ZNODE, &zn->flags);
__clear_bit(COW_ZNODE, &zn->flags);
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
ubifs_assert(!ubifs_zn_obsolete(znode));
__set_bit(OBSOLETE_ZNODE, &znode->flags);
if (znode->level != 0) {
......@@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
struct ubifs_znode *zn;
int err;
if (!test_bit(COW_ZNODE, &znode->flags)) {
if (!ubifs_zn_cow(znode)) {
/* znode is not being committed */
if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
atomic_long_inc(&c->dirty_zn_cnt);
......@@ -462,7 +462,7 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
err = ubi_read(c->ubi, lnum, buf, offs, len);
err = ubifs_leb_read(c, lnum, buf, offs, len, 1);
if (err) {
ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
type, lnum, offs, err);
......@@ -1666,7 +1666,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
if (!overlap) {
/* We may safely unlock the write-buffer and read the data */
spin_unlock(&wbuf->lock);
return ubi_read(c->ubi, lnum, buf, offs, len);
return ubifs_leb_read(c, lnum, buf, offs, len, 0);
}
/* Don't read under wbuf */
......@@ -1680,7 +1680,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
if (rlen > 0)
/* Read everything that goes before write-buffer */
return ubi_read(c->ubi, lnum, buf, offs, rlen);
return ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
return 0;
}
......@@ -1767,7 +1767,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
if (wbuf)
err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
else
err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
err = ubifs_leb_read(c, lnum, bu->buf, offs, len, 0);
/* Check for a race with GC */
if (maybe_leb_gced(c, lnum, bu->gc_seq))
......@@ -2423,7 +2423,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
*/
do {
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
ubifs_assert(!ubifs_zn_obsolete(znode));
ubifs_assert(ubifs_zn_dirty(znode));
zp = znode->parent;
......@@ -2479,9 +2479,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
c->zroot.offs = zbr->offs;
c->zroot.len = zbr->len;
c->zroot.znode = znode;
ubifs_assert(!test_bit(OBSOLETE_ZNODE,
&zp->flags));
ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
ubifs_assert(!ubifs_zn_obsolete(zp));
ubifs_assert(ubifs_zn_dirty(zp));
atomic_long_dec(&c->dirty_zn_cnt);
if (zp->cnext) {
......@@ -2865,7 +2864,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
struct ubifs_znode *znode = cnext;
cnext = cnext->cnext;
if (test_bit(OBSOLETE_ZNODE, &znode->flags))
if (ubifs_zn_obsolete(znode))
kfree(znode);
} while (cnext && cnext != c->cnext);
}
......@@ -3301,7 +3300,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
if (!S_ISREG(inode->i_mode))
return 0;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
if (!dbg_is_chk_gen(c))
return 0;
block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
......@@ -3337,9 +3336,10 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
"(data key %s)", (unsigned long)inode->i_ino, size,
((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
mutex_unlock(&c->tnc_mutex);
dbg_dump_inode(c, inode);
dbg_dump_stack();
err = -EINVAL;
return -EINVAL;
out_unlock:
mutex_unlock(&c->tnc_mutex);
......
......@@ -22,6 +22,7 @@
/* This file implements TNC functions for committing */
#include <linux/random.h>
#include "ubifs.h"
/**
......@@ -87,8 +88,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
atomic_long_dec(&c->dirty_zn_cnt);
ubifs_assert(ubifs_zn_dirty(znode));
ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
ubifs_assert(ubifs_zn_cow(znode));
/*
* Note, unlike 'write_index()' we do not add memory barriers here
* because this function is called with @c->tnc_mutex locked.
*/
__clear_bit(DIRTY_ZNODE, &znode->flags);
__clear_bit(COW_ZNODE, &znode->flags);
......@@ -377,7 +382,7 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
c->gap_lebs = NULL;
return err;
}
if (dbg_force_in_the_gaps_enabled()) {
if (!dbg_is_chk_index(c)) {
/*
* Do not print scary warnings if the debugging
* option which forces in-the-gaps is enabled.
......@@ -491,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c)
else
next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
if (c->min_io_size == 1) {
buf_offs += ALIGN(len, 8);
if (next_len) {
if (buf_offs + next_len <= c->leb_size)
continue;
err = ubifs_update_one_lp(c, lnum, 0,
c->leb_size - buf_offs, 0, 0);
if (err)
return err;
lnum = -1;
continue;
}
err = ubifs_update_one_lp(c, lnum,
c->leb_size - buf_offs, 0, 0, 0);
if (err)
return err;
break;
}
/* Update buffer positions */
wlen = used + len;
used += ALIGN(len, 8);
......@@ -658,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c)
}
cnt += 1;
while (1) {
ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
ubifs_assert(!ubifs_zn_cow(znode));
__set_bit(COW_ZNODE, &znode->flags);
znode->alt = 0;
cnext = find_next_dirty(znode);
......@@ -704,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
c->ilebs[c->ileb_cnt++] = lnum;
dbg_cmt("LEB %d", lnum);
}
if (dbg_force_in_the_gaps())
if (dbg_is_chk_index(c) && !(random32() & 7))
return -ENOSPC;
return 0;
}
......@@ -830,7 +816,7 @@ static int write_index(struct ubifs_info *c)
struct ubifs_idx_node *idx;
struct ubifs_znode *znode, *cnext;
int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
int avail, wlen, err, lnum_pos = 0;
int avail, wlen, err, lnum_pos = 0, blen, nxt_offs;
cnext = c->enext;
if (!cnext)
......@@ -907,7 +893,7 @@ static int write_index(struct ubifs_info *c)
cnext = znode->cnext;
ubifs_assert(ubifs_zn_dirty(znode));
ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
ubifs_assert(ubifs_zn_cow(znode));
/*
* It is important that other threads should see %DIRTY_ZNODE
......@@ -922,6 +908,28 @@ static int write_index(struct ubifs_info *c)
clear_bit(COW_ZNODE, &znode->flags);
smp_mb__after_clear_bit();
/*
* We have marked the znode as clean but have not updated the
* @c->clean_zn_cnt counter. If this znode becomes dirty again
* before 'free_obsolete_znodes()' is called, then
* @c->clean_zn_cnt will be decremented before it gets
* incremented (resulting in 2 decrements for the same znode).
* This means that @c->clean_zn_cnt may become negative for a
* while.
*
* Q: why we cannot increment @c->clean_zn_cnt?
* A: because we do not have the @c->tnc_mutex locked, and the
* following code would be racy and buggy:
*
* if (!ubifs_zn_obsolete(znode)) {
* atomic_long_inc(&c->clean_zn_cnt);
* atomic_long_inc(&ubifs_clean_zn_cnt);
* }
*
* Thus, we just delay the @c->clean_zn_cnt update until we
* have the mutex locked.
*/
/* Do not access znode from this point on */
/* Update buffer positions */
......@@ -938,65 +946,38 @@ static int write_index(struct ubifs_info *c)
else
next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
if (c->min_io_size == 1) {
/*
* Write the prepared index node immediately if there is
* no minimum IO size
*/
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
wlen, UBI_SHORTTERM);
if (err)
return err;
buf_offs += ALIGN(wlen, 8);
if (next_len) {
used = 0;
avail = buf_len;
if (buf_offs + next_len > c->leb_size) {
err = ubifs_update_one_lp(c, lnum,
LPROPS_NC, 0, 0, LPROPS_TAKEN);
if (err)
return err;
lnum = -1;
}
nxt_offs = buf_offs + used + next_len;
if (next_len && nxt_offs <= c->leb_size) {
if (avail > 0)
continue;
}
else
blen = buf_len;
} else {
int blen, nxt_offs = buf_offs + used + next_len;
if (next_len && nxt_offs <= c->leb_size) {
if (avail > 0)
continue;
else
blen = buf_len;
} else {
wlen = ALIGN(wlen, 8);
blen = ALIGN(wlen, c->min_io_size);
ubifs_pad(c, c->cbuf + wlen, blen - wlen);
}
/*
* The buffer is full or there are no more znodes
* to do
*/
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
blen, UBI_SHORTTERM);
if (err)
return err;
buf_offs += blen;
if (next_len) {
if (nxt_offs > c->leb_size) {
err = ubifs_update_one_lp(c, lnum,
LPROPS_NC, 0, 0, LPROPS_TAKEN);
if (err)
return err;
lnum = -1;
}
used -= blen;
if (used < 0)
used = 0;
avail = buf_len - used;
memmove(c->cbuf, c->cbuf + blen, used);
continue;
wlen = ALIGN(wlen, 8);
blen = ALIGN(wlen, c->min_io_size);
ubifs_pad(c, c->cbuf + wlen, blen - wlen);
}
/* The buffer is full or there are no more znodes to do */
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
UBI_SHORTTERM);
if (err)
return err;
buf_offs += blen;
if (next_len) {
if (nxt_offs > c->leb_size) {
err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
0, LPROPS_TAKEN);
if (err)
return err;
lnum = -1;
}
used -= blen;
if (used < 0)
used = 0;
avail = buf_len - used;
memmove(c->cbuf, c->cbuf + blen, used);
continue;
}
break;
}
......@@ -1029,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c)
do {
znode = cnext;
cnext = znode->cnext;
if (test_bit(OBSOLETE_ZNODE, &znode->flags))
if (ubifs_zn_obsolete(znode))
kfree(znode);
else {
znode->cnext = NULL;
......
......@@ -230,14 +230,14 @@ enum {
* LPT cnode flag bits.
*
* DIRTY_CNODE: cnode is dirty
* COW_CNODE: cnode is being committed and must be copied before writing
* OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
* so it can (and must) be freed when the commit is finished
* so it can (and must) be freed when the commit is finished
* COW_CNODE: cnode is being committed and must be copied before writing
*/
enum {
DIRTY_CNODE = 0,
COW_CNODE = 1,
OBSOLETE_CNODE = 2,
OBSOLETE_CNODE = 1,
COW_CNODE = 2,
};
/*
......@@ -1468,6 +1468,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
/* io.c */
void ubifs_ro_mode(struct ubifs_info *c, int err);
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
int len, int even_ebadmsg);
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
int len, int dtype);
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
int dtype);
int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
int dtype);
......@@ -1747,8 +1756,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
int offs, void *sbuf, int jhead);
struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
int offs, void *sbuf);
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
int ubifs_rcvry_gc_commit(struct ubifs_info *c);
int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
int deletion, loff_t new_size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment