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

* 'linux-next' of git://git.infradead.org/ubifs-2.6: (32 commits)
  MAINTAINERS: change e-mail of Adrian Hunter
  UBIFS: fix master node recovery
  UBIFS: improve power cut emulation testing
  UBIFS: rename recovery testing variables
  UBIFS: remove custom list of superblocks
  UBIFS: stop re-defining UBI operations
  UBIFS: switch to I/O helpers
  UBIFS: switch to ubifs_leb_write
  UBIFS: switch to ubifs_leb_read
  UBIFS: introduce more I/O helpers
  UBIFS: always print stacktrace when switching to R/O mode
  UBIFS: remove unused and unneeded debugging function
  UBIFS: add global debugfs knobs
  UBIFS: introduce debugfs helpers
  UBIFS: re-arrange debugging code a bit
  UBIFS: be more informative in failure mode
  UBIFS: switch self-check knobs to debugfs
  UBIFS: lessen amount of debugging check types
  UBIFS: introduce helper functions for debugging checks and tests
  UBIFS: amend debugging inode size check function prototype
  ...
This commit is contained in:
Linus Torvalds 2011-07-22 13:09:35 -07:00
commit 59a7ac1211
22 changed files with 991 additions and 713 deletions

View File

@ -111,34 +111,6 @@ The following is an example of the kernel boot arguments to attach mtd0
to UBI and mount volume "rootfs": to UBI and mount volume "rootfs":
ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs
Module Parameters for Debugging
===============================
When UBIFS has been compiled with debugging enabled, there are 2 module
parameters that are available to control aspects of testing and debugging.
debug_chks Selects extra checks that UBIFS can do while running:
Check Flag value
General checks 1
Check Tree Node Cache (TNC) 2
Check indexing tree size 4
Check orphan area 8
Check old indexing tree 16
Check LEB properties (lprops) 32
Check leaf nodes and inodes 64
debug_tsts Selects a mode of testing, as follows:
Test mode Flag value
Failure mode for recovery testing 4
For example, set debug_chks to 3 to enable general and TNC checks.
References References
========== ==========

View File

@ -1,4 +1,5 @@
List of maintainers and how to submit kernel changes List of maintainers and how to submit kernel changes
Please try to follow the guidelines below. This will make things Please try to follow the guidelines below. This will make things
@ -6321,7 +6322,7 @@ F: drivers/scsi/u14-34f.c
UBI FILE SYSTEM (UBIFS) UBI FILE SYSTEM (UBIFS)
M: Artem Bityutskiy <dedekind1@gmail.com> M: Artem Bityutskiy <dedekind1@gmail.com>
M: Adrian Hunter <adrian.hunter@nokia.com> M: Adrian Hunter <adrian.hunter@intel.com>
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
T: git git://git.infradead.org/ubifs-2.6.git T: git git://git.infradead.org/ubifs-2.6.git
W: http://www.linux-mtd.infradead.org/doc/ubifs.html W: http://www.linux-mtd.infradead.org/doc/ubifs.html

View File

@ -78,7 +78,7 @@ static int nothing_to_commit(struct ubifs_info *c)
* If the root TNC node is dirty, we definitely have something to * If the root TNC node is dirty, we definitely have something to
* commit. * commit.
*/ */
if (c->zroot.znode && test_bit(DIRTY_ZNODE, &c->zroot.znode->flags)) if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
return 0; return 0;
/* /*
@ -418,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c)
spin_lock(&c->cs_lock); spin_lock(&c->cs_lock);
if (c->cmt_state == COMMIT_BROKEN) { if (c->cmt_state == COMMIT_BROKEN) {
err = -EINVAL; err = -EROFS;
goto out; goto out;
} }
@ -444,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c)
* re-check it. * re-check it.
*/ */
if (c->cmt_state == COMMIT_BROKEN) { if (c->cmt_state == COMMIT_BROKEN) {
err = -EINVAL; err = -EROFS;
goto out_cmt_unlock; goto out_cmt_unlock;
} }
@ -576,7 +576,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
struct idx_node *i; struct idx_node *i;
size_t sz; size_t sz;
if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX)) if (!dbg_is_chk_index(c))
return 0; return 0;
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);

File diff suppressed because it is too large Load Diff

View File

