aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-11-02 17:50:41 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2012-12-10 23:43:42 -0500
commit902829aa0b722511369e4e6193e66390bc58e0a2 (patch)
tree3e0e5c61b26844f161505ceedc6e93a548689082 /fs/f2fs
parentd624c96fb3249e5d3dcf4e60a805e5e6b0dd7d91 (diff)
f2fs: move proc files to debugfs
This moves all of the f2fs debugging files into debugfs. The files are located in /sys/kernel/debug/f2fs/ Note, I think we are generating all of the same information in each of the files for every unique f2fs filesystem in the machine. This copies the functionality that was present in the proc files, but this should be fixed up in the future. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> [jaegeuk.kim@samsung.com: merged 3 debugfs entries into a *status* entry] Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/debug.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
new file mode 100644
index 000000000000..a56181c1b28b
--- /dev/null
+++ b/fs/f2fs/debug.c
@@ -0,0 +1,361 @@
1/**
2 * f2fs debugging statistics
3 *
4 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
6 * Copyright (c) 2012 Linux Foundation
7 * Copyright (c) 2012 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/fs.h>
15#include <linux/backing-dev.h>
16#include <linux/proc_fs.h>
17#include <linux/f2fs_fs.h>
18#include <linux/blkdev.h>
19#include <linux/debugfs.h>
20#include <linux/seq_file.h>
21
22#include "f2fs.h"
23#include "node.h"
24#include "segment.h"
25#include "gc.h"
26
27static LIST_HEAD(f2fs_stat_list);
28static struct dentry *debugfs_root;
29
30void update_general_status(struct f2fs_sb_info *sbi)
31{
32 struct f2fs_stat_info *si = sbi->stat_info;
33 int i;
34
35 /* valid check of the segment numbers */
36 si->hit_ext = sbi->read_hit_ext;
37 si->total_ext = sbi->total_hit_ext;
38 si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
39 si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
40 si->ndirty_dirs = sbi->n_dirty_dirs;
41 si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
42 si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
43 si->rsvd_segs = reserved_segments(sbi);
44 si->overp_segs = overprovision_segments(sbi);
45 si->valid_count = valid_user_blocks(sbi);
46 si->valid_node_count = valid_node_count(sbi);
47 si->valid_inode_count = valid_inode_count(sbi);
48 si->utilization = utilization(sbi);
49
50 si->free_segs = free_segments(sbi);
51 si->free_secs = free_sections(sbi);
52 si->prefree_count = prefree_segments(sbi);
53 si->dirty_count = dirty_segments(sbi);
54 si->node_pages = sbi->node_inode->i_mapping->nrpages;
55 si->meta_pages = sbi->meta_inode->i_mapping->nrpages;
56 si->nats = NM_I(sbi)->nat_cnt;
57 si->sits = SIT_I(sbi)->dirty_sentries;
58 si->fnids = NM_I(sbi)->fcnt;
59 si->bg_gc = sbi->bg_gc;
60 si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
61 * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
62 / 2;
63 si->util_valid = (int)(written_block_count(sbi) >>
64 sbi->log_blocks_per_seg)
65 * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
66 / 2;
67 si->util_invalid = 50 - si->util_free - si->util_valid;
68 for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) {
69 struct curseg_info *curseg = CURSEG_I(sbi, i);
70 si->curseg[i] = curseg->segno;
71 si->cursec[i] = curseg->segno / sbi->segs_per_sec;
72 si->curzone[i] = si->cursec[i] / sbi->secs_per_zone;
73 }
74
75 for (i = 0; i < 2; i++) {
76 si->segment_count[i] = sbi->segment_count[i];
77 si->block_count[i] = sbi->block_count[i];
78 }
79}
80
81/**
82 * This function calculates BDF of every segments
83 */
84static void update_sit_info(struct f2fs_sb_info *sbi)
85{
86 struct f2fs_stat_info *si = sbi->stat_info;
87 unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist;
88 struct sit_info *sit_i = SIT_I(sbi);
89 unsigned int segno, vblocks;
90 int ndirty = 0;
91
92 bimodal = 0;
93 total_vblocks = 0;
94 blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg);
95 hblks_per_sec = blks_per_sec / 2;
96 mutex_lock(&sit_i->sentry_lock);
97 for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) {
98 vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
99 dist = abs(vblocks - hblks_per_sec);
100 bimodal += dist * dist;
101
102 if (vblocks > 0 && vblocks < blks_per_sec) {
103 total_vblocks += vblocks;
104 ndirty++;
105 }
106 }
107 mutex_unlock(&sit_i->sentry_lock);
108 dist = sbi->total_sections * hblks_per_sec * hblks_per_sec / 100;
109 si->bimodal = bimodal / dist;
110 if (si->dirty_count)
111 si->avg_vblocks = total_vblocks / ndirty;
112 else
113 si->avg_vblocks = 0;
114}
115
116/**
117 * This function calculates memory footprint.
118 */
119static void update_mem_info(struct f2fs_sb_info *sbi)
120{
121 struct f2fs_stat_info *si = sbi->stat_info;
122 unsigned npages;
123
124 if (si->base_mem)
125 goto get_cache;
126
127 si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
128 si->base_mem += 2 * sizeof(struct f2fs_inode_info);
129 si->base_mem += sizeof(*sbi->ckpt);
130
131 /* build sm */
132 si->base_mem += sizeof(struct f2fs_sm_info);
133
134 /* build sit */
135 si->base_mem += sizeof(struct sit_info);
136 si->base_mem += TOTAL_SEGS(sbi) * sizeof(struct seg_entry);
137 si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi));
138 si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi);
139 if (sbi->segs_per_sec > 1)
140 si->base_mem += sbi->total_sections *
141 sizeof(struct sec_entry);
142 si->base_mem += __bitmap_size(sbi, SIT_BITMAP);
143
144 /* build free segmap */
145 si->base_mem += sizeof(struct free_segmap_info);
146 si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi));
147 si->base_mem += f2fs_bitmap_size(sbi->total_sections);
148
149 /* build curseg */
150 si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE;
151 si->base_mem += PAGE_CACHE_SIZE * NR_CURSEG_TYPE;
152
153 /* build dirty segmap */
154 si->base_mem += sizeof(struct dirty_seglist_info);
155 si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi));
156 si->base_mem += 2 * f2fs_bitmap_size(TOTAL_SEGS(sbi));
157
158 /* buld nm */
159 si->base_mem += sizeof(struct f2fs_nm_info);
160 si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
161
162 /* build gc */
163 si->base_mem += sizeof(struct f2fs_gc_kthread);
164
165get_cache:
166 /* free nids */
167 si->cache_mem = NM_I(sbi)->fcnt;
168 si->cache_mem += NM_I(sbi)->nat_cnt;
169 npages = sbi->node_inode->i_mapping->nrpages;
170 si->cache_mem += npages << PAGE_CACHE_SHIFT;
171 npages = sbi->meta_inode->i_mapping->nrpages;
172 si->cache_mem += npages << PAGE_CACHE_SHIFT;
173 si->cache_mem += sbi->n_orphans * sizeof(struct orphan_inode_entry);
174 si->cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry);
175}
176
177static int stat_show(struct seq_file *s, void *v)
178{
179 struct f2fs_stat_info *si, *next;
180 int i = 0;
181 int j;
182
183 list_for_each_entry_safe(si, next, &f2fs_stat_list, stat_list) {
184
185 mutex_lock(&si->stat_lock);
186 if (!si->sbi) {
187 mutex_unlock(&si->stat_lock);
188 continue;
189 }
190 update_general_status(si->sbi);
191
192 seq_printf(s, "\n=====[ partition info. #%d ]=====\n", i++);
193 seq_printf(s, "[SB: 1] [CP: 2] [NAT: %d] [SIT: %d] ",
194 si->nat_area_segs, si->sit_area_segs);
195 seq_printf(s, "[SSA: %d] [MAIN: %d",
196 si->ssa_area_segs, si->main_area_segs);
197 seq_printf(s, "(OverProv:%d Resv:%d)]\n\n",
198 si->overp_segs, si->rsvd_segs);
199 seq_printf(s, "Utilization: %d%% (%d valid blocks)\n",
200 si->utilization, si->valid_count);
201 seq_printf(s, " - Node: %u (Inode: %u, ",
202 si->valid_node_count, si->valid_inode_count);
203 seq_printf(s, "Other: %u)\n - Data: %u\n",
204 si->valid_node_count - si->valid_inode_count,
205 si->valid_count - si->valid_node_count);
206 seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
207 si->main_area_segs, si->main_area_sections,
208 si->main_area_zones);
209 seq_printf(s, " - COLD data: %d, %d, %d\n",
210 si->curseg[CURSEG_COLD_DATA],
211 si->cursec[CURSEG_COLD_DATA],
212 si->curzone[CURSEG_COLD_DATA]);
213 seq_printf(s, " - WARM data: %d, %d, %d\n",
214 si->curseg[CURSEG_WARM_DATA],
215 si->cursec[CURSEG_WARM_DATA],
216 si->curzone[CURSEG_WARM_DATA]);
217 seq_printf(s, " - HOT data: %d, %d, %d\n",
218 si->curseg[CURSEG_HOT_DATA],
219 si->cursec[CURSEG_HOT_DATA],
220 si->curzone[CURSEG_HOT_DATA]);
221 seq_printf(s, " - Dir dnode: %d, %d, %d\n",
222 si->curseg[CURSEG_HOT_NODE],
223 si->cursec[CURSEG_HOT_NODE],
224 si->curzone[CURSEG_HOT_NODE]);
225 seq_printf(s, " - File dnode: %d, %d, %d\n",
226 si->curseg[CURSEG_WARM_NODE],
227 si->cursec[CURSEG_WARM_NODE],
228 si->curzone[CURSEG_WARM_NODE]);
229 seq_printf(s, " - Indir nodes: %d, %d, %d\n",
230 si->curseg[CURSEG_COLD_NODE],
231 si->cursec[CURSEG_COLD_NODE],
232 si->curzone[CURSEG_COLD_NODE]);
233 seq_printf(s, "\n - Valid: %d\n - Dirty: %d\n",
234 si->main_area_segs - si->dirty_count -
235 si->prefree_count - si->free_segs,
236 si->dirty_count);
237 seq_printf(s, " - Prefree: %d\n - Free: %d (%d)\n\n",
238 si->prefree_count, si->free_segs, si->free_secs);
239 seq_printf(s, "GC calls: %d (BG: %d)\n",
240 si->call_count, si->bg_gc);
241 seq_printf(s, " - data segments : %d\n", si->data_segs);
242 seq_printf(s, " - node segments : %d\n", si->node_segs);
243 seq_printf(s, "Try to move %d blocks\n", si->tot_blks);
244 seq_printf(s, " - data blocks : %d\n", si->data_blks);
245 seq_printf(s, " - node blocks : %d\n", si->node_blks);
246 seq_printf(s, "\nExtent Hit Ratio: %d / %d\n",
247 si->hit_ext, si->total_ext);
248 seq_printf(s, "\nBalancing F2FS Async:\n");
249 seq_printf(s, " - nodes %4d in %4d\n",
250 si->ndirty_node, si->node_pages);
251 seq_printf(s, " - dents %4d in dirs:%4d\n",
252 si->ndirty_dent, si->ndirty_dirs);
253 seq_printf(s, " - meta %4d in %4d\n",
254 si->ndirty_meta, si->meta_pages);
255 seq_printf(s, " - NATs %5d > %lu\n",
256 si->nats, NM_WOUT_THRESHOLD);
257 seq_printf(s, " - SITs: %5d\n - free_nids: %5d\n",
258 si->sits, si->fnids);
259 seq_printf(s, "\nDistribution of User Blocks:");
260 seq_printf(s, " [ valid | invalid | free ]\n");
261 seq_printf(s, " [");
262
263 for (j = 0; j < si->util_valid; j++)
264 seq_printf(s, "-");
265 seq_printf(s, "|");
266
267 for (j = 0; j < si->util_invalid; j++)
268 seq_printf(s, "-");
269 seq_printf(s, "|");
270
271 for (j = 0; j < si->util_free; j++)
272 seq_printf(s, "-");
273 seq_printf(s, "]\n\n");
274 seq_printf(s, "SSR: %u blocks in %u segments\n",
275 si->block_count[SSR], si->segment_count[SSR]);
276 seq_printf(s, "LFS: %u blocks in %u segments\n",
277 si->block_count[LFS], si->segment_count[LFS]);
278
279 /* segment usage info */
280 update_sit_info(si->sbi);
281 seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n",
282 si->bimodal, si->avg_vblocks);
283
284 /* memory footprint */
285 update_mem_info(si->sbi);
286 seq_printf(s, "\nMemory: %u KB = static: %u + cached: %u\n",
287 (si->base_mem + si->cache_mem) >> 10,
288 si->base_mem >> 10, si->cache_mem >> 10);
289 mutex_unlock(&si->stat_lock);
290 }
291 return 0;
292}
293
294static int stat_open(struct inode *inode, struct file *file)
295{
296 return single_open(file, stat_show, inode->i_private);
297}
298
299static const struct file_operations stat_fops = {
300 .open = stat_open,
301 .read = seq_read,
302 .llseek = seq_lseek,
303 .release = single_release,
304};
305
306static int init_stats(struct f2fs_sb_info *sbi)
307{
308 struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
309 struct f2fs_stat_info *si;
310
311 sbi->stat_info = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
312 if (!sbi->stat_info)
313 return -ENOMEM;
314
315 si = sbi->stat_info;
316 mutex_init(&si->stat_lock);
317 list_add_tail(&si->stat_list, &f2fs_stat_list);
318
319 si->all_area_segs = le32_to_cpu(raw_super->segment_count);
320 si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit);
321 si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat);
322 si->ssa_area_segs = le32_to_cpu(raw_super->segment_count_ssa);
323 si->main_area_segs = le32_to_cpu(raw_super->segment_count_main);
324 si->main_area_sections = le32_to_cpu(raw_super->section_count);
325 si->main_area_zones = si->main_area_sections /
326 le32_to_cpu(raw_super->secs_per_zone);
327 si->sbi = sbi;
328 return 0;
329}
330
331int f2fs_build_stats(struct f2fs_sb_info *sbi)
332{
333 int retval;
334
335 retval = init_stats(sbi);
336 if (retval)
337 return retval;
338
339 if (!debugfs_root)
340 debugfs_root = debugfs_create_dir("f2fs", NULL);
341
342 debugfs_create_file("status", S_IRUGO, debugfs_root, NULL, &stat_fops);
343 return 0;
344}
345
346void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
347{
348 struct f2fs_stat_info *si = sbi->stat_info;
349
350 list_del(&si->stat_list);
351 mutex_lock(&si->stat_lock);
352 si->sbi = NULL;
353 mutex_unlock(&si->stat_lock);
354 kfree(sbi->stat_info);
355}
356
357void destroy_root_stats(void)
358{
359 debugfs_remove_recursive(debugfs_root);
360 debugfs_root = NULL;
361}