debug.c 16.1 KB
Newer Older
J
Jaegeuk Kim 已提交
1
/*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * f2fs debugging statistics
 *
 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
 *             http://www.samsung.com/
 * Copyright (c) 2012 Linux Foundation
 * Copyright (c) 2012 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/fs.h>
#include <linux/backing-dev.h>
#include <linux/f2fs_fs.h>
#include <linux/blkdev.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>

#include "f2fs.h"
#include "node.h"
#include "segment.h"
#include "gc.h"

static LIST_HEAD(f2fs_stat_list);
27
static struct dentry *f2fs_debugfs_root;
28
static DEFINE_MUTEX(f2fs_stat_mutex);
29

30
static void update_general_status(struct f2fs_sb_info *sbi)
31
{
32
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
33 34
	int i;

A
arter97 已提交
35
	/* validation check of the segment numbers */
36 37 38
	si->hit_largest = atomic64_read(&sbi->read_hit_largest);
	si->hit_cached = atomic64_read(&sbi->read_hit_cached);
	si->hit_rbtree = atomic64_read(&sbi->read_hit_rbtree);
39
	si->hit_total = si->hit_largest + si->hit_cached + si->hit_rbtree;
40
	si->total_ext = atomic64_read(&sbi->total_hit_ext);
41
	si->ext_tree = atomic_read(&sbi->total_ext_tree);
J
Jaegeuk Kim 已提交
42
	si->zombie_tree = atomic_read(&sbi->total_zombie_tree);
43
	si->ext_node = atomic_read(&sbi->total_ext_node);
44 45 46
	si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
	si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
	si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
C
Chao Yu 已提交
47
	si->ndirty_data = get_pages(sbi, F2FS_DIRTY_DATA);
C
Chao Yu 已提交
48
	si->ndirty_imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
C
Chao Yu 已提交
49 50
	si->ndirty_dirs = sbi->ndirty_inode[DIR_INODE];
	si->ndirty_files = sbi->ndirty_inode[FILE_INODE];
51
	si->ndirty_all = sbi->ndirty_inode[DIRTY_META];
52
	si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
53 54
	si->aw_cnt = atomic_read(&sbi->aw_cnt);
	si->max_aw_cnt = atomic_read(&sbi->max_aw_cnt);
55 56
	si->nr_wb_cp_data = get_pages(sbi, F2FS_WB_CP_DATA);
	si->nr_wb_data = get_pages(sbi, F2FS_WB_DATA);
57 58 59 60 61 62
	if (SM_I(sbi) && SM_I(sbi)->fcc_info)
		si->nr_flush =
			atomic_read(&SM_I(sbi)->fcc_info->submit_flush);
	if (SM_I(sbi) && SM_I(sbi)->dcc_info)
		si->nr_discard =
			atomic_read(&SM_I(sbi)->dcc_info->submit_discard);
63 64 65 66
	si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
	si->rsvd_segs = reserved_segments(sbi);
	si->overp_segs = overprovision_segments(sbi);
	si->valid_count = valid_user_blocks(sbi);
67
	si->discard_blks = discard_blocks(sbi);
68 69
	si->valid_node_count = valid_node_count(sbi);
	si->valid_inode_count = valid_inode_count(sbi);
C
Chao Yu 已提交
70
	si->inline_xattr = atomic_read(&sbi->inline_xattr);
71 72
	si->inline_inode = atomic_read(&sbi->inline_inode);
	si->inline_dir = atomic_read(&sbi->inline_dir);
73 74
	si->append = sbi->im[APPEND_INO].ino_num;
	si->update = sbi->im[UPDATE_INO].ino_num;
J
Jaegeuk Kim 已提交
75
	si->orphans = sbi->im[ORPHAN_INO].ino_num;
76 77 78 79 80 81
	si->utilization = utilization(sbi);

	si->free_segs = free_segments(sbi);
	si->free_secs = free_sections(sbi);
	si->prefree_count = prefree_segments(sbi);
	si->dirty_count = dirty_segments(sbi);
