1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* CacheFiles statistics
3  *
4  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  */
7 
8 #include <linux/module.h>
9 #include <linux/proc_fs.h>
10 #include <linux/seq_file.h>
11 #include "internal.h"
12 
13 atomic_t cachefiles_lookup_histogram[HZ];
14 atomic_t cachefiles_mkdir_histogram[HZ];
15 atomic_t cachefiles_create_histogram[HZ];
16 
17 /*
18  * display the latency histogram
19  */
cachefiles_histogram_show(struct seq_file * m,void * v)20 static int cachefiles_histogram_show(struct seq_file *m, void *v)
21 {
22 	unsigned long index;
23 	unsigned x, y, z, t;
24 
25 	switch ((unsigned long) v) {
26 	case 1:
27 		seq_puts(m, "JIFS  SECS  LOOKUPS   MKDIRS    CREATES\n");
28 		return 0;
29 	case 2:
30 		seq_puts(m, "===== ===== ========= ========= =========\n");
31 		return 0;
32 	default:
33 		index = (unsigned long) v - 3;
34 		x = atomic_read(&cachefiles_lookup_histogram[index]);
35 		y = atomic_read(&cachefiles_mkdir_histogram[index]);
36 		z = atomic_read(&cachefiles_create_histogram[index]);
37 		if (x == 0 && y == 0 && z == 0)
38 			return 0;
39 
40 		t = (index * 1000) / HZ;
41 
42 		seq_printf(m, "%4lu  0.%03u %9u %9u %9u\n", index, t, x, y, z);
43 		return 0;
44 	}
45 }
46 
47 /*
48  * set up the iterator to start reading from the first line
49  */
cachefiles_histogram_start(struct seq_file * m,loff_t * _pos)50 static void *cachefiles_histogram_start(struct seq_file *m, loff_t *_pos)
51 {
52 	if ((unsigned long long)*_pos >= HZ + 2)
53 		return NULL;
54 	if (*_pos == 0)
55 		*_pos = 1;
56 	return (void *)(unsigned long) *_pos;
57 }
58 
59 /*
60  * move to the next line
61  */
cachefiles_histogram_next(struct seq_file * m,void * v,loff_t * pos)62 static void *cachefiles_histogram_next(struct seq_file *m, void *v, loff_t *pos)
63 {
64 	(*pos)++;
65 	return (unsigned long long)*pos > HZ + 2 ?
66 		NULL : (void *)(unsigned long) *pos;
67 }
68 
69 /*
70  * clean up after reading
71  */
cachefiles_histogram_stop(struct seq_file * m,void * v)72 static void cachefiles_histogram_stop(struct seq_file *m, void *v)
73 {
74 }
75 
76 static const struct seq_operations cachefiles_histogram_ops = {
77 	.start		= cachefiles_histogram_start,
78 	.stop		= cachefiles_histogram_stop,
79 	.next		= cachefiles_histogram_next,
80 	.show		= cachefiles_histogram_show,
81 };
82 
83 /*
84  * initialise the /proc/fs/cachefiles/ directory
85  */
cachefiles_proc_init(void)86 int __init cachefiles_proc_init(void)
87 {
88 	_enter("");
89 
90 	if (!proc_mkdir("fs/cachefiles", NULL))
91 		goto error_dir;
92 
93 	if (!proc_create_seq("fs/cachefiles/histogram", S_IFREG | 0444, NULL,
94 			 &cachefiles_histogram_ops))
95 		goto error_histogram;
96 
97 	_leave(" = 0");
98 	return 0;
99 
100 error_histogram:
101 	remove_proc_entry("fs/cachefiles", NULL);
102 error_dir:
103 	_leave(" = -ENOMEM");
104 	return -ENOMEM;
105 }
106 
107 /*
108  * clean up the /proc/fs/cachefiles/ directory
109  */
cachefiles_proc_cleanup(void)110 void cachefiles_proc_cleanup(void)
111 {
112 	remove_proc_entry("fs/cachefiles/histogram", NULL);
113 	remove_proc_entry("fs/cachefiles", NULL);
114 }
115