diff options
Diffstat (limited to 'fs/ubifs/debug.c')
| -rw-r--r-- | fs/ubifs/debug.c | 63 | 
1 files changed, 46 insertions, 17 deletions
| diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index f25a7339f800..004d3745dc45 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -972,11 +972,39 @@ void dbg_dump_index(struct ubifs_info *c)  void dbg_save_space_info(struct ubifs_info *c)  {  	struct ubifs_debug_info *d = c->dbg; - -	ubifs_get_lp_stats(c, &d->saved_lst); +	int freeable_cnt;  	spin_lock(&c->space_lock); +	memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats)); + +	/* +	 * We use a dirty hack here and zero out @c->freeable_cnt, because it +	 * affects the free space calculations, and UBIFS might not know about +	 * all freeable eraseblocks. Indeed, we know about freeable eraseblocks +	 * only when we read their lprops, and we do this only lazily, upon the +	 * need. So at any given point of time @c->freeable_cnt might be not +	 * exactly accurate. +	 * +	 * Just one example about the issue we hit when we did not zero +	 * @c->freeable_cnt. +	 * 1. The file-system is mounted R/O, c->freeable_cnt is %0. We save the +	 *    amount of free space in @d->saved_free +	 * 2. We re-mount R/W, which makes UBIFS to read the "lsave" +	 *    information from flash, where we cache LEBs from various +	 *    categories ('ubifs_remount_fs()' -> 'ubifs_lpt_init()' +	 *    -> 'lpt_init_wr()' -> 'read_lsave()' -> 'ubifs_lpt_lookup()' +	 *    -> 'ubifs_get_pnode()' -> 'update_cats()' +	 *    -> 'ubifs_add_to_cat()'). +	 * 3. Lsave contains a freeable eraseblock, and @c->freeable_cnt +	 *    becomes %1. +	 * 4. We calculate the amount of free space when the re-mount is +	 *    finished in 'dbg_check_space_info()' and it does not match +	 *    @d->saved_free. +	 */ +	freeable_cnt = c->freeable_cnt; +	c->freeable_cnt = 0;  	d->saved_free = ubifs_get_free_space_nolock(c); +	c->freeable_cnt = freeable_cnt;  	spin_unlock(&c->space_lock);  } @@ -993,12 +1021,15 @@ 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; +	long long free; +	int freeable_cnt;  	spin_lock(&c->space_lock); -	avail = ubifs_calc_available(c, c->min_idx_lebs); +	freeable_cnt = c->freeable_cnt; +	c->freeable_cnt = 0; +	free = ubifs_get_free_space_nolock(c); +	c->freeable_cnt = freeable_cnt;  	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", @@ -2806,40 +2837,38 @@ int dbg_debugfs_init_fs(struct ubifs_info *c)  	struct ubifs_debug_info *d = c->dbg;  	sprintf(d->dfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); -	d->dfs_dir = debugfs_create_dir(d->dfs_dir_name, dfs_rootdir); -	if (IS_ERR(d->dfs_dir)) { -		err = PTR_ERR(d->dfs_dir); -		ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", -			  d->dfs_dir_name, err); +	fname = d->dfs_dir_name; +	dent = debugfs_create_dir(fname, dfs_rootdir); +	if (IS_ERR_OR_NULL(dent))  		goto out; -	} +	d->dfs_dir = dent;  	fname = "dump_lprops";  	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops); -	if (IS_ERR(dent)) +	if (IS_ERR_OR_NULL(dent))  		goto out_remove;  	d->dfs_dump_lprops = dent;  	fname = "dump_budg";  	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops); -	if (IS_ERR(dent)) +	if (IS_ERR_OR_NULL(dent))  		goto out_remove;  	d->dfs_dump_budg = dent;  	fname = "dump_tnc";  	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops); -	if (IS_ERR(dent)) +	if (IS_ERR_OR_NULL(dent))  		goto out_remove;  	d->dfs_dump_tnc = dent;  	return 0;  out_remove: -	err = PTR_ERR(dent); -	ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", -		  fname, err);  	debugfs_remove_recursive(d->dfs_dir);  out: +	err = dent ? PTR_ERR(dent) : -ENODEV; +	ubifs_err("cannot create \"%s\" debugfs directory, error %d\n", +		  fname, err);  	return err;  } | 
