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:
commit
59a7ac1211
|
@ -111,34 +111,6 @@ The following is an example of the kernel boot arguments to attach mtd0
|
|||
to UBI and mount volume "rootfs":
|
||||
ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs
|
||||
|
||||
|
||||
Module Parameters for Debugging
|
||||
===============================
|
||||
|
||||
When UBIFS has been compiled with debugging enabled, there are 2 module
|
||||
parameters that are available to control aspects of testing and debugging.
|
||||
|
||||
debug_chks Selects extra checks that UBIFS can do while running:
|
||||
|
||||
Check Flag value
|
||||
|
||||
General checks 1
|
||||
Check Tree Node Cache (TNC) 2
|
||||
Check indexing tree size 4
|
||||
Check orphan area 8
|
||||
Check old indexing tree 16
|
||||
Check LEB properties (lprops) 32
|
||||
Check leaf nodes and inodes 64
|
||||
|
||||
debug_tsts Selects a mode of testing, as follows:
|
||||
|
||||
Test mode Flag value
|
||||
|
||||
Failure mode for recovery testing 4
|
||||
|
||||
For example, set debug_chks to 3 to enable general and TNC checks.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
|
||||
List of maintainers and how to submit kernel changes
|
||||
|
||||
Please try to follow the guidelines below. This will make things
|
||||
|
@ -6321,7 +6322,7 @@ F: drivers/scsi/u14-34f.c
|
|||
|
||||
UBI FILE SYSTEM (UBIFS)
|
||||
M: Artem Bityutskiy <dedekind1@gmail.com>
|
||||
M: Adrian Hunter <adrian.hunter@nokia.com>
|
||||
M: Adrian Hunter <adrian.hunter@intel.com>
|
||||
L: linux-mtd@lists.infradead.org
|
||||
T: git git://git.infradead.org/ubifs-2.6.git
|
||||
W: http://www.linux-mtd.infradead.org/doc/ubifs.html
|
||||
|
|
|
@ -78,7 +78,7 @@ static int nothing_to_commit(struct ubifs_info *c)
|
|||
* If the root TNC node is dirty, we definitely have something to
|
||||
* commit.
|
||||
*/
|
||||
if (c->zroot.znode && test_bit(DIRTY_ZNODE, &c->zroot.znode->flags))
|
||||
if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -418,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c)
|
|||
|
||||
spin_lock(&c->cs_lock);
|
||||
if (c->cmt_state == COMMIT_BROKEN) {
|
||||
err = -EINVAL;
|
||||
err = -EROFS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -444,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c)
|
|||
* re-check it.
|
||||
*/
|
||||
if (c->cmt_state == COMMIT_BROKEN) {
|
||||
err = -EINVAL;
|
||||
err = -EROFS;
|
||||
goto out_cmt_unlock;
|
||||
}
|
||||
|
||||
|
@ -576,7 +576,7 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
|
|||
struct idx_node *i;
|
||||
size_t sz;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX))
|
||||
if (!dbg_is_chk_index(c))
|
||||
return 0;
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
|
|
790
fs/ubifs/debug.c
790
fs/ubifs/debug.c
File diff suppressed because it is too large
Load Diff
241
fs/ubifs/debug.h
241
fs/ubifs/debug.h
|
@ -31,18 +31,25 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
|
|||
|
||||
#ifdef CONFIG_UBIFS_FS_DEBUG
|
||||
|
||||
#include <linux/random.h>
|
||||
/*
|
||||
* The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi"
|
||||
* + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
|
||||
*/
|
||||
#define UBIFS_DFS_DIR_NAME "ubi%d_%d"
|
||||
#define UBIFS_DFS_DIR_LEN (3 + 1 + 2*2 + 1)
|
||||
|
||||
/**
|
||||
* ubifs_debug_info - per-FS debugging information.
|
||||
* @old_zroot: old index root - used by 'dbg_check_old_index()'
|
||||
* @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
|
||||
* @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
|
||||
* @failure_mode: failure mode for recovery testing
|
||||
* @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
|
||||
* @fail_timeout: time in jiffies when delay of failure mode expires
|
||||
* @fail_cnt: current number of calls to failure mode I/O functions
|
||||
* @fail_cnt_max: number of calls by which to delay failure mode
|
||||
*
|
||||
* @pc_happened: non-zero if an emulated power cut happened
|
||||
* @pc_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
|
||||
* @pc_timeout: time in jiffies when delay of failure mode expires
|
||||
* @pc_cnt: current number of calls to failure mode I/O functions
|
||||
* @pc_cnt_max: number of calls by which to delay failure mode
|
||||
*
|
||||
* @chk_lpt_sz: used by LPT tree size checker
|
||||
* @chk_lpt_sz2: used by LPT tree size checker
|
||||
* @chk_lpt_wastage: used by LPT tree size checker
|
||||
|
@ -56,21 +63,36 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
|
|||
* @saved_free: saved amount of free space
|
||||
* @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt
|
||||
*
|
||||
* @chk_gen: if general extra checks are enabled
|
||||
* @chk_index: if index xtra checks are enabled
|
||||
* @chk_orph: if orphans extra checks are enabled
|
||||
* @chk_lprops: if lprops extra checks are enabled
|
||||
* @chk_fs: if UBIFS contents extra checks are enabled
|
||||
* @tst_rcvry: if UBIFS recovery testing mode enabled
|
||||
*
|
||||
* @dfs_dir_name: name of debugfs directory containing this file-system's files
|
||||
* @dfs_dir: direntry object of the file-system debugfs directory
|
||||
* @dfs_dump_lprops: "dump lprops" debugfs knob
|
||||
* @dfs_dump_budg: "dump budgeting information" debugfs knob
|
||||
* @dfs_dump_tnc: "dump TNC" debugfs knob
|
||||
* @dfs_chk_gen: debugfs knob to enable UBIFS general extra checks
|
||||
* @dfs_chk_index: debugfs knob to enable UBIFS index extra checks
|
||||
* @dfs_chk_orph: debugfs knob to enable UBIFS orphans extra checks
|
||||
* @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks
|
||||
* @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks
|
||||
* @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing
|
||||
*/
|
||||
struct ubifs_debug_info {
|
||||
struct ubifs_zbranch old_zroot;
|
||||
int old_zroot_level;
|
||||
unsigned long long old_zroot_sqnum;
|
||||
int failure_mode;
|
||||
int fail_delay;
|
||||
unsigned long fail_timeout;
|
||||
unsigned int fail_cnt;
|
||||
unsigned int fail_cnt_max;
|
||||
|
||||
int pc_happened;
|
||||
int pc_delay;
|
||||
unsigned long pc_timeout;
|
||||
unsigned int pc_cnt;
|
||||
unsigned int pc_cnt_max;
|
||||
|
||||
long long chk_lpt_sz;
|
||||
long long chk_lpt_sz2;
|
||||
long long chk_lpt_wastage;
|
||||
|
@ -84,11 +106,43 @@ struct ubifs_debug_info {
|
|||
long long saved_free;
|
||||
int saved_idx_gc_cnt;
|
||||
|
||||
char dfs_dir_name[100];
|
||||
unsigned int chk_gen:1;
|
||||
unsigned int chk_index:1;
|
||||
unsigned int chk_orph:1;
|
||||
unsigned int chk_lprops:1;
|
||||
unsigned int chk_fs:1;
|
||||
unsigned int tst_rcvry:1;
|
||||
|
||||
char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1];
|
||||
struct dentry *dfs_dir;
|
||||
struct dentry *dfs_dump_lprops;
|
||||
struct dentry *dfs_dump_budg;
|
||||
struct dentry *dfs_dump_tnc;
|
||||
struct dentry *dfs_chk_gen;
|
||||
struct dentry *dfs_chk_index;
|
||||
struct dentry *dfs_chk_orph;
|
||||
struct dentry *dfs_chk_lprops;
|
||||
struct dentry *dfs_chk_fs;
|
||||
struct dentry *dfs_tst_rcvry;
|
||||
};
|
||||
|
||||
/**
|
||||
* ubifs_global_debug_info - global (not per-FS) UBIFS debugging information.
|
||||
*
|
||||
* @chk_gen: if general extra checks are enabled
|
||||
* @chk_index: if index xtra checks are enabled
|
||||
* @chk_orph: if orphans extra checks are enabled
|
||||
* @chk_lprops: if lprops extra checks are enabled
|
||||
* @chk_fs: if UBIFS contents extra checks are enabled
|
||||
* @tst_rcvry: if UBIFS recovery testing mode enabled
|
||||
*/
|
||||
struct ubifs_global_debug_info {
|
||||
unsigned int chk_gen:1;
|
||||
unsigned int chk_index:1;
|
||||
unsigned int chk_orph:1;
|
||||
unsigned int chk_lprops:1;
|
||||
unsigned int chk_fs:1;
|
||||
unsigned int tst_rcvry:1;
|
||||
};
|
||||
|
||||
#define ubifs_assert(expr) do { \
|
||||
|
@ -127,6 +181,8 @@ const char *dbg_key_str1(const struct ubifs_info *c,
|
|||
#define DBGKEY(key) dbg_key_str0(c, (key))
|
||||
#define DBGKEY1(key) dbg_key_str1(c, (key))
|
||||
|
||||
extern spinlock_t dbg_lock;
|
||||
|
||||
#define ubifs_dbg_msg(type, fmt, ...) do { \
|
||||
spin_lock(&dbg_lock); \
|
||||
pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
|
||||
|
@ -162,41 +218,36 @@ const char *dbg_key_str1(const struct ubifs_info *c,
|
|||
/* Additional recovery messages */
|
||||
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Debugging check flags.
|
||||
*
|
||||
* UBIFS_CHK_GEN: general checks
|
||||
* UBIFS_CHK_TNC: check TNC
|
||||
* UBIFS_CHK_IDX_SZ: check index size
|
||||
* UBIFS_CHK_ORPH: check orphans
|
||||
* UBIFS_CHK_OLD_IDX: check the old index
|
||||
* UBIFS_CHK_LPROPS: check lprops
|
||||
* UBIFS_CHK_FS: check the file-system
|
||||
*/
|
||||
enum {
|
||||
UBIFS_CHK_GEN = 0x1,
|
||||
UBIFS_CHK_TNC = 0x2,
|
||||
UBIFS_CHK_IDX_SZ = 0x4,
|
||||
UBIFS_CHK_ORPH = 0x8,
|
||||
UBIFS_CHK_OLD_IDX = 0x10,
|
||||
UBIFS_CHK_LPROPS = 0x20,
|
||||
UBIFS_CHK_FS = 0x40,
|
||||
};
|
||||
extern struct ubifs_global_debug_info ubifs_dbg;
|
||||
|
||||
/*
|
||||
* Special testing flags.
|
||||
*
|
||||
* UBIFS_TST_RCVRY: failure mode for recovery testing
|
||||
*/
|
||||
enum {
|
||||
UBIFS_TST_RCVRY = 0x4,
|
||||
};
|
||||
|
||||
extern spinlock_t dbg_lock;
|
||||
|
||||
extern unsigned int ubifs_msg_flags;
|
||||
extern unsigned int ubifs_chk_flags;
|
||||
extern unsigned int ubifs_tst_flags;
|
||||
static inline int dbg_is_chk_gen(const struct ubifs_info *c)
|
||||
{
|
||||
return !!(ubifs_dbg.chk_gen || c->dbg->chk_gen);
|
||||
}
|
||||
static inline int dbg_is_chk_index(const struct ubifs_info *c)
|
||||
{
|
||||
return !!(ubifs_dbg.chk_index || c->dbg->chk_index);
|
||||
}
|
||||
static inline int dbg_is_chk_orph(const struct ubifs_info *c)
|
||||
{
|
||||
return !!(ubifs_dbg.chk_orph || c->dbg->chk_orph);
|
||||
}
|
||||
static inline int dbg_is_chk_lprops(const struct ubifs_info *c)
|
||||
{
|
||||
return !!(ubifs_dbg.chk_lprops || c->dbg->chk_lprops);
|
||||
}
|
||||
static inline int dbg_is_chk_fs(const struct ubifs_info *c)
|
||||
{
|
||||
return !!(ubifs_dbg.chk_fs || c->dbg->chk_fs);
|
||||
}
|
||||
static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)
|
||||
{
|
||||
return !!(ubifs_dbg.tst_rcvry || c->dbg->tst_rcvry);
|
||||
}
|
||||
static inline int dbg_is_power_cut(const struct ubifs_info *c)
|
||||
{
|
||||
return !!c->dbg->pc_happened;
|
||||
}
|
||||
|
||||
int ubifs_debugging_init(struct ubifs_info *c);
|
||||
void ubifs_debugging_exit(struct ubifs_info *c);
|
||||
|
@ -207,7 +258,7 @@ const char *dbg_cstate(int cmt_state);
|
|||
const char *dbg_jhead(int jhead);
|
||||
const char *dbg_get_key_dump(const struct ubifs_info *c,
|
||||
const union ubifs_key *key);
|
||||
void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode);
|
||||
void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
|
||||
void dbg_dump_node(const struct ubifs_info *c, const void *node);
|
||||
void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
|
||||
int offs);
|
||||
|
@ -240,8 +291,8 @@ int dbg_check_cats(struct ubifs_info *c);
|
|||
int dbg_check_ltab(struct ubifs_info *c);
|
||||
int dbg_chk_lpt_free_spc(struct ubifs_info *c);
|
||||
int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len);
|
||||
int dbg_check_synced_i_size(struct inode *inode);
|
||||
int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir);
|
||||
int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode);
|
||||
int dbg_check_dir(struct ubifs_info *c, const struct inode *dir);
|
||||
int dbg_check_tnc(struct ubifs_info *c, int extra);
|
||||
int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
|
||||
int dbg_check_filesystem(struct ubifs_info *c);
|
||||
|
@ -254,54 +305,12 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
|
|||
int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
|
||||
int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
|
||||
|
||||
/* Force the use of in-the-gaps method for testing */
|
||||
static inline int dbg_force_in_the_gaps_enabled(void)
|
||||
{
|
||||
return ubifs_chk_flags & UBIFS_CHK_GEN;
|
||||
}
|
||||
int dbg_force_in_the_gaps(void);
|
||||
|
||||
/* Failure mode for recovery testing */
|
||||
#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
|
||||
|
||||
#ifndef UBIFS_DBG_PRESERVE_UBI
|
||||
#define ubi_leb_read dbg_leb_read
|
||||
#define ubi_leb_write dbg_leb_write
|
||||
#define ubi_leb_change dbg_leb_change
|
||||
#define ubi_leb_erase dbg_leb_erase
|
||||
#define ubi_leb_unmap dbg_leb_unmap
|
||||
#define ubi_is_mapped dbg_is_mapped
|
||||
#define ubi_leb_map dbg_leb_map
|
||||
#endif
|
||||
|
||||
int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
|
||||
int len, int check);
|
||||
int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
|
||||
int offset, int len, int dtype);
|
||||
int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
|
||||
int len, int dtype);
|
||||
int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum);
|
||||
int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum);
|
||||
int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum);
|
||||
int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
|
||||
|
||||
static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf,
|
||||
int offset, int len)
|
||||
{
|
||||
return dbg_leb_read(desc, lnum, buf, offset, len, 0);
|
||||
}
|
||||
|
||||
static inline int dbg_write(struct ubi_volume_desc *desc, int lnum,
|
||||
const void *buf, int offset, int len)
|
||||
{
|
||||
return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
|
||||
}
|
||||
|
||||
static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
|
||||
const void *buf, int len)
|
||||
{
|
||||
return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
|
||||
}
|
||||
int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
|
||||
int len, int dtype);
|
||||
int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
|
||||
int dtype);
|
||||
int dbg_leb_unmap(struct ubifs_info *c, int lnum);
|
||||
int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
|
||||
|
||||
/* Debugfs-related stuff */
|
||||
int dbg_debugfs_init(void);
|
||||
|
@ -313,7 +322,7 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
|
|||
|
||||
/* Use "if (0)" to make compiler check arguments even if debugging is off */
|
||||
#define ubifs_assert(expr) do { \
|
||||
if (0 && (expr)) \
|
||||
if (0) \
|
||||
printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
|
||||
__func__, __LINE__, current->pid); \
|
||||
} while (0)
|
||||
|
@ -323,6 +332,9 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
|
|||
ubifs_err(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DBGKEY(key) ((char *)(key))
|
||||
#define DBGKEY1(key) ((char *)(key))
|
||||
|
||||
#define ubifs_dbg_msg(fmt, ...) do { \
|
||||
if (0) \
|
||||
pr_debug(fmt "\n", ##__VA_ARGS__); \
|
||||
|
@ -346,9 +358,6 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
|
|||
#define dbg_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
|
||||
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
|
||||
|
||||
#define DBGKEY(key) ((char *)(key))
|
||||
#define DBGKEY1(key) ((char *)(key))
|
||||
|
||||
static inline int ubifs_debugging_init(struct ubifs_info *c) { return 0; }
|
||||
static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; }
|
||||
static inline const char *dbg_ntype(int type) { return ""; }
|
||||
|
@ -357,7 +366,7 @@ static inline const char *dbg_jhead(int jhead) { return ""; }
|
|||
static inline const char *
|
||||
dbg_get_key_dump(const struct ubifs_info *c,
|
||||
const union ubifs_key *key) { return ""; }
|
||||
static inline void dbg_dump_inode(const struct ubifs_info *c,
|
||||
static inline void dbg_dump_inode(struct ubifs_info *c,
|
||||
const struct inode *inode) { return; }
|
||||
static inline void dbg_dump_node(const struct ubifs_info *c,
|
||||
const void *node) { return; }
|
||||
|
@ -409,9 +418,11 @@ static inline int dbg_check_ltab(struct ubifs_info *c) { return 0; }
|
|||
static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c) { return 0; }
|
||||
static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
|
||||
int action, int len) { return 0; }
|
||||
static inline int dbg_check_synced_i_size(struct inode *inode) { return 0; }
|
||||
static inline int dbg_check_dir_size(struct ubifs_info *c,
|
||||
const struct inode *dir) { return 0; }
|
||||
static inline int
|
||||
dbg_check_synced_i_size(const struct ubifs_info *c,
|
||||
struct inode *inode) { return 0; }
|
||||
static inline int dbg_check_dir(struct ubifs_info *c,
|
||||
const struct inode *dir) { return 0; }
|
||||
static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; }
|
||||
static inline int dbg_check_idx_size(struct ubifs_info *c,
|
||||
long long idx_size) { return 0; }
|
||||
|
@ -431,9 +442,23 @@ static inline int
|
|||
dbg_check_nondata_nodes_order(struct ubifs_info *c,
|
||||
struct list_head *head) { return 0; }
|
||||
|
||||
static inline int dbg_force_in_the_gaps(void) { return 0; }
|
||||
#define dbg_force_in_the_gaps_enabled() 0
|
||||
#define dbg_failure_mode 0
|
||||
static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
|
||||
const void *buf, int offset,
|
||||
int len, int dtype) { return 0; }
|
||||
static inline int dbg_leb_change(struct ubifs_info *c, int lnum,
|
||||
const void *buf, int len,
|
||||
int dtype) { return 0; }
|
||||
static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum) { return 0; }
|
||||
static inline int dbg_leb_map(struct ubifs_info *c, int lnum,
|
||||
int dtype) { return 0; }
|
||||
|
||||
static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return 0; }
|
||||
static inline int dbg_is_chk_index(const struct ubifs_info *c) { return 0; }
|
||||
static inline int dbg_is_chk_orph(const struct ubifs_info *c) { return 0; }
|
||||
static inline int dbg_is_chk_lprops(const struct ubifs_info *c) { return 0; }
|
||||
static inline int dbg_is_chk_fs(const struct ubifs_info *c) { return 0; }
|
||||
static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) { return 0; }
|
||||
static inline int dbg_is_power_cut(const struct ubifs_info *c) { return 0; }
|
||||
|
||||
static inline int dbg_debugfs_init(void) { return 0; }
|
||||
static inline void dbg_debugfs_exit(void) { return; }
|
||||
|
|
|
@ -102,7 +102,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
|
|||
* UBIFS has to fully control "clean <-> dirty" transitions of inodes
|
||||
* to make budgeting work.
|
||||
*/
|
||||
inode->i_flags |= (S_NOCMTIME);
|
||||
inode->i_flags |= S_NOCMTIME;
|
||||
|
||||
inode_init_owner(inode, dir, mode);
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
||||
|
@ -172,9 +172,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
|
|||
|
||||
#ifdef CONFIG_UBIFS_FS_DEBUG
|
||||
|
||||
static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
|
||||
static int dbg_check_name(const struct ubifs_info *c,
|
||||
const struct ubifs_dent_node *dent,
|
||||
const struct qstr *nm)
|
||||
{
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
|
||||
if (!dbg_is_chk_gen(c))
|
||||
return 0;
|
||||
if (le16_to_cpu(dent->nlen) != nm->len)
|
||||
return -EINVAL;
|
||||
|
@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
|
|||
|
||||
#else
|
||||
|
||||
#define dbg_check_name(dent, nm) 0
|
||||
#define dbg_check_name(c, dent, nm) 0
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (dbg_check_name(dent, &dentry->d_name)) {
|
||||
if (dbg_check_name(c, dent, &dentry->d_name)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -522,7 +524,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
|
|||
ubifs_assert(mutex_is_locked(&dir->i_mutex));
|
||||
ubifs_assert(mutex_is_locked(&inode->i_mutex));
|
||||
|
||||
err = dbg_check_synced_i_size(inode);
|
||||
err = dbg_check_synced_i_size(c, inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -577,7 +579,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
inode->i_nlink, dir->i_ino);
|
||||
ubifs_assert(mutex_is_locked(&dir->i_mutex));
|
||||
ubifs_assert(mutex_is_locked(&inode->i_mutex));
|
||||
err = dbg_check_synced_i_size(inode);
|
||||
err = dbg_check_synced_i_size(c, inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -1263,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = dbg_check_synced_i_size(inode);
|
||||
err = dbg_check_synced_i_size(c, inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
168
fs/ubifs/io.c
168
fs/ubifs/io.c
|
@ -86,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
|
|||
c->no_chk_data_crc = 0;
|
||||
c->vfs_sb->s_flags |= MS_RDONLY;
|
||||
ubifs_warn("switched to read-only mode, error %d", err);
|
||||
dump_stack();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Below are simple wrappers over UBI I/O functions which include some
|
||||
* additional checks and UBIFS debugging stuff. See corresponding UBI function
|
||||
* for more information.
|
||||
*/
|
||||
|
||||
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
|
||||
int len, int even_ebadmsg)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ubi_read(c->ubi, lnum, buf, offs, len);
|
||||
/*
|
||||
* In case of %-EBADMSG print the error message only if the
|
||||
* @even_ebadmsg is true.
|
||||
*/
|
||||
if (err && (err != -EBADMSG || even_ebadmsg)) {
|
||||
ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
|
||||
len, lnum, offs, err);
|
||||
dbg_dump_stack();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
|
||||
int len, int dtype)
|
||||
{
|
||||
int err;
|
||||
|
||||
ubifs_assert(!c->ro_media && !c->ro_mount);
|
||||
if (c->ro_error)
|
||||
return -EROFS;
|
||||
if (!dbg_is_tst_rcvry(c))
|
||||
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
|
||||
else
|
||||
err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
|
||||
if (err) {
|
||||
ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
|
||||
len, lnum, offs, err);
|
||||
ubifs_ro_mode(c, err);
|
||||
dbg_dump_stack();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
|
||||
int dtype)
|
||||
{
|
||||
int err;
|
||||
|
||||
ubifs_assert(!c->ro_media && !c->ro_mount);
|
||||
if (c->ro_error)
|
||||
return -EROFS;
|
||||
if (!dbg_is_tst_rcvry(c))
|
||||
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
|
||||
else
|
||||
err = dbg_leb_change(c, lnum, buf, len, dtype);
|
||||
if (err) {
|
||||
ubifs_err("changing %d bytes in LEB %d failed, error %d",
|
||||
len, lnum, err);
|
||||
ubifs_ro_mode(c, err);
|
||||
dbg_dump_stack();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
|
||||
{
|
||||
int err;
|
||||
|
||||
ubifs_assert(!c->ro_media && !c->ro_mount);
|
||||
if (c->ro_error)
|
||||
return -EROFS;
|
||||
if (!dbg_is_tst_rcvry(c))
|
||||
err = ubi_leb_unmap(c->ubi, lnum);
|
||||
else
|
||||
err = dbg_leb_unmap(c, lnum);
|
||||
if (err) {
|
||||
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
|
||||
ubifs_ro_mode(c, err);
|
||||
dbg_dump_stack();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
|
||||
{
|
||||
int err;
|
||||
|
||||
ubifs_assert(!c->ro_media && !c->ro_mount);
|
||||
if (c->ro_error)
|
||||
return -EROFS;
|
||||
if (!dbg_is_tst_rcvry(c))
|
||||
err = ubi_leb_map(c->ubi, lnum, dtype);
|
||||
else
|
||||
err = dbg_leb_map(c, lnum, dtype);
|
||||
if (err) {
|
||||
ubifs_err("mapping LEB %d failed, error %d", lnum, err);
|
||||
ubifs_ro_mode(c, err);
|
||||
dbg_dump_stack();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ubi_is_mapped(c->ubi, lnum);
|
||||
if (err < 0) {
|
||||
ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
|
||||
lnum, err);
|
||||
dbg_dump_stack();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -406,14 +523,10 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
|
|||
dirt = sync_len - wbuf->used;
|
||||
if (dirt)
|
||||
ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
|
||||
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
|
||||
sync_len, wbuf->dtype);
|
||||
if (err) {
|
||||
ubifs_err("cannot write %d bytes to LEB %d:%d",
|
||||
sync_len, wbuf->lnum, wbuf->offs);
|
||||
dbg_dump_stack();
|
||||
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
|
||||
wbuf->dtype);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
spin_lock(&wbuf->lock);
|
||||
wbuf->offs += sync_len;
|
||||
|
@ -605,9 +718,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
|
|||
if (aligned_len == wbuf->avail) {
|
||||
dbg_io("flush jhead %s wbuf to LEB %d:%d",
|
||||
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
|
||||
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
|
||||
wbuf->offs, wbuf->size,
|
||||
wbuf->dtype);
|
||||
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
|
||||
wbuf->offs, wbuf->size,
|
||||
wbuf->dtype);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -642,8 +755,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
|
|||
dbg_io("flush jhead %s wbuf to LEB %d:%d",
|
||||
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
|
||||
memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
|
||||
err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
|
||||
wbuf->size, wbuf->dtype);
|
||||
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
|
||||
wbuf->size, wbuf->dtype);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -661,8 +774,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
|
|||
*/
|
||||
dbg_io("write %d bytes to LEB %d:%d",
|
||||
wbuf->size, wbuf->lnum, wbuf->offs);
|
||||
err = ubi_leb_write(c->ubi, wbuf->lnum, buf, wbuf->offs,
|
||||
wbuf->size, wbuf->dtype);
|
||||
err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
|
||||
wbuf->size, wbuf->dtype);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -683,8 +796,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
|
|||
n <<= c->max_write_shift;
|
||||
dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
|
||||
wbuf->offs);
|
||||
err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written,
|
||||
wbuf->offs, n, wbuf->dtype);
|
||||
err = ubifs_leb_write(c, wbuf->lnum, buf + written,
|
||||
wbuf->offs, n, wbuf->dtype);
|
||||
if (err)
|
||||
goto out;
|
||||
wbuf->offs += n;
|
||||
|
@ -766,13 +879,9 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
|
|||
return -EROFS;
|
||||
|
||||
ubifs_prepare_node(c, buf, len, 1);
|
||||
err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype);
|
||||
if (err) {
|
||||
ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
|
||||
buf_len, lnum, offs, err);
|
||||
err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
|
||||
if (err)
|
||||
dbg_dump_node(c, buf);
|
||||
dbg_dump_stack();
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -824,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
|
|||
|
||||
if (rlen > 0) {
|
||||
/* Read everything that goes before write-buffer */
|
||||
err = ubi_read(c->ubi, lnum, buf, offs, rlen);
|
||||
if (err && err != -EBADMSG) {
|
||||
ubifs_err("failed to read node %d from LEB %d:%d, "
|
||||
"error %d", type, lnum, offs, err);
|
||||
dbg_dump_stack();
|
||||
err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
|
||||
if (err && err != -EBADMSG)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != ch->node_type) {
|
||||
|
@ -885,12 +990,9 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
|
|||
ubifs_assert(!(offs & 7) && offs < c->leb_size);
|
||||
ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
|
||||
|
||||
err = ubi_read(c->ubi, lnum, buf, offs, len);
|
||||
if (err && err != -EBADMSG) {
|
||||
ubifs_err("cannot read node %d from LEB %d:%d, error %d",
|
||||
type, lnum, offs, err);
|
||||
err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
|
||||
if (err && err != -EBADMSG)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (type != ch->node_type) {
|
||||
ubifs_err("bad node type (%d but expected %d)",
|
||||
|
|
|
@ -262,7 +262,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
|
|||
* an unclean reboot, because the target LEB might have been
|
||||
* unmapped, but not yet physically erased.
|
||||
*/
|
||||
err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM);
|
||||
err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
@ -283,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
|
|||
return 0;
|
||||
|
||||
out_unlock:
|
||||
if (err != -EAGAIN)
|
||||
ubifs_ro_mode(c, err);
|
||||
mutex_unlock(&c->log_mutex);
|
||||
kfree(ref);
|
||||
kfree(bud);
|
||||
|
@ -752,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
|
|||
struct ubifs_bud *bud;
|
||||
long long bud_bytes = 0;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
|
||||
if (!dbg_is_chk_gen(c))
|
||||
return 0;
|
||||
|
||||
spin_lock(&c->buds_lock);
|
||||
|
|
|
@ -504,7 +504,7 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
|
|||
pnode = (struct ubifs_pnode *)container_of(lprops - pos,
|
||||
struct ubifs_pnode,
|
||||
lprops[0]);
|
||||
return !test_bit(COW_ZNODE, &pnode->flags) &&
|
||||
return !test_bit(COW_CNODE, &pnode->flags) &&
|
||||
test_bit(DIRTY_CNODE, &pnode->flags);
|
||||
}
|
||||
|
||||
|
@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c)
|
|||
struct list_head *pos;
|
||||
int i, cat;
|
||||
|
||||
if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
|
||||
if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(lprops, &c->empty_list, list) {
|
||||
|
@ -958,7 +958,7 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
|
|||
{
|
||||
int i = 0, j, err = 0;
|
||||
|
||||
if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
|
||||
if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
|
||||
return;
|
||||
|
||||
for (i = 0; i < heap->cnt; i++) {
|
||||
|
@ -1262,7 +1262,7 @@ int dbg_check_lprops(struct ubifs_info *c)
|
|||
int i, err;
|
||||
struct ubifs_lp_stats lst;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
|
||||
if (!dbg_is_chk_lprops(c))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
|
|
@ -701,8 +701,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
|
|||
alen = ALIGN(len, c->min_io_size);
|
||||
set_ltab(c, lnum, c->leb_size - alen, alen - len);
|
||||
memset(p, 0xff, alen - len);
|
||||
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
|
||||
UBI_SHORTTERM);
|
||||
err = ubifs_leb_change(c, lnum++, buf, alen,
|
||||
UBI_SHORTTERM);
|
||||
if (err)
|
||||
goto out;
|
||||
p = buf;
|
||||
|
@ -732,8 +732,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
|
|||
set_ltab(c, lnum, c->leb_size - alen,
|
||||
alen - len);
|
||||
memset(p, 0xff, alen - len);
|
||||
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
|
||||
UBI_SHORTTERM);
|
||||
err = ubifs_leb_change(c, lnum++, buf, alen,
|
||||
UBI_SHORTTERM);
|
||||
if (err)
|
||||
goto out;
|
||||
p = buf;
|
||||
|
@ -780,8 +780,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
|
|||
alen = ALIGN(len, c->min_io_size);
|
||||
set_ltab(c, lnum, c->leb_size - alen, alen - len);
|
||||
memset(p, 0xff, alen - len);
|
||||
err = ubi_leb_change(c->ubi, lnum++, buf, alen,
|
||||
UBI_SHORTTERM);
|
||||
err = ubifs_leb_change(c, lnum++, buf, alen,
|
||||
UBI_SHORTTERM);
|
||||
if (err)
|
||||
goto out;
|
||||
p = buf;
|
||||
|
@ -806,7 +806,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
|
|||
alen = ALIGN(len, c->min_io_size);
|
||||
set_ltab(c, lnum, c->leb_size - alen, alen - len);
|
||||
memset(p, 0xff, alen - len);
|
||||
err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM);
|
||||
err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
|
||||
if (err)
|
||||
goto out;
|
||||
p = buf;
|
||||
|
@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
|
|||
|
||||
/* Write remaining buffer */
|
||||
memset(p, 0xff, alen - len);
|
||||
err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM);
|
||||
err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
|
|||
if (c->big_lpt)
|
||||
nnode->num = calc_nnode_num_from_parent(c, parent, iip);
|
||||
} else {
|
||||
err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
|
||||
err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ubifs_unpack_nnode(c, buf, nnode);
|
||||
|
@ -1247,6 +1247,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
|
|||
|
||||
out:
|
||||
ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
|
||||
dbg_dump_stack();
|
||||
kfree(nnode);
|
||||
return err;
|
||||
}
|
||||
|
@ -1290,7 +1291,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
|
|||
lprops->flags = ubifs_categorize_lprops(c, lprops);
|
||||
}
|
||||
} else {
|
||||
err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
|
||||
err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
err = unpack_pnode(c, buf, pnode);
|
||||
|
@ -1312,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
|
|||
out:
|
||||
ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
|
||||
dbg_dump_pnode(c, pnode, parent, iip);
|
||||
dbg_dump_stack();
|
||||
dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
|
||||
kfree(pnode);
|
||||
return err;
|
||||
|
@ -1331,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c)
|
|||
buf = vmalloc(c->ltab_sz);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
|
||||
err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
err = unpack_ltab(c, buf);
|
||||
|
@ -1354,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c)
|
|||
buf = vmalloc(c->lsave_sz);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz);
|
||||
err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
|
||||
c->lsave_sz, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
err = unpack_lsave(c, buf);
|
||||
|
@ -1814,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
|
|||
if (c->big_lpt)
|
||||
nnode->num = calc_nnode_num_from_parent(c, parent, iip);
|
||||
} else {
|
||||
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
|
||||
c->nnode_sz);
|
||||
err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
|
||||
c->nnode_sz, 1);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
err = ubifs_unpack_nnode(c, buf, nnode);
|
||||
|
@ -1883,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
|
|||
ubifs_assert(branch->lnum >= c->lpt_first &&
|
||||
branch->lnum <= c->lpt_last);
|
||||
ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
|
||||
err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
|
||||
c->pnode_sz);
|
||||
err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
|
||||
c->pnode_sz, 1);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
err = unpack_pnode(c, buf, pnode);
|
||||
|
@ -2224,7 +2227,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
|
|||
struct ubifs_cnode *cn;
|
||||
int num, iip = 0, err;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
|
||||
if (!dbg_is_chk_lprops(c))
|
||||
return 0;
|
||||
|
||||
while (cnode) {
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <linux/crc16.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/random.h>
|
||||
#include "ubifs.h"
|
||||
|
||||
#ifdef CONFIG_UBIFS_FS_DEBUG
|
||||
|
@ -116,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)
|
|||
return 0;
|
||||
cnt += 1;
|
||||
while (1) {
|
||||
ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags));
|
||||
__set_bit(COW_ZNODE, &cnode->flags);
|
||||
ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
|
||||
__set_bit(COW_CNODE, &cnode->flags);
|
||||
cnext = next_dirty_cnode(cnode);
|
||||
if (!cnext) {
|
||||
cnode->cnext = c->lpt_cnext;
|
||||
|
@ -465,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c)
|
|||
*/
|
||||
clear_bit(DIRTY_CNODE, &cnode->flags);
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(COW_ZNODE, &cnode->flags);
|
||||
clear_bit(COW_CNODE, &cnode->flags);
|
||||
smp_mb__after_clear_bit();
|
||||
offs += len;
|
||||
dbg_chk_lpt_sz(c, 1, len);
|
||||
|
@ -1160,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
|
|||
void *buf = c->lpt_buf;
|
||||
|
||||
dbg_lp("LEB %d", lnum);
|
||||
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
|
||||
if (err) {
|
||||
ubifs_err("cannot read LEB %d, error %d", lnum, err);
|
||||
|
||||
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!is_a_node(c, buf, len)) {
|
||||
int pad_len;
|
||||
|
@ -1640,7 +1641,7 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
|
|||
int ret;
|
||||
void *buf, *p;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
|
||||
if (!dbg_is_chk_lprops(c))
|
||||
return 0;
|
||||
|
||||
buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
|
||||
|
@ -1650,11 +1651,11 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
|
|||
}
|
||||
|
||||
dbg_lp("LEB %d", lnum);
|
||||
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
|
||||
if (err) {
|
||||
dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err);
|
||||
|
||||
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!is_a_node(c, p, len)) {
|
||||
int i, pad_len;
|
||||
|
@ -1711,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c)
|
|||
{
|
||||
int lnum, err, i, cnt;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
|
||||
if (!dbg_is_chk_lprops(c))
|
||||
return 0;
|
||||
|
||||
/* Bring the entire tree into memory */
|
||||
|
@ -1754,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
|
|||
long long free = 0;
|
||||
int i;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
|
||||
if (!dbg_is_chk_lprops(c))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < c->lpt_lebs; i++) {
|
||||
|
@ -1796,7 +1797,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
|
|||
long long chk_lpt_sz, lpt_sz;
|
||||
int err = 0;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
|
||||
if (!dbg_is_chk_lprops(c))
|
||||
return 0;
|
||||
|
||||
switch (action) {
|
||||
|
@ -1901,11 +1902,10 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
|
|||
return;
|
||||
}
|
||||
|
||||
err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
|
||||
if (err) {
|
||||
ubifs_err("cannot read LEB %d, error %d", lnum, err);
|
||||
err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
offs = c->leb_size - len;
|
||||
if (!is_a_node(c, p, len)) {
|
||||
|
@ -2019,7 +2019,7 @@ static int dbg_populate_lsave(struct ubifs_info *c)
|
|||
struct ubifs_lpt_heap *heap;
|
||||
int i;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
|
||||
if (!dbg_is_chk_gen(c))
|
||||
return 0;
|
||||
if (random32() & 3)
|
||||
return 0;
|
||||
|
|
103
fs/ubifs/misc.h
103
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
|
||||
|
@ -121,86 +144,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_leb_unmap - unmap an LEB.
|
||||
* @c: UBIFS file-system description object
|
||||
* @lnum: LEB number to unmap
|
||||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
|
||||
{
|
||||
int err;
|
||||
|
||||
ubifs_assert(!c->ro_media && !c->ro_mount);
|
||||
if (c->ro_error)
|
||||
return -EROFS;
|
||||
err = ubi_leb_unmap(c->ubi, lnum);
|
||||
if (err) {
|
||||
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_leb_write - write to a LEB.
|
||||
* @c: UBIFS file-system description object
|
||||
* @lnum: LEB number to write
|
||||
* @buf: buffer to write from
|
||||
* @offs: offset within LEB to write to
|
||||
* @len: length to write
|
||||
* @dtype: data type
|
||||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
|
||||
const void *buf, int offs, int len, int dtype)
|
||||
{
|
||||
int err;
|
||||
|
||||
ubifs_assert(!c->ro_media && !c->ro_mount);
|
||||
if (c->ro_error)
|
||||
return -EROFS;
|
||||
err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
|
||||
if (err) {
|
||||
ubifs_err("writing %d bytes at %d:%d, error %d",
|
||||
len, lnum, offs, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_leb_change - atomic LEB change.
|
||||
* @c: UBIFS file-system description object
|
||||
* @lnum: LEB number to write
|
||||
* @buf: buffer to write from
|
||||
* @len: length to write
|
||||
* @dtype: data type
|
||||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
|
||||
const void *buf, int len, int dtype)
|
||||
{
|
||||
int err;
|
||||
|
||||
ubifs_assert(!c->ro_media && !c->ro_mount);
|
||||
if (c->ro_error)
|
||||
return -EROFS;
|
||||
err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
|
||||
if (err) {
|
||||
ubifs_err("changing %d bytes in LEB %d, error %d",
|
||||
len, lnum, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_encode_dev - encode device node IDs.
|
||||
* @dev: UBIFS device node information
|
||||
|
|
|
@ -929,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c)
|
|||
struct check_info ci;
|
||||
int err;
|
||||
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_ORPH))
|
||||
if (!dbg_is_chk_orph(c))
|
||||
return 0;
|
||||
|
||||
ci.last_ino = 0;
|
||||
|
|
|
@ -117,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
|
|||
if (!sbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
|
||||
err = ubifs_leb_read(c, lnum, sbuf, 0, c->leb_size, 0);
|
||||
if (err && err != -EBADMSG)
|
||||
goto out_free;
|
||||
|
||||
|
@ -213,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
|
|||
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
|
||||
|
||||
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
|
||||
err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
|
||||
err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
|
||||
err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
|
||||
if (err)
|
||||
goto out;
|
||||
out:
|
||||
|
@ -274,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c)
|
|||
if (cor1)
|
||||
goto out_err;
|
||||
mst = mst1;
|
||||
} else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
|
||||
} else if (offs1 == 0 &&
|
||||
c->leb_size - offs2 - sz < sz) {
|
||||
/* 1st LEB was unmapped and written, 2nd not */
|
||||
if (cor1)
|
||||
goto out_err;
|
||||
|
@ -539,8 +540,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
|
|||
int len = ALIGN(endpt, c->min_io_size);
|
||||
|
||||
if (start) {
|
||||
err = ubi_read(c->ubi, lnum, sleb->buf, 0,
|
||||
start);
|
||||
err = ubifs_leb_read(c, lnum, sleb->buf, 0,
|
||||
start, 1);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -554,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
|
|||
ubifs_pad(c, buf, pad_len);
|
||||
}
|
||||
}
|
||||
err = ubi_leb_change(c->ubi, lnum, sleb->buf, len,
|
||||
UBI_UNKNOWN);
|
||||
err = ubifs_leb_change(c, lnum, sleb->buf, len,
|
||||
UBI_UNKNOWN);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -819,7 +820,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
|
|||
return -ENOMEM;
|
||||
if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
|
||||
goto out_err;
|
||||
err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
|
||||
err = ubifs_leb_read(c, lnum, (void *)cs_node, offs,
|
||||
UBIFS_CS_NODE_SZ, 0);
|
||||
if (err && err != -EBADMSG)
|
||||
goto out_free;
|
||||
ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
|
||||
|
@ -919,8 +921,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
|
|||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
static int recover_head(const struct ubifs_info *c, int lnum, int offs,
|
||||
void *sbuf)
|
||||
static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
|
||||
{
|
||||
int len = c->max_write_size, err;
|
||||
|
||||
|
@ -931,15 +932,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
|
|||
return 0;
|
||||
|
||||
/* Read at the head location and check it is empty flash */
|
||||
err = ubi_read(c->ubi, lnum, sbuf, offs, len);
|
||||
err = ubifs_leb_read(c, lnum, sbuf, offs, len, 1);
|
||||
if (err || !is_empty(sbuf, len)) {
|
||||
dbg_rcvry("cleaning head at %d:%d", lnum, offs);
|
||||
if (offs == 0)
|
||||
return ubifs_leb_unmap(c, lnum);
|
||||
err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
|
||||
err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
|
||||
if (err)
|
||||
return err;
|
||||
return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
|
||||
return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -962,7 +963,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
|
|||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
|
||||
int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -993,7 +994,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
|
|||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
static int clean_an_unclean_leb(const struct ubifs_info *c,
|
||||
static int clean_an_unclean_leb(struct ubifs_info *c,
|
||||
struct ubifs_unclean_leb *ucleb, void *sbuf)
|
||||
{
|
||||
int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
|
||||
|
@ -1009,7 +1010,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
|
|||
return 0;
|
||||
}
|
||||
|
||||
err = ubi_read(c->ubi, lnum, buf, offs, len);
|
||||
err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
|
||||
if (err && err != -EBADMSG)
|
||||
return err;
|
||||
|
||||
|
@ -1069,7 +1070,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
|
|||
}
|
||||
|
||||
/* Write back the LEB atomically */
|
||||
err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
|
||||
err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -1089,7 +1090,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
|
|||
*
|
||||
* This function returns %0 on success and a negative error code on failure.
|
||||
*/
|
||||
int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
|
||||
int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
|
||||
{
|
||||
dbg_rcvry("recovery");
|
||||
while (!list_empty(&c->unclean_leb_list)) {
|
||||
|
@ -1454,7 +1455,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
|
|||
if (i_size >= e->d_size)
|
||||
return 0;
|
||||
/* Read the LEB */
|
||||
err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size);
|
||||
err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
/* Change the size field and recalculate the CRC */
|
||||
|
@ -1470,7 +1471,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
|
|||
len -= 1;
|
||||
len = ALIGN(len + 1, c->min_io_size);
|
||||
/* Atomically write the fixed LEB back again */
|
||||
err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
|
||||
err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
|
||||
if (err)
|
||||
goto out;
|
||||
dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
|
||||
|
|
|
@ -523,8 +523,7 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
|
|||
if (!list_is_last(&next->list, &jh->buds_list))
|
||||
return 0;
|
||||
|
||||
err = ubi_read(c->ubi, next->lnum, (char *)&data,
|
||||
next->start, 4);
|
||||
err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -674,15 +674,15 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int len)
|
|||
|
||||
if (len == 0) {
|
||||
dbg_mnt("unmap empty LEB %d", lnum);
|
||||
return ubi_leb_unmap(c->ubi, lnum);
|
||||
return ubifs_leb_unmap(c, lnum);
|
||||
}
|
||||
|
||||
dbg_mnt("fixup LEB %d, data len %d", lnum, len);
|
||||
err = ubi_read(c->ubi, lnum, c->sbuf, 0, len);
|
||||
err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
|
||||
return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -148,7 +148,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
|
|||
INIT_LIST_HEAD(&sleb->nodes);
|
||||
sleb->buf = sbuf;
|
||||
|
||||
err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
|
||||
err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs, 0);
|
||||
if (err && err != -EBADMSG) {
|
||||
ubifs_err("cannot read %d bytes from LEB %d:%d,"
|
||||
" error %d", c->leb_size - offs, lnum, offs, err);
|
||||
|
@ -240,7 +240,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
|
|||
int len;
|
||||
|
||||
ubifs_err("corruption at LEB %d:%d", lnum, offs);
|
||||
if (dbg_failure_mode)
|
||||
if (dbg_is_tst_rcvry(c))
|
||||
return;
|
||||
len = c->leb_size - offs;
|
||||
if (len > 8192)
|
||||
|
|
|
@ -85,7 +85,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
|
|||
if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
|
||||
return 4;
|
||||
|
||||
if (ui->xattr && (inode->i_mode & S_IFMT) != S_IFREG)
|
||||
if (ui->xattr && !S_ISREG(inode->i_mode))
|
||||
return 5;
|
||||
|
||||
if (!ubifs_compr_present(ui->compr_type)) {
|
||||
|
@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
|
|||
ubifs_compr_name(ui->compr_type));
|
||||
}
|
||||
|
||||
err = dbg_check_dir_size(c, inode);
|
||||
err = dbg_check_dir(c, inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -914,7 +914,7 @@ static int check_volume_empty(struct ubifs_info *c)
|
|||
|
||||
c->empty = 1;
|
||||
for (lnum = 0; lnum < c->leb_cnt; lnum++) {
|
||||
err = ubi_is_mapped(c->ubi, lnum);
|
||||
err = ubifs_is_mapped(c, lnum);
|
||||
if (unlikely(err < 0))
|
||||
return err;
|
||||
if (err == 1) {
|
||||
|
|
|
@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
|
|||
__set_bit(DIRTY_ZNODE, &zn->flags);
|
||||
__clear_bit(COW_ZNODE, &zn->flags);
|
||||
|
||||
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
|
||||
ubifs_assert(!ubifs_zn_obsolete(znode));
|
||||
__set_bit(OBSOLETE_ZNODE, &znode->flags);
|
||||
|
||||
if (znode->level != 0) {
|
||||
|
@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
|
|||
struct ubifs_znode *zn;
|
||||
int err;
|
||||
|
||||
if (!test_bit(COW_ZNODE, &znode->flags)) {
|
||||
if (!ubifs_zn_cow(znode)) {
|
||||
/* znode is not being committed */
|
||||
if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
|
||||
atomic_long_inc(&c->dirty_zn_cnt);
|
||||
|
@ -462,7 +462,7 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
|
|||
|
||||
dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
|
||||
|
||||
err = ubi_read(c->ubi, lnum, buf, offs, len);
|
||||
err = ubifs_leb_read(c, lnum, buf, offs, len, 1);
|
||||
if (err) {
|
||||
ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
|
||||
type, lnum, offs, err);
|
||||
|
@ -1666,7 +1666,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
|
|||
if (!overlap) {
|
||||
/* We may safely unlock the write-buffer and read the data */
|
||||
spin_unlock(&wbuf->lock);
|
||||
return ubi_read(c->ubi, lnum, buf, offs, len);
|
||||
return ubifs_leb_read(c, lnum, buf, offs, len, 0);
|
||||
}
|
||||
|
||||
/* Don't read under wbuf */
|
||||
|
@ -1680,7 +1680,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
|
|||
|
||||
if (rlen > 0)
|
||||
/* Read everything that goes before write-buffer */
|
||||
return ubi_read(c->ubi, lnum, buf, offs, rlen);
|
||||
return ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1767,7 +1767,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
|
|||
if (wbuf)
|
||||
err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
|
||||
else
|
||||
err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
|
||||
err = ubifs_leb_read(c, lnum, bu->buf, offs, len, 0);
|
||||
|
||||
/* Check for a race with GC */
|
||||
if (maybe_leb_gced(c, lnum, bu->gc_seq))
|
||||
|
@ -2423,7 +2423,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
|
|||
*/
|
||||
|
||||
do {
|
||||
ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
|
||||
ubifs_assert(!ubifs_zn_obsolete(znode));
|
||||
ubifs_assert(ubifs_zn_dirty(znode));
|
||||
|
||||
zp = znode->parent;
|
||||
|
@ -2479,9 +2479,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
|
|||
c->zroot.offs = zbr->offs;
|
||||
c->zroot.len = zbr->len;
|
||||
c->zroot.znode = znode;
|
||||
ubifs_assert(!test_bit(OBSOLETE_ZNODE,
|
||||
&zp->flags));
|
||||
ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
|
||||
ubifs_assert(!ubifs_zn_obsolete(zp));
|
||||
ubifs_assert(ubifs_zn_dirty(zp));
|
||||
atomic_long_dec(&c->dirty_zn_cnt);
|
||||
|
||||
if (zp->cnext) {
|
||||
|
@ -2865,7 +2864,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
|
|||
struct ubifs_znode *znode = cnext;
|
||||
|
||||
cnext = cnext->cnext;
|
||||
if (test_bit(OBSOLETE_ZNODE, &znode->flags))
|
||||
if (ubifs_zn_obsolete(znode))
|
||||
kfree(znode);
|
||||
} while (cnext && cnext != c->cnext);
|
||||
}
|
||||
|
@ -3301,7 +3300,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
|
|||
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
|
||||
if (!dbg_is_chk_gen(c))
|
||||
return 0;
|
||||
|
||||
block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
|
||||
|
@ -3337,9 +3336,10 @@ 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);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
/* This file implements TNC functions for committing */
|
||||
|
||||
#include <linux/random.h>
|
||||
#include "ubifs.h"
|
||||
|
||||
/**
|
||||
|
@ -87,8 +88,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
|
|||
atomic_long_dec(&c->dirty_zn_cnt);
|
||||
|
||||
ubifs_assert(ubifs_zn_dirty(znode));
|
||||
ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
|
||||
ubifs_assert(ubifs_zn_cow(znode));
|
||||
|
||||
/*
|
||||
* Note, unlike 'write_index()' we do not add memory barriers here
|
||||
* because this function is called with @c->tnc_mutex locked.
|
||||
*/
|
||||
__clear_bit(DIRTY_ZNODE, &znode->flags);
|
||||
__clear_bit(COW_ZNODE, &znode->flags);
|
||||
|
||||
|
@ -377,7 +382,7 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
|
|||
c->gap_lebs = NULL;
|
||||
return err;
|
||||
}
|
||||
if (dbg_force_in_the_gaps_enabled()) {
|
||||
if (!dbg_is_chk_index(c)) {
|
||||
/*
|
||||
* Do not print scary warnings if the debugging
|
||||
* option which forces in-the-gaps is enabled.
|
||||
|
@ -491,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c)
|
|||
else
|
||||
next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
|
||||
|
||||
if (c->min_io_size == 1) {
|
||||
buf_offs += ALIGN(len, 8);
|
||||
if (next_len) {
|
||||
if (buf_offs + next_len <= c->leb_size)
|
||||
continue;
|
||||
err = ubifs_update_one_lp(c, lnum, 0,
|
||||
c->leb_size - buf_offs, 0, 0);
|
||||
if (err)
|
||||
return err;
|
||||
lnum = -1;
|
||||
continue;
|
||||
}
|
||||
err = ubifs_update_one_lp(c, lnum,
|
||||
c->leb_size - buf_offs, 0, 0, 0);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update buffer positions */
|
||||
wlen = used + len;
|
||||
used += ALIGN(len, 8);
|
||||
|
@ -658,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c)
|
|||
}
|
||||
cnt += 1;
|
||||
while (1) {
|
||||
ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
|
||||
ubifs_assert(!ubifs_zn_cow(znode));
|
||||
__set_bit(COW_ZNODE, &znode->flags);
|
||||
znode->alt = 0;
|
||||
cnext = find_next_dirty(znode);
|
||||
|
@ -704,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
|
|||
c->ilebs[c->ileb_cnt++] = lnum;
|
||||
dbg_cmt("LEB %d", lnum);
|
||||
}
|
||||
if (dbg_force_in_the_gaps())
|
||||
if (dbg_is_chk_index(c) && !(random32() & 7))
|
||||
return -ENOSPC;
|
||||
return 0;
|
||||
}
|
||||
|
@ -830,7 +816,7 @@ static int write_index(struct ubifs_info *c)
|
|||
struct ubifs_idx_node *idx;
|
||||
struct ubifs_znode *znode, *cnext;
|
||||
int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
|
||||
int avail, wlen, err, lnum_pos = 0;
|
||||
int avail, wlen, err, lnum_pos = 0, blen, nxt_offs;
|
||||
|
||||
cnext = c->enext;
|
||||
if (!cnext)
|
||||
|
@ -907,7 +893,7 @@ static int write_index(struct ubifs_info *c)
|
|||
cnext = znode->cnext;
|
||||
|
||||
ubifs_assert(ubifs_zn_dirty(znode));
|
||||
ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
|
||||
ubifs_assert(ubifs_zn_cow(znode));
|
||||
|
||||
/*
|
||||
* It is important that other threads should see %DIRTY_ZNODE
|
||||
|
@ -922,6 +908,28 @@ static int write_index(struct ubifs_info *c)
|
|||
clear_bit(COW_ZNODE, &znode->flags);
|
||||
smp_mb__after_clear_bit();
|
||||
|
||||
/*
|
||||
* We have marked the znode as clean but have not updated the
|
||||
* @c->clean_zn_cnt counter. If this znode becomes dirty again
|
||||
* before 'free_obsolete_znodes()' is called, then
|
||||
* @c->clean_zn_cnt will be decremented before it gets
|
||||
* incremented (resulting in 2 decrements for the same znode).
|
||||
* This means that @c->clean_zn_cnt may become negative for a
|
||||
* while.
|
||||
*
|
||||
* Q: why we cannot increment @c->clean_zn_cnt?
|
||||
* A: because we do not have the @c->tnc_mutex locked, and the
|
||||
* following code would be racy and buggy:
|
||||
*
|
||||
* if (!ubifs_zn_obsolete(znode)) {
|
||||
* atomic_long_inc(&c->clean_zn_cnt);
|
||||
* atomic_long_inc(&ubifs_clean_zn_cnt);
|
||||
* }
|
||||
*
|
||||
* Thus, we just delay the @c->clean_zn_cnt update until we
|
||||
* have the mutex locked.
|
||||
*/
|
||||
|
||||
/* Do not access znode from this point on */
|
||||
|
||||
/* Update buffer positions */
|
||||
|
@ -938,65 +946,38 @@ static int write_index(struct ubifs_info *c)
|
|||
else
|
||||
next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
|
||||
|
||||
if (c->min_io_size == 1) {
|
||||
/*
|
||||
* Write the prepared index node immediately if there is
|
||||
* no minimum IO size
|
||||
*/
|
||||
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
|
||||
wlen, UBI_SHORTTERM);
|
||||
if (err)
|
||||
return err;
|
||||
buf_offs += ALIGN(wlen, 8);
|
||||
if (next_len) {
|
||||
used = 0;
|
||||
avail = buf_len;
|
||||
if (buf_offs + next_len > c->leb_size) {
|
||||
err = ubifs_update_one_lp(c, lnum,
|
||||
LPROPS_NC, 0, 0, LPROPS_TAKEN);
|
||||
if (err)
|
||||
return err;
|
||||
lnum = -1;
|
||||
}
|
||||
nxt_offs = buf_offs + used + next_len;
|
||||
if (next_len && nxt_offs <= c->leb_size) {
|
||||
if (avail > 0)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
blen = buf_len;
|
||||
} else {
|
||||
int blen, nxt_offs = buf_offs + used + next_len;
|
||||
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) {
|
||||
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;
|
||||
/* The buffer is full or there are no more znodes to do */
|
||||
err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
|
||||
UBI_SHORTTERM);
|
||||
if (err)
|
||||
return err;
|
||||
buf_offs += blen;
|
||||
if (next_len) {
|
||||
if (nxt_offs > c->leb_size) {
|
||||
err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
|
||||
0, LPROPS_TAKEN);
|
||||
if (err)
|
||||
return err;
|
||||
lnum = -1;
|
||||
}
|
||||
used -= blen;
|
||||
if (used < 0)
|
||||
used = 0;
|
||||
avail = buf_len - used;
|
||||
memmove(c->cbuf, c->cbuf + blen, used);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1029,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c)
|
|||
do {
|
||||
znode = cnext;
|
||||
cnext = znode->cnext;
|
||||
if (test_bit(OBSOLETE_ZNODE, &znode->flags))
|
||||
if (ubifs_zn_obsolete(znode))
|
||||
kfree(znode);
|
||||
else {
|
||||
znode->cnext = NULL;
|
||||
|
|
|
@ -230,14 +230,14 @@ enum {
|
|||
* LPT cnode flag bits.
|
||||
*
|
||||
* DIRTY_CNODE: cnode is dirty
|
||||
* COW_CNODE: cnode is being committed and must be copied before writing
|
||||
* OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
|
||||
* so it can (and must) be freed when the commit is finished
|
||||
* so it can (and must) be freed when the commit is finished
|
||||
* COW_CNODE: cnode is being committed and must be copied before writing
|
||||
*/
|
||||
enum {
|
||||
DIRTY_CNODE = 0,
|
||||
COW_CNODE = 1,
|
||||
OBSOLETE_CNODE = 2,
|
||||
OBSOLETE_CNODE = 1,
|
||||
COW_CNODE = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1468,6 +1468,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
|
|||
|
||||
/* io.c */
|
||||
void ubifs_ro_mode(struct ubifs_info *c, int err);
|
||||
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
|
||||
int len, int even_ebadmsg);
|
||||
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
|
||||
int len, int dtype);
|
||||
int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
|
||||
int dtype);
|
||||
int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
|
||||
int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
|
||||
int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
|
||||
int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
|
||||
int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
|
||||
int dtype);
|
||||
|
@ -1747,8 +1756,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
|
|||
int offs, void *sbuf, int jhead);
|
||||
struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
|
||||
int offs, void *sbuf);
|
||||
int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
|
||||
int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
|
||||
int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
|
||||
int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
|
||||
int ubifs_rcvry_gc_commit(struct ubifs_info *c);
|
||||
int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
|
||||
int deletion, loff_t new_size);
|
||||
|
|
Loading…
Reference in New Issue