82
	si->node_pages = NODE_MAPPING(sbi)->nrpages;
G
Gu Zheng 已提交
83
	si->meta_pages = META_MAPPING(sbi)->nrpages;
84
	si->nats = NM_I(sbi)->nat_cnt;
85 86 87
	si->dirty_nats = NM_I(sbi)->dirty_nat_cnt;
	si->sits = MAIN_SEGS(sbi);
	si->dirty_sits = SIT_I(sbi)->dirty_sentries;
C
Chao Yu 已提交
88 89
	si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID_LIST];
	si->alloc_nids = NM_I(sbi)->nid_cnt[ALLOC_NID_LIST];
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
	si->bg_gc = sbi->bg_gc;
	si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
		* 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
		/ 2;
	si->util_valid = (int)(written_block_count(sbi) >>
						sbi->log_blocks_per_seg)
		* 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
		/ 2;
	si->util_invalid = 50 - si->util_free - si->util_valid;
	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) {
		struct curseg_info *curseg = CURSEG_I(sbi, i);
		si->curseg[i] = curseg->segno;
		si->cursec[i] = curseg->segno / sbi->segs_per_sec;
		si->curzone[i] = si->cursec[i] / sbi->secs_per_zone;
	}

	for (i = 0; i < 2; i++) {
		si->segment_count[i] = sbi->segment_count[i];
		si->block_count[i] = sbi->block_count[i];
	}
110 111

	si->inplace_count = atomic_read(&sbi->inplace_count);
112 113
}

J
Jaegeuk Kim 已提交
114
/*
115 116 117 118
 * This function calculates BDF of every segments
 */
static void update_sit_info(struct f2fs_sb_info *sbi)
{
119
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
120 121
	unsigned long long blks_per_sec, hblks_per_sec, total_vblocks;
	unsigned long long bimodal, dist;
122 123 124 125 126
	unsigned int segno, vblocks;
	int ndirty = 0;

	bimodal = 0;
	total_vblocks = 0;
127
	blks_per_sec = sbi->segs_per_sec * sbi->blocks_per_seg;
128
	hblks_per_sec = blks_per_sec / 2;
129
	for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
130 131 132 133 134 135 136 137 138
		vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
		dist = abs(vblocks - hblks_per_sec);
		bimodal += dist * dist;

		if (vblocks > 0 && vblocks < blks_per_sec) {
			total_vblocks += vblocks;
			ndirty++;
		}
	}
139
	dist = div_u64(MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec, 100);
C
Chao Yu 已提交
140
	si->bimodal = div64_u64(bimodal, dist);
141
	if (si->dirty_count)
142
		si->avg_vblocks = div_u64(total_vblocks, ndirty);
143 144 145 146
	else
		si->avg_vblocks = 0;
}

J
Jaegeuk Kim 已提交
147
/*
148 149 150 151
 * This function calculates memory footprint.
 */
static void update_mem_info(struct f2fs_sb_info *sbi)
{
152
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
153
	unsigned npages;
154
	int i;
155 156 157 158 159 160 161

	if (si->base_mem)
		goto get_cache;

	si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
	si->base_mem += 2 * sizeof(struct f2fs_inode_info);
	si->base_mem += sizeof(*sbi->ckpt);
162
	si->base_mem += sizeof(struct percpu_counter) * NR_COUNT_TYPE;
163 164 165 166 167 168

	/* build sm */
	si->base_mem += sizeof(struct f2fs_sm_info);

	/* build sit */
	si->base_mem += sizeof(struct sit_info);
169 170
	si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry);
	si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
171 172 173
	si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
	if (f2fs_discard_en(sbi))
		si->base_mem += SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi);
J
Jaegeuk Kim 已提交
174
	si->base_mem += SIT_VBLOCK_MAP_SIZE;
