diff options
Diffstat (limited to 'fs/ubifs/debug.c')
| -rw-r--r-- | fs/ubifs/debug.c | 167 | 
1 files changed, 108 insertions, 59 deletions
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 004d3745dc4..0bb2bcef0de 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -34,7 +34,6 @@  #include <linux/moduleparam.h>  #include <linux/debugfs.h>  #include <linux/math64.h> -#include <linux/slab.h>  #ifdef CONFIG_UBIFS_FS_DEBUG @@ -43,15 +42,12 @@ DEFINE_SPINLOCK(dbg_lock);  static char dbg_key_buf0[128];  static char dbg_key_buf1[128]; -unsigned int ubifs_msg_flags;  unsigned int ubifs_chk_flags;  unsigned int ubifs_tst_flags; -module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);  module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);  module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_msgs, "Debug message type flags");  MODULE_PARM_DESC(debug_chks, "Debug check flags");  MODULE_PARM_DESC(debug_tsts, "Debug special test flags"); @@ -317,6 +313,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)  		printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);  		printk(KERN_DEBUG "\t  big_lpt      %u\n",  		       !!(sup_flags & UBIFS_FLG_BIGLPT)); +		printk(KERN_DEBUG "\t  space_fixup  %u\n", +		       !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));  		printk(KERN_DEBUG "\tmin_io_size    %u\n",  		       le32_to_cpu(sup->min_io_size));  		printk(KERN_DEBUG "\tleb_size       %u\n", @@ -602,7 +600,7 @@ void dbg_dump_lstats(const struct ubifs_lp_stats *lst)  	spin_unlock(&dbg_lock);  } -void dbg_dump_budg(struct ubifs_info *c) +void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)  {  	int i;  	struct rb_node *rb; @@ -610,26 +608,42 @@ void dbg_dump_budg(struct ubifs_info *c)  	struct ubifs_gced_idx_leb *idx_gc;  	long long available, outstanding, free; -	ubifs_assert(spin_is_locked(&c->space_lock)); +	spin_lock(&c->space_lock);  	spin_lock(&dbg_lock); -	printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, " -	       "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid, -	       c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth); -	printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, " -	       "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth, -	       c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth, -	       c->freeable_cnt); -	printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, " -	       "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs, -	       c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt); +	printk(KERN_DEBUG "(pid %d) Budgeting info: data budget sum %lld, " +	       "total budget sum %lld\n", current->pid, +	       bi->data_growth + bi->dd_growth, +	       bi->data_growth + bi->dd_growth + bi->idx_growth); +	printk(KERN_DEBUG "\tbudg_data_growth %lld, budg_dd_growth %lld, " +	       "budg_idx_growth %lld\n", bi->data_growth, bi->dd_growth, +	       bi->idx_growth); +	printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %llu, " +	       "uncommitted_idx %lld\n", bi->min_idx_lebs, bi->old_idx_sz, +	       bi->uncommitted_idx); +	printk(KERN_DEBUG "\tpage_budget %d, inode_budget %d, dent_budget %d\n", +	       bi->page_budget, bi->inode_budget, bi->dent_budget); +	printk(KERN_DEBUG "\tnospace %u, nospace_rp %u\n", +	       bi->nospace, bi->nospace_rp); +	printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n", +	       c->dark_wm, c->dead_wm, c->max_idx_node_sz); + +	if (bi != &c->bi) +		/* +		 * If we are dumping saved budgeting data, do not print +		 * additional information which is about the current state, not +		 * the old one which corresponded to the saved budgeting data. +		 */ +		goto out_unlock; + +	printk(KERN_DEBUG "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n", +	       c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);  	printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "  	       "clean_zn_cnt %ld\n", atomic_long_read(&c->dirty_pg_cnt),  	       atomic_long_read(&c->dirty_zn_cnt),  	       atomic_long_read(&c->clean_zn_cnt)); -	printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n", -	       c->dark_wm, c->dead_wm, c->max_idx_node_sz);  	printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",  	       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++) @@ -648,13 +662,15 @@ void dbg_dump_budg(struct ubifs_info *c)  	printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);  	/* Print budgeting predictions */ -	available = ubifs_calc_available(c, c->min_idx_lebs); -	outstanding = c->budg_data_growth + c->budg_dd_growth; +	available = ubifs_calc_available(c, c->bi.min_idx_lebs); +	outstanding = c->bi.data_growth + c->bi.dd_growth;  	free = ubifs_get_free_space_nolock(c);  	printk(KERN_DEBUG "Budgeting predictions:\n");  	printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",  	       available, outstanding, free); +out_unlock:  	spin_unlock(&dbg_lock); +	spin_unlock(&c->space_lock);  }  void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp) @@ -729,7 +745,13 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)  		if (bud->lnum == lp->lnum) {  			int head = 0;  			for (i = 0; i < c->jhead_cnt; i++) { -				if (lp->lnum == c->jheads[i].wbuf.lnum) { +				/* +				 * Note, if we are in R/O mode or in the middle +				 * of mounting/re-mounting, the write-buffers do +				 * not exist. +				 */ +				if (c->jheads && +				    lp->lnum == c->jheads[i].wbuf.lnum) {  					printk(KERN_CONT ", jhead %s",  					       dbg_jhead(i));  					head = 1; @@ -976,6 +998,8 @@ void dbg_save_space_info(struct ubifs_info *c)  	spin_lock(&c->space_lock);  	memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats)); +	memcpy(&d->saved_bi, &c->bi, sizeof(struct ubifs_budg_info)); +	d->saved_idx_gc_cnt = c->idx_gc_cnt;  	/*  	 * We use a dirty hack here and zero out @c->freeable_cnt, because it @@ -1042,14 +1066,14 @@ int dbg_check_space_info(struct ubifs_info *c)  out:  	ubifs_msg("saved lprops statistics dump");  	dbg_dump_lstats(&d->saved_lst); -	ubifs_get_lp_stats(c, &lst); - +	ubifs_msg("saved budgeting info dump"); +	dbg_dump_budg(c, &d->saved_bi); +	ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);  	ubifs_msg("current lprops statistics dump"); +	ubifs_get_lp_stats(c, &lst);  	dbg_dump_lstats(&lst); - -	spin_lock(&c->space_lock); -	dbg_dump_budg(c); -	spin_unlock(&c->space_lock); +	ubifs_msg("current budgeting info dump"); +	dbg_dump_budg(c, &c->bi);  	dump_stack();  	return -EINVAL;  } @@ -1793,6 +1817,8 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,  	struct rb_node **p, *parent = NULL;  	struct fsck_inode *fscki;  	ino_t inum = key_inum_flash(c, &ino->key); +	struct inode *inode; +	struct ubifs_inode *ui;  	p = &fsckd->inodes.rb_node;  	while (*p) { @@ -1816,19 +1842,46 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,  	if (!fscki)  		return ERR_PTR(-ENOMEM); +	inode = ilookup(c->vfs_sb, inum); +  	fscki->inum = inum; -	fscki->nlink = le32_to_cpu(ino->nlink); -	fscki->size = le64_to_cpu(ino->size); -	fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt); -	fscki->xattr_sz = le32_to_cpu(ino->xattr_size); -	fscki->xattr_nms = le32_to_cpu(ino->xattr_names); -	fscki->mode = le32_to_cpu(ino->mode); +	/* +	 * If the inode is present in the VFS inode cache, use it instead of +	 * the on-flash inode which might be out-of-date. E.g., the size might +	 * be out-of-date. If we do not do this, the following may happen, for +	 * example: +	 *   1. A power cut happens +	 *   2. We mount the file-system R/O, the replay process fixes up the +	 *      inode size in the VFS cache, but on on-flash. +	 *   3. 'check_leaf()' fails because it hits a data node beyond inode +	 *      size. +	 */ +	if (!inode) { +		fscki->nlink = le32_to_cpu(ino->nlink); +		fscki->size = le64_to_cpu(ino->size); +		fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt); +		fscki->xattr_sz = le32_to_cpu(ino->xattr_size); +		fscki->xattr_nms = le32_to_cpu(ino->xattr_names); +		fscki->mode = le32_to_cpu(ino->mode); +	} else { +		ui = ubifs_inode(inode); +		fscki->nlink = inode->i_nlink; +		fscki->size = inode->i_size; +		fscki->xattr_cnt = ui->xattr_cnt; +		fscki->xattr_sz = ui->xattr_size; +		fscki->xattr_nms = ui->xattr_names; +		fscki->mode = inode->i_mode; +		iput(inode); +	} +  	if (S_ISDIR(fscki->mode)) {  		fscki->calc_sz = UBIFS_INO_NODE_SZ;  		fscki->calc_cnt = 2;  	} +  	rb_link_node(&fscki->rb, parent, p);  	rb_insert_color(&fscki->rb, &fsckd->inodes); +  	return fscki;  } @@ -2421,7 +2474,8 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)  		hashb = key_block(c, &sb->key);  		if (hasha > hashb) { -			ubifs_err("larger hash %u goes before %u", hasha, hashb); +			ubifs_err("larger hash %u goes before %u", +				  hasha, hashb);  			goto error_dump;  		}  	} @@ -2437,14 +2491,12 @@ error_dump:  	return 0;  } -static int invocation_cnt; -  int dbg_force_in_the_gaps(void)  { -	if (!dbg_force_in_the_gaps_enabled) +	if (!(ubifs_chk_flags & UBIFS_CHK_GEN))  		return 0; -	/* Force in-the-gaps every 8th commit */ -	return !((invocation_cnt++) & 0x7); + +	return !(random32() & 7);  }  /* Failure mode for recovery testing */ @@ -2632,7 +2684,7 @@ int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,  		 int len, int check)  {  	if (in_failure_mode(desc)) -		return -EIO; +		return -EROFS;  	return ubi_leb_read(desc, lnum, buf, offset, len, check);  } @@ -2642,7 +2694,7 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,  	int err, failing;  	if (in_failure_mode(desc)) -		return -EIO; +		return -EROFS;  	failing = do_fail(desc, lnum, 1);  	if (failing)  		cut_data(buf, len); @@ -2650,7 +2702,7 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,  	if (err)  		return err;  	if (failing) -		return -EIO; +		return -EROFS;  	return 0;  } @@ -2660,12 +2712,12 @@ int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,  	int err;  	if (do_fail(desc, lnum, 1)) -		return -EIO; +		return -EROFS;  	err = ubi_leb_change(desc, lnum, buf, len, dtype);  	if (err)  		return err;  	if (do_fail(desc, lnum, 1)) -		return -EIO; +		return -EROFS;  	return 0;  } @@ -2674,12 +2726,12 @@ int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum)  	int err;  	if (do_fail(desc, lnum, 0)) -		return -EIO; +		return -EROFS;  	err = ubi_leb_erase(desc, lnum);  	if (err)  		return err;  	if (do_fail(desc, lnum, 0)) -		return -EIO; +		return -EROFS;  	return 0;  } @@ -2688,19 +2740,19 @@ int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)  	int err;  	if (do_fail(desc, lnum, 0)) -		return -EIO; +		return -EROFS;  	err = ubi_leb_unmap(desc, lnum);  	if (err)  		return err;  	if (do_fail(desc, lnum, 0)) -		return -EIO; +		return -EROFS;  	return 0;  }  int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum)  {  	if (in_failure_mode(desc)) -		return -EIO; +		return -EROFS;  	return ubi_is_mapped(desc, lnum);  } @@ -2709,12 +2761,12 @@ int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)  	int err;  	if (do_fail(desc, lnum, 0)) -		return -EIO; +		return -EROFS;  	err = ubi_leb_map(desc, lnum, dtype);  	if (err)  		return err;  	if (do_fail(desc, lnum, 0)) -		return -EIO; +		return -EROFS;  	return 0;  } @@ -2784,7 +2836,7 @@ void dbg_debugfs_exit(void)  static int open_debugfs_file(struct inode *inode, struct file *file)  {  	file->private_data = inode->i_private; -	return 0; +	return nonseekable_open(inode, file);  }  static ssize_t write_debugfs_file(struct file *file, const char __user *buf, @@ -2795,18 +2847,15 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf,  	if (file->f_path.dentry == d->dfs_dump_lprops)  		dbg_dump_lprops(c); -	else if (file->f_path.dentry == d->dfs_dump_budg) { -		spin_lock(&c->space_lock); -		dbg_dump_budg(c); -		spin_unlock(&c->space_lock); -	} else if (file->f_path.dentry == d->dfs_dump_tnc) { +	else if (file->f_path.dentry == d->dfs_dump_budg) +		dbg_dump_budg(c, &c->bi); +	else if (file->f_path.dentry == d->dfs_dump_tnc) {  		mutex_lock(&c->tnc_mutex);  		dbg_dump_tnc(c);  		mutex_unlock(&c->tnc_mutex);  	} else  		return -EINVAL; -	*ppos += count;  	return count;  } @@ -2814,7 +2863,7 @@ static const struct file_operations dfs_fops = {  	.open = open_debugfs_file,  	.write = write_debugfs_file,  	.owner = THIS_MODULE, -	.llseek = default_llseek, +	.llseek = no_llseek,  };  /**  |