@ -31,18 +31,25 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
#include <linux/random.h> /*
* The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi"
* + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
*/
#define UBIFS_DFS_DIR_NAME "ubi%d_%d"
#define UBIFS_DFS_DIR_LEN (3 + 1 + 2*2 + 1)
/** /**
* ubifs_debug_info - per-FS debugging information. * ubifs_debug_info - per-FS debugging information.
* @old_zroot: old index root - used by 'dbg_check_old_index()' * @old_zroot: old index root - used by 'dbg_check_old_index()'
* @old_zroot_level: old index root level - used by 'dbg_check_old_index()' * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
* @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()' * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
* @failure_mode: failure mode for recovery testing *
* @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls * @pc_happened: non-zero if an emulated power cut happened
* @fail_timeout: time in jiffies when delay of failure mode expires * @pc_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
* @fail_cnt: current number of calls to failure mode I/O functions * @pc_timeout: time in jiffies when delay of failure mode expires
* @fail_cnt_max: number of calls by which to delay failure mode * @pc_cnt: current number of calls to failure mode I/O functions
* @pc_cnt_max: number of calls by which to delay failure mode
*
* @chk_lpt_sz: used by LPT tree size checker * @chk_lpt_sz: used by LPT tree size checker
* @chk_lpt_sz2: used by LPT tree size checker * @chk_lpt_sz2: used by LPT tree size checker
* @chk_lpt_wastage: used by LPT tree size checker * @chk_lpt_wastage: used by LPT tree size checker
@ -56,21 +63,36 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
* @saved_free: saved amount of free space * @saved_free: saved amount of free space
* @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt
* *
* @chk_gen: if general extra checks are enabled
* @chk_index: if index xtra checks are enabled
* @chk_orph: if orphans extra checks are enabled
* @chk_lprops: if lprops extra checks are enabled
* @chk_fs: if UBIFS contents extra checks are enabled
* @tst_rcvry: if UBIFS recovery testing mode enabled
*
* @dfs_dir_name: name of debugfs directory containing this file-system's files * @dfs_dir_name: name of debugfs directory containing this file-system's files
* @dfs_dir: direntry object of the file-system debugfs directory * @dfs_dir: direntry object of the file-system debugfs directory
* @dfs_dump_lprops: "dump lprops" debugfs knob * @dfs_dump_lprops: "dump lprops" debugfs knob
* @dfs_dump_budg: "dump budgeting information" debugfs knob * @dfs_dump_budg: "dump budgeting information" debugfs knob
* @dfs_dump_tnc: "dump TNC" debugfs knob * @dfs_dump_tnc: "dump TNC" debugfs knob
* @dfs_chk_gen: debugfs knob to enable UBIFS general extra checks
* @dfs_chk_index: debugfs knob to enable UBIFS index extra checks
* @dfs_chk_orph: debugfs knob to enable UBIFS orphans extra checks
* @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks
* @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks
* @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing
*/ */
struct ubifs_debug_info { struct ubifs_debug_info {
struct ubifs_zbranch old_zroot; struct ubifs_zbranch old_zroot;
int old_zroot_level; int old_zroot_level;
unsigned long long old_zroot_sqnum; unsigned long long old_zroot_sqnum;
int failure_mode;
int fail_delay; int pc_happened;
unsigned long fail_timeout; int pc_delay;
unsigned int fail_cnt; unsigned long pc_timeout;
unsigned int fail_cnt_max; unsigned int pc_cnt;
unsigned int pc_cnt_max;
long long chk_lpt_sz; long long chk_lpt_sz;
long long chk_lpt_sz2; long long chk_lpt_sz2;
long long chk_lpt_wastage; long long chk_lpt_wastage;
@ -84,11 +106,43 @@ struct ubifs_debug_info {
long long saved_free; long long saved_free;
int saved_idx_gc_cnt; int saved_idx_gc_cnt;
char dfs_dir_name[100]; unsigned int chk_gen:1;
unsigned int chk_index:1;
unsigned int chk_orph:1;
unsigned int chk_lprops:1;
unsigned int chk_fs:1;
unsigned int tst_rcvry:1;
char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1];
struct dentry *dfs_dir; struct dentry *dfs_dir;
struct dentry *dfs_dump_lprops; struct dentry *dfs_dump_lprops;
struct dentry *dfs_dump_budg; struct dentry *dfs_dump_budg;
struct dentry *dfs_dump_tnc; struct dentry *dfs_dump_tnc;
struct dentry *dfs_chk_gen;
struct dentry *dfs_chk_index;
struct dentry *dfs_chk_orph;
struct dentry *dfs_chk_lprops;
struct dentry *dfs_chk_fs;
struct dentry *dfs_tst_rcvry;
};
/**
* ubifs_global_debug_info - global (not per-FS) UBIFS debugging information.
*
* @chk_gen: if general extra checks are enabled
* @chk_index: if index xtra checks are enabled
* @chk_orph: if orphans extra checks are enabled
* @chk_lprops: if lprops extra checks are enabled
* @chk_fs: if UBIFS contents extra checks are enabled
* @tst_rcvry: if UBIFS recovery testing mode enabled
*/
struct ubifs_global_debug_info {
unsigned int chk_gen:1;
unsigned int chk_index:1;
unsigned int chk_orph:1;
unsigned int chk_lprops:1;
unsigned int chk_fs:1;
unsigned int tst_rcvry:1;
}; };
#define ubifs_assert(expr) do { \ #define ubifs_assert(expr) do { \
@ -127,6 +181,8 @@ const char *dbg_key_str1(const struct ubifs_info *c,
#define DBGKEY(key) dbg_key_str0(c, (key)) #define DBGKEY(key) dbg_key_str0(c, (key))
#define DBGKEY1(key) dbg_key_str1(c, (key)) #define DBGKEY1(key) dbg_key_str1(c, (key))
extern spinlock_t dbg_lock;
#define ubifs_dbg_msg(type, fmt, ...) do { \ #define ubifs_dbg_msg(type, fmt, ...) do { \
spin_lock(&dbg_lock); \ spin_lock(&dbg_lock); \
pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \ pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
@ -162,41 +218,36 @@ const char *dbg_key_str1(const struct ubifs_info *c,
/* Additional recovery messages */ /* Additional recovery messages */
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__) #define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
/* extern struct ubifs_global_debug_info ubifs_dbg;
* Debugging check flags.
*
* UBIFS_CHK_GEN: general checks
* UBIFS_CHK_TNC: check TNC
* UBIFS_CHK_IDX_SZ: check index size
* UBIFS_CHK_ORPH: check orphans
* UBIFS_CHK_OLD_IDX: check the old index
* UBIFS_CHK_LPROPS: check lprops
* UBIFS_CHK_FS: check the file-system
*/
enum {
UBIFS_CHK_GEN = 0x1,
UBIFS_CHK_TNC = 0x2,
UBIFS_CHK_IDX_SZ = 0x4,
UBIFS_CHK_ORPH = 0x8,
UBIFS_CHK_OLD_IDX = 0x10,
UBIFS_CHK_LPROPS = 0x20,
UBIFS_CHK_FS = 0x40,
};
/* static inline int dbg_is_chk_gen(const struct ubifs_info *c)
* Special testing flags. {
* return !!(ubifs_dbg.chk_gen || c->dbg->chk_gen);
* UBIFS_TST_RCVRY: failure mode for recovery testing }
*/ static inline int dbg_is_chk_index(const struct ubifs_info *c)
enum { {
UBIFS_TST_RCVRY = 0x4, return !!(ubifs_dbg.chk_index || c->dbg->chk_index);
}; }
static inline int dbg_is_chk_orph(const struct ubifs_info *c)
extern spinlock_t dbg_lock; {
return !!(ubifs_dbg.chk_orph || c->dbg->chk_orph);
extern unsigned int ubifs_msg_flags; }
extern unsigned int ubifs_chk_flags; static inline int dbg_is_chk_lprops(const struct ubifs_info *c)
extern unsigned int ubifs_tst_flags; {
return !!(ubifs_dbg.chk_lprops || c->dbg->chk_lprops);
}
static inline int dbg_is_chk_fs(const struct ubifs_info *c)
{
return !!(ubifs_dbg.chk_fs || c->dbg->chk_fs);
}
static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)
{
return !!(ubifs_dbg.tst_rcvry || c->dbg->tst_rcvry);
}
static inline int dbg_is_power_cut(const struct ubifs_info *c)
{
return !!c->dbg->pc_happened;
}
int ubifs_debugging_init(struct ubifs_info *c); int ubifs_debugging_init(struct ubifs_info *c);
void ubifs_debugging_exit(struct ubifs_info *c); void ubifs_debugging_exit(struct ubifs_info *c);
@ -207,7 +258,7 @@ const char *dbg_cstate(int cmt_state);
const char *dbg_jhead(int jhead); const char *dbg_jhead(int jhead);
const char *dbg_get_key_dump(const struct ubifs_info *c, const char *dbg_get_key_dump(const struct ubifs_info *c,
const union ubifs_key *key); const union ubifs_key *key);
void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode); void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
void dbg_dump_node(const struct ubifs_info *c, const void *node); void dbg_dump_node(const struct ubifs_info *c, const void *node);
void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum, void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
int offs); int offs);
@ -240,8 +291,8 @@ int dbg_check_cats(struct ubifs_info *c);
int dbg_check_ltab(struct ubifs_info *c); int dbg_check_ltab(struct ubifs_info *c);
int dbg_chk_lpt_free_spc(struct ubifs_info *c); int dbg_chk_lpt_free_spc(struct ubifs_info *c);
int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len); int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len);
int dbg_check_synced_i_size(struct inode *inode); int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode);
int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir); int dbg_check_dir(struct ubifs_info *c, const struct inode *dir);
int dbg_check_tnc(struct ubifs_info *c, int extra); int dbg_check_tnc(struct ubifs_info *c, int extra);
int dbg_check_idx_size(struct ubifs_info *c, long long idx_size); int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
int dbg_check_filesystem(struct ubifs_info *c); int dbg_check_filesystem(struct ubifs_info *c);
@ -254,54 +305,12 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head); int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head); int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
/* Force the use of in-the-gaps method for testing */ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
static inline int dbg_force_in_the_gaps_enabled(void) int len, int dtype);
{ int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
return ubifs_chk_flags & UBIFS_CHK_GEN; int dtype);
} int dbg_leb_unmap(struct ubifs_info *c, int lnum);
int dbg_force_in_the_gaps(void); int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
/* Failure mode for recovery testing */
#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
#ifndef UBIFS_DBG_PRESERVE_UBI
#define ubi_leb_read dbg_leb_read
#define ubi_leb_write dbg_leb_write
#define ubi_leb_change dbg_leb_change
#define ubi_leb_erase dbg_leb_erase
#define ubi_leb_unmap dbg_leb_unmap
#define ubi_is_mapped dbg_is_mapped
#define ubi_leb_map dbg_leb_map
#endif
int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
int len, int check);
int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
int offset, int len, int dtype);
int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
int len, int dtype);
int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum);
int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum);
int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum);
int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf,
int offset, int len)
{
return dbg_leb_read(desc, lnum, buf, offset, len, 0);
}
static inline int dbg_write(struct ubi_volume_desc *desc, int lnum,
const void *buf, int offset, int len)
{
return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
}
static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
const void *buf, int len)
{
return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
}
/* Debugfs-related stuff */ /* Debugfs-related stuff */
int dbg_debugfs_init(void); int dbg_debugfs_init(void);
@ -313,7 +322,7 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
/* Use "if (0)" to make compiler check arguments even if debugging is off */ /* Use "if (0)" to make compiler check arguments even if debugging is off */
#define ubifs_assert(expr) do { \ #define ubifs_assert(expr) do { \
if (0 && (expr)) \ if (0) \
printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
__func__, __LINE__, current->pid); \ __func__, __LINE__, current->pid); \
} while (0) } while (0)
@ -323,6 +332,9 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
ubifs_err(fmt, ##__VA_ARGS__); \ ubifs_err(fmt, ##__VA_ARGS__); \
} while (0) } while (0)
#define DBGKEY(key) ((char *)(key))
#define DBGKEY1(key) ((char *)(key))
#define ubifs_dbg_msg(fmt, ...) do { \ #define ubifs_dbg_msg(fmt, ...) do { \
if (0) \ if (0) \
pr_debug(fmt "\n", ##__VA_ARGS__); \ pr_debug(fmt "\n", ##__VA_ARGS__); \
@ -346,9 +358,6 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
#define dbg_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) #define dbg_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__) #define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
#define DBGKEY(key) ((char *)(key))
#define DBGKEY1(key) ((char *)(key))
static inline int ubifs_debugging_init(struct ubifs_info *c) { return 0; } static inline int ubifs_debugging_init(struct ubifs_info *c) { return 0; }
static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; } static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; }
static inline const char *dbg_ntype(int type) { return ""; } static inline const char *dbg_ntype(int type) { return ""; }
@ -357,7 +366,7 @@ static inline const char *dbg_jhead(int jhead) { return ""; }
static inline const char * static inline const char *
dbg_get_key_dump(const struct ubifs_info *c, dbg_get_key_dump(const struct ubifs_info *c,
const union ubifs_key *key) { return ""; } const union ubifs_key *key) { return ""; }
static inline void dbg_dump_inode(const struct ubifs_info *c, static inline void dbg_dump_inode(struct ubifs_info *c,
const struct inode *inode) { return; } const struct inode *inode) { return; }
static inline void dbg_dump_node(const struct ubifs_info *c, static inline void dbg_dump_node(const struct ubifs_info *c,
const void *node) { return; } const void *node) { return; }
@ -409,9 +418,11 @@ static inline int dbg_check_ltab(struct ubifs_info *c) { return 0; }
static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c) { return 0; } static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c) { return 0; }
static inline int dbg_chk_lpt_sz(struct ubifs_info *c, static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
int action, int len) { return 0; } int action, int len) { return 0; }
static inline int dbg_check_synced_i_size(struct inode *inode) { return 0; } static inline int
static inline int dbg_check_dir_size(struct ubifs_info *c, dbg_check_synced_i_size(const struct ubifs_info *c,
const struct inode *dir) { return 0; } struct inode *inode) { return 0; }
static inline int dbg_check_dir(struct ubifs_info *c,
const struct inode *dir) { return 0; }
static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; } static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; }
static inline int dbg_check_idx_size(struct ubifs_info *c, static inline int dbg_check_idx_size(struct ubifs_info *c,
long long idx_size) { return 0; } long long idx_size) { return 0; }
@ -431,9 +442,23 @@ static inline int
dbg_check_nondata_nodes_order(struct ubifs_info *c, dbg_check_nondata_nodes_order(struct ubifs_info *c,
struct list_head *head) { return 0; } struct list_head *head) { return 0; }
static inline int dbg_force_in_the_gaps(void) { return 0; } static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
#define dbg_force_in_the_gaps_enabled() 0 const void *buf, int offset,
#define dbg_failure_mode 0 int len, int dtype) { return 0; }
static inline int dbg_leb_change(struct ubifs_info *c, int lnum,
const void *buf, int len,
int dtype) { return 0; }
static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum) { return 0; }
static inline int dbg_leb_map(struct ubifs_info *c, int lnum,
int dtype) { return 0; }
static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_chk_index(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_chk_orph(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_chk_lprops(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_chk_fs(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) { return 0; }
static inline int dbg_is_power_cut(const struct ubifs_info *c) { return 0; }
static inline int dbg_debugfs_init(void) { return 0; } static inline int dbg_debugfs_init(void) { return 0; }
static inline void dbg_debugfs_exit(void) { return; } static inline void dbg_debugfs_exit(void) { return; }

View File

@ -102,7 +102,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
* UBIFS has to fully control "clean <-> dirty" transitions of inodes * UBIFS has to fully control "clean <-> dirty" transitions of inodes
* to make budgeting work. * to make budgeting work.
*/ */
inode->i_flags |= (S_NOCMTIME); inode->i_flags |= S_NOCMTIME;
inode_init_owner(inode, dir, mode); inode_init_owner(inode, dir, mode);
inode->i_mtime = inode->i_atime = inode->i_ctime = inode->i_mtime = inode->i_atime = inode->i_ctime =
@ -172,9 +172,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm) static int dbg_check_name(const struct ubifs_info *c,
const struct ubifs_dent_node *dent,
const struct qstr *nm)
{ {
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
if (le16_to_cpu(dent->nlen) != nm->len) if (le16_to_cpu(dent->nlen) != nm->len)
return -EINVAL; return -EINVAL;
@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
#else #else
#define dbg_check_name(dent, nm) 0 #define dbg_check_name(c, dent, nm) 0
#endif #endif
@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
goto out; goto out;
} }
if (dbg_check_name(dent, &dentry->d_name)) { if (dbg_check_name(c, dent, &dentry->d_name)) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
@ -522,7 +524,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex));
err = dbg_check_synced_i_size(inode); err = dbg_check_synced_i_size(c, inode);
if (err) if (err)
return err; return err;
@ -577,7 +579,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
inode->i_nlink, dir->i_ino); inode->i_nlink, dir->i_ino);
ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex));
err = dbg_check_synced_i_size(inode); err = dbg_check_synced_i_size(c, inode);
if (err) if (err)
return err; return err;