175
	if (sbi->segs_per_sec > 1)
176
		si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry);
177 178 179 180
	si->base_mem += __bitmap_size(sbi, SIT_BITMAP);

	/* build free segmap */
	si->base_mem += sizeof(struct free_segmap_info);
181 182
	si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi));
	si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
183 184 185

	/* build curseg */
	si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE;
186
	si->base_mem += PAGE_SIZE * NR_CURSEG_TYPE;
187 188 189

	/* build dirty segmap */
	si->base_mem += sizeof(struct dirty_seglist_info);
190 191
	si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(MAIN_SEGS(sbi));
	si->base_mem += f2fs_bitmap_size(MAIN_SECS(sbi));
192

A
arter97 已提交
193
	/* build nm */
194 195
	si->base_mem += sizeof(struct f2fs_nm_info);
	si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
196
	si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS);
C
Chao Yu 已提交
197 198
	si->base_mem += NM_I(sbi)->nat_blocks * NAT_ENTRY_BITMAP_SIZE;
	si->base_mem += NM_I(sbi)->nat_blocks / 8;
199
	si->base_mem += NM_I(sbi)->nat_blocks * sizeof(unsigned short);
200

201 202 203
get_cache:
	si->cache_mem = 0;

204
	/* build gc */
205 206 207 208
	if (sbi->gc_thread)
		si->cache_mem += sizeof(struct f2fs_gc_kthread);

	/* build merge flush thread */
209
	if (SM_I(sbi)->fcc_info)
210
		si->cache_mem += sizeof(struct flush_cmd_control);
211 212
	if (SM_I(sbi)->dcc_info)
		si->cache_mem += sizeof(struct discard_cmd_control);
213 214

	/* free nids */
C
Chao Yu 已提交
215 216 217
	si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] +
				NM_I(sbi)->nid_cnt[ALLOC_NID_LIST]) *
				sizeof(struct free_nid);
218
	si->cache_mem += NM_I(sbi)->nat_cnt * sizeof(struct nat_entry);
219 220 221
	si->cache_mem += NM_I(sbi)->dirty_nat_cnt *
					sizeof(struct nat_entry_set);
	si->cache_mem += si->inmem_pages * sizeof(struct inmem_pages);
J
Jaegeuk Kim 已提交
222
	for (i = 0; i <= ORPHAN_INO; i++)
223
		si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
224 225
	si->cache_mem += atomic_read(&sbi->total_ext_tree) *
						sizeof(struct extent_tree);
226 227
	si->cache_mem += atomic_read(&sbi->total_ext_node) *
						sizeof(struct extent_node);
228 229 230

	si->page_mem = 0;
	npages = NODE_MAPPING(sbi)->nrpages;
231
	si->page_mem += (unsigned long long)npages << PAGE_SHIFT;
232
	npages = META_MAPPING(sbi)->nrpages;
233
	si->page_mem += (unsigned long long)npages << PAGE_SHIFT;
234 235 236 237
}

