Commit f96c08e8 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'linux-next' of git://git.infradead.org/ubifs-2.6:
  UBIFS: remove fast unmounting
  UBIFS: return sensible error codes
  UBIFS: remount ro fixes
  UBIFS: spelling fix 'date' -> 'data'
  UBIFS: sync wbufs after syncing inodes and pages
  UBIFS: fix LPT out-of-space bug (again)
  UBIFS: fix no_chk_data_crc
  UBIFS: fix assertions
  UBIFS: ensure orphan area head is initialized
  UBIFS: always clean up GC LEB space
  UBIFS: add re-mount debugging checks
  UBIFS: fix LEB list freeing
  UBIFS: simplify locking
  UBIFS: document dark_wm and dead_wm better
  UBIFS: do not treat all data as short term
  UBIFS: constify operations
  UBIFS: do not commit twice
parents 7420b73d 27ad2799
...@@ -79,13 +79,6 @@ Mount options ...@@ -79,13 +79,6 @@ Mount options
(*) == default. (*) == default.
norm_unmount (*) commit on unmount; the journal is committed
when the file-system is unmounted so that the
next mount does not have to replay the journal
and it becomes very fast;
fast_unmount do not commit on unmount; this option makes
unmount faster, but the next mount slower
because of the need to replay the journal.
bulk_read read more in one go to take advantage of flash bulk_read read more in one go to take advantage of flash
media that read faster sequentially media that read faster sequentially
no_bulk_read (*) do not bulk-read no_bulk_read (*) do not bulk-read
......
...@@ -689,7 +689,7 @@ long long ubifs_reported_space(const struct ubifs_info *c, long long free) ...@@ -689,7 +689,7 @@ long long ubifs_reported_space(const struct ubifs_info *c, long long free)
} }
/** /**
* ubifs_get_free_space - return amount of free space. * ubifs_get_free_space_nolock - return amount of free space.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* *
* This function calculates amount of free space to report to user-space. * This function calculates amount of free space to report to user-space.
...@@ -704,16 +704,14 @@ long long ubifs_reported_space(const struct ubifs_info *c, long long free) ...@@ -704,16 +704,14 @@ long long ubifs_reported_space(const struct ubifs_info *c, long long free)
* traditional file-systems, because they have way less overhead than UBIFS. * traditional file-systems, because they have way less overhead than UBIFS.
* So, to keep users happy, UBIFS tries to take the overhead into account. * So, to keep users happy, UBIFS tries to take the overhead into account.
*/ */
long long ubifs_get_free_space(struct ubifs_info *c) long long ubifs_get_free_space_nolock(struct ubifs_info *c)
{ {
int min_idx_lebs, rsvd_idx_lebs, lebs; int rsvd_idx_lebs, lebs;
long long available, outstanding, free; long long available, outstanding, free;
spin_lock(&c->space_lock); ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
min_idx_lebs = c->min_idx_lebs;
ubifs_assert(min_idx_lebs == ubifs_calc_min_idx_lebs(c));
outstanding = c->budg_data_growth + c->budg_dd_growth; outstanding = c->budg_data_growth + c->budg_dd_growth;
available = ubifs_calc_available(c, min_idx_lebs); available = ubifs_calc_available(c, c->min_idx_lebs);
/* /*
* When reporting free space to user-space, UBIFS guarantees that it is * When reporting free space to user-space, UBIFS guarantees that it is
...@@ -726,15 +724,14 @@ long long ubifs_get_free_space(struct ubifs_info *c) ...@@ -726,15 +724,14 @@ long long ubifs_get_free_space(struct ubifs_info *c)
* Note, the calculations below are similar to what we have in * Note, the calculations below are similar to what we have in
* 'do_budget_space()', so refer there for comments. * 'do_budget_space()', so refer there for comments.
*/ */
if (min_idx_lebs > c->lst.idx_lebs) if (c->min_idx_lebs > c->lst.idx_lebs)
rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs; rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs;
else else
rsvd_idx_lebs = 0; rsvd_idx_lebs = 0;
lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt - lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
c->lst.taken_empty_lebs; c->lst.taken_empty_lebs;
lebs -= rsvd_idx_lebs; lebs -= rsvd_idx_lebs;
available += lebs * (c->dark_wm - c->leb_overhead); available += lebs * (c->dark_wm - c->leb_overhead);
spin_unlock(&c->space_lock);
if (available > outstanding) if (available > outstanding)
free = ubifs_reported_space(c, available - outstanding); free = ubifs_reported_space(c, available - outstanding);
...@@ -742,3 +739,21 @@ long long ubifs_get_free_space(struct ubifs_info *c) ...@@ -742,3 +739,21 @@ long long ubifs_get_free_space(struct ubifs_info *c)
free = 0; free = 0;
return free; return free;
} }
/**
* ubifs_get_free_space - return amount of free space.
* @c: UBIFS file-system description object
*
* This function calculates and retuns amount of free space to report to
* user-space.
*/
long long ubifs_get_free_space(struct ubifs_info *c)
{
long long free;
spin_lock(&c->space_lock);
free = ubifs_get_free_space_nolock(c);
spin_unlock(&c->space_lock);
return free;
}
...@@ -620,6 +620,8 @@ void dbg_dump_budg(struct ubifs_info *c) ...@@ -620,6 +620,8 @@ void dbg_dump_budg(struct ubifs_info *c)
c->dark_wm, c->dead_wm, c->max_idx_node_sz); c->dark_wm, c->dead_wm, c->max_idx_node_sz);
printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n", printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
c->gc_lnum, c->ihead_lnum); c->gc_lnum, c->ihead_lnum);
/* If we are in R/O mode, journal heads do not exist */
if (c->jheads)
for (i = 0; i < c->jhead_cnt; i++) for (i = 0; i < c->jhead_cnt; i++)
printk(KERN_DEBUG "\tjhead %d\t LEB %d\n", printk(KERN_DEBUG "\tjhead %d\t LEB %d\n",
c->jheads[i].wbuf.jhead, c->jheads[i].wbuf.lnum); c->jheads[i].wbuf.jhead, c->jheads[i].wbuf.lnum);
...@@ -637,10 +639,7 @@ void dbg_dump_budg(struct ubifs_info *c) ...@@ -637,10 +639,7 @@ void dbg_dump_budg(struct ubifs_info *c)
/* Print budgeting predictions */ /* Print budgeting predictions */
available = ubifs_calc_available(c, c->min_idx_lebs); available = ubifs_calc_available(c, c->min_idx_lebs);
outstanding = c->budg_data_growth + c->budg_dd_growth; outstanding = c->budg_data_growth + c->budg_dd_growth;
if (available > outstanding) free = ubifs_get_free_space_nolock(c);
free = ubifs_reported_space(c, available - outstanding);
else
free = 0;
printk(KERN_DEBUG "Budgeting predictions:\n"); printk(KERN_DEBUG "Budgeting predictions:\n");
printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n", printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
available, outstanding, free); available, outstanding, free);
...@@ -860,6 +859,65 @@ void dbg_dump_index(struct ubifs_info *c) ...@@ -860,6 +859,65 @@ void dbg_dump_index(struct ubifs_info *c)
dbg_walk_index(c, NULL, dump_znode, NULL); dbg_walk_index(c, NULL, dump_znode, NULL);
} }
/**
* dbg_save_space_info - save information about flash space.
* @c: UBIFS file-system description object
*
* This function saves information about UBIFS free space, dirty space, etc, in
* order to check it later.
*/
void dbg_save_space_info(struct ubifs_info *c)
{
struct ubifs_debug_info *d = c->dbg;
ubifs_get_lp_stats(c, &d->saved_lst);
spin_lock(&c->space_lock);
d->saved_free = ubifs_get_free_space_nolock(c);
spin_unlock(&c->space_lock);
}
/**
* dbg_check_space_info - check flash space information.
* @c: UBIFS file-system description object
*
* This function compares current flash space information with the information
* which was saved when the 'dbg_save_space_info()' function was called.
* Returns zero if the information has not changed, and %-EINVAL it it has
* changed.
*/
int dbg_check_space_info(struct ubifs_info *c)
{
struct ubifs_debug_info *d = c->dbg;
struct ubifs_lp_stats lst;
long long avail, free;
spin_lock(&c->space_lock);
avail = ubifs_calc_available(c, c->min_idx_lebs);
spin_unlock(&c->space_lock);
free = ubifs_get_free_space(c);
if (free != d->saved_free) {
ubifs_err("free space changed from %lld to %lld",
d->saved_free, free);
goto out;
}
return 0;
out:
ubifs_msg("saved lprops statistics dump");
dbg_dump_lstats(&d->saved_lst);
ubifs_get_lp_stats(c, &lst);
ubifs_msg("current lprops statistics dump");
dbg_dump_lstats(&d->saved_lst);
spin_lock(&c->space_lock);
dbg_dump_budg(c);
spin_unlock(&c->space_lock);
dump_stack();
return -EINVAL;
}
/** /**
* dbg_check_synced_i_size - check synchronized inode size. * dbg_check_synced_i_size - check synchronized inode size.
* @inode: inode to check * @inode: inode to check
...@@ -1349,7 +1407,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra) ...@@ -1349,7 +1407,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra)
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @leaf_cb: called for each leaf node * @leaf_cb: called for each leaf node
* @znode_cb: called for each indexing node * @znode_cb: called for each indexing node
* @priv: private date which is passed to callbacks * @priv: private data which is passed to callbacks
* *
* This function walks the UBIFS index and calls the @leaf_cb for each leaf * This function walks the UBIFS index and calls the @leaf_cb for each leaf
* node and @znode_cb for each indexing node. Returns zero in case of success * node and @znode_cb for each indexing node. Returns zero in case of success
...@@ -2409,7 +2467,7 @@ void ubifs_debugging_exit(struct ubifs_info *c) ...@@ -2409,7 +2467,7 @@ void ubifs_debugging_exit(struct ubifs_info *c)
* Root directory for UBIFS stuff in debugfs. Contains sub-directories which * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
* contain the stuff specific to particular file-system mounts. * contain the stuff specific to particular file-system mounts.
*/ */
static struct dentry *debugfs_rootdir; static struct dentry *dfs_rootdir;
/** /**
* dbg_debugfs_init - initialize debugfs file-system. * dbg_debugfs_init - initialize debugfs file-system.
...@@ -2421,9 +2479,9 @@ static struct dentry *debugfs_rootdir; ...@@ -2421,9 +2479,9 @@ static struct dentry *debugfs_rootdir;
*/ */
int dbg_debugfs_init(void) int dbg_debugfs_init(void)
{ {
debugfs_rootdir = debugfs_create_dir("ubifs", NULL); dfs_rootdir = debugfs_create_dir("ubifs", NULL);
if (IS_ERR(debugfs_rootdir)) { if (IS_ERR(dfs_rootdir)) {
int err = PTR_ERR(debugfs_rootdir); int err = PTR_ERR(dfs_rootdir);
ubifs_err("cannot create \"ubifs\" debugfs directory, " ubifs_err("cannot create \"ubifs\" debugfs directory, "
"error %d\n", err); "error %d\n", err);
return err; return err;
...@@ -2437,7 +2495,7 @@ int dbg_debugfs_init(void) ...@@ -2437,7 +2495,7 @@ int dbg_debugfs_init(void)
*/ */
void dbg_debugfs_exit(void) void dbg_debugfs_exit(void)
{ {
debugfs_remove(debugfs_rootdir); debugfs_remove(dfs_rootdir);
} }
static int open_debugfs_file(struct inode *inode, struct file *file) static int open_debugfs_file(struct inode *inode, struct file *file)
...@@ -2452,13 +2510,13 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf, ...@@ -2452,13 +2510,13 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
struct ubifs_info *c = file->private_data; struct ubifs_info *c = file->private_data;
struct ubifs_debug_info *d = c->dbg; struct ubifs_debug_info *d = c->dbg;
if (file->f_path.dentry == d->dump_lprops) if (file->f_path.dentry == d->dfs_dump_lprops)
dbg_dump_lprops(c); dbg_dump_lprops(c);
else if (file->f_path.dentry == d->dump_budg) { else if (file->f_path.dentry == d->dfs_dump_budg) {
spin_lock(&c->space_lock); spin_lock(&c->space_lock);
dbg_dump_budg(c); dbg_dump_budg(c);
spin_unlock(&c->space_lock); spin_unlock(&c->space_lock);
} else if (file->f_path.dentry == d->dump_tnc) { } else if (file->f_path.dentry == d->dfs_dump_tnc) {
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
dbg_dump_tnc(c); dbg_dump_tnc(c);
mutex_unlock(&c->tnc_mutex); mutex_unlock(&c->tnc_mutex);
...@@ -2469,7 +2527,7 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf, ...@@ -2469,7 +2527,7 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
return count; return count;
} }
static const struct file_operations debugfs_fops = { static const struct file_operations dfs_fops = {
.open = open_debugfs_file, .open = open_debugfs_file,
.write = write_debugfs_file, .write = write_debugfs_file,
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -2494,36 +2552,32 @@ int dbg_debugfs_init_fs(struct ubifs_info *c) ...@@ -2494,36 +2552,32 @@ int dbg_debugfs_init_fs(struct ubifs_info *c)
struct dentry *dent; struct dentry *dent;
struct ubifs_debug_info *d = c->dbg; struct ubifs_debug_info *d = c->dbg;
sprintf(d->debugfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); sprintf(d->dfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
d->debugfs_dir = debugfs_create_dir(d->debugfs_dir_name, d->dfs_dir = debugfs_create_dir(d->dfs_dir_name, dfs_rootdir);
debugfs_rootdir); if (IS_ERR(d->dfs_dir)) {
if (IS_ERR(d->debugfs_dir)) { err = PTR_ERR(d->dfs_dir);
err = PTR_ERR(d->debugfs_dir);
ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
d->debugfs_dir_name, err); d->dfs_dir_name, err);
goto out; goto out;
} }
fname = "dump_lprops"; fname = "dump_lprops";
dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
&debugfs_fops);
if (IS_ERR(dent)) if (IS_ERR(dent))
goto out_remove; goto out_remove;
d->dump_lprops = dent; d->dfs_dump_lprops = dent;
fname = "dump_budg"; fname = "dump_budg";
dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
&debugfs_fops);
if (IS_ERR(dent)) if (IS_ERR(dent))
goto out_remove; goto out_remove;
d->dump_budg = dent; d->dfs_dump_budg = dent;
fname = "dump_tnc"; fname = "dump_tnc";
dent = debugfs_create_file(fname, S_IWUGO, d->debugfs_dir, c, dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
&debugfs_fops);
if (IS_ERR(dent)) if (IS_ERR(dent))
goto out_remove; goto out_remove;
d->dump_tnc = dent; d->dfs_dump_tnc = dent;
return 0; return 0;
...@@ -2531,7 +2585,7 @@ out_remove: ...@@ -2531,7 +2585,7 @@ out_remove:
err = PTR_ERR(dent); err = PTR_ERR(dent);
ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
fname, err); fname, err);
debugfs_remove_recursive(d->debugfs_dir); debugfs_remove_recursive(d->dfs_dir);
out: out:
return err; return err;
} }
...@@ -2542,7 +2596,7 @@ out: ...@@ -2542,7 +2596,7 @@ out:
*/ */
void dbg_debugfs_exit_fs(struct ubifs_info *c) void dbg_debugfs_exit_fs(struct ubifs_info *c)
{ {
debugfs_remove_recursive(c->dbg->debugfs_dir); debugfs_remove_recursive(c->dbg->dfs_dir);
} }
#endif /* CONFIG_UBIFS_FS_DEBUG */ #endif /* CONFIG_UBIFS_FS_DEBUG */
...@@ -41,15 +41,17 @@ ...@@ -41,15 +41,17 @@
* @chk_lpt_wastage: used by LPT tree size checker * @chk_lpt_wastage: used by LPT tree size checker
* @chk_lpt_lebs: used by LPT tree size checker * @chk_lpt_lebs: used by LPT tree size checker
* @new_nhead_offs: used by LPT tree size checker * @new_nhead_offs: used by LPT tree size checker
* @new_ihead_lnum: used by debugging to check ihead_lnum * @new_ihead_lnum: used by debugging to check @c->ihead_lnum
* @new_ihead_offs: used by debugging to check ihead_offs * @new_ihead_offs: used by debugging to check @c->ihead_offs
* *
* debugfs_dir_name: name of debugfs directory containing this file-system's * @saved_lst: saved lprops statistics (used by 'dbg_save_space_info()')
* files * @saved_free: saved free space (used by 'dbg_save_space_info()')
* debugfs_dir: direntry object of the file-system debugfs directory *
* dump_lprops: "dump lprops" debugfs knob * dfs_dir_name: name of debugfs directory containing this file-system's files
* dump_budg: "dump budgeting information" debugfs knob * dfs_dir: direntry object of the file-system debugfs directory
* dump_tnc: "dump TNC" debugfs knob * dfs_dump_lprops: "dump lprops" debugfs knob
* dfs_dump_budg: "dump budgeting information" debugfs knob
* dfs_dump_tnc: "dump TNC" debugfs knob
*/ */
struct ubifs_debug_info { struct ubifs_debug_info {
void *buf; void *buf;
...@@ -69,11 +71,14 @@ struct ubifs_debug_info { ...@@ -69,11 +71,14 @@ struct ubifs_debug_info {
int new_ihead_lnum; int new_ihead_lnum;
int new_ihead_offs; int new_ihead_offs;
char debugfs_dir_name[100]; struct ubifs_lp_stats saved_lst;
struct dentry *debugfs_dir; long long saved_free;
struct dentry *dump_lprops;
struct dentry *dump_budg; char dfs_dir_name[100];
struct dentry *dump_tnc; struct dentry *dfs_dir;
struct dentry *dfs_dump_lprops;
struct dentry *dfs_dump_budg;
struct dentry *dfs_dump_tnc;
}; };
#define ubifs_assert(expr) do { \ #define ubifs_assert(expr) do { \
...@@ -297,7 +302,8 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, ...@@ -297,7 +302,8 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
dbg_znode_callback znode_cb, void *priv); dbg_znode_callback znode_cb, void *priv);
/* Checking functions */ /* Checking functions */
void dbg_save_space_info(struct ubifs_info *c);
int dbg_check_space_info(struct ubifs_info *c);
int dbg_check_lprops(struct ubifs_info *c); int dbg_check_lprops(struct ubifs_info *c);
int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot); int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot);
int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot); int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot);
...@@ -439,6 +445,8 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c); ...@@ -439,6 +445,8 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
#define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0 #define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0
#define dbg_old_index_check_init(c, zroot) 0 #define dbg_old_index_check_init(c, zroot) 0
#define dbg_save_space_info(c) ({})
#define dbg_check_space_info(c) 0
#define dbg_check_old_index(c, zroot) 0 #define dbg_check_old_index(c, zroot) 0
#define dbg_check_cats(c) 0 #define dbg_check_cats(c) 0
#define dbg_check_ltab(c) 0 #define dbg_check_ltab(c) 0
......
...@@ -482,30 +482,29 @@ static int ubifs_dir_release(struct inode *dir, struct file *file) ...@@ -482,30 +482,29 @@ static int ubifs_dir_release(struct inode *dir, struct file *file)
} }
/** /**
* lock_2_inodes - lock two UBIFS inodes. * lock_2_inodes - a wrapper for locking two UBIFS inodes.
* @inode1: first inode * @inode1: first inode
* @inode2: second inode * @inode2: second inode
*
* We do not implement any tricks to guarantee strict lock ordering, because
* VFS has already done it for us on the @i_mutex. So this is just a simple
* wrapper function.
*/ */
static void lock_2_inodes(struct inode *inode1, struct inode *inode2) static void lock_2_inodes(struct inode *inode1, struct inode *inode2)
{ {
if (inode1->i_ino < inode2->i_ino) { mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_2);
mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_3);
} else {
mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_3);
}
} }
/** /**
* unlock_2_inodes - unlock two UBIFS inodes inodes. * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes.
* @inode1: first inode * @inode1: first inode
* @inode2: second inode * @inode2: second inode
*/ */
static void unlock_2_inodes(struct inode *inode1, struct inode *inode2) static void unlock_2_inodes(struct inode *inode1, struct inode *inode2)
{ {
mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
mutex_unlock(&ubifs_inode(inode2)->ui_mutex); mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
} }
static int ubifs_link(struct dentry *old_dentry, struct inode *dir, static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
...@@ -527,6 +526,8 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -527,6 +526,8 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
dbg_gen("dent '%.*s' to ino %lu (nlink %d) in dir ino %lu", dbg_gen("dent '%.*s' to ino %lu (nlink %d) in dir ino %lu",
dentry->d_name.len, dentry->d_name.name, inode->i_ino, dentry->d_name.len, dentry->d_name.name, inode->i_ino,
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(&inode->i_mutex));
err = dbg_check_synced_i_size(inode); err = dbg_check_synced_i_size(inode);
if (err) if (err)
return err; return err;
...@@ -580,6 +581,8 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -580,6 +581,8 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
dbg_gen("dent '%.*s' from ino %lu (nlink %d) in dir ino %lu", dbg_gen("dent '%.*s' from ino %lu (nlink %d) in dir ino %lu",
dentry->d_name.len, dentry->d_name.name, inode->i_ino, dentry->d_name.len, dentry->d_name.name, inode->i_ino,
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(&inode->i_mutex));
err = dbg_check_synced_i_size(inode); err = dbg_check_synced_i_size(inode);
if (err) if (err)
return err; return err;
...@@ -667,7 +670,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -667,7 +670,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
dbg_gen("directory '%.*s', ino %lu in dir ino %lu", dentry->d_name.len, dbg_gen("directory '%.*s', ino %lu in dir ino %lu", dentry->d_name.len,
dentry->d_name.name, inode->i_ino, dir->i_ino); dentry->d_name.name, inode->i_ino, dir->i_ino);
ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex));
err = check_dir_empty(c, dentry->d_inode); err = check_dir_empty(c, dentry->d_inode);
if (err) if (err)
return err; return err;
...@@ -922,59 +926,30 @@ out_budg: ...@@ -922,59 +926,30 @@ out_budg:
} }
/** /**
* lock_3_inodes - lock three UBIFS inodes for rename. * lock_3_inodes - a wrapper for locking three UBIFS inodes.
* @inode1: first inode * @inode1: first inode
* @inode2: second inode * @inode2: second inode
* @inode3: third inode * @inode3: third inode
* *
* For 'ubifs_rename()', @inode1 may be the same as @inode2 whereas @inode3 may * This function is used for 'ubifs_rename()' and @inode1 may be the same as
* be null. * @inode2 whereas @inode3 may be %NULL.
*
* We do not implement any tricks to guarantee strict lock ordering, because
* VFS has already done it for us on the @i_mutex. So this is just a simple
* wrapper function.
*/ */
static void lock_3_inodes(struct inode *inode1, struct inode *inode2, static void lock_3_inodes(struct inode *inode1, struct inode *inode2,
struct inode *inode3) struct inode *inode3)
{ {
struct inode *i1, *i2, *i3;
if (!inode3) {
if (inode1 != inode2) {
lock_2_inodes(inode1, inode2);
return;
}
mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
return; if (inode2 != inode1)
} mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
if (inode3)
if (inode1 == inode2) { mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3);
lock_2_inodes(inode1, inode3);
return;
}
/* 3 different inodes */
if (inode1 < inode2) {
i3 = inode2;
if (inode1 < inode3) {
i1 = inode1;
i2 = inode3;
} else {
i1 = inode3;
i2 = inode1;
}
} else {
i3 = inode1;
if (inode2 < inode3) {
i1 = inode2;
i2 = inode3;
} else {
i1 = inode3;
i2 = inode2;
}
}
mutex_lock_nested(&ubifs_inode(i1)->ui_mutex, WB_MUTEX_1);
lock_2_inodes(i2, i3);
} }
/** /**
* unlock_3_inodes - unlock three UBIFS inodes for rename. * unlock_3_inodes - a wrapper for unlocking three UBIFS inodes for rename.
* @inode1: first inode * @inode1: first inode
* @inode2: second inode * @inode2: second inode
* @inode3: third inode * @inode3: third inode
...@@ -982,11 +957,11 @@ static void lock_3_inodes(struct inode *inode1, struct inode *inode2, ...@@ -982,11 +957,11 @@ static void lock_3_inodes(struct inode *inode1, struct inode *inode2,
static void unlock_3_inodes(struct inode *inode1, struct inode *inode2, static void unlock_3_inodes(struct inode *inode1, struct inode *inode2,
struct inode *inode3) struct inode *inode3)
{ {
mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
if (inode1 != inode2)
mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
if (inode3) if (inode3)
mutex_unlock(&ubifs_inode(inode3)->ui_mutex); mutex_unlock(&ubifs_inode(inode3)->ui_mutex);
if (inode1 != inode2)
mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
} }
static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
...@@ -1020,6 +995,11 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1020,6 +995,11 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
"dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name, "dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name,
old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len, old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len,
new_dentry->d_name.name, new_dir->i_ino); new_dentry->d_name.name, new_dir->i_ino);
ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
ubifs_assert(mutex_is_locked(&new_dir->i_mutex));
if (unlink)
ubifs_assert(mutex_is_locked(&new_inode->i_mutex));
if (unlink && is_dir) { if (unlink && is_dir) {
err = check_dir_empty(c, new_inode); err = check_dir_empty(c, new_inode);
...@@ -1199,7 +1179,7 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -1199,7 +1179,7 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
return 0; return 0;
} }
struct inode_operations ubifs_dir_inode_operations = { const struct inode_operations ubifs_dir_inode_operations = {
.lookup = ubifs_lookup, .lookup = ubifs_lookup,
.create = ubifs_create, .create = ubifs_create,
.link = ubifs_link, .link = ubifs_link,
...@@ -1219,7 +1199,7 @@ struct inode_operations ubifs_dir_inode_operations = { ...@@ -1219,7 +1199,7 @@ struct inode_operations ubifs_dir_inode_operations = {
#endif #endif
}; };
struct file_operations ubifs_dir_operations = { const struct file_operations ubifs_dir_operations = {
.llseek = ubifs_dir_llseek, .llseek = ubifs_dir_llseek,
.release = ubifs_dir_release, .release = ubifs_dir_release,
.read = generic_read_dir, .read = generic_read_dir,
......
...@@ -432,7 +432,6 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping, ...@@ -432,7 +432,6 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
int uninitialized_var(err), appending = !!(pos + len > inode->i_size); int uninitialized_var(err), appending = !!(pos + len > inode->i_size);
struct page *page; struct page *page;
ubifs_assert(ubifs_inode(inode)->ui_size == inode->i_size); ubifs_assert(ubifs_inode(inode)->ui_size == inode->i_size);
if (unlikely(c->ro_media)) if (unlikely(c->ro_media))
...@@ -1541,7 +1540,7 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1541,7 +1540,7 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
return 0; return 0;
} }
struct address_space_operations ubifs_file_address_operations = { const struct address_space_operations ubifs_file_address_operations = {
.readpage = ubifs_readpage, .readpage = ubifs_readpage,
.writepage = ubifs_writepage, .writepage = ubifs_writepage,
.write_begin = ubifs_write_begin, .write_begin = ubifs_write_begin,
...@@ -1551,7 +1550,7 @@ struct address_space_operations ubifs_file_address_operations = { ...@@ -1551,7 +1550,7 @@ struct address_space_operations ubifs_file_address_operations = {
.releasepage = ubifs_releasepage, .releasepage = ubifs_releasepage,
}; };
struct inode_operations ubifs_file_inode_operations = { const struct inode_operations ubifs_file_inode_operations = {
.setattr = ubifs_setattr, .setattr = ubifs_setattr,
.getattr = ubifs_getattr, .getattr = ubifs_getattr,
#ifdef CONFIG_UBIFS_FS_XATTR #ifdef CONFIG_UBIFS_FS_XATTR
...@@ -1562,14 +1561,14 @@ struct inode_operations ubifs_file_inode_operations = { ...@@ -1562,14 +1561,14 @@ struct inode_operations ubifs_file_inode_operations = {
#endif #endif
}; };
struct inode_operations ubifs_symlink_inode_operations = { const struct inode_operations ubifs_symlink_inode_operations = {
.readlink = generic_readlink, .readlink = generic_readlink,
.follow_link = ubifs_follow_link, .follow_link = ubifs_follow_link,
.setattr = ubifs_setattr, .setattr = ubifs_setattr,
.getattr = ubifs_getattr, .getattr = ubifs_getattr,
}; };
struct file_operations ubifs_file_operations = { const struct file_operations ubifs_file_operations = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
.read = do_sync_read, .read = do_sync_read,
.write = do_sync_write, .write = do_sync_write,
......
...@@ -31,6 +31,26 @@ ...@@ -31,6 +31,26 @@
* to be reused. Garbage collection will cause the number of dirty index nodes * to be reused. Garbage collection will cause the number of dirty index nodes
* to grow, however sufficient space is reserved for the index to ensure the * to grow, however sufficient space is reserved for the index to ensure the
* commit will never run out of space. * commit will never run out of space.
*
* Notes about dead watermark. At current UBIFS implementation we assume that
* LEBs which have less than @c->dead_wm bytes of free + dirty space are full
* and not worth garbage-collecting. The dead watermark is one min. I/O unit
* size, or min. UBIFS node size, depending on what is greater. Indeed, UBIFS
* Garbage Collector has to synchronize the GC head's write buffer before
* returning, so this is about wasting one min. I/O unit. However, UBIFS GC can
* actually reclaim even very small pieces of dirty space by garbage collecting
* enough dirty LEBs, but we do not bother doing this at this implementation.
*
* Notes about dark watermark. The results of GC work depends on how big are
* the UBIFS nodes GC deals with. Large nodes make GC waste more space. Indeed,
* if GC move data from LEB A to LEB B and nodes in LEB A are large, GC would
* have to waste large pieces of free space at the end of LEB B, because nodes
* from LEB A would not fit. And the worst situation is when all nodes are of
* maximum size. So dark watermark is the amount of free + dirty space in LEB
* which are guaranteed to be reclaimable. If LEB has less space, the GC migh
* be unable to reclaim it. So, LEBs with free + dirty greater than dark
* watermark are "good" LEBs from GC's point of few. The other LEBs are not so
* good, and GC takes extra care when moving them.
*/ */
#include <linux/pagemap.h> #include <linux/pagemap.h>
...@@ -381,7 +401,7 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp) ...@@ -381,7 +401,7 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
/* /*
* Don't release the LEB until after the next commit, because * Don't release the LEB until after the next commit, because
* it may contain date which is needed for recovery. So * it may contain data which is needed for recovery. So
* although we freed this LEB, it will become usable only after * although we freed this LEB, it will become usable only after
* the commit. * the commit.
*/ */
...@@ -810,8 +830,9 @@ out: ...@@ -810,8 +830,9 @@ out:
* ubifs_destroy_idx_gc - destroy idx_gc list. * ubifs_destroy_idx_gc - destroy idx_gc list.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* *
* This function destroys the idx_gc list. It is called when unmounting or * This function destroys the @c->idx_gc list. It is called when unmounting
* remounting read-only so locks are not needed. * so locks are not needed. Returns zero in case of success and a negative
* error code in case of failure.
*/ */
void ubifs_destroy_idx_gc(struct ubifs_info *c) void ubifs_destroy_idx_gc(struct ubifs_info *c)
{ {
...@@ -824,7 +845,6 @@ void ubifs_destroy_idx_gc(struct ubifs_info *c) ...@@ -824,7 +845,6 @@ void ubifs_destroy_idx_gc(struct ubifs_info *c)
list_del(&idx_gc->list); list_del(&idx_gc->list);
kfree(idx_gc); kfree(idx_gc);
} }
} }
/** /**
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* would have been wasted for padding to the nearest minimal I/O unit boundary. * would have been wasted for padding to the nearest minimal I/O unit boundary.
* Instead, data first goes to the write-buffer and is flushed when the * Instead, data first goes to the write-buffer and is flushed when the
* buffer is full or when it is not used for some time (by timer). This is * buffer is full or when it is not used for some time (by timer). This is
* similarto the mechanism is used by JFFS2. * similar to the mechanism is used by JFFS2.
* *
* Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
* mutexes defined inside these objects. Since sometimes upper-level code * mutexes defined inside these objects. Since sometimes upper-level code
...@@ -75,7 +75,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err) ...@@ -75,7 +75,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
* @lnum: logical eraseblock number * @lnum: logical eraseblock number
* @offs: offset within the logical eraseblock * @offs: offset within the logical eraseblock
* @quiet: print no messages * @quiet: print no messages
* @chk_crc: indicates whether to always check the CRC * @must_chk_crc: indicates whether to always check the CRC
* *
* This function checks node magic number and CRC checksum. This function also * This function checks node magic number and CRC checksum. This function also
* validates node length to prevent UBIFS from becoming crazy when an attacker * validates node length to prevent UBIFS from becoming crazy when an attacker
...@@ -83,11 +83,17 @@ void ubifs_ro_mode(struct ubifs_info *c, int err) ...@@ -83,11 +83,17 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
* node length in the common header could cause UBIFS to read memory outside of * node length in the common header could cause UBIFS to read memory outside of
* allocated buffer when checking the CRC checksum. * allocated buffer when checking the CRC checksum.
* *
* This function returns zero in case of success %-EUCLEAN in case of bad CRC * This function may skip data nodes CRC checking if @c->no_chk_data_crc is
* or magic. * true, which is controlled by corresponding UBIFS mount option. However, if
* @must_chk_crc is true, then @c->no_chk_data_crc is ignored and CRC is
* checked. Similarly, if @c->always_chk_crc is true, @c->no_chk_data_crc is
* ignored and CRC is checked.
*
* This function returns zero in case of success and %-EUCLEAN in case of bad
* CRC or magic.
*/ */
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
int offs, int quiet, int chk_crc) int offs, int quiet, int must_chk_crc)
{ {
int err = -EINVAL, type, node_len; int err = -EINVAL, type, node_len;
uint32_t crc, node_crc, magic; uint32_t crc, node_crc, magic;
...@@ -123,8 +129,8 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, ...@@ -123,8 +129,8 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
node_len > c->ranges[type].max_len) node_len > c->ranges[type].max_len)
goto out_len; goto out_len;
if (!chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc) if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc &&
if (c->no_chk_data_crc) c->no_chk_data_crc)
return 0; return 0;
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
......
...@@ -208,7 +208,7 @@ again: ...@@ -208,7 +208,7 @@ again:
offs = 0; offs = 0;
out: out:
err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, UBI_SHORTTERM); err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
if (err) if (err)
goto out_unlock; goto out_unlock;
......
...@@ -635,10 +635,10 @@ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c, ...@@ -635,10 +635,10 @@ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @st: return statistics * @st: return statistics
*/ */
void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *st) void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
{ {
spin_lock(&c->space_lock); spin_lock(&c->space_lock);
memcpy(st, &c->lst, sizeof(struct ubifs_lp_stats)); memcpy(lst, &c->lst, sizeof(struct ubifs_lp_stats));
spin_unlock(&c->space_lock); spin_unlock(&c->space_lock);
} }
...@@ -678,6 +678,9 @@ int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, ...@@ -678,6 +678,9 @@ int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
out: out:
ubifs_release_lprops(c); ubifs_release_lprops(c);
if (err)
ubifs_err("cannot change properties of LEB %d, error %d",
lnum, err);
return err; return err;
} }
...@@ -714,6 +717,9 @@ int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, ...@@ -714,6 +717,9 @@ int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
out: out:
ubifs_release_lprops(c); ubifs_release_lprops(c);
if (err)
ubifs_err("cannot update properties of LEB %d, error %d",
lnum, err);
return err; return err;
} }
...@@ -737,6 +743,8 @@ int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp) ...@@ -737,6 +743,8 @@ int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
lpp = ubifs_lpt_lookup(c, lnum); lpp = ubifs_lpt_lookup(c, lnum);
if (IS_ERR(lpp)) { if (IS_ERR(lpp)) {
err = PTR_ERR(lpp); err = PTR_ERR(lpp);
ubifs_err("cannot read properties of LEB %d, error %d",
lnum, err);
goto out; goto out;
} }
......
...@@ -556,13 +556,15 @@ no_space: ...@@ -556,13 +556,15 @@ no_space:
} }
/** /**
* next_pnode - find next pnode. * next_pnode_to_dirty - find next pnode to dirty.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @pnode: pnode * @pnode: pnode
* *
* This function returns the next pnode or %NULL if there are no more pnodes. * This function returns the next pnode to dirty or %NULL if there are no more
* pnodes. Note that pnodes that have never been written (lnum == 0) are
* skipped.
*/ */
static struct ubifs_pnode *next_pnode(struct ubifs_info *c, static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
struct ubifs_pnode *pnode) struct ubifs_pnode *pnode)
{ {
struct ubifs_nnode *nnode; struct ubifs_nnode *nnode;
...@@ -570,9 +572,7 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c, ...@@ -570,9 +572,7 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c,
/* Try to go right */ /* Try to go right */
nnode = pnode->parent; nnode = pnode->parent;
iip = pnode->iip + 1; for (iip = pnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
if (iip < UBIFS_LPT_FANOUT) {
/* We assume here that LEB zero is never an LPT LEB */
if (nnode->nbranch[iip].lnum) if (nnode->nbranch[iip].lnum)
return ubifs_get_pnode(c, nnode, iip); return ubifs_get_pnode(c, nnode, iip);
} }
...@@ -583,8 +583,11 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c, ...@@ -583,8 +583,11 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c,
nnode = nnode->parent; nnode = nnode->parent;
if (!nnode) if (!nnode)
return NULL; return NULL;
/* We assume here that LEB zero is never an LPT LEB */ for (; iip < UBIFS_LPT_FANOUT; iip++) {
} while (iip >= UBIFS_LPT_FANOUT || !nnode->nbranch[iip].lnum); if (nnode->nbranch[iip].lnum)
break;
}
} while (iip >= UBIFS_LPT_FANOUT);
/* Go right */ /* Go right */
nnode = ubifs_get_nnode(c, nnode, iip); nnode = ubifs_get_nnode(c, nnode, iip);
...@@ -593,12 +596,29 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c, ...@@ -593,12 +596,29 @@ static struct ubifs_pnode *next_pnode(struct ubifs_info *c,
/* Go down to level 1 */ /* Go down to level 1 */
while (nnode->level > 1) { while (nnode->level > 1) {
nnode = ubifs_get_nnode(c, nnode, 0); for (iip = 0; iip < UBIFS_LPT_FANOUT; iip++) {
if (nnode->nbranch[iip].lnum)
break;
}
if (iip >= UBIFS_LPT_FANOUT) {
/*
* Should not happen, but we need to keep going
* if it does.
*/
iip = 0;
}
nnode = ubifs_get_nnode(c, nnode, iip);
if (IS_ERR(nnode)) if (IS_ERR(nnode))
return (void *)nnode; return (void *)nnode;
} }
return ubifs_get_pnode(c, nnode, 0); for (iip = 0; iip < UBIFS_LPT_FANOUT; iip++)
if (nnode->nbranch[iip].lnum)
break;
if (iip >= UBIFS_LPT_FANOUT)
/* Should not happen, but we need to keep going if it does */
iip = 0;
return ubifs_get_pnode(c, nnode, iip);
} }
/** /**
...@@ -688,7 +708,7 @@ static int make_tree_dirty(struct ubifs_info *c) ...@@ -688,7 +708,7 @@ static int make_tree_dirty(struct ubifs_info *c)
pnode = pnode_lookup(c, 0); pnode = pnode_lookup(c, 0);
while (pnode) { while (pnode) {
do_make_pnode_dirty(c, pnode); do_make_pnode_dirty(c, pnode);
pnode = next_pnode(c, pnode); pnode = next_pnode_to_dirty(c, pnode);
if (IS_ERR(pnode)) if (IS_ERR(pnode))
return PTR_ERR(pnode); return PTR_ERR(pnode);
} }
......
...@@ -354,7 +354,7 @@ int ubifs_write_master(struct ubifs_info *c) ...@@ -354,7 +354,7 @@ int ubifs_write_master(struct ubifs_info *c)
int err, lnum, offs, len; int err, lnum, offs, len;
if (c->ro_media) if (c->ro_media)
return -EINVAL; return -EROFS;
lnum = UBIFS_MST_LNUM; lnum = UBIFS_MST_LNUM;
offs = c->mst_offs + c->mst_node_alsz; offs = c->mst_offs + c->mst_node_alsz;
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
* Orphans are accumulated in a rb-tree. When an inode's link count drops to * Orphans are accumulated in a rb-tree. When an inode's link count drops to
* zero, the inode number is added to the rb-tree. It is removed from the tree * zero, the inode number is added to the rb-tree. It is removed from the tree
* when the inode is deleted. Any new orphans that are in the orphan tree when * when the inode is deleted. Any new orphans that are in the orphan tree when
* the commit is run, are written to the orphan area in 1 or more orph nodes. * the commit is run, are written to the orphan area in 1 or more orphan nodes.
* If the orphan area is full, it is consolidated to make space. There is * If the orphan area is full, it is consolidated to make space. There is
* always enough space because validation prevents the user from creating more * always enough space because validation prevents the user from creating more
* than the maximum number of orphans allowed. * than the maximum number of orphans allowed.
...@@ -231,7 +231,7 @@ static int tot_avail_orphs(struct ubifs_info *c) ...@@ -231,7 +231,7 @@ static int tot_avail_orphs(struct ubifs_info *c)
} }
/** /**
* do_write_orph_node - write a node * do_write_orph_node - write a node to the orphan head.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @len: length of node * @len: length of node
* @atomic: write atomically * @atomic: write atomically
...@@ -264,11 +264,11 @@ static int do_write_orph_node(struct ubifs_info *c, int len, int atomic) ...@@ -264,11 +264,11 @@ static int do_write_orph_node(struct ubifs_info *c, int len, int atomic)
} }
/** /**
* write_orph_node - write an orph node * write_orph_node - write an orphan node.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @atomic: write atomically * @atomic: write atomically
* *
* This function builds an orph node from the cnext list and writes it to the * This function builds an orphan node from the cnext list and writes it to the
* orphan head. On success, %0 is returned, otherwise a negative error code * orphan head. On success, %0 is returned, otherwise a negative error code
* is returned. * is returned.
*/ */
...@@ -326,11 +326,11 @@ static int write_orph_node(struct ubifs_info *c, int atomic) ...@@ -326,11 +326,11 @@ static int write_orph_node(struct ubifs_info *c, int atomic)
} }
/** /**
* write_orph_nodes - write orph nodes until there are no more to commit * write_orph_nodes - write orphan nodes until there are no more to commit.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @atomic: write atomically * @atomic: write atomically
* *
* This function writes orph nodes for all the orphans to commit. On success, * This function writes orphan nodes for all the orphans to commit. On success,
* %0 is returned, otherwise a negative error code is returned. * %0 is returned, otherwise a negative error code is returned.
*/ */
static int write_orph_nodes(struct ubifs_info *c, int atomic) static int write_orph_nodes(struct ubifs_info *c, int atomic)
...@@ -478,14 +478,14 @@ int ubifs_orphan_end_commit(struct ubifs_info *c) ...@@ -478,14 +478,14 @@ int ubifs_orphan_end_commit(struct ubifs_info *c)
} }
/** /**
* clear_orphans - erase all LEBs used for orphans. * ubifs_clear_orphans - erase all LEBs used for orphans.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* *
* If recovery is not required, then the orphans from the previous session * If recovery is not required, then the orphans from the previous session
* are not needed. This function locates the LEBs used to record * are not needed. This function locates the LEBs used to record
* orphans, and un-maps them. * orphans, and un-maps them.
*/ */
static int clear_orphans(struct ubifs_info *c) int ubifs_clear_orphans(struct ubifs_info *c)
{ {
int lnum, err; int lnum, err;
...@@ -547,9 +547,9 @@ static int insert_dead_orphan(struct ubifs_info *c, ino_t inum) ...@@ -547,9 +547,9 @@ static int insert_dead_orphan(struct ubifs_info *c, ino_t inum)
* do_kill_orphans - remove orphan inodes from the index. * do_kill_orphans - remove orphan inodes from the index.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @sleb: scanned LEB * @sleb: scanned LEB
* @last_cmt_no: cmt_no of last orph node read is passed and returned here * @last_cmt_no: cmt_no of last orphan node read is passed and returned here
* @outofdate: whether the LEB is out of date is returned here * @outofdate: whether the LEB is out of date is returned here
* @last_flagged: whether the end orph node is encountered * @last_flagged: whether the end orphan node is encountered
* *
* This function is a helper to the 'kill_orphans()' function. It goes through * This function is a helper to the 'kill_orphans()' function. It goes through
* every orphan node in a LEB and for every inode number recorded, removes * every orphan node in a LEB and for every inode number recorded, removes
...@@ -580,8 +580,8 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -580,8 +580,8 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
/* /*
* The commit number on the master node may be less, because * The commit number on the master node may be less, because
* of a failed commit. If there are several failed commits in a * of a failed commit. If there are several failed commits in a
* row, the commit number written on orph nodes will continue to * row, the commit number written on orphan nodes will continue
* increase (because the commit number is adjusted here) even * to increase (because the commit number is adjusted here) even
* though the commit number on the master node stays the same * though the commit number on the master node stays the same
* because the master node has not been re-written. * because the master node has not been re-written.
*/ */
...@@ -589,9 +589,9 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -589,9 +589,9 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
c->cmt_no = cmt_no; c->cmt_no = cmt_no;
if (cmt_no < *last_cmt_no && *last_flagged) { if (cmt_no < *last_cmt_no && *last_flagged) {
/* /*
* The last orph node had a higher commit number and was * The last orphan node had a higher commit number and
* flagged as the last written for that commit number. * was flagged as the last written for that commit
* That makes this orph node, out of date. * number. That makes this orphan node, out of date.
*/ */
if (!first) { if (!first) {
ubifs_err("out of order commit number %llu in " ubifs_err("out of order commit number %llu in "
...@@ -658,10 +658,10 @@ static int kill_orphans(struct ubifs_info *c) ...@@ -658,10 +658,10 @@ static int kill_orphans(struct ubifs_info *c)
/* /*
* Orph nodes always start at c->orph_first and are written to each * Orph nodes always start at c->orph_first and are written to each
* successive LEB in turn. Generally unused LEBs will have been unmapped * successive LEB in turn. Generally unused LEBs will have been unmapped
* but may contain out of date orph nodes if the unmap didn't go * but may contain out of date orphan nodes if the unmap didn't go
* through. In addition, the last orph node written for each commit is * through. In addition, the last orphan node written for each commit is
* marked (top bit of orph->cmt_no is set to 1). It is possible that * marked (top bit of orph->cmt_no is set to 1). It is possible that
* there are orph nodes from the next commit (i.e. the commit did not * there are orphan nodes from the next commit (i.e. the commit did not
* complete successfully). In that case, no orphans will have been lost * complete successfully). In that case, no orphans will have been lost
* due to the way that orphans are written, and any orphans added will * due to the way that orphans are written, and any orphans added will
* be valid orphans anyway and so can be deleted. * be valid orphans anyway and so can be deleted.
...@@ -718,7 +718,7 @@ int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only) ...@@ -718,7 +718,7 @@ int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only)
if (unclean) if (unclean)
err = kill_orphans(c); err = kill_orphans(c);
else if (!read_only) else if (!read_only)
err = clear_orphans(c); err = ubifs_clear_orphans(c);
return err; return err;
} }
......
...@@ -397,6 +397,7 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -397,6 +397,7 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_namelen = UBIFS_MAX_NLEN; buf->f_namelen = UBIFS_MAX_NLEN;
buf->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[2]); buf->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[2]);
buf->f_fsid.val[1] = le32_to_cpu(uuid[1]) ^ le32_to_cpu(uuid[3]); buf->f_fsid.val[1] = le32_to_cpu(uuid[1]) ^ le32_to_cpu(uuid[3]);
ubifs_assert(buf->f_bfree <= c->block_cnt);
return 0; return 0;
} }
...@@ -432,32 +433,23 @@ static int ubifs_sync_fs(struct super_block *sb, int wait) ...@@ -432,32 +433,23 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
int i, err; int i, err;
struct ubifs_info *c = sb->s_fs_info; struct ubifs_info *c = sb->s_fs_info;
struct writeback_control wbc = { struct writeback_control wbc = {
.sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_NONE, .sync_mode = WB_SYNC_ALL,
.range_start = 0, .range_start = 0,
.range_end = LLONG_MAX, .range_end = LLONG_MAX,
.nr_to_write = LONG_MAX, .nr_to_write = LONG_MAX,
}; };
/* /*
* Note by akpm about WB_SYNC_NONE used above: zero @wait is just an * Zero @wait is just an advisory thing to help the file system shove
* advisory thing to help the file system shove lots of data into the * lots of data into the queues, and there will be the second
* queues. If some gets missed then it'll be picked up on the second
* '->sync_fs()' call, with non-zero @wait. * '->sync_fs()' call, with non-zero @wait.
*/ */
if (!wait)
return 0;
if (sb->s_flags & MS_RDONLY) if (sb->s_flags & MS_RDONLY)
return 0; return 0;
/*
* Synchronize write buffers, because 'ubifs_run_commit()' does not
* do this if it waits for an already running commit.
*/
for (i = 0; i < c->jhead_cnt; i++) {
err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
if (err)
return err;
}
/* /*
* VFS calls '->sync_fs()' before synchronizing all dirty inodes and * VFS calls '->sync_fs()' before synchronizing all dirty inodes and
* pages, so synchronize them first, then commit the journal. Strictly * pages, so synchronize them first, then commit the journal. Strictly
...@@ -469,6 +461,16 @@ static int ubifs_sync_fs(struct super_block *sb, int wait) ...@@ -469,6 +461,16 @@ static int ubifs_sync_fs(struct super_block *sb, int wait)
*/ */
generic_sync_sb_inodes(sb, &wbc); generic_sync_sb_inodes(sb, &wbc);
/*
* Synchronize write buffers, because 'ubifs_run_commit()' does not
* do this if it waits for an already running commit.
*/
for (i = 0; i < c->jhead_cnt; i++) {
err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
if (err)
return err;
}
err = ubifs_run_commit(c); err = ubifs_run_commit(c);
if (err) if (err)
return err; return err;
...@@ -572,15 +574,8 @@ static int init_constants_early(struct ubifs_info *c) ...@@ -572,15 +574,8 @@ static int init_constants_early(struct ubifs_info *c)
c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX; c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX;
/* /*
* Initialize dead and dark LEB space watermarks. * Initialize dead and dark LEB space watermarks. See gc.c for comments
* * about these values.
* Dead space is the space which cannot be used. Its watermark is
* equivalent to min. I/O unit or minimum node size if it is greater
* then min. I/O unit.
*
* Dark space is the space which might be used, or might not, depending
* on which node should be written to the LEB. Its watermark is
* equivalent to maximum UBIFS node size.
*/ */
c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
...@@ -741,12 +736,12 @@ static void init_constants_master(struct ubifs_info *c) ...@@ -741,12 +736,12 @@ static void init_constants_master(struct ubifs_info *c)
* take_gc_lnum - reserve GC LEB. * take_gc_lnum - reserve GC LEB.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* *
* This function ensures that the LEB reserved for garbage collection is * This function ensures that the LEB reserved for garbage collection is marked
* unmapped and is marked as "taken" in lprops. We also have to set free space * as "taken" in lprops. We also have to set free space to LEB size and dirty
* to LEB size and dirty space to zero, because lprops may contain out-of-date * space to zero, because lprops may contain out-of-date information if the
* information if the file-system was un-mounted before it has been committed. * file-system was un-mounted before it has been committed. This function
* This function returns zero in case of success and a negative error code in * returns zero in case of success and a negative error code in case of
* case of failure. * failure.
*/ */
static int take_gc_lnum(struct ubifs_info *c) static int take_gc_lnum(struct ubifs_info *c)
{ {
...@@ -757,10 +752,6 @@ static int take_gc_lnum(struct ubifs_info *c) ...@@ -757,10 +752,6 @@ static int take_gc_lnum(struct ubifs_info *c)
return -EINVAL; return -EINVAL;
} }
err = ubifs_leb_unmap(c, c->gc_lnum);
if (err)
return err;
/* And we have to tell lprops that this LEB is taken */ /* And we have to tell lprops that this LEB is taken */
err = ubifs_change_one_lp(c, c->gc_lnum, c->leb_size, 0, err = ubifs_change_one_lp(c, c->gc_lnum, c->leb_size, 0,
LPROPS_TAKEN, 0, 0); LPROPS_TAKEN, 0, 0);
...@@ -966,13 +957,16 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, ...@@ -966,13 +957,16 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
token = match_token(p, tokens, args); token = match_token(p, tokens, args);
switch (token) { switch (token) {
/*
* %Opt_fast_unmount and %Opt_norm_unmount options are ignored.
* We accepte them in order to be backware-compatible. But this
* should be removed at some point.
*/
case Opt_fast_unmount: case Opt_fast_unmount:
c->mount_opts.unmount_mode = 2; c->mount_opts.unmount_mode = 2;
c->fast_unmount = 1;
break; break;
case Opt_norm_unmount: case Opt_norm_unmount:
c->mount_opts.unmount_mode = 1; c->mount_opts.unmount_mode = 1;
c->fast_unmount = 0;
break; break;
case Opt_bulk_read: case Opt_bulk_read:
c->mount_opts.bulk_read = 2; c->mount_opts.bulk_read = 2;
...@@ -1094,12 +1088,7 @@ static int check_free_space(struct ubifs_info *c) ...@@ -1094,12 +1088,7 @@ static int check_free_space(struct ubifs_info *c)
ubifs_err("insufficient free space to mount in read/write mode"); ubifs_err("insufficient free space to mount in read/write mode");
dbg_dump_budg(c); dbg_dump_budg(c);
dbg_dump_lprops(c); dbg_dump_lprops(c);
/* return -ENOSPC;
* We return %-EINVAL instead of %-ENOSPC because it seems to
* be the closest error code mentioned in the mount function
* documentation.
*/
return -EINVAL;
} }
return 0; return 0;
} }
...@@ -1286,11 +1275,20 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1286,11 +1275,20 @@ static int mount_ubifs(struct ubifs_info *c)
if (err) if (err)
goto out_orphans; goto out_orphans;
err = ubifs_rcvry_gc_commit(c); err = ubifs_rcvry_gc_commit(c);
} else } else {
err = take_gc_lnum(c); err = take_gc_lnum(c);
if (err) if (err)
goto out_orphans; goto out_orphans;
/*
* GC LEB may contain garbage if there was an unclean
* reboot, and it should be un-mapped.
*/
err = ubifs_leb_unmap(c, c->gc_lnum);
if (err)
return err;
}
err = dbg_check_lprops(c); err = dbg_check_lprops(c);
if (err) if (err)
goto out_orphans; goto out_orphans;
...@@ -1298,6 +1296,16 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1298,6 +1296,16 @@ static int mount_ubifs(struct ubifs_info *c)
err = ubifs_recover_size(c); err = ubifs_recover_size(c);
if (err) if (err)
goto out_orphans; goto out_orphans;
} else {
/*
* Even if we mount read-only, we have to set space in GC LEB
* to proper value because this affects UBIFS free space
* reporting. We do not want to have a situation when
* re-mounting from R/O to R/W changes amount of free space.
*/
err = take_gc_lnum(c);
if (err)
goto out_orphans;
} }
spin_lock(&ubifs_infos_lock); spin_lock(&ubifs_infos_lock);
...@@ -1310,14 +1318,17 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1310,14 +1318,17 @@ static int mount_ubifs(struct ubifs_info *c)
else { else {
c->need_recovery = 0; c->need_recovery = 0;
ubifs_msg("recovery completed"); ubifs_msg("recovery completed");
/* GC LEB has to be empty and taken at this point */
ubifs_assert(c->lst.taken_empty_lebs == 1);
} }
} } else
ubifs_assert(c->lst.taken_empty_lebs == 1);
err = dbg_debugfs_init_fs(c); err = dbg_check_filesystem(c);
if (err) if (err)
goto out_infos; goto out_infos;
err = dbg_check_filesystem(c); err = dbg_debugfs_init_fs(c);
if (err) if (err)
goto out_infos; goto out_infos;
...@@ -1351,7 +1362,6 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1351,7 +1362,6 @@ static int mount_ubifs(struct ubifs_info *c)
c->uuid[4], c->uuid[5], c->uuid[6], c->uuid[7], c->uuid[4], c->uuid[5], c->uuid[6], c->uuid[7],
c->uuid[8], c->uuid[9], c->uuid[10], c->uuid[11], c->uuid[8], c->uuid[9], c->uuid[10], c->uuid[11],
c->uuid[12], c->uuid[13], c->uuid[14], c->uuid[15]); c->uuid[12], c->uuid[13], c->uuid[14], c->uuid[15]);
dbg_msg("fast unmount: %d", c->fast_unmount);
dbg_msg("big_lpt %d", c->big_lpt); dbg_msg("big_lpt %d", c->big_lpt);
dbg_msg("log LEBs: %d (%d - %d)", dbg_msg("log LEBs: %d (%d - %d)",
c->log_lebs, UBIFS_LOG_LNUM, c->log_last); c->log_lebs, UBIFS_LOG_LNUM, c->log_last);
...@@ -1475,10 +1485,8 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1475,10 +1485,8 @@ static int ubifs_remount_rw(struct ubifs_info *c)
{ {
int err, lnum; int err, lnum;
if (c->ro_media)
return -EINVAL;
mutex_lock(&c->umount_mutex); mutex_lock(&c->umount_mutex);
dbg_save_space_info(c);
c->remounting_rw = 1; c->remounting_rw = 1;
c->always_chk_crc = 1; c->always_chk_crc = 1;
...@@ -1514,6 +1522,12 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1514,6 +1522,12 @@ static int ubifs_remount_rw(struct ubifs_info *c)
err = ubifs_recover_inl_heads(c, c->sbuf); err = ubifs_recover_inl_heads(c, c->sbuf);
if (err) if (err)
goto out; goto out;
} else {
/* A readonly mount is not allowed to have orphans */
ubifs_assert(c->tot_orphans == 0);
err = ubifs_clear_orphans(c);
if (err)
goto out;
} }
if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) { if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) {
...@@ -1569,7 +1583,7 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1569,7 +1583,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
if (c->need_recovery) if (c->need_recovery)
err = ubifs_rcvry_gc_commit(c); err = ubifs_rcvry_gc_commit(c);
else else
err = take_gc_lnum(c); err = ubifs_leb_unmap(c, c->gc_lnum);
if (err) if (err)
goto out; goto out;
...@@ -1582,8 +1596,9 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1582,8 +1596,9 @@ static int ubifs_remount_rw(struct ubifs_info *c)
c->vfs_sb->s_flags &= ~MS_RDONLY; c->vfs_sb->s_flags &= ~MS_RDONLY;
c->remounting_rw = 0; c->remounting_rw = 0;
c->always_chk_crc = 0; c->always_chk_crc = 0;
err = dbg_check_space_info(c);
mutex_unlock(&c->umount_mutex); mutex_unlock(&c->umount_mutex);
return 0; return err;
out: out:
vfree(c->orph_buf); vfree(c->orph_buf);
...@@ -1602,44 +1617,19 @@ out: ...@@ -1602,44 +1617,19 @@ out:
return err; return err;
} }
/**
* commit_on_unmount - commit the journal when un-mounting.
* @c: UBIFS file-system description object
*
* This function is called during un-mounting and re-mounting, and it commits
* the journal unless the "fast unmount" mode is enabled.
*/
static void commit_on_unmount(struct ubifs_info *c)
{
struct super_block *sb = c->vfs_sb;
long long bud_bytes;
/*
* This function is called before the background thread is stopped, so
* we may race with ongoing commit, which means we have to take
* @c->bud_lock to access @c->bud_bytes.
*/
spin_lock(&c->buds_lock);
bud_bytes = c->bud_bytes;
spin_unlock(&c->buds_lock);
if (!c->fast_unmount && !(sb->s_flags & MS_RDONLY) && bud_bytes)
ubifs_run_commit(c);
}
/** /**
* ubifs_remount_ro - re-mount in read-only mode. * ubifs_remount_ro - re-mount in read-only mode.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* *
* We rely on VFS to have stopped writing. Possibly the background thread could * We assume VFS has stopped writing. Possibly the background thread could be
* be running a commit, however kthread_stop will wait in that case. * running a commit, however kthread_stop will wait in that case.
*/ */
static void ubifs_remount_ro(struct ubifs_info *c) static void ubifs_remount_ro(struct ubifs_info *c)
{ {
int i, err; int i, err;
ubifs_assert(!c->need_recovery); ubifs_assert(!c->need_recovery);
commit_on_unmount(c); ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY));
mutex_lock(&c->umount_mutex); mutex_lock(&c->umount_mutex);
if (c->bgt) { if (c->bgt) {
...@@ -1647,27 +1637,29 @@ static void ubifs_remount_ro(struct ubifs_info *c) ...@@ -1647,27 +1637,29 @@ static void ubifs_remount_ro(struct ubifs_info *c)
c->bgt = NULL; c->bgt = NULL;
} }
dbg_save_space_info(c);
for (i = 0; i < c->jhead_cnt; i++) { for (i = 0; i < c->jhead_cnt; i++) {
ubifs_wbuf_sync(&c->jheads[i].wbuf); ubifs_wbuf_sync(&c->jheads[i].wbuf);
del_timer_sync(&c->jheads[i].wbuf.timer); del_timer_sync(&c->jheads[i].wbuf.timer);
} }
if (!c->ro_media) {
c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum);
err = ubifs_write_master(c); err = ubifs_write_master(c);
if (err) if (err)
ubifs_ro_mode(c, err); ubifs_ro_mode(c, err);
}
ubifs_destroy_idx_gc(c);
free_wbufs(c); free_wbufs(c);
vfree(c->orph_buf); vfree(c->orph_buf);
c->orph_buf = NULL; c->orph_buf = NULL;
vfree(c->ileb_buf); vfree(c->ileb_buf);
c->ileb_buf = NULL; c->ileb_buf = NULL;
ubifs_lpt_free(c, 1); ubifs_lpt_free(c, 1);
err = dbg_check_space_info(c);
if (err)
ubifs_ro_mode(c, err);
mutex_unlock(&c->umount_mutex); mutex_unlock(&c->umount_mutex);
} }
...@@ -1760,11 +1752,20 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) ...@@ -1760,11 +1752,20 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
} }
if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
if (c->ro_media) {
ubifs_msg("cannot re-mount due to prior errors");
return -EROFS;
}
err = ubifs_remount_rw(c); err = ubifs_remount_rw(c);
if (err) if (err)
return err; return err;
} else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
if (c->ro_media) {
ubifs_msg("cannot re-mount due to prior errors");
return -EROFS;
}
ubifs_remount_ro(c); ubifs_remount_ro(c);
}
if (c->bulk_read == 1) if (c->bulk_read == 1)
bu_init(c); bu_init(c);
...@@ -1774,10 +1775,11 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) ...@@ -1774,10 +1775,11 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
c->bu.buf = NULL; c->bu.buf = NULL;
} }
ubifs_assert(c->lst.taken_empty_lebs == 1);
return 0; return 0;
} }
struct super_operations ubifs_super_operations = { const struct super_operations ubifs_super_operations = {
.alloc_inode = ubifs_alloc_inode, .alloc_inode = ubifs_alloc_inode,
.destroy_inode = ubifs_destroy_inode, .destroy_inode = ubifs_destroy_inode,
.put_super = ubifs_put_super, .put_super = ubifs_put_super,
...@@ -2044,15 +2046,6 @@ out_close: ...@@ -2044,15 +2046,6 @@ out_close:
static void ubifs_kill_sb(struct super_block *sb) static void ubifs_kill_sb(struct super_block *sb)
{ {
struct ubifs_info *c = sb->s_fs_info;
/*
* We do 'commit_on_unmount()' here instead of 'ubifs_put_super()'
* in order to be outside BKL.
*/
if (sb->s_root)
commit_on_unmount(c);
/* The un-mount routine is actually done in put_super() */
generic_shutdown_super(sb); generic_shutdown_super(sb);
} }
......
...@@ -443,6 +443,11 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr, ...@@ -443,6 +443,11 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
* This function performs that same function as ubifs_read_node except that * This function performs that same function as ubifs_read_node except that
* it does not require that there is actually a node present and instead * it does not require that there is actually a node present and instead
* the return code indicates if a node was read. * the return code indicates if a node was read.
*
* Note, this function does not check CRC of data nodes if @c->no_chk_data_crc
* is true (it is controlled by corresponding mount option). However, if
* @c->always_chk_crc is true, @c->no_chk_data_crc is ignored and CRC is always
* checked.
*/ */
static int try_read_node(const struct ubifs_info *c, void *buf, int type, static int try_read_node(const struct ubifs_info *c, void *buf, int type,
int len, int lnum, int offs) int len, int lnum, int offs)
...@@ -470,9 +475,8 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type, ...@@ -470,9 +475,8 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
if (node_len != len) if (node_len != len)
return 0; return 0;
if (type == UBIFS_DATA_NODE && !c->always_chk_crc) if (type == UBIFS_DATA_NODE && !c->always_chk_crc && c->no_chk_data_crc)
if (c->no_chk_data_crc) return 1;
return 0;
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
node_crc = le32_to_cpu(ch->crc); node_crc = le32_to_cpu(ch->crc);
...@@ -1506,7 +1510,7 @@ out: ...@@ -1506,7 +1510,7 @@ out:
* *
* Note, if the bulk-read buffer length (@bu->buf_len) is known, this function * Note, if the bulk-read buffer length (@bu->buf_len) is known, this function
* makes sure bulk-read nodes fit the buffer. Otherwise, this function prepares * makes sure bulk-read nodes fit the buffer. Otherwise, this function prepares
* maxumum possible amount of nodes for bulk-read. * maximum possible amount of nodes for bulk-read.
*/ */
int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu) int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
{ {
......
...@@ -426,9 +426,9 @@ struct ubifs_unclean_leb { ...@@ -426,9 +426,9 @@ struct ubifs_unclean_leb {
* LEB properties flags. * LEB properties flags.
* *
* LPROPS_UNCAT: not categorized * LPROPS_UNCAT: not categorized
* LPROPS_DIRTY: dirty > 0, not index * LPROPS_DIRTY: dirty > free, dirty >= @c->dead_wm, not index
* LPROPS_DIRTY_IDX: dirty + free > @c->min_idx_node_sze and index * LPROPS_DIRTY_IDX: dirty + free > @c->min_idx_node_sze and index
* LPROPS_FREE: free > 0, not empty, not index * LPROPS_FREE: free > 0, dirty < @c->dead_wm, not empty, not index
* LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs * LPROPS_HEAP_CNT: number of heaps used for storing categorized LEBs
* LPROPS_EMPTY: LEB is empty, not taken * LPROPS_EMPTY: LEB is empty, not taken
* LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken * LPROPS_FREEABLE: free + dirty == leb_size, not index, not taken
...@@ -961,7 +961,6 @@ struct ubifs_debug_info; ...@@ -961,7 +961,6 @@ struct ubifs_debug_info;
* @cs_lock: commit state lock * @cs_lock: commit state lock
* @cmt_wq: wait queue to sleep on if the log is full and a commit is running * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
* *
* @fast_unmount: do not run journal commit before un-mounting
* @big_lpt: flag that LPT is too big to write whole during commit * @big_lpt: flag that LPT is too big to write whole during commit
* @no_chk_data_crc: do not check CRCs when reading data nodes (except during * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
* recovery) * recovery)
...@@ -1202,7 +1201,6 @@ struct ubifs_info { ...@@ -1202,7 +1201,6 @@ struct ubifs_info {
spinlock_t cs_lock; spinlock_t cs_lock;
wait_queue_head_t cmt_wq; wait_queue_head_t cmt_wq;
unsigned int fast_unmount:1;
unsigned int big_lpt:1; unsigned int big_lpt:1;
unsigned int no_chk_data_crc:1; unsigned int no_chk_data_crc:1;
unsigned int bulk_read:1; unsigned int bulk_read:1;
...@@ -1405,13 +1403,13 @@ extern struct list_head ubifs_infos; ...@@ -1405,13 +1403,13 @@ extern struct list_head ubifs_infos;
extern spinlock_t ubifs_infos_lock; extern spinlock_t ubifs_infos_lock;
extern atomic_long_t ubifs_clean_zn_cnt; extern atomic_long_t ubifs_clean_zn_cnt;
extern struct kmem_cache *ubifs_inode_slab; extern struct kmem_cache *ubifs_inode_slab;
extern struct super_operations ubifs_super_operations; extern const struct super_operations ubifs_super_operations;
extern struct address_space_operations ubifs_file_address_operations; extern const struct address_space_operations ubifs_file_address_operations;
extern struct file_operations ubifs_file_operations; extern const struct file_operations ubifs_file_operations;
extern struct inode_operations ubifs_file_inode_operations; extern const struct inode_operations ubifs_file_inode_operations;
extern struct file_operations ubifs_dir_operations; extern const struct file_operations ubifs_dir_operations;
extern struct inode_operations ubifs_dir_inode_operations; extern const struct inode_operations ubifs_dir_inode_operations;
extern struct inode_operations ubifs_symlink_inode_operations; extern const struct inode_operations ubifs_symlink_inode_operations;
extern struct backing_dev_info ubifs_backing_dev_info; extern struct backing_dev_info ubifs_backing_dev_info;
extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
...@@ -1428,7 +1426,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, ...@@ -1428,7 +1426,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum, int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
int offs, int dtype); int offs, int dtype);
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
int offs, int quiet, int chk_crc); int offs, int quiet, int must_chk_crc);
void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad); void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last); void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
int ubifs_io_init(struct ubifs_info *c); int ubifs_io_init(struct ubifs_info *c);
...@@ -1495,6 +1493,7 @@ void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode, ...@@ -1495,6 +1493,7 @@ void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode,
void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode, void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode,
struct ubifs_budget_req *req); struct ubifs_budget_req *req);
long long ubifs_get_free_space(struct ubifs_info *c); long long ubifs_get_free_space(struct ubifs_info *c);
long long ubifs_get_free_space_nolock(struct ubifs_info *c);
int ubifs_calc_min_idx_lebs(struct ubifs_info *c); int ubifs_calc_min_idx_lebs(struct ubifs_info *c);
void ubifs_convert_page_budget(struct ubifs_info *c); void ubifs_convert_page_budget(struct ubifs_info *c);
long long ubifs_reported_space(const struct ubifs_info *c, long long free); long long ubifs_reported_space(const struct ubifs_info *c, long long free);
...@@ -1603,6 +1602,7 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum); ...@@ -1603,6 +1602,7 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum);
int ubifs_orphan_start_commit(struct ubifs_info *c); int ubifs_orphan_start_commit(struct ubifs_info *c);
int ubifs_orphan_end_commit(struct ubifs_info *c); int ubifs_orphan_end_commit(struct ubifs_info *c);
int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only); int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only);
int ubifs_clear_orphans(struct ubifs_info *c);
/* lpt.c */ /* lpt.c */
int ubifs_calc_lpt_geom(struct ubifs_info *c); int ubifs_calc_lpt_geom(struct ubifs_info *c);
...@@ -1646,7 +1646,7 @@ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c, ...@@ -1646,7 +1646,7 @@ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
const struct ubifs_lprops *lp, const struct ubifs_lprops *lp,
int free, int dirty, int flags, int free, int dirty, int flags,
int idx_gc_cnt); int idx_gc_cnt);
void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *stats); void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst);
void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops, void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
int cat); int cat);
void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops, void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment