1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* Miscellaneous bits for the netfs support library. |
3 | * |
4 | * Copyright (C) 2022 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/export.h> |
10 | #include <linux/proc_fs.h> |
11 | #include <linux/seq_file.h> |
12 | #include "internal.h" |
13 | #define CREATE_TRACE_POINTS |
14 | #include <trace/events/netfs.h> |
15 | |
16 | MODULE_DESCRIPTION("Network fs support" ); |
17 | MODULE_AUTHOR("Red Hat, Inc." ); |
18 | MODULE_LICENSE("GPL" ); |
19 | |
20 | EXPORT_TRACEPOINT_SYMBOL(netfs_sreq); |
21 | |
22 | unsigned netfs_debug; |
23 | module_param_named(debug, netfs_debug, uint, S_IWUSR | S_IRUGO); |
24 | MODULE_PARM_DESC(netfs_debug, "Netfs support debugging mask" ); |
25 | |
26 | #ifdef CONFIG_PROC_FS |
27 | LIST_HEAD(netfs_io_requests); |
28 | DEFINE_SPINLOCK(netfs_proc_lock); |
29 | |
30 | static const char *netfs_origins[nr__netfs_io_origin] = { |
31 | [NETFS_READAHEAD] = "RA" , |
32 | [NETFS_READPAGE] = "RP" , |
33 | [NETFS_READ_FOR_WRITE] = "RW" , |
34 | [NETFS_WRITEBACK] = "WB" , |
35 | [NETFS_WRITETHROUGH] = "WT" , |
36 | [NETFS_LAUNDER_WRITE] = "LW" , |
37 | [NETFS_UNBUFFERED_WRITE] = "UW" , |
38 | [NETFS_DIO_READ] = "DR" , |
39 | [NETFS_DIO_WRITE] = "DW" , |
40 | }; |
41 | |
42 | /* |
43 | * Generate a list of I/O requests in /proc/fs/netfs/requests |
44 | */ |
45 | static int netfs_requests_seq_show(struct seq_file *m, void *v) |
46 | { |
47 | struct netfs_io_request *rreq; |
48 | |
49 | if (v == &netfs_io_requests) { |
50 | seq_puts(m, |
51 | s: "REQUEST OR REF FL ERR OPS COVERAGE\n" |
52 | "======== == === == ==== === =========\n" |
53 | ); |
54 | return 0; |
55 | } |
56 | |
57 | rreq = list_entry(v, struct netfs_io_request, proc_link); |
58 | seq_printf(m, |
59 | fmt: "%08x %s %3d %2lx %4d %3d @%04llx %zx/%zx" , |
60 | rreq->debug_id, |
61 | netfs_origins[rreq->origin], |
62 | refcount_read(r: &rreq->ref), |
63 | rreq->flags, |
64 | rreq->error, |
65 | atomic_read(v: &rreq->nr_outstanding), |
66 | rreq->start, rreq->submitted, rreq->len); |
67 | seq_putc(m, c: '\n'); |
68 | return 0; |
69 | } |
70 | |
71 | static void *netfs_requests_seq_start(struct seq_file *m, loff_t *_pos) |
72 | __acquires(rcu) |
73 | { |
74 | rcu_read_lock(); |
75 | return seq_list_start_head(head: &netfs_io_requests, pos: *_pos); |
76 | } |
77 | |
78 | static void *netfs_requests_seq_next(struct seq_file *m, void *v, loff_t *_pos) |
79 | { |
80 | return seq_list_next(v, head: &netfs_io_requests, ppos: _pos); |
81 | } |
82 | |
83 | static void netfs_requests_seq_stop(struct seq_file *m, void *v) |
84 | __releases(rcu) |
85 | { |
86 | rcu_read_unlock(); |
87 | } |
88 | |
89 | static const struct seq_operations netfs_requests_seq_ops = { |
90 | .start = netfs_requests_seq_start, |
91 | .next = netfs_requests_seq_next, |
92 | .stop = netfs_requests_seq_stop, |
93 | .show = netfs_requests_seq_show, |
94 | }; |
95 | #endif /* CONFIG_PROC_FS */ |
96 | |
97 | static int __init netfs_init(void) |
98 | { |
99 | int ret = -ENOMEM; |
100 | |
101 | if (!proc_mkdir("fs/netfs" , NULL)) |
102 | goto error; |
103 | if (!proc_create_seq("fs/netfs/requests" , S_IFREG | 0444, NULL, |
104 | &netfs_requests_seq_ops)) |
105 | goto error_proc; |
106 | #ifdef CONFIG_FSCACHE_STATS |
107 | if (!proc_create_single("fs/netfs/stats" , S_IFREG | 0444, NULL, |
108 | netfs_stats_show)) |
109 | goto error_proc; |
110 | #endif |
111 | |
112 | ret = fscache_init(); |
113 | if (ret < 0) |
114 | goto error_proc; |
115 | return 0; |
116 | |
117 | error_proc: |
118 | remove_proc_entry("fs/netfs" , NULL); |
119 | error: |
120 | return ret; |
121 | } |
122 | fs_initcall(netfs_init); |
123 | |
124 | static void __exit netfs_exit(void) |
125 | { |
126 | fscache_exit(); |
127 | remove_proc_entry("fs/netfs" , NULL); |
128 | } |
129 | module_exit(netfs_exit); |
130 | |