static int stat_show(struct seq_file *s, void *v)
{
238
	struct f2fs_stat_info *si;
239 240 241
	int i = 0;
	int j;

242
	mutex_lock(&f2fs_stat_mutex);
243
	list_for_each_entry(si, &f2fs_stat_list, stat_list) {
244 245
		update_general_status(si->sbi);

J
Jaegeuk Kim 已提交
246 247 248
		seq_printf(s, "\n=====[ partition info(%pg). #%d, %s]=====\n",
			si->sbi->sb->s_bdev, i++,
			f2fs_readonly(si->sbi->sb) ? "RO": "RW");
249 250
		seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
			   si->sit_area_segs, si->nat_area_segs);
251 252 253 254
		seq_printf(s, "[SSA: %d] [MAIN: %d",
			   si->ssa_area_segs, si->main_area_segs);
		seq_printf(s, "(OverProv:%d Resv:%d)]\n\n",
			   si->overp_segs, si->rsvd_segs);
255 256 257 258 259 260 261
		if (test_opt(si->sbi, DISCARD))
			seq_printf(s, "Utilization: %u%% (%u valid blocks, %u discard blocks)\n",
				si->utilization, si->valid_count, si->discard_blks);
		else
			seq_printf(s, "Utilization: %u%% (%u valid blocks)\n",
				si->utilization, si->valid_count);

262 263 264 265 266
		seq_printf(s, "  - Node: %u (Inode: %u, ",
			   si->valid_node_count, si->valid_inode_count);
		seq_printf(s, "Other: %u)\n  - Data: %u\n",
			   si->valid_node_count - si->valid_inode_count,
			   si->valid_count - si->valid_node_count);
C
Chao Yu 已提交
267 268
		seq_printf(s, "  - Inline_xattr Inode: %u\n",
			   si->inline_xattr);
269 270
		seq_printf(s, "  - Inline_data Inode: %u\n",
			   si->inline_inode);
271 272
		seq_printf(s, "  - Inline_dentry Inode: %u\n",
			   si->inline_dir);
273 274
		seq_printf(s, "  - Orphan/Append/Update Inode: %u, %u, %u\n",
			   si->orphans, si->append, si->update);
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
		seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
			   si->main_area_segs, si->main_area_sections,
			   si->main_area_zones);
		seq_printf(s, "  - COLD  data: %d, %d, %d\n",
			   si->curseg[CURSEG_COLD_DATA],
			   si->cursec[CURSEG_COLD_DATA],
			   si->curzone[CURSEG_COLD_DATA]);
		seq_printf(s, "  - WARM  data: %d, %d, %d\n",
			   si->curseg[CURSEG_WARM_DATA],
			   si->cursec[CURSEG_WARM_DATA],
			   si->curzone[CURSEG_WARM_DATA]);
		seq_printf(s, "  - HOT   data: %d, %d, %d\n",
			   si->curseg[CURSEG_HOT_DATA],
			   si->cursec[CURSEG_HOT_DATA],
			   si->curzone[CURSEG_HOT_DATA]);
		seq_printf(s, "  - Dir   dnode: %d, %d, %d\n",
			   si->curseg[CURSEG_HOT_NODE],
			   si->cursec[CURSEG_HOT_NODE],
			   si->curzone[CURSEG_HOT_NODE]);
		seq_printf(s, "  - File   dnode: %d, %d, %d\n",
			   si->curseg[CURSEG_WARM_NODE],
			   si->cursec[CURSEG_WARM_NODE],
			   si->curzone[CURSEG_WARM_NODE]);
		seq_printf(s, "  - Indir nodes: %d, %d, %d\n",
			   si->curseg[CURSEG_COLD_NODE],
			   si->cursec[CURSEG_COLD_NODE],
			   si->curzone[CURSEG_COLD_NODE]);
		seq_printf(s, "\n  - Valid: %d\n  - Dirty: %d\n",
			   si->main_area_segs - si->dirty_count -
			   si->prefree_count - si->free_segs,
			   si->dirty_count);
		seq_printf(s, "  - Prefree: %d\n  - Free: %d (%d)\n\n",
			   si->prefree_count, si->free_segs, si->free_secs);
308 309
		seq_printf(s, "CP calls: %d (BG: %d)\n",
				si->cp_count, si->bg_cp_count);
310 311
		seq_printf(s, "GC calls: %d (BG: %d)\n",
			   si->call_count, si->bg_gc);
312 313 314 315 316 317 318 319 320 321
		seq_printf(s, "  - data segments : %d (%d)\n",
				si->data_segs, si->bg_data_segs);
		seq_printf(s, "  - node segments : %d (%d)\n",
				si->node_segs, si->bg_node_segs);
		seq_printf(s, "Try to move %d blocks (BG: %d)\n", si->tot_blks,
				si->bg_data_blks + si->bg_node_blks);
		seq_printf(s, "  - data blocks : %d (%d)\n", si->data_blks,
				si->bg_data_blks);
		seq_printf(s, "  - node blocks : %d (%d)\n", si->node_blks,
				si->bg_node_blks);
322
		seq_puts(s, "\nExtent Cache:\n");
323
		seq_printf(s, "  - Hit Count: L1-1:%llu L1-2:%llu L2:%llu\n",
324
				si->hit_largest, si->hit_cached,
325
				si->hit_rbtree);
326
		seq_printf(s, "  - Hit Ratio: %llu%% (%llu / %llu)\n",
327
				!si->total_ext ? 0 :
328
				div64_u64(si->hit_total * 100, si->total_ext),
329
				si->hit_total, si->total_ext);
J
Jaegeuk Kim 已提交
330 331
		seq_printf(s, "  - Inner Struct Count: tree: %d(%d), node: %d\n",
				si->ext_tree, si->zombie_tree, si->ext_node);
C
Chris Fries 已提交
332
		seq_puts(s, "\nBalancing F2FS Async:\n");
333 334 335
		seq_printf(s, "  - IO (CP: %4d, Data: %4d, Flush: %4d, Discard: %4d)\n",
			   si->nr_wb_cp_data, si->nr_wb_data,
			   si->nr_flush, si->nr_discard);
J
Jaegeuk Kim 已提交
336 337
		seq_printf(s, "  - inmem: %4d, atomic IO: %4d (Max. %4d)\n",
			   si->inmem_pages, si->aw_cnt, si->max_aw_cnt);
338
		seq_printf(s, "  - nodes: %4d in %4d\n",
339
			   si->ndirty_node, si->node_pages);
340
		seq_printf(s, "  - dents: %4d in dirs:%4d (%4d)\n",
341
			   si->ndirty_dent, si->ndirty_dirs, si->ndirty_all);
342
		seq_printf(s, "  - datas: %4d in files:%4d\n",
C
Chao Yu 已提交
343
			   si->ndirty_data, si->ndirty_files);
344
		seq_printf(s, "  - meta: %4d in %4d\n",
345
			   si->ndirty_meta, si->meta_pages);
346
		seq_printf(s, "  - imeta: %4d\n",
C
Chao Yu 已提交
347
			   si->ndirty_imeta);
348 349
		seq_printf(s, "  - NATs: %9d/%9d\n  - SITs: %9d/%9d\n",
			   si->dirty_nats, si->nats, si->dirty_sits, si->sits);
C
Chao Yu 已提交
350 351
		seq_printf(s, "  - free_nids: %9d, alloc_nids: %9d\n",
			   si->free_nids, si->alloc_nids);
352 353 354
		seq_puts(s, "\nDistribution of User Blocks:");
		seq_puts(s, " [ valid | invalid | free ]\n");
		seq_puts(s, "  [");
355 356

		for (j = 0; j < si->util_valid; j++)
357 358
			seq_putc(s, '-');
		seq_putc(s, '|');
359 360

		for (j = 0; j < si->util_invalid; j++)
361 362
			seq_putc(s, '-');
		seq_putc(s, '|');
363 364

		for (j = 0; j < si->util_free; j++)
365 366
			seq_putc(s, '-');
		seq_puts(s, "]\n\n");
367
		seq_printf(s, "IPU: %u blocks\n", si->inplace_count);
368 369 370 371 372 373 374 375 376 377 378 379
		seq_printf(s, "SSR: %u blocks in %u segments\n",
			   si->block_count[SSR], si->segment_count[SSR]);
		seq_printf(s, "LFS: %u blocks in %u segments\n",
			   si->block_count[LFS], si->segment_count[LFS]);

		/* segment usage info */
		update_sit_info(si->sbi);
		seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n",
			   si->bimodal, si->avg_vblocks);

		/* memory footprint */
		update_mem_info(si->sbi);
