Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f96c08e8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+0 −7
Original line number Original line Diff line number Diff line
@@ -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
+25 −10
Original line number Original line Diff line number Diff line
@@ -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)
 * 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)
	 * 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)
		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;
}
+88 −34
Original line number Original line Diff line number Diff line
@@ -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)
	/* 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)
	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)
 * @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)
 * 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;
 */
 */
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)
 */
 */
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,
	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,
	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)
	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:
	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:
 */
 */
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 */
+22 −14
Original line number Original line Diff line number Diff line
@@ -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 {
	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,
		   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);


#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
+38 −58
Original line number Original line Diff line number Diff line
@@ -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,
	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)
	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)


	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:
}
}


/**
/**
 * 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,
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,
		"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,
	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 = {
#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,
Loading