From 549c999a768a7a144c60a0faa58f34c48f39112b Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 26 May 2011 16:57:14 +0300 Subject: UBIFS: return EROFS in case of broken commit If commit failed and it is in broken state, UBIFS switches to R/O mode. Most operations return -EROFS in this case, except of commit which returns -EINVAL. Make it return -EROFS too for consistency. This is also important for our power cut emulation testing. Signed-off-by: Artem Bityutskiy --- fs/ubifs/commit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c index 87cd0ead8633..8ab03d12d5c0 100644 --- a/fs/ubifs/commit.c +++ b/fs/ubifs/commit.c @@ -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; } -- cgit v1.2.3 From ae380ce04731579f45f27b3a84d7d8d8ee1f9b1b Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 19 May 2011 14:13:16 +0300 Subject: UBIFS: lessen the size of debugging info data structure This patch lessens the 'struct ubifs_debug_info' size by 90 bytes by allocating less bytes for the debugfs root directory name. It introduces macros for the name patter an length instead of hard-coding 100 bytes. It also makes UBIFS use 'snprintf()' and teaches it to gracefully catch situations when the name array is too short. Additionally, this patch makes 2 unrelated changes - I just thought they do not deserve separate commits: simplifies 'ubifs_assert()' for non-debugging case and makes 'dbg_debugfs_init()' properly verify debugfs return code which may be an error code or NULL, so we should you 'IS_ERR_OR_NULL()' instead of 'IS_ERR()'. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 18 +++++++++++++----- fs/ubifs/debug.h | 11 +++++++++-- 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 0bb2bcef0de9..c9609a63512e 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2815,8 +2815,8 @@ static struct dentry *dfs_rootdir; int dbg_debugfs_init(void) { dfs_rootdir = debugfs_create_dir("ubifs", NULL); - if (IS_ERR(dfs_rootdir)) { - int err = PTR_ERR(dfs_rootdir); + if (IS_ERR_OR_NULL(dfs_rootdir)) { + int err = dfs_rootdir ? PTR_ERR(dfs_rootdir) : -ENODEV; ubifs_err("cannot create \"ubifs\" debugfs directory, " "error %d\n", err); return err; @@ -2880,12 +2880,20 @@ static const struct file_operations dfs_fops = { */ int dbg_debugfs_init_fs(struct ubifs_info *c) { - int err; + int err, n; const char *fname; struct dentry *dent; struct ubifs_debug_info *d = c->dbg; - sprintf(d->dfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); + n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME, + c->vi.ubi_num, c->vi.vol_id); + if (n == UBIFS_DFS_DIR_LEN) { + /* The array size is too small */ + fname = UBIFS_DFS_DIR_NAME; + dent = ERR_PTR(-EINVAL); + goto out; + } + fname = d->dfs_dir_name; dent = debugfs_create_dir(fname, dfs_rootdir); if (IS_ERR_OR_NULL(dent)) @@ -2916,7 +2924,7 @@ out_remove: debugfs_remove_recursive(d->dfs_dir); out: err = dent ? PTR_ERR(dent) : -ENODEV; - ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", + ubifs_err("cannot create \"%s\" debugfs filr or directory, error %d\n", fname, err); return err; } diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index a811ac4a26bb..b59c43a4149c 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -33,6 +33,13 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c, #include +/* + * The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi" + * + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte. + */ +#define UBIFS_DFS_DIR_NAME "ubi%d_%d" +#define UBIFS_DFS_DIR_LEN (3 + 1 + 2*2 + 1) + /** * ubifs_debug_info - per-FS debugging information. * @old_zroot: old index root - used by 'dbg_check_old_index()' @@ -84,7 +91,7 @@ struct ubifs_debug_info { long long saved_free; int saved_idx_gc_cnt; - char dfs_dir_name[100]; + char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1]; struct dentry *dfs_dir; struct dentry *dfs_dump_lprops; struct dentry *dfs_dump_budg; @@ -313,7 +320,7 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); /* Use "if (0)" to make compiler check arguments even if debugging is off */ #define ubifs_assert(expr) do { \ - if (0 && (expr)) \ + if (0) \ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ __func__, __LINE__, current->pid); \ } while (0) -- cgit v1.2.3 From bfcf677decd8051c305b1d8fda407d069c2361e3 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 24 May 2011 14:10:03 +0300 Subject: UBIFS: dump stack when pnode or nnode reading fails When we fail to read a pnode or nnode - print stacktrace if debugging is enabled. Signed-off-by: Artem Bityutskiy --- fs/ubifs/lpt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs') diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c index ef5155e109a2..04713cd22679 100644 --- a/fs/ubifs/lpt.c +++ b/fs/ubifs/lpt.c @@ -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; } @@ -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; -- cgit v1.2.3 From 4315fb4072905e45da94d51e2c1e86fa41c5fc5f Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 25 May 2011 17:32:42 +0300 Subject: UBIFS: improve inode dumping function Teach 'dbg_dump_inode()' dump directory entries for directory inodes. This requires few additional changes: 1. The 'c' argument of 'dbg_dump_inode()' cannot be const any more. 2. Users of 'dbg_dump_inode()' should not have 'tnc_mutex' locked. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/ubifs/debug.h | 6 +++--- fs/ubifs/tnc.c | 3 ++- 3 files changed, 60 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index c9609a63512e..4a2170dce0db 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -91,6 +91,28 @@ static const char *get_key_type(int type) } } +static const char *get_dent_type(int type) +{ + switch (type) { + case UBIFS_ITYPE_REG: + return "file"; + case UBIFS_ITYPE_DIR: + return "dir"; + case UBIFS_ITYPE_LNK: + return "symlink"; + case UBIFS_ITYPE_BLK: + return "blkdev"; + case UBIFS_ITYPE_CHR: + return "char dev"; + case UBIFS_ITYPE_FIFO: + return "fifo"; + case UBIFS_ITYPE_SOCK: + return "socket"; + default: + return "unknown/invalid type"; + } +} + static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key, char *buffer) { @@ -234,9 +256,13 @@ static void dump_ch(const struct ubifs_ch *ch) printk(KERN_DEBUG "\tlen %u\n", le32_to_cpu(ch->len)); } -void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode) +void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode) { const struct ubifs_inode *ui = ubifs_inode(inode); + struct qstr nm = { .name = NULL }; + union ubifs_key key; + struct ubifs_dent_node *dent, *pdent = NULL; + int count = 2; printk(KERN_DEBUG "Dump in-memory inode:"); printk(KERN_DEBUG "\tinode %lu\n", inode->i_ino); @@ -270,6 +296,32 @@ void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode) printk(KERN_DEBUG "\tlast_page_read %lu\n", ui->last_page_read); printk(KERN_DEBUG "\tread_in_a_row %lu\n", ui->read_in_a_row); printk(KERN_DEBUG "\tdata_len %d\n", ui->data_len); + + if (!S_ISDIR(inode->i_mode)) + return; + + printk(KERN_DEBUG "List of directory entries:\n"); + ubifs_assert(!mutex_is_locked(&c->tnc_mutex)); + + lowest_dent_key(c, &key, inode->i_ino); + while (1) { + dent = ubifs_tnc_next_ent(c, &key, &nm); + if (IS_ERR(dent)) { + if (PTR_ERR(dent) != -ENOENT) + printk(KERN_DEBUG "error %ld\n", PTR_ERR(dent)); + break; + } + + printk(KERN_DEBUG "\t%d: %s (%s)\n", + count++, dent->name, get_dent_type(dent->type)); + + nm.name = dent->name; + nm.len = le16_to_cpu(dent->nlen); + kfree(pdent); + pdent = dent; + key_read(c, &dent->key, &key); + } + kfree(pdent); } void dbg_dump_node(const struct ubifs_info *c, const void *node) @@ -1167,12 +1219,14 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir) "but calculated size is %llu", dir->i_ino, (unsigned long long)i_size_read(dir), (unsigned long long)size); + dbg_dump_inode(c, dir); dump_stack(); return -EINVAL; } if (dir->i_nlink != nlink) { ubifs_err("directory inode %lu has nlink %u, but calculated " "nlink is %u", dir->i_ino, dir->i_nlink, nlink); + dbg_dump_inode(c, dir); dump_stack(); return -EINVAL; } diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index b59c43a4149c..c6ad9ea15e3c 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -214,7 +214,7 @@ const char *dbg_cstate(int cmt_state); const char *dbg_jhead(int jhead); const char *dbg_get_key_dump(const struct ubifs_info *c, const union ubifs_key *key); -void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode); +void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode); void dbg_dump_node(const struct ubifs_info *c, const void *node); void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum, int offs); @@ -364,7 +364,7 @@ static inline const char *dbg_jhead(int jhead) { return ""; } static inline const char * dbg_get_key_dump(const struct ubifs_info *c, const union ubifs_key *key) { return ""; } -static inline void dbg_dump_inode(const struct ubifs_info *c, +static inline void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode) { return; } static inline void dbg_dump_node(const struct ubifs_info *c, const void *node) { return; } @@ -418,7 +418,7 @@ static inline int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) { return 0; } static inline int dbg_check_synced_i_size(struct inode *inode) { return 0; } static inline int dbg_check_dir_size(struct ubifs_info *c, - const struct inode *dir) { return 0; } + const struct inode *dir) { return 0; } static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; } static inline int dbg_check_idx_size(struct ubifs_info *c, long long idx_size) { return 0; } diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 91b4213dde84..48b6ee6fa848 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -3337,9 +3337,10 @@ out_dump: 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); -- cgit v1.2.3 From 1b51e98365e42c27eb2664f8353bc62ab8c55c85 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 25 May 2011 17:38:29 +0300 Subject: UBIFS: rename dbg_check_dir_size function Since this function is not only about size checking, rename it to 'dbg_check_dir()'. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 2 +- fs/ubifs/debug.h | 4 ++-- fs/ubifs/super.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 4a2170dce0db..26d4c6173181 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -1177,7 +1177,7 @@ int dbg_check_synced_i_size(struct inode *inode) * Note, it is good idea to make sure the @dir->i_mutex is locked before * calling this function. */ -int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir) +int dbg_check_dir(struct ubifs_info *c, const struct inode *dir) { unsigned int nlink = 2; union ubifs_key key; diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index c6ad9ea15e3c..a51c20be655d 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -248,7 +248,7 @@ int dbg_check_ltab(struct ubifs_info *c); int dbg_chk_lpt_free_spc(struct ubifs_info *c); int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len); int dbg_check_synced_i_size(struct inode *inode); -int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir); +int dbg_check_dir(struct ubifs_info *c, const struct inode *dir); int dbg_check_tnc(struct ubifs_info *c, int extra); int dbg_check_idx_size(struct ubifs_info *c, long long idx_size); int dbg_check_filesystem(struct ubifs_info *c); @@ -417,7 +417,7 @@ static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c) { return 0; } static inline int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) { return 0; } static inline int dbg_check_synced_i_size(struct inode *inode) { return 0; } -static inline int dbg_check_dir_size(struct ubifs_info *c, +static inline int dbg_check_dir(struct ubifs_info *c, const struct inode *dir) { return 0; } static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; } static inline int dbg_check_idx_size(struct ubifs_info *c, diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 529be0582029..de82c5d04ab9 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -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; } -- cgit v1.2.3 From a29fa9dfa4d5d1b962825c79f19d9b6f3f15843b Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 26 May 2011 09:43:34 +0300 Subject: UBIFS: minor cleanup: use S_ISREG helper Instead of using long "(inode->i_mode & S_IFMT) != S_IFREG" expression, use shorted "!S_ISREG(inode->i_mode)". Signed-off-by: Artem Bityutskiy --- fs/ubifs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index de82c5d04ab9..285038548da9 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -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)) { -- cgit v1.2.3 From 12e776a0882def45e7ee50918016968b392ac7bd Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 27 May 2011 15:50:39 +0300 Subject: UBIFS: remove unnecessary brackets Remove unnecessary brackets in "inode->i_flags |= (S_NOCMTIME)" statement to make the code not look silly. Signed-off-by: Artem Bityutskiy --- fs/ubifs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index ef5abd38f0bf..c6cbdd0f636c 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -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 = -- cgit v1.2.3 From 1f42596ec0a7d3d50a494d95e3f1afbd117250f8 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 30 May 2011 14:30:51 +0300 Subject: UBIFS: remove dead code Remove dead pieces of code under "if (c->min_io_size == 1)" statement - we never execute it because in UBIFS 'c->min_io_size' is always at least 8. This are leftovers from old pre-mainline prototype. Signed-off-by: Artem Bityutskiy --- fs/ubifs/tnc_commit.c | 106 ++++++++++++++------------------------------------ 1 file changed, 30 insertions(+), 76 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c index 41920f357bbf..8315387be3fd 100644 --- a/fs/ubifs/tnc_commit.c +++ b/fs/ubifs/tnc_commit.c @@ -491,25 +491,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); @@ -830,7 +811,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) @@ -938,65 +919,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; } -- cgit v1.2.3 From f42eed7cba7f83197b0ffbb023e7d89a0b2fd71d Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 30 May 2011 14:45:30 +0300 Subject: UBIFS: harmonize znode flag helpers We have 3 znode flags: cow, obsolete, dirty. For the last flag we have a 'ubifs_zn_dirty()' helper function, but for the other 2 flags we use 'test_bit()' directly. This patch makes the situation more consistent and introduces helpers for the other 2 flags: 'ubifs_zn_cow()' and 'ubifs_zn_obsolete()'. Signed-off-by: Artem Bityutskiy --- fs/ubifs/commit.c | 2 +- fs/ubifs/misc.h | 23 +++++++++++++++++++++++ fs/ubifs/tnc.c | 13 ++++++------- fs/ubifs/tnc_commit.c | 8 ++++---- 4 files changed, 34 insertions(+), 12 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c index 8ab03d12d5c0..637e07673c3a 100644 --- a/fs/ubifs/commit.c +++ b/fs/ubifs/commit.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 * 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; /* diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h index 0b5296a9a4c5..160cd909e957 100644 --- a/fs/ubifs/misc.h +++ b/fs/ubifs/misc.h @@ -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 diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 48b6ee6fa848..b32a5376b7b4 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -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); @@ -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); } diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c index 8315387be3fd..f50c3e5da263 100644 --- a/fs/ubifs/tnc_commit.c +++ b/fs/ubifs/tnc_commit.c @@ -87,7 +87,7 @@ 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)); __clear_bit(DIRTY_ZNODE, &znode->flags); __clear_bit(COW_ZNODE, &znode->flags); @@ -639,7 +639,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); @@ -888,7 +888,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 @@ -983,7 +983,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; -- cgit v1.2.3 From 376624476921e43d8b87498161a2ffba6ab8d5aa Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 30 May 2011 14:51:20 +0300 Subject: UBIFS: use correct flags in lprops The UBIFS lpt tree is in many aspects similar to the TNC tree, and we have similar flags for these trees. And by mistake we use the COW_ZNODE flag for LPT in some places, instead of the right flag COW_CNODE. And this works only because these two constants have the same value. This patch makes all the LPT code to use COW_CNODE and also changes COW_CNODE constant value to make sure we do not misuse the flags any more. Signed-off-by: Artem Bityutskiy --- fs/ubifs/lprops.c | 2 +- fs/ubifs/lpt_commit.c | 6 +++--- fs/ubifs/ubifs.h | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c index 667884f4a615..98b8e73c454c 100644 --- a/fs/ubifs/lprops.c +++ b/fs/ubifs/lprops.c @@ -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); } diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index dfcb5748a7dc..254e8d32fc67 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c @@ -116,8 +116,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 +465,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); diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index f79983d6f860..3304aad04885 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -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, }; /* -- cgit v1.2.3 From 06b282a4cc02f37414c14c94a2f154ca250cf73f Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 30 May 2011 18:19:34 +0300 Subject: UBIFS: add few commentaries about TNC Add a couple of comments - while looking into TNC I could not easily figure out few facts, so it is a good idea to document them in the code. Signed-off-by: Artem Bityutskiy --- fs/ubifs/tnc_commit.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'fs') diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c index f50c3e5da263..d6fab1a9986c 100644 --- a/fs/ubifs/tnc_commit.c +++ b/fs/ubifs/tnc_commit.c @@ -89,6 +89,10 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, ubifs_assert(ubifs_zn_dirty(znode)); 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); @@ -903,6 +907,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 */ -- cgit v1.2.3 From bb2615d4d14777fd37e2b91bd99b92c0354813d1 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 31 May 2011 17:47:53 +0300 Subject: UBIFS: amend debugging name check function prototype Add 'struct ubifs_info *c' parameter to the 'dbg_check_name()' debugging function - it will be needed in one of the following commits where we switch to debugfs. So this is just a preparation. Mark parameters as 'const' while on it. Signed-off-by: Artem Bityutskiy --- fs/ubifs/dir.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index c6cbdd0f636c..d1725a9914ac 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -172,7 +172,9 @@ 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)) return 0; @@ -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; } -- cgit v1.2.3 From d808efb407e1a2cf83a8d21411157195f26bdef9 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 31 May 2011 18:14:38 +0300 Subject: UBIFS: amend debugging inode size check function prototype Add 'const struct ubifs_info *c' parameter to 'dbg_check_synced_i_size()' function because we'll need it in the next patch when we switch to debugfs. So this patch is just a preparation. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 3 ++- fs/ubifs/debug.h | 6 ++++-- fs/ubifs/dir.c | 4 ++-- fs/ubifs/file.c | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 26d4c6173181..7adf9fe91817 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -1132,6 +1132,7 @@ out: /** * dbg_check_synced_i_size - check synchronized inode size. + * @c: UBIFS file-system description object * @inode: inode to check * * If inode is clean, synchronized inode size has to be equivalent to current @@ -1139,7 +1140,7 @@ out: * has to be locked). Returns %0 if synchronized inode size if correct, and * %-EINVAL if not. */ -int dbg_check_synced_i_size(struct inode *inode) +int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode) { int err = 0; struct ubifs_inode *ui = ubifs_inode(inode); diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index a51c20be655d..90805bd49456 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -247,7 +247,7 @@ int dbg_check_cats(struct ubifs_info *c); int dbg_check_ltab(struct ubifs_info *c); int dbg_chk_lpt_free_spc(struct ubifs_info *c); int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len); -int dbg_check_synced_i_size(struct inode *inode); +int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode); int dbg_check_dir(struct ubifs_info *c, const struct inode *dir); int dbg_check_tnc(struct ubifs_info *c, int extra); int dbg_check_idx_size(struct ubifs_info *c, long long idx_size); @@ -416,7 +416,9 @@ static inline int dbg_check_ltab(struct ubifs_info *c) { return 0; } static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c) { return 0; } static inline int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len) { return 0; } -static inline int dbg_check_synced_i_size(struct inode *inode) { return 0; } +static inline int +dbg_check_synced_i_size(const struct ubifs_info *c, + struct inode *inode) { return 0; } static inline int dbg_check_dir(struct ubifs_info *c, const struct inode *dir) { return 0; } static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; } diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index d1725a9914ac..98014bf1d8b4 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -524,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; @@ -579,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; diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 5e7fccfc4b29..7cf738a4544d 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -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; -- cgit v1.2.3 From 2b1844a8c934723134ee1ff313e51d0d281cdef1 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 08:31:29 +0300 Subject: UBIFS: introduce helper functions for debugging checks and tests This patch introduces helper functions for all debugging checks, so instead of doing if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) we now do if (!dbg_is_chk_gen(c)) This is a preparation to further changes where the flags will go away, and we'll need to only change the helper functions, but the code which utilizes them won't be touched. At the same time this patch removes 'dbg_force_in_the_gaps()', 'dbg_force_in_the_gaps_enabled()', and dbg_failure_mode helpers for consistency. Signed-off-by: Artem Bityutskiy --- fs/ubifs/commit.c | 2 +- fs/ubifs/debug.c | 30 +++++++++-------------- fs/ubifs/debug.h | 66 +++++++++++++++++++++++++++++++++++---------------- fs/ubifs/dir.c | 2 +- fs/ubifs/log.c | 2 +- fs/ubifs/lprops.c | 6 ++--- fs/ubifs/lpt.c | 2 +- fs/ubifs/lpt_commit.c | 10 ++++---- fs/ubifs/orphan.c | 2 +- fs/ubifs/scan.c | 2 +- fs/ubifs/tnc.c | 2 +- fs/ubifs/tnc_commit.c | 5 ++-- 12 files changed, 75 insertions(+), 56 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c index 637e07673c3a..63c4e447f977 100644 --- a/fs/ubifs/commit.c +++ b/fs/ubifs/commit.c @@ -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_old_idx(c)) return 0; INIT_LIST_HEAD(&list); diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 7adf9fe91817..79d8924aca5b 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -330,7 +330,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node) union ubifs_key key; const struct ubifs_ch *ch = node; - if (dbg_failure_mode) + if (dbg_is_tst_rcvry(c)) return; /* If the magic is incorrect, just hexdump the first bytes */ @@ -886,7 +886,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum) struct ubifs_scan_node *snod; void *buf; - if (dbg_failure_mode) + if (dbg_is_tst_rcvry(c)) return; printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n", @@ -1145,7 +1145,7 @@ int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode) int err = 0; struct ubifs_inode *ui = ubifs_inode(inode); - if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) + if (!dbg_is_chk_gen(c)) return 0; if (!S_ISREG(inode->i_mode)) return 0; @@ -1186,7 +1186,7 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir) struct qstr nm = { .name = NULL }; loff_t size = UBIFS_INO_NODE_SZ; - if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) + if (!dbg_is_chk_gen(c)) return 0; if (!S_ISDIR(dir->i_mode)) @@ -1544,7 +1544,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra) long clean_cnt = 0, dirty_cnt = 0; int err, last; - if (!(ubifs_chk_flags & UBIFS_CHK_TNC)) + if (!dbg_is_chk_tnc(c)) return 0; ubifs_assert(mutex_is_locked(&c->tnc_mutex)); @@ -1791,7 +1791,7 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size) int err; long long calc = 0; - if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ)) + if (!dbg_is_chk_idx_sz(c)) return 0; err = dbg_walk_index(c, NULL, add_size, &calc); @@ -2367,7 +2367,7 @@ int dbg_check_filesystem(struct ubifs_info *c) int err; struct fsck_data fsckd; - if (!(ubifs_chk_flags & UBIFS_CHK_FS)) + if (!dbg_is_chk_fs(c)) return 0; fsckd.inodes = RB_ROOT; @@ -2402,7 +2402,7 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head) struct list_head *cur; struct ubifs_scan_node *sa, *sb; - if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) + if (!dbg_is_chk_gen(c)) return 0; for (cur = head->next; cur->next != head; cur = cur->next) { @@ -2469,7 +2469,7 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head) struct list_head *cur; struct ubifs_scan_node *sa, *sb; - if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) + if (!dbg_is_chk_gen(c)) return 0; for (cur = head->next; cur->next != head; cur = cur->next) { @@ -2546,14 +2546,6 @@ error_dump: return 0; } -int dbg_force_in_the_gaps(void) -{ - if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) - return 0; - - return !(random32() & 7); -} - /* Failure mode for recovery testing */ #define chance(n, d) (simple_rand() <= (n) * 32768LL / (d)) @@ -2624,7 +2616,7 @@ static int in_failure_mode(struct ubi_volume_desc *desc) { struct ubifs_info *c = dbg_find_info(desc); - if (c && dbg_failure_mode) + if (c && dbg_is_tst_rcvry(c)) return c->dbg->failure_mode; return 0; } @@ -2634,7 +2626,7 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) struct ubifs_info *c = dbg_find_info(desc); struct ubifs_debug_info *d; - if (!c || !dbg_failure_mode) + if (!c || !dbg_is_tst_rcvry(c)) return 0; d = c->dbg; if (d->failure_mode) diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 90805bd49456..c3d1ffd0610a 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -31,8 +31,6 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c, #ifdef CONFIG_UBIFS_FS_DEBUG -#include - /* * 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. @@ -169,6 +167,8 @@ const char *dbg_key_str1(const struct ubifs_info *c, /* Additional recovery messages */ #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__) +extern spinlock_t dbg_lock; + /* * Debugging check flags. * @@ -199,12 +199,43 @@ enum { UBIFS_TST_RCVRY = 0x4, }; -extern spinlock_t dbg_lock; - extern unsigned int ubifs_msg_flags; extern unsigned int ubifs_chk_flags; extern unsigned int ubifs_tst_flags; +static inline int dbg_is_chk_gen(const struct ubifs_info *c) +{ + return !!(ubifs_chk_flags & UBIFS_CHK_GEN); +} +static inline int dbg_is_chk_tnc(const struct ubifs_info *c) +{ + return !!(ubifs_chk_flags & UBIFS_CHK_TNC); +} +static inline int dbg_is_chk_idx_sz(const struct ubifs_info *c) +{ + return !!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ); +} +static inline int dbg_is_chk_orph(const struct ubifs_info *c) +{ + return !!(ubifs_chk_flags & UBIFS_CHK_ORPH); +} +static inline int dbg_is_chk_old_idx(const struct ubifs_info *c) +{ + return !!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX); +} +static inline int dbg_is_chk_lprops(const struct ubifs_info *c) +{ + return !!(ubifs_chk_flags & UBIFS_CHK_LPROPS); +} +static inline int dbg_is_chk_fs(const struct ubifs_info *c) +{ + return !!(ubifs_chk_flags & UBIFS_CHK_FS); +} +static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) +{ + return !!(ubifs_tst_flags & UBIFS_TST_RCVRY); +} + int ubifs_debugging_init(struct ubifs_info *c); void ubifs_debugging_exit(struct ubifs_info *c); @@ -261,16 +292,6 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode, int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head); int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head); -/* Force the use of in-the-gaps method for testing */ -static inline int dbg_force_in_the_gaps_enabled(void) -{ - return ubifs_chk_flags & UBIFS_CHK_GEN; -} -int dbg_force_in_the_gaps(void); - -/* Failure mode for recovery testing */ -#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY) - #ifndef UBIFS_DBG_PRESERVE_UBI #define ubi_leb_read dbg_leb_read #define ubi_leb_write dbg_leb_write @@ -330,6 +351,9 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); ubifs_err(fmt, ##__VA_ARGS__); \ } while (0) +#define DBGKEY(key) ((char *)(key)) +#define DBGKEY1(key) ((char *)(key)) + #define ubifs_dbg_msg(fmt, ...) do { \ if (0) \ pr_debug(fmt "\n", ##__VA_ARGS__); \ @@ -353,9 +377,6 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); #define dbg_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) #define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) -#define DBGKEY(key) ((char *)(key)) -#define DBGKEY1(key) ((char *)(key)) - static inline int ubifs_debugging_init(struct ubifs_info *c) { return 0; } static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; } static inline const char *dbg_ntype(int type) { return ""; } @@ -440,9 +461,14 @@ static inline int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head) { return 0; } -static inline int dbg_force_in_the_gaps(void) { return 0; } -#define dbg_force_in_the_gaps_enabled() 0 -#define dbg_failure_mode 0 +static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return 0; } +static inline int dbg_is_chk_tnc(const struct ubifs_info *c) { return 0; } +static inline int dbg_is_chk_idx_sz(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_old_idx(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_debugfs_init(void) { return 0; } static inline void dbg_debugfs_exit(void) { return; } diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 98014bf1d8b4..683492043317 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -176,7 +176,7 @@ 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; diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c index affea9494ae2..fabfb53c4fee 100644 --- a/fs/ubifs/log.c +++ b/fs/ubifs/log.c @@ -752,7 +752,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); diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c index 98b8e73c454c..f8a181e647cc 100644 --- a/fs/ubifs/lprops.c +++ b/fs/ubifs/lprops.c @@ -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; /* diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c index 04713cd22679..ab91ca628455 100644 --- a/fs/ubifs/lpt.c +++ b/fs/ubifs/lpt.c @@ -2226,7 +2226,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) { diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index 254e8d32fc67..f8e286ba8095 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c @@ -1640,7 +1640,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); @@ -1711,7 +1711,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 +1754,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 +1796,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) { @@ -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; diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c index a5422fffbd69..c542c73cfa3c 100644 --- a/fs/ubifs/orphan.c +++ b/fs/ubifs/orphan.c @@ -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; diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c index 36216b46f772..c7df916dce97 100644 --- a/fs/ubifs/scan.c +++ b/fs/ubifs/scan.c @@ -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) diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index b32a5376b7b4..526b63cd3333 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -3300,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; diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c index d6fab1a9986c..8959c726b024 100644 --- a/fs/ubifs/tnc_commit.c +++ b/fs/ubifs/tnc_commit.c @@ -23,6 +23,7 @@ /* This file implements TNC functions for committing */ #include "ubifs.h" +#include /** * make_idx_node - make an index node for fill-the-gaps method of TNC commit. @@ -381,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_gen(c)) { /* * Do not print scary warnings if the debugging * option which forces in-the-gaps is enabled. @@ -689,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_gen(c) && !(random32() & 7)) return -ENOSPC; return 0; } -- cgit v1.2.3 From 8d7819b4af697eec45339cc24db7c3fe45fea0e7 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 08:53:35 +0300 Subject: UBIFS: lessen amount of debugging check types We have too many different debugging checks - lessen the amount by merging all index-related checks into one. At the same time, move the "force in-the-gap" test to the "index checks" class, because it is too heavy for the "general" class. This patch merges TNC, Old index, and Index size check and calles this just "index checks". Signed-off-by: Artem Bityutskiy --- Documentation/filesystems/ubifs.txt | 4 +--- fs/ubifs/commit.c | 2 +- fs/ubifs/debug.c | 4 ++-- fs/ubifs/debug.h | 24 +++++------------------- fs/ubifs/lpt_commit.c | 1 + fs/ubifs/tnc_commit.c | 6 +++--- 6 files changed, 13 insertions(+), 28 deletions(-) (limited to 'fs') diff --git a/Documentation/filesystems/ubifs.txt b/Documentation/filesystems/ubifs.txt index 8e4fab639d9c..91ef07652cd2 100644 --- a/Documentation/filesystems/ubifs.txt +++ b/Documentation/filesystems/ubifs.txt @@ -123,10 +123,8 @@ 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 the index 2 Check orphan area 8 - Check old indexing tree 16 Check LEB properties (lprops) 32 Check leaf nodes and inodes 64 diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c index 63c4e447f977..fb3b5c813a30 100644 --- a/fs/ubifs/commit.c +++ b/fs/ubifs/commit.c @@ -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 (!dbg_is_chk_old_idx(c)) + if (!dbg_is_chk_index(c)) return 0; INIT_LIST_HEAD(&list); diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 79d8924aca5b..a967d6800ead 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -1544,7 +1544,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra) long clean_cnt = 0, dirty_cnt = 0; int err, last; - if (!dbg_is_chk_tnc(c)) + if (!dbg_is_chk_index(c)) return 0; ubifs_assert(mutex_is_locked(&c->tnc_mutex)); @@ -1791,7 +1791,7 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size) int err; long long calc = 0; - if (!dbg_is_chk_idx_sz(c)) + if (!dbg_is_chk_index(c)) return 0; err = dbg_walk_index(c, NULL, add_size, &calc); diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index c3d1ffd0610a..44265a3a08ce 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -173,19 +173,15 @@ extern spinlock_t dbg_lock; * Debugging check flags. * * UBIFS_CHK_GEN: general checks - * UBIFS_CHK_TNC: check TNC - * UBIFS_CHK_IDX_SZ: check index size + * UBIFS_CHK_INDEX: check the index * 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_INDEX = 0x2, UBIFS_CHK_ORPH = 0x8, - UBIFS_CHK_OLD_IDX = 0x10, UBIFS_CHK_LPROPS = 0x20, UBIFS_CHK_FS = 0x40, }; @@ -207,22 +203,14 @@ static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return !!(ubifs_chk_flags & UBIFS_CHK_GEN); } -static inline int dbg_is_chk_tnc(const struct ubifs_info *c) +static inline int dbg_is_chk_index(const struct ubifs_info *c) { - return !!(ubifs_chk_flags & UBIFS_CHK_TNC); -} -static inline int dbg_is_chk_idx_sz(const struct ubifs_info *c) -{ - return !!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ); + return !!(ubifs_chk_flags & UBIFS_CHK_INDEX); } static inline int dbg_is_chk_orph(const struct ubifs_info *c) { return !!(ubifs_chk_flags & UBIFS_CHK_ORPH); } -static inline int dbg_is_chk_old_idx(const struct ubifs_info *c) -{ - return !!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX); -} static inline int dbg_is_chk_lprops(const struct ubifs_info *c) { return !!(ubifs_chk_flags & UBIFS_CHK_LPROPS); @@ -462,10 +450,8 @@ dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head) { return 0; } static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return 0; } -static inline int dbg_is_chk_tnc(const struct ubifs_info *c) { return 0; } -static inline int dbg_is_chk_idx_sz(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_old_idx(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; } diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index f8e286ba8095..f13addf72e89 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c @@ -27,6 +27,7 @@ #include #include +#include #include "ubifs.h" #ifdef CONFIG_UBIFS_FS_DEBUG diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c index 8959c726b024..4c15f07a8bb2 100644 --- a/fs/ubifs/tnc_commit.c +++ b/fs/ubifs/tnc_commit.c @@ -22,8 +22,8 @@ /* This file implements TNC functions for committing */ -#include "ubifs.h" #include +#include "ubifs.h" /** * make_idx_node - make an index node for fill-the-gaps method of TNC commit. @@ -382,7 +382,7 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt) c->gap_lebs = NULL; return err; } - if (!dbg_is_chk_gen(c)) { + if (!dbg_is_chk_index(c)) { /* * Do not print scary warnings if the debugging * option which forces in-the-gaps is enabled. @@ -690,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_is_chk_gen(c) && !(random32() & 7)) + if (dbg_is_chk_index(c) && !(random32() & 7)) return -ENOSPC; return 0; } -- cgit v1.2.3 From 81e79d38df5a17bb1c738a14f8e5f3412fb33afa Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 31 May 2011 18:16:34 +0300 Subject: UBIFS: switch self-check knobs to debugfs UBIFS has many built-in self-check functions which can be enabled using the debug_chks module parameter or the corresponding sysfs file (/sys/module/ubifs/parameters/debug_chks). However, this is not flexible enough because it is not per-filesystem. This patch moves this to debugfs interfaces. We already have debugfs support, so this patch just adds more debugfs files. While looking at debugfs support I've noticed that it is racy WRT file-system unmount, and added a TODO entry for that. This problem has been there for long time and it is quite standard debugfs PITA. The plan is to fix this later. This patch is simple, but it is large because it changes many places where we check if a particular type of checks is enabled or disabled. Signed-off-by: Artem Bityutskiy --- Documentation/filesystems/ubifs.txt | 26 ------- fs/ubifs/debug.c | 140 +++++++++++++++++++++++++++++++----- fs/ubifs/debug.h | 72 +++++++++---------- 3 files changed, 159 insertions(+), 79 deletions(-) (limited to 'fs') diff --git a/Documentation/filesystems/ubifs.txt b/Documentation/filesystems/ubifs.txt index 91ef07652cd2..a0a61d2f389f 100644 --- a/Documentation/filesystems/ubifs.txt +++ b/Documentation/filesystems/ubifs.txt @@ -111,32 +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 the index 2 - Check orphan area 8 - 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 ========== diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index a967d6800ead..fdfa5dea5b95 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -31,9 +31,9 @@ #include "ubifs.h" #include -#include #include #include +#include #ifdef CONFIG_UBIFS_FS_DEBUG @@ -42,15 +42,6 @@ DEFINE_SPINLOCK(dbg_lock); static char dbg_key_buf0[128]; static char dbg_key_buf1[128]; -unsigned int ubifs_chk_flags; -unsigned int ubifs_tst_flags; - -module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR); -module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR); - -MODULE_PARM_DESC(debug_chks, "Debug check flags"); -MODULE_PARM_DESC(debug_tsts, "Debug special test flags"); - static const char *get_key_fmt(int fmt) { switch (fmt) { @@ -2886,21 +2877,93 @@ static int open_debugfs_file(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } -static ssize_t write_debugfs_file(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count, + loff_t *ppos) +{ + struct dentry *dent = file->f_path.dentry; + struct ubifs_info *c = file->private_data; + struct ubifs_debug_info *d = c->dbg; + char buf[3]; + 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; + + if (val) + buf[0] = '1'; + else + buf[0] = '0'; + buf[1] = '\n'; + buf[2] = 0x00; + + return simple_read_from_buffer(u, count, ppos, buf, 2); +} + +static ssize_t dfs_file_write(struct file *file, const char __user *u, + size_t count, loff_t *ppos) { struct ubifs_info *c = file->private_data; struct ubifs_debug_info *d = c->dbg; + struct dentry *dent = file->f_path.dentry; + size_t buf_size; + char buf[8]; + int val; - if (file->f_path.dentry == d->dfs_dump_lprops) + /* + * FIXME: this is racy - the file-system might have already been + * unmounted and we'd oops in this case. + */ + if (file->f_path.dentry == d->dfs_dump_lprops) { dbg_dump_lprops(c); - else if (file->f_path.dentry == d->dfs_dump_budg) + return count; + } + if (file->f_path.dentry == d->dfs_dump_budg) { dbg_dump_budg(c, &c->bi); - else if (file->f_path.dentry == d->dfs_dump_tnc) { + return count; + } + if (file->f_path.dentry == d->dfs_dump_tnc) { mutex_lock(&c->tnc_mutex); dbg_dump_tnc(c); mutex_unlock(&c->tnc_mutex); - } else + return count; + } + + buf_size = min_t(size_t, count, (sizeof(buf) - 1)); + if (copy_from_user(buf, u, buf_size)) + return -EFAULT; + + if (buf[0] == '1') + val = 1; + else if (buf[0] == '0') + val = 0; + else + return -EINVAL; + + if (dent == d->dfs_chk_gen) + d->chk_gen = val; + else if (dent == d->dfs_chk_index) + d->chk_index = val; + else if (dent == d->dfs_chk_orph) + d->chk_orph = val; + else if (dent == d->dfs_chk_lprops) + d->chk_lprops = val; + else if (dent == d->dfs_chk_fs) + d->chk_fs = val; + else if (dent == d->dfs_tst_rcvry) + d->tst_rcvry = val; + else return -EINVAL; return count; @@ -2908,7 +2971,8 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf, static const struct file_operations dfs_fops = { .open = open_debugfs_file, - .write = write_debugfs_file, + .read = dfs_file_read, + .write = dfs_file_write, .owner = THIS_MODULE, .llseek = no_llseek, }; @@ -2965,6 +3029,48 @@ int dbg_debugfs_init_fs(struct ubifs_info *c) goto out_remove; d->dfs_dump_tnc = dent; + fname = "chk_general"; + dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, + &dfs_fops); + if (IS_ERR_OR_NULL(dent)) + goto out_remove; + d->dfs_chk_gen = dent; + + fname = "chk_index"; + dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, + &dfs_fops); + if (IS_ERR_OR_NULL(dent)) + goto out_remove; + d->dfs_chk_index = dent; + + fname = "chk_orphans"; + dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, + &dfs_fops); + if (IS_ERR_OR_NULL(dent)) + goto out_remove; + d->dfs_chk_orph = dent; + + fname = "chk_lprops"; + dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, + &dfs_fops); + if (IS_ERR_OR_NULL(dent)) + goto out_remove; + d->dfs_chk_lprops = dent; + + fname = "chk_fs"; + dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, + &dfs_fops); + if (IS_ERR_OR_NULL(dent)) + goto out_remove; + d->dfs_chk_fs = dent; + + fname = "tst_recovery"; + dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c, + &dfs_fops); + if (IS_ERR_OR_NULL(dent)) + goto out_remove; + d->dfs_tst_rcvry = dent; + return 0; out_remove: diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 44265a3a08ce..8c3bdd378037 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -43,11 +43,13 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c, * @old_zroot: old index root - used by 'dbg_check_old_index()' * @old_zroot_level: old index root level - used by 'dbg_check_old_index()' * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()' + * * @failure_mode: failure mode for recovery testing * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls * @fail_timeout: time in jiffies when delay of failure mode expires * @fail_cnt: current number of calls to failure mode I/O functions * @fail_cnt_max: number of calls by which to delay failure mode + * * @chk_lpt_sz: used by LPT tree size checker * @chk_lpt_sz2: used by LPT tree size checker * @chk_lpt_wastage: used by LPT tree size checker @@ -61,21 +63,36 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c, * @saved_free: saved amount of free space * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt * + * @chk_gen: if general extra checks are enabled + * @chk_index: if index xtra checks are enabled + * @chk_orph: if orphans extra checks are enabled + * @chk_lprops: if lprops extra checks are enabled + * @chk_fs: if UBIFS contents extra checks are enabled + * @tst_rcvry: if UBIFS recovery testing mode enabled + * * @dfs_dir_name: name of debugfs directory containing this file-system's files * @dfs_dir: direntry object of the file-system debugfs directory * @dfs_dump_lprops: "dump lprops" debugfs knob * @dfs_dump_budg: "dump budgeting information" debugfs knob * @dfs_dump_tnc: "dump TNC" debugfs knob + * @dfs_chk_gen: debugfs knob to enable UBIFS general extra checks + * @dfs_chk_index: debugfs knob to enable UBIFS index extra checks + * @dfs_chk_orph: debugfs knob to enable UBIFS orphans extra checks + * @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks + * @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks + * @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing */ struct ubifs_debug_info { struct ubifs_zbranch old_zroot; int old_zroot_level; unsigned long long old_zroot_sqnum; + int failure_mode; int fail_delay; unsigned long fail_timeout; unsigned int fail_cnt; unsigned int fail_cnt_max; + long long chk_lpt_sz; long long chk_lpt_sz2; long long chk_lpt_wastage; @@ -89,11 +106,24 @@ struct ubifs_debug_info { long long saved_free; int saved_idx_gc_cnt; + unsigned int chk_gen:1; + unsigned int chk_index:1; + unsigned int chk_orph:1; + unsigned int chk_lprops:1; + unsigned int chk_fs:1; + unsigned int tst_rcvry:1; + char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1]; struct dentry *dfs_dir; struct dentry *dfs_dump_lprops; struct dentry *dfs_dump_budg; struct dentry *dfs_dump_tnc; + struct dentry *dfs_chk_gen; + struct dentry *dfs_chk_index; + struct dentry *dfs_chk_orph; + struct dentry *dfs_chk_lprops; + struct dentry *dfs_chk_fs; + struct dentry *dfs_tst_rcvry; }; #define ubifs_assert(expr) do { \ @@ -169,59 +199,29 @@ const char *dbg_key_str1(const struct ubifs_info *c, extern spinlock_t dbg_lock; -/* - * Debugging check flags. - * - * UBIFS_CHK_GEN: general checks - * UBIFS_CHK_INDEX: check the index - * UBIFS_CHK_ORPH: check orphans - * UBIFS_CHK_LPROPS: check lprops - * UBIFS_CHK_FS: check the file-system - */ -enum { - UBIFS_CHK_GEN = 0x1, - UBIFS_CHK_INDEX = 0x2, - UBIFS_CHK_ORPH = 0x8, - 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 unsigned int ubifs_msg_flags; -extern unsigned int ubifs_chk_flags; -extern unsigned int ubifs_tst_flags; - static inline int dbg_is_chk_gen(const struct ubifs_info *c) { - return !!(ubifs_chk_flags & UBIFS_CHK_GEN); + return c->dbg->chk_gen; } static inline int dbg_is_chk_index(const struct ubifs_info *c) { - return !!(ubifs_chk_flags & UBIFS_CHK_INDEX); + return c->dbg->chk_index; } static inline int dbg_is_chk_orph(const struct ubifs_info *c) { - return !!(ubifs_chk_flags & UBIFS_CHK_ORPH); + return c->dbg->chk_orph; } static inline int dbg_is_chk_lprops(const struct ubifs_info *c) { - return !!(ubifs_chk_flags & UBIFS_CHK_LPROPS); + return c->dbg->chk_lprops; } static inline int dbg_is_chk_fs(const struct ubifs_info *c) { - return !!(ubifs_chk_flags & UBIFS_CHK_FS); + return c->dbg->chk_fs; } static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) { - return !!(ubifs_tst_flags & UBIFS_TST_RCVRY); + return c->dbg->tst_rcvry; } int ubifs_debugging_init(struct ubifs_info *c); -- cgit v1.2.3 From 24a4f8009ee9e259a412d86373e0d2aac3a80333 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 1 Jun 2011 15:23:25 +0300 Subject: UBIFS: be more informative in failure mode When we are testing UBIFS recovery, it is better to print in which eraseblock we are going to fail. Currently UBIFS prints it only if recovery debugging messages are enabled, but this is not very practical. So change 'dbg_rcvry()' messages to 'ubifs_warn()' messages. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index fdfa5dea5b95..e4a3630eb520 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2631,11 +2631,11 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) d->fail_delay = 1; d->fail_timeout = jiffies + msecs_to_jiffies(delay); - dbg_rcvry("failing after %ums", delay); + ubifs_warn("failing after %ums", delay); } else { d->fail_delay = 2; d->fail_cnt_max = delay; - dbg_rcvry("failing after %u calls", delay); + ubifs_warn("failing after %u calls", delay); } } d->fail_cnt += 1; @@ -2653,56 +2653,56 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) return 0; } else if (chance(19, 20)) return 0; - dbg_rcvry("failing in super block LEB %d", lnum); + ubifs_warn("failing in super block LEB %d", lnum); } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) { if (chance(19, 20)) return 0; - dbg_rcvry("failing in master LEB %d", lnum); + ubifs_warn("failing in master LEB %d", lnum); } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) { if (write) { if (chance(99, 100)) return 0; } else if (chance(399, 400)) return 0; - dbg_rcvry("failing in log LEB %d", lnum); + ubifs_warn("failing in log LEB %d", lnum); } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) { if (write) { if (chance(7, 8)) return 0; } else if (chance(19, 20)) return 0; - dbg_rcvry("failing in LPT LEB %d", lnum); + ubifs_warn("failing in LPT LEB %d", lnum); } else if (lnum >= c->orph_first && lnum <= c->orph_last) { if (write) { if (chance(1, 2)) return 0; } else if (chance(9, 10)) return 0; - dbg_rcvry("failing in orphan LEB %d", lnum); + ubifs_warn("failing in orphan LEB %d", lnum); } else if (lnum == c->ihead_lnum) { if (chance(99, 100)) return 0; - dbg_rcvry("failing in index head LEB %d", lnum); + ubifs_warn("failing in index head LEB %d", lnum); } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) { if (chance(9, 10)) return 0; - dbg_rcvry("failing in GC head LEB %d", lnum); + ubifs_warn("failing in GC head LEB %d", lnum); } else if (write && !RB_EMPTY_ROOT(&c->buds) && !ubifs_search_bud(c, lnum)) { if (chance(19, 20)) return 0; - dbg_rcvry("failing in non-bud LEB %d", lnum); + ubifs_warn("failing in non-bud LEB %d", lnum); } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND || c->cmt_state == COMMIT_RUNNING_REQUIRED) { if (chance(999, 1000)) return 0; - dbg_rcvry("failing in bud LEB %d commit running", lnum); + ubifs_warn("failing in bud LEB %d commit running", lnum); } else { if (chance(9999, 10000)) return 0; - dbg_rcvry("failing in bud LEB %d commit not running", lnum); + ubifs_warn("failing in bud LEB %d commit not running", lnum); } - ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum); + d->failure_mode = 1; dump_stack(); return 1; @@ -2922,8 +2922,16 @@ static ssize_t dfs_file_write(struct file *file, const char __user *u, int val; /* - * FIXME: this is racy - the file-system might have already been - * unmounted and we'd oops in this case. + * 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); -- cgit v1.2.3 From 7dae997de62bbd78f12305bf10019ec8f1103bd4 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 1 Jun 2011 15:44:14 +0300 Subject: UBIFS: re-arrange debugging code a bit Move 'dbg_debugfs_init()' and 'dbg_debugfs_exit()' functions which initialize debugfs for whole UBIFS subsystem below the code which initializes debugfs for a particular UBIFS instance. And do the same for 'ubifs_debugging_init()' and 'ubifs_debugging_exit()' functions. This layout is a bit better for the next patches, so this is just a preparation. Also, rename 'open_debugfs_file()' into 'dfs_file_open()' for consistency. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 118 +++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index e4a3630eb520..24a85073ac6c 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2808,70 +2808,13 @@ int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) return 0; } -/** - * 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; - - failure_mode_init(c); - return 0; -} - -/** - * ubifs_debugging_exit - free debugging data. - * @c: UBIFS file-system description object - */ -void ubifs_debugging_exit(struct ubifs_info *c) -{ - failure_mode_exit(c); - kfree(c->dbg); -} - /* * 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. - * - * 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) -{ - dfs_rootdir = debugfs_create_dir("ubifs", NULL); - if (IS_ERR_OR_NULL(dfs_rootdir)) { - int err = dfs_rootdir ? PTR_ERR(dfs_rootdir) : -ENODEV; - ubifs_err("cannot create \"ubifs\" debugfs directory, " - "error %d\n", err); - return err; - } - - return 0; -} - -/** - * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system. - */ -void dbg_debugfs_exit(void) -{ - debugfs_remove(dfs_rootdir); -} - -static int open_debugfs_file(struct inode *inode, struct file *file) +static int dfs_file_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return nonseekable_open(inode, file); @@ -2978,7 +2921,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *u, } static const struct file_operations dfs_fops = { - .open = open_debugfs_file, + .open = dfs_file_open, .read = dfs_file_read, .write = dfs_file_write, .owner = THIS_MODULE, @@ -3099,4 +3042,61 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c) debugfs_remove_recursive(c->dbg->dfs_dir); } +/** + * 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) +{ + dfs_rootdir = debugfs_create_dir("ubifs", NULL); + if (IS_ERR_OR_NULL(dfs_rootdir)) { + int err = dfs_rootdir ? PTR_ERR(dfs_rootdir) : -ENODEV; + ubifs_err("cannot create \"ubifs\" debugfs directory, " + "error %d\n", err); + return err; + } + + return 0; +} + +/** + * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system. + */ +void dbg_debugfs_exit(void) +{ + debugfs_remove(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; + + failure_mode_init(c); + return 0; +} + +/** + * ubifs_debugging_exit - free debugging data. + * @c: UBIFS file-system description object + */ +void ubifs_debugging_exit(struct ubifs_info *c) +{ + failure_mode_exit(c); + kfree(c->dbg); +} + #endif /* CONFIG_UBIFS_FS_DEBUG */ -- cgit v1.2.3 From 28488fc28aa39815b78c2cbeaaf25f33fef92ce8 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 09:58:23 +0300 Subject: UBIFS: introduce debugfs helpers Separate out pieces of code from the debugfs file read/write functions and create separate 'interpret_user_input()'/'provide_user_output()' helpers. These helpers will be needed in one of the following patches, so this is just a preparational change. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 76 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 20 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 24a85073ac6c..b98638eb0fcb 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2820,13 +2820,39 @@ static int dfs_file_open(struct inode *inode, struct file *file) return nonseekable_open(inode, file); } +/** + * provide_user_output - provide output to the user reading a debugfs file. + * @val: boolean value for the answer + * @u: the buffer to store the answer at + * @count: size of the buffer + * @ppos: position in the @u output buffer + * + * This is a simple helper function which stores @val boolean value in the user + * buffer when the user reads one of UBIFS debugfs files. Returns amount of + * bytes written to @u in case of success and a negative error code in case of + * failure. + */ +static int provide_user_output(int val, char __user *u, size_t count, + loff_t *ppos) +{ + char buf[3]; + + if (val) + buf[0] = '1'; + else + buf[0] = '0'; + buf[1] = '\n'; + buf[2] = 0x00; + + return simple_read_from_buffer(u, count, ppos, buf, 2); +} + static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count, loff_t *ppos) { struct dentry *dent = file->f_path.dentry; struct ubifs_info *c = file->private_data; struct ubifs_debug_info *d = c->dbg; - char buf[3]; int val; if (dent == d->dfs_chk_gen) @@ -2844,14 +2870,33 @@ static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count, else return -EINVAL; - if (val) - buf[0] = '1'; - else - buf[0] = '0'; - buf[1] = '\n'; - buf[2] = 0x00; + return provide_user_output(val, u, count, ppos); +} - return simple_read_from_buffer(u, count, ppos, buf, 2); +/** + * interpret_user_input - interpret user debugfs file input. + * @u: user-provided buffer with the input + * @count: buffer size + * + * This is a helper function which interpret user input to a boolean UBIFS + * debugfs file. Returns %0 or %1 in case of success and a negative error code + * in case of failure. + */ +static int interpret_user_input(const char __user *u, size_t count) +{ + size_t buf_size; + char buf[8]; + + buf_size = min_t(size_t, count, (sizeof(buf) - 1)); + if (copy_from_user(buf, u, buf_size)) + return -EFAULT; + + if (buf[0] == '1') + return 1; + else if (buf[0] == '0') + return 0; + + return -EINVAL; } static ssize_t dfs_file_write(struct file *file, const char __user *u, @@ -2860,8 +2905,6 @@ static ssize_t dfs_file_write(struct file *file, const char __user *u, struct ubifs_info *c = file->private_data; struct ubifs_debug_info *d = c->dbg; struct dentry *dent = file->f_path.dentry; - size_t buf_size; - char buf[8]; int val; /* @@ -2891,16 +2934,9 @@ static ssize_t dfs_file_write(struct file *file, const char __user *u, return count; } - buf_size = min_t(size_t, count, (sizeof(buf) - 1)); - if (copy_from_user(buf, u, buf_size)) - return -EFAULT; - - if (buf[0] == '1') - val = 1; - else if (buf[0] == '0') - val = 0; - else - return -EINVAL; + val = interpret_user_input(u, count); + if (val < 0) + return val; if (dent == d->dfs_chk_gen) d->chk_gen = val; -- cgit v1.2.3 From e7717060ddd509e6c305ad7bf5a090a95e91c8cf Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 1 Jun 2011 17:43:43 +0300 Subject: UBIFS: add global debugfs knobs Now we have per-FS (superblock) debugfs knobs, but they have one drawback - you have to first mount the FS and only after this you can switch self-checks on/off. But often we want to have the checks enabled during the mount. Introduce global debugging knobs for this purpose. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++---- fs/ubifs/debug.h | 35 +++++++++++--- 2 files changed, 157 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index b98638eb0fcb..15bec635bf3e 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -3064,7 +3064,7 @@ out_remove: debugfs_remove_recursive(d->dfs_dir); out: err = dent ? PTR_ERR(dent) : -ENODEV; - ubifs_err("cannot create \"%s\" debugfs filr or directory, error %d\n", + ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n", fname, err); return err; } @@ -3078,6 +3078,74 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c) debugfs_remove_recursive(c->dbg->dfs_dir); } +struct ubifs_global_debug_info ubifs_dbg; + +static struct dentry *dfs_chk_gen; +static struct dentry *dfs_chk_index; +static struct dentry *dfs_chk_orph; +static struct dentry *dfs_chk_lprops; +static struct dentry *dfs_chk_fs; +static struct dentry *dfs_tst_rcvry; + +static ssize_t dfs_global_file_read(struct file *file, char __user *u, + size_t count, loff_t *ppos) +{ + struct dentry *dent = file->f_path.dentry; + int val; + + if (dent == dfs_chk_gen) + val = ubifs_dbg.chk_gen; + else if (dent == dfs_chk_index) + val = ubifs_dbg.chk_index; + else if (dent == dfs_chk_orph) + val = ubifs_dbg.chk_orph; + else if (dent == dfs_chk_lprops) + val = ubifs_dbg.chk_lprops; + else if (dent == dfs_chk_fs) + val = ubifs_dbg.chk_fs; + else if (dent == dfs_tst_rcvry) + val = ubifs_dbg.tst_rcvry; + else + return -EINVAL; + + return provide_user_output(val, u, count, ppos); +} + +static ssize_t dfs_global_file_write(struct file *file, const char __user *u, + size_t count, loff_t *ppos) +{ + struct dentry *dent = file->f_path.dentry; + int val; + + val = interpret_user_input(u, count); + if (val < 0) + return val; + + if (dent == dfs_chk_gen) + ubifs_dbg.chk_gen = val; + else if (dent == dfs_chk_index) + ubifs_dbg.chk_index = val; + else if (dent == dfs_chk_orph) + ubifs_dbg.chk_orph = val; + else if (dent == dfs_chk_lprops) + ubifs_dbg.chk_lprops = val; + else if (dent == dfs_chk_fs) + ubifs_dbg.chk_fs = val; + else if (dent == dfs_tst_rcvry) + ubifs_dbg.tst_rcvry = val; + else + return -EINVAL; + + return count; +} + +static const struct file_operations dfs_global_fops = { + .read = dfs_global_file_read, + .write = dfs_global_file_write, + .owner = THIS_MODULE, + .llseek = no_llseek, +}; + /** * dbg_debugfs_init - initialize debugfs file-system. * @@ -3088,15 +3156,67 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c) */ int dbg_debugfs_init(void) { - dfs_rootdir = debugfs_create_dir("ubifs", NULL); - if (IS_ERR_OR_NULL(dfs_rootdir)) { - int err = dfs_rootdir ? PTR_ERR(dfs_rootdir) : -ENODEV; - ubifs_err("cannot create \"ubifs\" debugfs directory, " - "error %d\n", err); - return err; - } + 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; } /** @@ -3104,7 +3224,7 @@ int dbg_debugfs_init(void) */ void dbg_debugfs_exit(void) { - debugfs_remove(dfs_rootdir); + debugfs_remove_recursive(dfs_rootdir); } /** diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 8c3bdd378037..43ec5d120d7c 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -126,6 +126,25 @@ struct ubifs_debug_info { 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 { \ if (unlikely(!(expr))) { \ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ @@ -162,6 +181,8 @@ const char *dbg_key_str1(const struct ubifs_info *c, #define DBGKEY(key) dbg_key_str0(c, (key)) #define DBGKEY1(key) dbg_key_str1(c, (key)) +extern spinlock_t dbg_lock; + #define ubifs_dbg_msg(type, fmt, ...) do { \ spin_lock(&dbg_lock); \ pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \ @@ -197,31 +218,31 @@ const char *dbg_key_str1(const struct ubifs_info *c, /* Additional recovery messages */ #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__) -extern spinlock_t dbg_lock; +extern struct ubifs_global_debug_info ubifs_dbg; static inline int dbg_is_chk_gen(const struct ubifs_info *c) { - return c->dbg->chk_gen; + return !!(ubifs_dbg.chk_gen || c->dbg->chk_gen); } static inline int dbg_is_chk_index(const struct ubifs_info *c) { - return c->dbg->chk_index; + return !!(ubifs_dbg.chk_index || c->dbg->chk_index); } static inline int dbg_is_chk_orph(const struct ubifs_info *c) { - return c->dbg->chk_orph; + return !!(ubifs_dbg.chk_orph || c->dbg->chk_orph); } static inline int dbg_is_chk_lprops(const struct ubifs_info *c) { - return c->dbg->chk_lprops; + return !!(ubifs_dbg.chk_lprops || c->dbg->chk_lprops); } static inline int dbg_is_chk_fs(const struct ubifs_info *c) { - return c->dbg->chk_fs; + return !!(ubifs_dbg.chk_fs || c->dbg->chk_fs); } static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) { - return c->dbg->tst_rcvry; + return !!(ubifs_dbg.tst_rcvry || c->dbg->tst_rcvry); } int ubifs_debugging_init(struct ubifs_info *c); -- cgit v1.2.3 From 891a54a153646f9b16bffe5df6cb74cb3f1e9dc6 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 11:32:21 +0300 Subject: UBIFS: remove unused and unneeded debugging function This patch contains several minor clean-up and preparational cahnges. 1. Remove 'dbg_read()', 'dbg_write()', 'dbg_change()', and 'dbg_leb_erase()' functions as they are not used. 2. Remove 'dbg_leb_read()' and 'dbg_is_mapped()' as they are not really needed, it is fine to let reads go through in failure mode. 3. Rename 'offset' argument to 'offs' to be consistent with the rest of UBIFS code. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 33 ++------------------------------- fs/ubifs/debug.h | 27 +-------------------------- 2 files changed, 3 insertions(+), 57 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 15bec635bf3e..059c586b5ef8 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2718,16 +2718,8 @@ static void cut_data(const void *buf, int len) p[i] = 0xff; } -int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, - int len, int check) -{ - if (in_failure_mode(desc)) - return -EROFS; - return ubi_leb_read(desc, lnum, buf, offset, len, check); -} - int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, - int offset, int len, int dtype) + int offs, int len, int dtype) { int err, failing; @@ -2736,7 +2728,7 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, failing = do_fail(desc, lnum, 1); if (failing) cut_data(buf, len); - err = ubi_leb_write(desc, lnum, buf, offset, len, dtype); + err = ubi_leb_write(desc, lnum, buf, offs, len, dtype); if (err) return err; if (failing) @@ -2759,20 +2751,6 @@ int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, return 0; } -int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum) -{ - int err; - - if (do_fail(desc, lnum, 0)) - return -EROFS; - err = ubi_leb_erase(desc, lnum); - if (err) - return err; - if (do_fail(desc, lnum, 0)) - return -EROFS; - return 0; -} - int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum) { int err; @@ -2787,13 +2765,6 @@ int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum) return 0; } -int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum) -{ - if (in_failure_mode(desc)) - return -EROFS; - return ubi_is_mapped(desc, lnum); -} - int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) { int err; diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 43ec5d120d7c..e1dcfd29c9aa 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -302,44 +302,19 @@ 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); #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 offs, 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 */ int dbg_debugfs_init(void); void dbg_debugfs_exit(void); -- cgit v1.2.3 From d033c98b17ecf30d64d83d96938ce7bfb47f7520 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 13:16:08 +0300 Subject: UBIFS: always print stacktrace when switching to R/O mode When switching to R/O mode due to an I/O error, always dump the stack, not only when debugging is enabled. Signed-off-by: Artem Bityutskiy --- fs/ubifs/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 3be645e012c9..48e16804ca57 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -86,7 +86,7 @@ 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); - dbg_dump_stack(); + dump_stack(); } } -- cgit v1.2.3 From 83cef708c606f46a2b527af025acb3d24555f0c4 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 13:45:09 +0300 Subject: UBIFS: introduce more I/O helpers Introduce the following I/O helper functions: 'ubifs_leb_read()', 'ubifs_leb_write()', 'ubifs_leb_change()', 'ubifs_leb_unmap()', 'ubifs_leb_map()', 'ubifs_is_mapped(). The idea is to wrap all UBI I/O functions in order to encapsulate various assertions and error path handling (error message, stack dump, switching to R/O mode). And there are some other benefits of this which will be used in the following patches. This patch does not switch whole UBIFS to use these functions yet. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.h | 16 +++++++ fs/ubifs/io.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ubifs/misc.h | 80 ----------------------------------- fs/ubifs/recovery.c | 9 ++-- fs/ubifs/ubifs.h | 13 +++++- 5 files changed, 148 insertions(+), 87 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index e1dcfd29c9aa..b0b005b97279 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -244,6 +244,10 @@ 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->failure_mode; +} int ubifs_debugging_init(struct ubifs_info *c); void ubifs_debugging_exit(struct ubifs_info *c); @@ -445,12 +449,24 @@ static inline int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head) { return 0; } +static inline int dbg_leb_write(struct ubi_volume_desc *desc, + int lnum, const void *buf, + int offset, int len, int dtype) { return 0; } +static inline int dbg_leb_change(struct ubi_volume_desc *desc, + int lnum, const void *buf, + int len, int dtype) { return 0; } +static inline int dbg_leb_unmap(struct ubi_volume_desc *desc, + int lnum) { return 0; } +static inline int dbg_leb_map(struct ubi_volume_desc *desc, + int lnum, int dtype) { return 0; } + static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return 0; } static inline int dbg_is_chk_index(const struct ubifs_info *c) { return 0; } static inline int dbg_is_chk_orph(const struct ubifs_info *c) { return 0; } static inline int dbg_is_chk_lprops(const struct ubifs_info *c) { return 0; } static inline int dbg_is_chk_fs(const struct ubifs_info *c) { return 0; } static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) { return 0; } +static inline int dbg_is_power_cut(const struct ubifs_info *c) { return 0; } static inline int dbg_debugfs_init(void) { return 0; } static inline void dbg_debugfs_exit(void) { return; } diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 48e16804ca57..239899d7bf3f 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -90,6 +90,123 @@ void ubifs_ro_mode(struct ubifs_info *c, int err) } } +/* + * 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->ubi, 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->ubi, 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->ubi, 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->ubi, 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; +} + /** * ubifs_check_node - check node. * @c: UBIFS file-system description object diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h index 160cd909e957..ee7cb5ebb6e8 100644 --- a/fs/ubifs/misc.h +++ b/fs/ubifs/misc.h @@ -144,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 diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 783d8e0beb76..c59154980719 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -919,8 +919,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; @@ -962,7 +961,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 +992,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; @@ -1089,7 +1088,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)) { diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 3304aad04885..702b79258e30 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -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); -- cgit v1.2.3 From d304820a1f6cdacab691bbcb7faa35ec631c6398 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 14:03:25 +0300 Subject: UBIFS: switch to ubifs_leb_read Instead of using 'ubi_read()' function directly, used the 'ubifs_leb_read()' helper function instead. This allows to get rid of several redundant error messages and make sure that we always have a stack dump on read errors. Signed-off-by: Artem Bityutskiy --- fs/ubifs/io.c | 15 ++++----------- fs/ubifs/lpt.c | 17 +++++++++-------- fs/ubifs/lpt_commit.c | 23 +++++++++++------------ fs/ubifs/recovery.c | 17 +++++++++-------- fs/ubifs/replay.c | 3 +-- fs/ubifs/sb.c | 2 +- fs/ubifs/scan.c | 2 +- fs/ubifs/tnc.c | 8 ++++---- 8 files changed, 40 insertions(+), 47 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 239899d7bf3f..f58f11bed387 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -941,13 +941,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) { @@ -1002,12 +998,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)", diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c index ab91ca628455..8b9ee9fe0a41 100644 --- a/fs/ubifs/lpt.c +++ b/fs/ubifs/lpt.c @@ -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); @@ -1291,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); @@ -1333,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); @@ -1356,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); @@ -1816,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); @@ -1885,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); diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index f13addf72e89..cddd6bd214f4 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c @@ -1161,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; @@ -1651,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; @@ -1902,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)) { diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index c59154980719..f28070cb00c6 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -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; @@ -539,8 +539,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; } @@ -819,7 +819,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); @@ -930,12 +931,12 @@ static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf) 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); @@ -1008,7 +1009,7 @@ static int clean_an_unclean_leb(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; @@ -1453,7 +1454,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 */ diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index 5e97161ce4d3..ccabaf1164b3 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c @@ -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; diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c index c606f010e8df..701dccc1d6de 100644 --- a/fs/ubifs/sb.c +++ b/fs/ubifs/sb.c @@ -678,7 +678,7 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int 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) return err; diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c index c7df916dce97..37383e8011b1 100644 --- a/fs/ubifs/scan.c +++ b/fs/ubifs/scan.c @@ -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); diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 526b63cd3333..066738647685 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -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)) -- cgit v1.2.3 From 987226a5d3a356792650f8e9028132a79815f6ef Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 14:12:10 +0300 Subject: UBIFS: switch to ubifs_leb_write Stop using 'ubi_leb_write()' directly and switch to the 'ubifs_leb_write()' helper. Signed-off-by: Artem Bityutskiy --- fs/ubifs/io.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index f58f11bed387..a0c5fb4b6fa8 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -523,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; @@ -722,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; @@ -759,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; @@ -778,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; @@ -800,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; @@ -883,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; } -- cgit v1.2.3 From d3b2578f56e0a77b9e261d83e9b5a0a666b82980 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 14:22:05 +0300 Subject: UBIFS: switch to I/O helpers Switch the rest of direct UBI calls to UBIFS helper functions. Signed-off-by: Artem Bityutskiy --- fs/ubifs/log.c | 4 +--- fs/ubifs/lpt.c | 16 ++++++++-------- fs/ubifs/recovery.c | 14 +++++++------- fs/ubifs/sb.c | 4 ++-- fs/ubifs/super.c | 2 +- 5 files changed, 19 insertions(+), 21 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c index fabfb53c4fee..f9fd068d1ae0 100644 --- a/fs/ubifs/log.c +++ b/fs/ubifs/log.c @@ -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); diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c index 8b9ee9fe0a41..6189c74d97f0 100644 --- a/fs/ubifs/lpt.c +++ b/fs/ubifs/lpt.c @@ -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; diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index f28070cb00c6..51bcf4227b29 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -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: @@ -554,8 +554,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; } @@ -939,7 +939,7 @@ static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf) 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; @@ -1069,7 +1069,7 @@ static int clean_an_unclean_leb(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; @@ -1470,7 +1470,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", diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c index 701dccc1d6de..93d938ad3d2a 100644 --- a/fs/ubifs/sb.c +++ b/fs/ubifs/sb.c @@ -674,7 +674,7 @@ 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); @@ -682,7 +682,7 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int len) 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); } /** diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 285038548da9..b28121278d46 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -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) { -- cgit v1.2.3 From 0a541b14e819f972d14f29d17cb9fd8b4b71222e Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 14:38:50 +0300 Subject: UBIFS: stop re-defining UBI operations Now when we use UBIFS helpers for all the I/O, we can remove the horrible hack of re-defining UBI I/O functions. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 2 -- fs/ubifs/debug.h | 7 ------- 2 files changed, 9 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 059c586b5ef8..3a7344124f30 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -27,8 +27,6 @@ * various local functions of those subsystems. */ -#define UBIFS_DBG_PRESERVE_UBI - #include "ubifs.h" #include #include diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index b0b005b97279..b5bc09deeb32 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -305,13 +305,6 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode, int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head); int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head); -#ifndef UBIFS_DBG_PRESERVE_UBI -#define ubi_leb_write dbg_leb_write -#define ubi_leb_change dbg_leb_change -#define ubi_leb_unmap dbg_leb_unmap -#define ubi_leb_map dbg_leb_map -#endif - int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, int offs, int len, int dtype); int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, -- cgit v1.2.3 From f57cb188ccd9c0242111d99b7283eda7827746c4 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 14:51:41 +0300 Subject: UBIFS: remove custom list of superblocks This is a clean-up of the power-cut emulation code - remove the custom list of superblocks which we maintained to find the superblock by the UBI volume descriptor. We do not need that crud any longer, because now we can get the superblock as a function argument. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 105 +++++++++++-------------------------------------------- fs/ubifs/debug.h | 31 ++++++++-------- fs/ubifs/io.c | 8 ++--- 3 files changed, 39 insertions(+), 105 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 3a7344124f30..1e880cedefa4 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2539,16 +2539,7 @@ error_dump: #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) @@ -2557,69 +2548,15 @@ static int simple_rand(void) 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; - - 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) +static int do_fail(struct ubifs_info *c, int lnum, int write) { - 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); + struct ubifs_debug_info *d = c->dbg; - if (c && dbg_is_tst_rcvry(c)) - return c->dbg->failure_mode; - return 0; -} + ubifs_assert(dbg_is_tst_rcvry(c)); -static int do_fail(struct ubi_volume_desc *desc, int lnum, int write) -{ - struct ubifs_info *c = dbg_find_info(desc); - struct ubifs_debug_info *d; - - if (!c || !dbg_is_tst_rcvry(c)) - return 0; - d = c->dbg; if (d->failure_mode) return 1; + if (!d->fail_cnt) { /* First call - decide delay to failure */ if (chance(1, 2)) { @@ -2716,17 +2653,17 @@ static void cut_data(const void *buf, int len) p[i] = 0xff; } -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 offs, int len, int dtype) { int err, failing; - if (in_failure_mode(desc)) + if (c->dbg->failure_mode) return -EROFS; - failing = do_fail(desc, lnum, 1); + failing = do_fail(c, lnum, 1); if (failing) cut_data(buf, len); - err = ubi_leb_write(desc, lnum, buf, offs, len, dtype); + err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype); if (err) return err; if (failing) @@ -2734,45 +2671,45 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, return 0; } -int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, +int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len, int dtype) { int err; - if (do_fail(desc, lnum, 1)) + if (do_fail(c, lnum, 1)) return -EROFS; - err = ubi_leb_change(desc, lnum, buf, len, dtype); + err = ubi_leb_change(c->ubi, lnum, buf, len, dtype); if (err) return err; - if (do_fail(desc, lnum, 1)) + if (do_fail(c, lnum, 1)) return -EROFS; return 0; } -int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum) +int dbg_leb_unmap(struct ubifs_info *c, int lnum) { int err; - if (do_fail(desc, lnum, 0)) + if (do_fail(c, lnum, 0)) return -EROFS; - err = ubi_leb_unmap(desc, lnum); + err = ubi_leb_unmap(c->ubi, lnum); if (err) return err; - if (do_fail(desc, lnum, 0)) + if (do_fail(c, lnum, 0)) return -EROFS; return 0; } -int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) +int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype) { int err; - if (do_fail(desc, lnum, 0)) + if (do_fail(c, lnum, 0)) return -EROFS; - err = ubi_leb_map(desc, lnum, dtype); + err = ubi_leb_map(c->ubi, lnum, dtype); if (err) return err; - if (do_fail(desc, lnum, 0)) + if (do_fail(c, lnum, 0)) return -EROFS; return 0; } @@ -3210,7 +3147,6 @@ int ubifs_debugging_init(struct ubifs_info *c) if (!c->dbg) return -ENOMEM; - failure_mode_init(c); return 0; } @@ -3220,7 +3156,6 @@ int ubifs_debugging_init(struct ubifs_info *c) */ void ubifs_debugging_exit(struct ubifs_info *c) { - failure_mode_exit(c); kfree(c->dbg); } diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index b5bc09deeb32..0ab3757ef0e3 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -305,12 +305,12 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode, int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head); int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head); -int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, - int offs, 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_unmap(struct ubi_volume_desc *desc, int lnum); -int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype); +int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs, + int len, int dtype); +int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len, + int dtype); +int dbg_leb_unmap(struct ubifs_info *c, int lnum); +int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype); /* Debugfs-related stuff */ int dbg_debugfs_init(void); @@ -442,16 +442,15 @@ static inline int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head) { return 0; } -static inline int dbg_leb_write(struct ubi_volume_desc *desc, - int lnum, const void *buf, - int offset, int len, int dtype) { return 0; } -static inline int dbg_leb_change(struct ubi_volume_desc *desc, - int lnum, const void *buf, - int len, int dtype) { return 0; } -static inline int dbg_leb_unmap(struct ubi_volume_desc *desc, - int lnum) { return 0; } -static inline int dbg_leb_map(struct ubi_volume_desc *desc, - int lnum, int dtype) { return 0; } +static inline int dbg_leb_write(struct ubifs_info *c, int lnum, + const void *buf, int offset, + int len, int dtype) { return 0; } +static inline int dbg_leb_change(struct ubifs_info *c, int lnum, + const void *buf, int len, + int dtype) { return 0; } +static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum) { return 0; } +static inline int dbg_leb_map(struct ubifs_info *c, int lnum, + int dtype) { return 0; } static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return 0; } static inline int dbg_is_chk_index(const struct ubifs_info *c) { return 0; } diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index a0c5fb4b6fa8..9228950a658f 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -125,7 +125,7 @@ int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs, if (!dbg_is_tst_rcvry(c)) err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype); else - err = dbg_leb_write(c->ubi, lnum, buf, offs, len, dtype); + 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); @@ -146,7 +146,7 @@ int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len, if (!dbg_is_tst_rcvry(c)) err = ubi_leb_change(c->ubi, lnum, buf, len, dtype); else - err = dbg_leb_change(c->ubi, lnum, buf, len, dtype); + 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); @@ -166,7 +166,7 @@ int ubifs_leb_unmap(struct ubifs_info *c, int lnum) if (!dbg_is_tst_rcvry(c)) err = ubi_leb_unmap(c->ubi, lnum); else - err = dbg_leb_unmap(c->ubi, lnum); + err = dbg_leb_unmap(c, lnum); if (err) { ubifs_err("unmap LEB %d failed, error %d", lnum, err); ubifs_ro_mode(c, err); @@ -185,7 +185,7 @@ int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype) if (!dbg_is_tst_rcvry(c)) err = ubi_leb_map(c->ubi, lnum, dtype); else - err = dbg_leb_map(c->ubi, lnum, dtype); + err = dbg_leb_map(c, lnum, dtype); if (err) { ubifs_err("mapping LEB %d failed, error %d", lnum, err); ubifs_ro_mode(c, err); -- cgit v1.2.3 From d27462a518c31a4b1093ad866229f85b2b765e7e Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 15:10:33 +0300 Subject: UBIFS: rename recovery testing variables Since the recovery testing is effectively about emulating power cuts by UBIFS, use "power cut" as the base term for all the related variables and name them correspondingly. This is just a minor clean-up for the sake of readability. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 52 ++++++++++++++++++++++++++++------------------------ fs/ubifs/debug.h | 22 +++++++++++----------- 2 files changed, 39 insertions(+), 35 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 1e880cedefa4..b801af7837e9 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2548,39 +2548,36 @@ static int simple_rand(void) return (next >> 16) & 32767; } -static int do_fail(struct ubifs_info *c, int lnum, int write) +static int power_cut_emulated(struct ubifs_info *c, int lnum, int write) { struct ubifs_debug_info *d = c->dbg; ubifs_assert(dbg_is_tst_rcvry(c)); - if (d->failure_mode) - return 1; - - if (!d->fail_cnt) { - /* First call - decide delay to failure */ + if (!d->pc_cnt) { + /* First call - decide delay to the power cut */ if (chance(1, 2)) { unsigned int delay = 1 << (simple_rand() >> 11); if (chance(1, 2)) { - d->fail_delay = 1; - d->fail_timeout = jiffies + + d->pc_delay = 1; + d->pc_timeout = jiffies + msecs_to_jiffies(delay); ubifs_warn("failing after %ums", delay); } else { - d->fail_delay = 2; - d->fail_cnt_max = delay; + d->pc_delay = 2; + d->pc_cnt_max = delay; ubifs_warn("failing after %u calls", delay); } } - d->fail_cnt += 1; + d->pc_cnt += 1; } /* Determine if failure delay has expired */ - if (d->fail_delay == 1) { - if (time_before(jiffies, d->fail_timeout)) + if (d->pc_delay == 1) { + if (time_before(jiffies, d->pc_timeout)) return 0; - } else if (d->fail_delay == 2) - if (d->fail_cnt++ < d->fail_cnt_max) + } else if (d->pc_delay == 2) + if (d->pc_cnt++ < d->pc_cnt_max) return 0; if (lnum == UBIFS_SB_LNUM) { if (write) { @@ -2638,7 +2635,7 @@ static int do_fail(struct ubifs_info *c, int lnum, int write) ubifs_warn("failing in bud LEB %d commit not running", lnum); } - d->failure_mode = 1; + d->pc_happened = 1; dump_stack(); return 1; } @@ -2658,9 +2655,10 @@ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, { int err, failing; - if (c->dbg->failure_mode) + if (c->dbg->pc_happened) return -EROFS; - failing = do_fail(c, lnum, 1); + + failing = power_cut_emulated(c, lnum, 1); if (failing) cut_data(buf, len); err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype); @@ -2676,12 +2674,14 @@ int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, { int err; - if (do_fail(c, lnum, 1)) + if (c->dbg->pc_happened) + return -EROFS; + if (power_cut_emulated(c, lnum, 1)) return -EROFS; err = ubi_leb_change(c->ubi, lnum, buf, len, dtype); if (err) return err; - if (do_fail(c, lnum, 1)) + if (power_cut_emulated(c, lnum, 1)) return -EROFS; return 0; } @@ -2690,12 +2690,14 @@ int dbg_leb_unmap(struct ubifs_info *c, int lnum) { int err; - if (do_fail(c, lnum, 0)) + if (c->dbg->pc_happened) + return -EROFS; + if (power_cut_emulated(c, lnum, 0)) return -EROFS; err = ubi_leb_unmap(c->ubi, lnum); if (err) return err; - if (do_fail(c, lnum, 0)) + if (power_cut_emulated(c, lnum, 0)) return -EROFS; return 0; } @@ -2704,12 +2706,14 @@ int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype) { int err; - if (do_fail(c, lnum, 0)) + if (c->dbg->pc_happened) + return -EROFS; + if (power_cut_emulated(c, lnum, 0)) return -EROFS; err = ubi_leb_map(c->ubi, lnum, dtype); if (err) return err; - if (do_fail(c, lnum, 0)) + if (power_cut_emulated(c, lnum, 0)) return -EROFS; return 0; } diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 0ab3757ef0e3..45174b534377 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -44,11 +44,11 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c, * @old_zroot_level: old index root level - used by 'dbg_check_old_index()' * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()' * - * @failure_mode: failure mode for recovery testing - * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls - * @fail_timeout: time in jiffies when delay of failure mode expires - * @fail_cnt: current number of calls to failure mode I/O functions - * @fail_cnt_max: number of calls by which to delay failure mode + * @pc_happened: non-zero if an emulated power cut happened + * @pc_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls + * @pc_timeout: time in jiffies when delay of failure mode expires + * @pc_cnt: current number of calls to failure mode I/O functions + * @pc_cnt_max: number of calls by which to delay failure mode * * @chk_lpt_sz: used by LPT tree size checker * @chk_lpt_sz2: used by LPT tree size checker @@ -87,11 +87,11 @@ struct ubifs_debug_info { int old_zroot_level; unsigned long long old_zroot_sqnum; - int failure_mode; - int fail_delay; - unsigned long fail_timeout; - unsigned int fail_cnt; - unsigned int fail_cnt_max; + int pc_happened; + int pc_delay; + unsigned long pc_timeout; + unsigned int pc_cnt; + unsigned int pc_cnt_max; long long chk_lpt_sz; long long chk_lpt_sz2; @@ -246,7 +246,7 @@ static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) } static inline int dbg_is_power_cut(const struct ubifs_info *c) { - return !!c->dbg->failure_mode; + return !!c->dbg->pc_happened; } int ubifs_debugging_init(struct ubifs_info *c); -- cgit v1.2.3 From a7fa94a9fe26a4925914083a31b5387bca530eb1 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 3 Jun 2011 16:20:03 +0300 Subject: UBIFS: improve power cut emulation testing This patch cleans-up and improves the power cut testing: 1. Kill custom 'simple_random()' function and use 'random32()' instead. 2. Make timeout larger 3. When cutting the buffer - fill the end with random data sometimes, not only with 0xFFs. 4. Some times cut in the middle of the buffer, not always at the end. Signed-off-by: Artem Bityutskiy --- fs/ubifs/debug.c | 91 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 41 deletions(-) (limited to 'fs') diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index b801af7837e9..eef109a1a927 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -27,11 +27,12 @@ * various local functions of those subsystems. */ -#include "ubifs.h" #include #include #include #include +#include +#include "ubifs.h" #ifdef CONFIG_UBIFS_FS_DEBUG @@ -2535,17 +2536,10 @@ error_dump: return 0; } -/* Failure mode for recovery testing */ - -#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d)) - -static unsigned int next; -static int simple_rand(void) +static inline int chance(unsigned int n, unsigned int out_of) { - if (next == 0) - next = current->pid; - next = next * 1103515245 + 12345; - return (next >> 16) & 32767; + return !!((random32() % out_of) + 1 <= n); + } static int power_cut_emulated(struct ubifs_info *c, int lnum, int write) @@ -2557,33 +2551,37 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write) if (!d->pc_cnt) { /* First call - decide delay to the power cut */ if (chance(1, 2)) { - unsigned int delay = 1 << (simple_rand() >> 11); + unsigned long delay; if (chance(1, 2)) { d->pc_delay = 1; - d->pc_timeout = jiffies + - msecs_to_jiffies(delay); - ubifs_warn("failing after %ums", delay); + /* Fail withing 1 minute */ + delay = random32() % 60000; + d->pc_timeout = jiffies; + d->pc_timeout += msecs_to_jiffies(delay); + ubifs_warn("failing after %lums", delay); } else { d->pc_delay = 2; + delay = random32() % 10000; + /* Fail within 10000 operations */ d->pc_cnt_max = delay; - ubifs_warn("failing after %u calls", delay); + ubifs_warn("failing after %lu calls", delay); } } + d->pc_cnt += 1; } + /* Determine if failure delay has expired */ - if (d->pc_delay == 1) { - if (time_before(jiffies, d->pc_timeout)) + if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout)) return 0; - } else if (d->pc_delay == 2) - if (d->pc_cnt++ < d->pc_cnt_max) + if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max) return 0; + if (lnum == UBIFS_SB_LNUM) { - if (write) { - if (chance(1, 2)) - return 0; - } else if (chance(19, 20)) + if (write && chance(1, 2)) + return 0; + if (chance(19, 20)) return 0; ubifs_warn("failing in super block LEB %d", lnum); } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) { @@ -2591,24 +2589,21 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write) return 0; ubifs_warn("failing in master LEB %d", lnum); } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) { - if (write) { - if (chance(99, 100)) - return 0; - } else if (chance(399, 400)) + if (write && chance(99, 100)) + return 0; + if (chance(399, 400)) return 0; ubifs_warn("failing in log LEB %d", lnum); } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) { - if (write) { - if (chance(7, 8)) - return 0; - } else if (chance(19, 20)) + if (write && chance(7, 8)) + return 0; + if (chance(19, 20)) return 0; ubifs_warn("failing in LPT LEB %d", lnum); } else if (lnum >= c->orph_first && lnum <= c->orph_last) { - if (write) { - if (chance(1, 2)) - return 0; - } else if (chance(9, 10)) + if (write && chance(1, 2)) + return 0; + if (chance(9, 10)) return 0; ubifs_warn("failing in orphan LEB %d", lnum); } else if (lnum == c->ihead_lnum) { @@ -2636,18 +2631,32 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write) } d->pc_happened = 1; + ubifs_warn("========== Power cut emulated =========="); dump_stack(); return 1; } -static void cut_data(const void *buf, int len) +static void cut_data(const void *buf, unsigned int len) { - int flen, i; + unsigned int from, to, i, ffs = chance(1, 2); unsigned char *p = (void *)buf; - flen = (len * (long long)simple_rand()) >> 15; - for (i = flen; i < len; i++) - p[i] = 0xff; + from = random32() % (len + 1); + if (chance(1, 2)) + to = random32() % (len - from + 1); + else + to = len; + + if (from < to) + ubifs_warn("filled bytes %u-%u with %s", from, to - 1, + ffs ? "0xFFs" : "random data"); + + if (ffs) + for (i = from; i < to; i++) + p[i] = 0xFF; + else + for (i = from; i < to; i++) + p[i] = random32() % 0x100; } int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, -- cgit v1.2.3 From 19495f70d1ebcdc732dd3c94f5968a4bff198ae5 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 7 Jul 2011 12:25:02 +0200 Subject: UBIFS: fix master node recovery When the 1st LEB was unmapped and written but 2nd LEB not, the master node recovery doesn't succeed after power cut. We see following error when mounting UBIFS partition on NOR flash: UBIFS error (pid 1137): ubifs_recover_master_node: failed to recover master node Correct 2nd master node offset check is needed to fix the problem. If the 2nd master node is at the end in the 2nd LEB, first master node is used for recovery. When checking for this condition we should check whether the master node is exactly at the end of the LEB (without remaining empty space) or whether it is followed by an empty space less than the master node size. Artem: when the error happened, offs2 = 261120, sz = 512, c->leb_size = 262016. Signed-off-by: Anatolij Gustschin Signed-off-by: Artem Bityutskiy --- fs/ubifs/recovery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 51bcf4227b29..af02790d9328 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -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; -- cgit v1.2.3