C
Chao Yu 已提交
380
		seq_printf(s, "\nMemory: %llu KB\n",
381
			(si->base_mem + si->cache_mem + si->page_mem) >> 10);
C
Chao Yu 已提交
382
		seq_printf(s, "  - static: %llu KB\n",
383
				si->base_mem >> 10);
C
Chao Yu 已提交
384
		seq_printf(s, "  - cached: %llu KB\n",
385
				si->cache_mem >> 10);
C
Chao Yu 已提交
386
		seq_printf(s, "  - paged : %llu KB\n",
387
				si->page_mem >> 10);
388
	}
389
	mutex_unlock(&f2fs_stat_mutex);
390 391 392 393 394 395 396 397 398
	return 0;
}

static int stat_open(struct inode *inode, struct file *file)
{
	return single_open(file, stat_show, inode->i_private);
}

static const struct file_operations stat_fops = {
399
	.owner = THIS_MODULE,
400 401 402 403 404 405
	.open = stat_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
};

406
int f2fs_build_stats(struct f2fs_sb_info *sbi)
407 408 409 410
{
	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
	struct f2fs_stat_info *si;

411 412
	si = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
	if (!si)
413 414 415 416 417 418 419 420 421 422 423
		return -ENOMEM;

	si->all_area_segs = le32_to_cpu(raw_super->segment_count);
	si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit);
	si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat);
	si->ssa_area_segs = le32_to_cpu(raw_super->segment_count_ssa);
	si->main_area_segs = le32_to_cpu(raw_super->segment_count_main);
	si->main_area_sections = le32_to_cpu(raw_super->section_count);
	si->main_area_zones = si->main_area_sections /
				le32_to_cpu(raw_super->secs_per_zone);
	si->sbi = sbi;
424
	sbi->stat_info = si;
425

426 427 428 429
	atomic64_set(&sbi->total_hit_ext, 0);
	atomic64_set(&sbi->read_hit_rbtree, 0);
	atomic64_set(&sbi->read_hit_largest, 0);
	atomic64_set(&sbi->read_hit_cached, 0);
430

C
Chao Yu 已提交
431
	atomic_set(&sbi->inline_xattr, 0);
432 433
	atomic_set(&sbi->inline_inode, 0);
	atomic_set(&sbi->inline_dir, 0);
434
	atomic_set(&sbi->inplace_count, 0);
435

436 437 438
	atomic_set(&sbi->aw_cnt, 0);
	atomic_set(&sbi->max_aw_cnt, 0);

439 440 441 442
	mutex_lock(&f2fs_stat_mutex);
	list_add_tail(&si->stat_list, &f2fs_stat_list);
	mutex_unlock(&f2fs_stat_mutex);

443 444 445 446 447
	return 0;
}

void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
{
448
	struct f2fs_stat_info *si = F2FS_STAT(sbi);
449

450
	mutex_lock(&f2fs_stat_mutex);
451
	list_del(&si->stat_list);
452 453
	mutex_unlock(&f2fs_stat_mutex);

454
	kfree(si);
455 456
}

457
int __init f2fs_create_root_stats(void)
458
{
459 460
	struct dentry *file;

461 462
	f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL);
	if (!f2fs_debugfs_root)
463
		return -ENOMEM;
464

465
	file = debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root,
466
			NULL, &stat_fops);
467 468 469
	if (!file) {
		debugfs_remove(f2fs_debugfs_root);
		f2fs_debugfs_root = NULL;
470
		return -ENOMEM;
471
	}
472 473

	return 0;
474 475 476
}

void f2fs_destroy_root_stats(void)
477
{
478
	if (!f2fs_debugfs_root)
479 480
		return;

481 482
	debugfs_remove_recursive(f2fs_debugfs_root);
	f2fs_debugfs_root = NULL;
483
}