View File

@ -1263,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
if (err) if (err)
return err; return err;
err = dbg_check_synced_i_size(inode); err = dbg_check_synced_i_size(c, inode);
if (err) if (err)
return err; return err;

View File

@ -86,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
c->no_chk_data_crc = 0; c->no_chk_data_crc = 0;
c->vfs_sb->s_flags |= MS_RDONLY; c->vfs_sb->s_flags |= MS_RDONLY;
ubifs_warn("switched to read-only mode, error %d", err); ubifs_warn("switched to read-only mode, error %d", err);
dump_stack();
}
}
/*
* Below are simple wrappers over UBI I/O functions which include some
* additional checks and UBIFS debugging stuff. See corresponding UBI function
* for more information.
*/
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
int len, int even_ebadmsg)
{
int err;
err = ubi_read(c->ubi, lnum, buf, offs, len);
/*
* In case of %-EBADMSG print the error message only if the
* @even_ebadmsg is true.
*/
if (err && (err != -EBADMSG || even_ebadmsg)) {
ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
len, lnum, offs, err);
dbg_dump_stack(); dbg_dump_stack();
} }
return err;
}
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
else
err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
if (err) {
ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
len, lnum, offs, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
else
err = dbg_leb_change(c, lnum, buf, len, dtype);
if (err) {
ubifs_err("changing %d bytes in LEB %d failed, error %d",
len, lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_unmap(c->ubi, lnum);
else
err = dbg_leb_unmap(c, lnum);
if (err) {
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
err = ubi_leb_map(c->ubi, lnum, dtype);
else
err = dbg_leb_map(c, lnum, dtype);
if (err) {
ubifs_err("mapping LEB %d failed, error %d", lnum, err);
ubifs_ro_mode(c, err);
dbg_dump_stack();
}
return err;
}
int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
{
int err;
err = ubi_is_mapped(c->ubi, lnum);
if (err < 0) {
ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
lnum, err);
dbg_dump_stack();
}
return err;
} }
/** /**
@ -406,14 +523,10 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
dirt = sync_len - wbuf->used; dirt = sync_len - wbuf->used;
if (dirt) if (dirt)
ubifs_pad(c, wbuf->buf + wbuf->used, dirt); ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
sync_len, wbuf->dtype); wbuf->dtype);
if (err) { if (err)
ubifs_err("cannot write %d bytes to LEB %d:%d",
sync_len, wbuf->lnum, wbuf->offs);
dbg_dump_stack();
return err; return err;
}
spin_lock(&wbuf->lock); spin_lock(&wbuf->lock);
wbuf->offs += sync_len; wbuf->offs += sync_len;
@ -605,9 +718,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
if (aligned_len == wbuf->avail) { if (aligned_len == wbuf->avail) {
dbg_io("flush jhead %s wbuf to LEB %d:%d", dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs); dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
wbuf->offs, wbuf->size, wbuf->offs, wbuf->size,
wbuf->dtype); wbuf->dtype);
if (err) if (err)
goto out; goto out;
@ -642,8 +755,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
dbg_io("flush jhead %s wbuf to LEB %d:%d", dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs); dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail); memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
wbuf->size, wbuf->dtype); wbuf->size, wbuf->dtype);
if (err) if (err)
goto out; goto out;
@ -661,8 +774,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
*/ */
dbg_io("write %d bytes to LEB %d:%d", dbg_io("write %d bytes to LEB %d:%d",
wbuf->size, wbuf->lnum, wbuf->offs); wbuf->size, wbuf->lnum, wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf, wbuf->offs, err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
wbuf->size, wbuf->dtype); wbuf->size, wbuf->dtype);
if (err) if (err)
goto out; goto out;
@ -683,8 +796,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
n <<= c->max_write_shift; n <<= c->max_write_shift;
dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
wbuf->offs); wbuf->offs);
err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, err = ubifs_leb_write(c, wbuf->lnum, buf + written,
wbuf->offs, n, wbuf->dtype); wbuf->offs, n, wbuf->dtype);
if (err) if (err)
goto out; goto out;
wbuf->offs += n; wbuf->offs += n;
@ -766,13 +879,9 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
return -EROFS; return -EROFS;
ubifs_prepare_node(c, buf, len, 1); ubifs_prepare_node(c, buf, len, 1);
err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype); err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
if (err) { if (err)
ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
buf_len, lnum, offs, err);
dbg_dump_node(c, buf); dbg_dump_node(c, buf);
dbg_dump_stack();
}
return err; return err;
} }
@ -824,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
if (rlen > 0) { if (rlen > 0) {
/* Read everything that goes before write-buffer */ /* Read everything that goes before write-buffer */
err = ubi_read(c->ubi, lnum, buf, offs, rlen); err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
if (err && err != -EBADMSG) { if (err && err != -EBADMSG)
ubifs_err("failed to read node %d from LEB %d:%d, "
"error %d", type, lnum, offs, err);
dbg_dump_stack();
return err; return err;
}
} }
if (type != ch->node_type) { if (type != ch->node_type) {
@ -885,12 +990,9 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
ubifs_assert(!(offs & 7) && offs < c->leb_size); ubifs_assert(!(offs & 7) && offs < c->leb_size);
ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
err = ubi_read(c->ubi, lnum, buf, offs, len); err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
if (err && err != -EBADMSG) { if (err && err != -EBADMSG)
ubifs_err("cannot read node %d from LEB %d:%d, error %d",
type, lnum, offs, err);
return err; return err;
}
if (type != ch->node_type) { if (type != ch->node_type) {
ubifs_err("bad node type (%d but expected %d)", ubifs_err("bad node type (%d but expected %d)",

View File

@ -262,7 +262,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
* an unclean reboot, because the target LEB might have been * an unclean reboot, because the target LEB might have been
* unmapped, but not yet physically erased. * unmapped, but not yet physically erased.
*/ */
err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM); err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
if (err) if (err)
goto out_unlock; goto out_unlock;
} }
@ -283,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
return 0; return 0;
out_unlock: out_unlock:
if (err != -EAGAIN)
ubifs_ro_mode(c, err);
mutex_unlock(&c->log_mutex); mutex_unlock(&c->log_mutex);
kfree(ref); kfree(ref);
kfree(bud); kfree(bud);
@ -752,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
struct ubifs_bud *bud; struct ubifs_bud *bud;
long long bud_bytes = 0; long long bud_bytes = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
spin_lock(&c->buds_lock); spin_lock(&c->buds_lock);

View File

@ -504,7 +504,7 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
pnode = (struct ubifs_pnode *)container_of(lprops - pos, pnode = (struct ubifs_pnode *)container_of(lprops - pos,
struct ubifs_pnode, struct ubifs_pnode,
lprops[0]); lprops[0]);
return !test_bit(COW_ZNODE, &pnode->flags) && return !test_bit(COW_CNODE, &pnode->flags) &&
test_bit(DIRTY_CNODE, &pnode->flags); test_bit(DIRTY_CNODE, &pnode->flags);
} }
@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c)
struct list_head *pos; struct list_head *pos;
int i, cat; int i, cat;
if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS))) if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
return 0; return 0;
list_for_each_entry(lprops, &c->empty_list, list) { list_for_each_entry(lprops, &c->empty_list, list) {
@ -958,7 +958,7 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
{ {
int i = 0, j, err = 0; int i = 0, j, err = 0;
if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS))) if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
return; return;
for (i = 0; i < heap->cnt; i++) { for (i = 0; i < heap->cnt; i++) {
@ -1262,7 +1262,7 @@ int dbg_check_lprops(struct ubifs_info *c)
int i, err; int i, err;
struct ubifs_lp_stats lst; struct ubifs_lp_stats lst;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
/* /*

View File

@ -701,8 +701,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size); alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len); set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len); memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM); UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
p = buf; p = buf;
@ -732,8 +732,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
set_ltab(c, lnum, c->leb_size - alen, set_ltab(c, lnum, c->leb_size - alen,
alen - len); alen - len);
memset(p, 0xff, alen - len); memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM); UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
p = buf; p = buf;
@ -780,8 +780,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size); alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len); set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len); memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, err = ubifs_leb_change(c, lnum++, buf, alen,
UBI_SHORTTERM); UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
p = buf; p = buf;
@ -806,7 +806,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size); alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len); set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len); memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM); err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
p = buf; p = buf;
@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
/* Write remaining buffer */ /* Write remaining buffer */
memset(p, 0xff, alen - len); memset(p, 0xff, alen - len);
err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM); err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
if (c->big_lpt) if (c->big_lpt)
nnode->num = calc_nnode_num_from_parent(c, parent, iip); nnode->num = calc_nnode_num_from_parent(c, parent, iip);
} else { } else {
err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz); err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
if (err) if (err)
goto out; goto out;
err = ubifs_unpack_nnode(c, buf, nnode); err = ubifs_unpack_nnode(c, buf, nnode);
@ -1247,6 +1247,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out: out:
ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs); ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
dbg_dump_stack();
kfree(nnode); kfree(nnode);
return err; return err;
} }
@ -1290,7 +1291,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
lprops->flags = ubifs_categorize_lprops(c, lprops); lprops->flags = ubifs_categorize_lprops(c, lprops);
} }
} else { } else {
err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz); err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
if (err) if (err)
goto out; goto out;
err = unpack_pnode(c, buf, pnode); err = unpack_pnode(c, buf, pnode);
@ -1312,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out: out:
ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs); ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
dbg_dump_pnode(c, pnode, parent, iip); dbg_dump_pnode(c, pnode, parent, iip);
dbg_dump_stack();
dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip)); dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
kfree(pnode); kfree(pnode);
return err; return err;
@ -1331,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c)
buf = vmalloc(c->ltab_sz); buf = vmalloc(c->ltab_sz);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz); err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
if (err) if (err)
goto out; goto out;
err = unpack_ltab(c, buf); err = unpack_ltab(c, buf);
@ -1354,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c)
buf = vmalloc(c->lsave_sz); buf = vmalloc(c->lsave_sz);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz); err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
c->lsave_sz, 1);
if (err) if (err)
goto out; goto out;
err = unpack_lsave(c, buf); err = unpack_lsave(c, buf);
@ -1814,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
if (c->big_lpt) if (c->big_lpt)
nnode->num = calc_nnode_num_from_parent(c, parent, iip); nnode->num = calc_nnode_num_from_parent(c, parent, iip);
} else { } else {
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs, err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
c->nnode_sz); c->nnode_sz, 1);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
err = ubifs_unpack_nnode(c, buf, nnode); err = ubifs_unpack_nnode(c, buf, nnode);
@ -1883,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
ubifs_assert(branch->lnum >= c->lpt_first && ubifs_assert(branch->lnum >= c->lpt_first &&
branch->lnum <= c->lpt_last); branch->lnum <= c->lpt_last);
ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size); ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs, err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
c->pnode_sz); c->pnode_sz, 1);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
err = unpack_pnode(c, buf, pnode); err = unpack_pnode(c, buf, pnode);
@ -2224,7 +2227,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
struct ubifs_cnode *cn; struct ubifs_cnode *cn;
int num, iip = 0, err; int num, iip = 0, err;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
while (cnode) { while (cnode) {

View File

@ -27,6 +27,7 @@
#include <linux/crc16.h> #include <linux/crc16.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/random.h>
#include "ubifs.h" #include "ubifs.h"
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
@ -116,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)
return 0; return 0;
cnt += 1; cnt += 1;
while (1) { while (1) {
ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags)); ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
__set_bit(COW_ZNODE, &cnode->flags); __set_bit(COW_CNODE, &cnode->flags);
cnext = next_dirty_cnode(cnode); cnext = next_dirty_cnode(cnode);
if (!cnext) { if (!cnext) {
cnode->cnext = c->lpt_cnext; cnode->cnext = c->lpt_cnext;
@ -465,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c)
*/ */
clear_bit(DIRTY_CNODE, &cnode->flags); clear_bit(DIRTY_CNODE, &cnode->flags);
smp_mb__before_clear_bit(); smp_mb__before_clear_bit();
clear_bit(COW_ZNODE, &cnode->flags); clear_bit(COW_CNODE, &cnode->flags);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
offs += len; offs += len;
dbg_chk_lpt_sz(c, 1, len); dbg_chk_lpt_sz(c, 1, len);
@ -1160,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
void *buf = c->lpt_buf; void *buf = c->lpt_buf;
dbg_lp("LEB %d", lnum); dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) { err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
ubifs_err("cannot read LEB %d, error %d", lnum, err); if (err)
return err; return err;
}
while (1) { while (1) {
if (!is_a_node(c, buf, len)) { if (!is_a_node(c, buf, len)) {
int pad_len; int pad_len;
@ -1640,7 +1641,7 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
int ret; int ret;
void *buf, *p; void *buf, *p;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL); buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
@ -1650,11 +1651,11 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
} }
dbg_lp("LEB %d", lnum); dbg_lp("LEB %d", lnum);
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
if (err) { err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err); if (err)
goto out; goto out;
}
while (1) { while (1) {
if (!is_a_node(c, p, len)) { if (!is_a_node(c, p, len)) {
int i, pad_len; int i, pad_len;
@ -1711,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c)
{ {
int lnum, err, i, cnt; int lnum, err, i, cnt;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
/* Bring the entire tree into memory */ /* Bring the entire tree into memory */
@ -1754,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
long long free = 0; long long free = 0;
int i; int i;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
for (i = 0; i < c->lpt_lebs; i++) { for (i = 0; i < c->lpt_lebs; i++) {
@ -1796,7 +1797,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
long long chk_lpt_sz, lpt_sz; long long chk_lpt_sz, lpt_sz;
int err = 0; int err = 0;
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS)) if (!dbg_is_chk_lprops(c))
return 0; return 0;
switch (action) { switch (action) {
@ -1901,11 +1902,10 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
return; return;
} }
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size); err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
if (err) { if (err)
ubifs_err("cannot read LEB %d, error %d", lnum, err);
goto out; goto out;
}
while (1) { while (1) {
offs = c->leb_size - len; offs = c->leb_size - len;
if (!is_a_node(c, p, len)) { if (!is_a_node(c, p, len)) {
@ -2019,7 +2019,7 @@ static int dbg_populate_lsave(struct ubifs_info *c)
struct ubifs_lpt_heap *heap; struct ubifs_lpt_heap *heap;
int i; int i;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
if (random32() & 3) if (random32() & 3)
return 0; return 0;

View File

@ -38,6 +38,29 @@ static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
return !!test_bit(DIRTY_ZNODE, &znode->flags); return !!test_bit(DIRTY_ZNODE, &znode->flags);
} }
/**
* ubifs_zn_obsolete - check if znode is obsolete.
* @znode: znode to check
*
* This helper function returns %1 if @znode is obsolete and %0 otherwise.
*/
static inline int ubifs_zn_obsolete(const struct ubifs_znode *znode)
{
return !!test_bit(OBSOLETE_ZNODE, &znode->flags);
}
/**
* ubifs_zn_cow - check if znode has to be copied on write.
* @znode: znode to check
*
* This helper function returns %1 if @znode is has COW flag set and %0
* otherwise.
*/
static inline int ubifs_zn_cow(const struct ubifs_znode *znode)
{
return !!test_bit(COW_ZNODE, &znode->flags);
}
/** /**
* ubifs_wake_up_bgt - wake up background thread. * ubifs_wake_up_bgt - wake up background thread.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
@ -121,86 +144,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
return err; return err;
} }
/**
* ubifs_leb_unmap - unmap an LEB.
* @c: UBIFS file-system description object
* @lnum: LEB number to unmap
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_unmap(c->ubi, lnum);
if (err) {
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
return err;
}
return 0;
}
/**
* ubifs_leb_write - write to a LEB.
* @c: UBIFS file-system description object
* @lnum: LEB number to write
* @buf: buffer to write from
* @offs: offset within LEB to write to
* @len: length to write
* @dtype: data type
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
const void *buf, int offs, int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
if (err) {
ubifs_err("writing %d bytes at %d:%d, error %d",
len, lnum, offs, err);
return err;
}
return 0;
}
/**
* ubifs_leb_change - atomic LEB change.
* @c: UBIFS file-system description object
* @lnum: LEB number to write
* @buf: buffer to write from
* @len: length to write
* @dtype: data type
*
* This function returns %0 on success and a negative error code on failure.
*/
static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
const void *buf, int len, int dtype)
{
int err;
ubifs_assert(!c->ro_media && !c->ro_mount);
if (c->ro_error)
return -EROFS;
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
if (err) {
ubifs_err("changing %d bytes in LEB %d, error %d",
len, lnum, err);
return err;
}
return 0;
}
/** /**
* ubifs_encode_dev - encode device node IDs. * ubifs_encode_dev - encode device node IDs.
* @dev: UBIFS device node information * @dev: UBIFS device node information

View File

@ -929,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c)
struct check_info ci; struct check_info ci;
int err; int err;
if (!(ubifs_chk_flags & UBIFS_CHK_ORPH)) if (!dbg_is_chk_orph(c))
return 0; return 0;
ci.last_ino = 0; ci.last_ino = 0;

View File

@ -117,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
if (!sbuf) if (!sbuf)
return -ENOMEM; return -ENOMEM;
err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size); err = ubifs_leb_read(c, lnum, sbuf, 0, c->leb_size, 0);
if (err && err != -EBADMSG) if (err && err != -EBADMSG)
goto out_free; goto out_free;
@ -213,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY); mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1); ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM); err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM); err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
if (err) if (err)
goto out; goto out;
out: out:
@ -274,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c)
if (cor1) if (cor1)
goto out_err; goto out_err;
mst = mst1; mst = mst1;
} else if (offs1 == 0 && offs2 + sz >= c->leb_size) { } else if (offs1 == 0 &&
c->leb_size - offs2 - sz < sz) {
/* 1st LEB was unmapped and written, 2nd not */ /* 1st LEB was unmapped and written, 2nd not */
if (cor1) if (cor1)
goto out_err; goto out_err;
@ -539,8 +540,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
int len = ALIGN(endpt, c->min_io_size); int len = ALIGN(endpt, c->min_io_size);
if (start) { if (start) {
err = ubi_read(c->ubi, lnum, sleb->buf, 0, err = ubifs_leb_read(c, lnum, sleb->buf, 0,
start); start, 1);
if (err) if (err)
return err; return err;
} }
@ -554,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ubifs_pad(c, buf, pad_len); ubifs_pad(c, buf, pad_len);
} }
} }
err = ubi_leb_change(c->ubi, lnum, sleb->buf, len, err = ubifs_leb_change(c, lnum, sleb->buf, len,
UBI_UNKNOWN); UBI_UNKNOWN);
if (err) if (err)
return err; return err;
} }
@ -819,7 +820,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
return -ENOMEM; return -ENOMEM;
if (c->leb_size - offs < UBIFS_CS_NODE_SZ) if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
goto out_err; goto out_err;
err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ); err = ubifs_leb_read(c, lnum, (void *)cs_node, offs,
UBIFS_CS_NODE_SZ, 0);
if (err && err != -EBADMSG) if (err && err != -EBADMSG)
goto out_free; goto out_free;
ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0); ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
@ -919,8 +921,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
static int recover_head(const struct ubifs_info *c, int lnum, int offs, static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
void *sbuf)
{ {
int len = c->max_write_size, err; int len = c->max_write_size, err;
@ -931,15 +932,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
return 0; return 0;
/* Read at the head location and check it is empty flash */ /* Read at the head location and check it is empty flash */
err = ubi_read(c->ubi, lnum, sbuf, offs, len); err = ubifs_leb_read(c, lnum, sbuf, offs, len, 1);
if (err || !is_empty(sbuf, len)) { if (err || !is_empty(sbuf, len)) {
dbg_rcvry("cleaning head at %d:%d", lnum, offs); dbg_rcvry("cleaning head at %d:%d", lnum, offs);
if (offs == 0) if (offs == 0)
return ubifs_leb_unmap(c, lnum); return ubifs_leb_unmap(c, lnum);
err = ubi_read(c->ubi, lnum, sbuf, 0, offs); err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
if (err) if (err)
return err; return err;
return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN); return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
} }
return 0; return 0;
@ -962,7 +963,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf) int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
{ {
int err; int err;
@ -993,7 +994,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
static int clean_an_unclean_leb(const struct ubifs_info *c, static int clean_an_unclean_leb(struct ubifs_info *c,
struct ubifs_unclean_leb *ucleb, void *sbuf) struct ubifs_unclean_leb *ucleb, void *sbuf)
{ {
int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1; int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
@ -1009,7 +1010,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
return 0; return 0;
} }
err = ubi_read(c->ubi, lnum, buf, offs, len); err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
if (err && err != -EBADMSG) if (err && err != -EBADMSG)
return err; return err;
@ -1069,7 +1070,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
} }
/* Write back the LEB atomically */ /* Write back the LEB atomically */
err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN); err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
if (err) if (err)
return err; return err;
@ -1089,7 +1090,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf) int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
{ {
dbg_rcvry("recovery"); dbg_rcvry("recovery");
while (!list_empty(&c->unclean_leb_list)) { while (!list_empty(&c->unclean_leb_list)) {
@ -1454,7 +1455,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
if (i_size >= e->d_size) if (i_size >= e->d_size)
return 0; return 0;
/* Read the LEB */ /* Read the LEB */
err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size); err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1);
if (err) if (err)
goto out; goto out;
/* Change the size field and recalculate the CRC */ /* Change the size field and recalculate the CRC */
@ -1470,7 +1471,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
len -= 1; len -= 1;
len = ALIGN(len + 1, c->min_io_size); len = ALIGN(len + 1, c->min_io_size);
/* Atomically write the fixed LEB back again */ /* Atomically write the fixed LEB back again */
err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN); err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
if (err) if (err)
goto out; goto out;
dbg_rcvry("inode %lu at %d:%d size %lld -> %lld", dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",

View File

@ -523,8 +523,7 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
if (!list_is_last(&next->list, &jh->buds_list)) if (!list_is_last(&next->list, &jh->buds_list))
return 0; return 0;
err = ubi_read(c->ubi, next->lnum, (char *)&data, err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
next->start, 4);
if (err) if (err)
return 0; return 0;

View File

@ -674,15 +674,15 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int len)
if (len == 0) { if (len == 0) {
dbg_mnt("unmap empty LEB %d", lnum); dbg_mnt("unmap empty LEB %d", lnum);
return ubi_leb_unmap(c->ubi, lnum); return ubifs_leb_unmap(c, lnum);
} }
dbg_mnt("fixup LEB %d, data len %d", lnum, len); dbg_mnt("fixup LEB %d, data len %d", lnum, len);
err = ubi_read(c->ubi, lnum, c->sbuf, 0, len); err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 1);
if (err) if (err)
return err; return err;
return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN); return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
} }
/** /**

View File

@ -148,7 +148,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
INIT_LIST_HEAD(&sleb->nodes); INIT_LIST_HEAD(&sleb->nodes);
sleb->buf = sbuf; sleb->buf = sbuf;
err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs); err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs, 0);
if (err && err != -EBADMSG) { if (err && err != -EBADMSG) {
ubifs_err("cannot read %d bytes from LEB %d:%d," ubifs_err("cannot read %d bytes from LEB %d:%d,"
" error %d", c->leb_size - offs, lnum, offs, err); " error %d", c->leb_size - offs, lnum, offs, err);
@ -240,7 +240,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
int len; int len;
ubifs_err("corruption at LEB %d:%d", lnum, offs); ubifs_err("corruption at LEB %d:%d", lnum, offs);
if (dbg_failure_mode) if (dbg_is_tst_rcvry(c))
return; return;
len = c->leb_size - offs; len = c->leb_size - offs;
if (len > 8192) if (len > 8192)

View File

@ -85,7 +85,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA) if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
return 4; return 4;
if (ui->xattr && (inode->i_mode & S_IFMT) != S_IFREG) if (ui->xattr && !S_ISREG(inode->i_mode))
return 5; return 5;
if (!ubifs_compr_present(ui->compr_type)) { if (!ubifs_compr_present(ui->compr_type)) {
@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
ubifs_compr_name(ui->compr_type)); ubifs_compr_name(ui->compr_type));
} }
err = dbg_check_dir_size(c, inode); err = dbg_check_dir(c, inode);
return err; return err;
} }
@ -914,7 +914,7 @@ static int check_volume_empty(struct ubifs_info *c)
c->empty = 1; c->empty = 1;
for (lnum = 0; lnum < c->leb_cnt; lnum++) { for (lnum = 0; lnum < c->leb_cnt; lnum++) {
err = ubi_is_mapped(c->ubi, lnum); err = ubifs_is_mapped(c, lnum);
if (unlikely(err < 0)) if (unlikely(err < 0))
return err; return err;
if (err == 1) { if (err == 1) {

View File

@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
__set_bit(DIRTY_ZNODE, &zn->flags); __set_bit(DIRTY_ZNODE, &zn->flags);
__clear_bit(COW_ZNODE, &zn->flags); __clear_bit(COW_ZNODE, &zn->flags);
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags)); ubifs_assert(!ubifs_zn_obsolete(znode));
__set_bit(OBSOLETE_ZNODE, &znode->flags); __set_bit(OBSOLETE_ZNODE, &znode->flags);
if (znode->level != 0) { if (znode->level != 0) {
@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
struct ubifs_znode *zn; struct ubifs_znode *zn;
int err; int err;
if (!test_bit(COW_ZNODE, &znode->flags)) { if (!ubifs_zn_cow(znode)) {
/* znode is not being committed */ /* znode is not being committed */
if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) { if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
atomic_long_inc(&c->dirty_zn_cnt); atomic_long_inc(&c->dirty_zn_cnt);
@ -462,7 +462,7 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
err = ubi_read(c->ubi, lnum, buf, offs, len); err = ubifs_leb_read(c, lnum, buf, offs, len, 1);
if (err) { if (err) {
ubifs_err("cannot read node type %d from LEB %d:%d, error %d", ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
type, lnum, offs, err); type, lnum, offs, err);
@ -1666,7 +1666,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
if (!overlap) { if (!overlap) {
/* We may safely unlock the write-buffer and read the data */ /* We may safely unlock the write-buffer and read the data */
spin_unlock(&wbuf->lock); spin_unlock(&wbuf->lock);
return ubi_read(c->ubi, lnum, buf, offs, len); return ubifs_leb_read(c, lnum, buf, offs, len, 0);
} }
/* Don't read under wbuf */ /* Don't read under wbuf */
@ -1680,7 +1680,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
if (rlen > 0) if (rlen > 0)
/* Read everything that goes before write-buffer */ /* Read everything that goes before write-buffer */
return ubi_read(c->ubi, lnum, buf, offs, rlen); return ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
return 0; return 0;
} }
@ -1767,7 +1767,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
if (wbuf) if (wbuf)
err = read_wbuf(wbuf, bu->buf, len, lnum, offs); err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
else else
err = ubi_read(c->ubi, lnum, bu->buf, offs, len); err = ubifs_leb_read(c, lnum, bu->buf, offs, len, 0);
/* Check for a race with GC */ /* Check for a race with GC */
if (maybe_leb_gced(c, lnum, bu->gc_seq)) if (maybe_leb_gced(c, lnum, bu->gc_seq))
@ -2423,7 +2423,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
*/ */
do { do {
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags)); ubifs_assert(!ubifs_zn_obsolete(znode));
ubifs_assert(ubifs_zn_dirty(znode)); ubifs_assert(ubifs_zn_dirty(znode));
zp = znode->parent; zp = znode->parent;
@ -2479,9 +2479,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
c->zroot.offs = zbr->offs; c->zroot.offs = zbr->offs;
c->zroot.len = zbr->len; c->zroot.len = zbr->len;
c->zroot.znode = znode; c->zroot.znode = znode;
ubifs_assert(!test_bit(OBSOLETE_ZNODE, ubifs_assert(!ubifs_zn_obsolete(zp));
&zp->flags)); ubifs_assert(ubifs_zn_dirty(zp));
ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
atomic_long_dec(&c->dirty_zn_cnt); atomic_long_dec(&c->dirty_zn_cnt);
if (zp->cnext) { if (zp->cnext) {
@ -2865,7 +2864,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
struct ubifs_znode *znode = cnext; struct ubifs_znode *znode = cnext;
cnext = cnext->cnext; cnext = cnext->cnext;
if (test_bit(OBSOLETE_ZNODE, &znode->flags)) if (ubifs_zn_obsolete(znode))
kfree(znode); kfree(znode);
} while (cnext && cnext != c->cnext); } while (cnext && cnext != c->cnext);
} }
@ -3301,7 +3300,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return 0; return 0;
if (!(ubifs_chk_flags & UBIFS_CHK_GEN)) if (!dbg_is_chk_gen(c))
return 0; return 0;
block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT; block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
@ -3337,9 +3336,10 @@ out_dump:
ubifs_err("inode %lu has size %lld, but there are data at offset %lld " ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
"(data key %s)", (unsigned long)inode->i_ino, size, "(data key %s)", (unsigned long)inode->i_ino, size,
((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key)); ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
mutex_unlock(&c->tnc_mutex);
dbg_dump_inode(c, inode); dbg_dump_inode(c, inode);
dbg_dump_stack(); dbg_dump_stack();
err = -EINVAL; return -EINVAL;
out_unlock: out_unlock:
mutex_unlock(&c->tnc_mutex); mutex_unlock(&c->tnc_mutex);

View File

@ -22,6 +22,7 @@
/* This file implements TNC functions for committing */ /* This file implements TNC functions for committing */
#include <linux/random.h>
#include "ubifs.h" #include "ubifs.h"
/** /**
@ -87,8 +88,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
atomic_long_dec(&c->dirty_zn_cnt); atomic_long_dec(&c->dirty_zn_cnt);
ubifs_assert(ubifs_zn_dirty(znode)); ubifs_assert(ubifs_zn_dirty(znode));
ubifs_assert(test_bit(COW_ZNODE, &znode->flags)); ubifs_assert(ubifs_zn_cow(znode));
/*
* Note, unlike 'write_index()' we do not add memory barriers here
* because this function is called with @c->tnc_mutex locked.
*/
__clear_bit(DIRTY_ZNODE, &znode->flags); __clear_bit(DIRTY_ZNODE, &znode->flags);
__clear_bit(COW_ZNODE, &znode->flags); __clear_bit(COW_ZNODE, &znode->flags);
@ -377,7 +382,7 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
c->gap_lebs = NULL; c->gap_lebs = NULL;
return err; return err;
} }
if (dbg_force_in_the_gaps_enabled()) { if (!dbg_is_chk_index(c)) {
/* /*
* Do not print scary warnings if the debugging * Do not print scary warnings if the debugging
* option which forces in-the-gaps is enabled. * option which forces in-the-gaps is enabled.
@ -491,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c)
else else
next_len = ubifs_idx_node_sz(c, cnext->child_cnt); next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
if (c->min_io_size == 1) {
buf_offs += ALIGN(len, 8);
if (next_len) {
if (buf_offs + next_len <= c->leb_size)
continue;
err = ubifs_update_one_lp(c, lnum, 0,
c->leb_size - buf_offs, 0, 0);
if (err)
return err;
lnum = -1;
continue;
}
err = ubifs_update_one_lp(c, lnum,
c->leb_size - buf_offs, 0, 0, 0);
if (err)
return err;
break;
}
/* Update buffer positions */ /* Update buffer positions */
wlen = used + len; wlen = used + len;
used += ALIGN(len, 8); used += ALIGN(len, 8);
@ -658,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c)
} }
cnt += 1; cnt += 1;
while (1) { while (1) {
ubifs_assert(!test_bit(COW_ZNODE, &znode->flags)); ubifs_assert(!ubifs_zn_cow(znode));
__set_bit(COW_ZNODE, &znode->flags); __set_bit(COW_ZNODE, &znode->flags);
znode->alt = 0; znode->alt = 0;
cnext = find_next_dirty(znode); cnext = find_next_dirty(znode);
@ -704,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
c->ilebs[c->ileb_cnt++] = lnum; c->ilebs[c->ileb_cnt++] = lnum;
dbg_cmt("LEB %d", lnum); dbg_cmt("LEB %d", lnum);
} }
if (dbg_force_in_the_gaps()) if (dbg_is_chk_index(c) && !(random32() & 7))
return -ENOSPC; return -ENOSPC;
return 0; return 0;
} }
@ -830,7 +816,7 @@ static int write_index(struct ubifs_info *c)
struct ubifs_idx_node *idx; struct ubifs_idx_node *idx;
struct ubifs_znode *znode, *cnext; struct ubifs_znode *znode, *cnext;
int i, lnum, offs, len, next_len, buf_len, buf_offs, used; int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
int avail, wlen, err, lnum_pos = 0; int avail, wlen, err, lnum_pos = 0, blen, nxt_offs;
cnext = c->enext; cnext = c->enext;
if (!cnext) if (!cnext)
@ -907,7 +893,7 @@ static int write_index(struct ubifs_info *c)
cnext = znode->cnext; cnext = znode->cnext;
ubifs_assert(ubifs_zn_dirty(znode)); ubifs_assert(ubifs_zn_dirty(znode));
ubifs_assert(test_bit(COW_ZNODE, &znode->flags)); ubifs_assert(ubifs_zn_cow(znode));
/* /*
* It is important that other threads should see %DIRTY_ZNODE * It is important that other threads should see %DIRTY_ZNODE
@ -922,6 +908,28 @@ static int write_index(struct ubifs_info *c)
clear_bit(COW_ZNODE, &znode->flags); clear_bit(COW_ZNODE, &znode->flags);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
/*
* We have marked the znode as clean but have not updated the
* @c->clean_zn_cnt counter. If this znode becomes dirty again
* before 'free_obsolete_znodes()' is called, then
* @c->clean_zn_cnt will be decremented before it gets
* incremented (resulting in 2 decrements for the same znode).
* This means that @c->clean_zn_cnt may become negative for a
* while.
*
* Q: why we cannot increment @c->clean_zn_cnt?
* A: because we do not have the @c->tnc_mutex locked, and the
* following code would be racy and buggy:
*
* if (!ubifs_zn_obsolete(znode)) {
* atomic_long_inc(&c->clean_zn_cnt);
* atomic_long_inc(&ubifs_clean_zn_cnt);
* }
*
* Thus, we just delay the @c->clean_zn_cnt update until we
* have the mutex locked.
*/
/* Do not access znode from this point on */ /* Do not access znode from this point on */
/* Update buffer positions */ /* Update buffer positions */
@ -938,65 +946,38 @@ static int write_index(struct ubifs_info *c)
else else
next_len = ubifs_idx_node_sz(c, cnext->child_cnt); next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
if (c->min_io_size == 1) { nxt_offs = buf_offs + used + next_len;
/* if (next_len && nxt_offs <= c->leb_size) {
* Write the prepared index node immediately if there is if (avail > 0)
* no minimum IO size
*/
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
wlen, UBI_SHORTTERM);
if (err)
return err;
buf_offs += ALIGN(wlen, 8);
if (next_len) {
used = 0;
avail = buf_len;
if (buf_offs + next_len > c->leb_size) {
err = ubifs_update_one_lp(c, lnum,
LPROPS_NC, 0, 0, LPROPS_TAKEN);
if (err)
return err;
lnum = -1;
}
continue; continue;
} else
blen = buf_len;
} else { } else {
int blen, nxt_offs = buf_offs + used + next_len; wlen = ALIGN(wlen, 8);
blen = ALIGN(wlen, c->min_io_size);
ubifs_pad(c, c->cbuf + wlen, blen - wlen);
}
if (next_len && nxt_offs <= c->leb_size) { /* The buffer is full or there are no more znodes to do */
if (avail > 0) err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
continue; UBI_SHORTTERM);
else if (err)
blen = buf_len; return err;
} else { buf_offs += blen;
wlen = ALIGN(wlen, 8); if (next_len) {
blen = ALIGN(wlen, c->min_io_size); if (nxt_offs > c->leb_size) {
ubifs_pad(c, c->cbuf + wlen, blen - wlen); err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
} 0, LPROPS_TAKEN);
/* if (err)
* The buffer is full or there are no more znodes return err;
* to do lnum = -1;
*/
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;
} }
used -= blen;
if (used < 0)
used = 0;
avail = buf_len - used;
memmove(c->cbuf, c->cbuf + blen, used);
continue;
} }
break; break;
} }
@ -1029,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c)
do { do {
znode = cnext; znode = cnext;
cnext = znode->cnext; cnext = znode->cnext;
if (test_bit(OBSOLETE_ZNODE, &znode->flags)) if (ubifs_zn_obsolete(znode))
kfree(znode); kfree(znode);
else { else {
znode->cnext = NULL; znode->cnext = NULL;

View File

@ -230,14 +230,14 @@ enum {
* LPT cnode flag bits. * LPT cnode flag bits.
* *
* DIRTY_CNODE: cnode is dirty * DIRTY_CNODE: cnode is dirty
* COW_CNODE: cnode is being committed and must be copied before writing
* OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted), * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
* so it can (and must) be freed when the commit is finished * so it can (and must) be freed when the commit is finished
* COW_CNODE: cnode is being committed and must be copied before writing
*/ */
enum { enum {
DIRTY_CNODE = 0, DIRTY_CNODE = 0,
COW_CNODE = 1, OBSOLETE_CNODE = 1,
OBSOLETE_CNODE = 2, COW_CNODE = 2,
}; };
/* /*
@ -1468,6 +1468,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
/* io.c */ /* io.c */
void ubifs_ro_mode(struct ubifs_info *c, int err); void ubifs_ro_mode(struct ubifs_info *c, int err);
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
int len, int even_ebadmsg);
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
int len, int dtype);
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
int dtype);
int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len); int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
int dtype); int dtype);
@ -1747,8 +1756,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
int offs, void *sbuf, int jhead); int offs, void *sbuf, int jhead);
struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
int offs, void *sbuf); int offs, void *sbuf);
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf); int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf); int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
int ubifs_rcvry_gc_commit(struct ubifs_info *c); int ubifs_rcvry_gc_commit(struct ubifs_info *c);
int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
int deletion, loff_t new_size); int deletion, loff_t new_size);