| 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/mempool.h> | 
|---|
| 11 | #include <linux/proc_fs.h> | 
|---|
| 12 | #include <linux/seq_file.h> | 
|---|
| 13 | #include "internal.h" | 
|---|
| 14 | #define CREATE_TRACE_POINTS | 
|---|
| 15 | #include <trace/events/netfs.h> | 
|---|
| 16 |  | 
|---|
| 17 | MODULE_DESCRIPTION( "Network fs support"); | 
|---|
| 18 | MODULE_AUTHOR( "Red Hat, Inc."); | 
|---|
| 19 | MODULE_LICENSE( "GPL"); | 
|---|
| 20 |  | 
|---|
| 21 | EXPORT_TRACEPOINT_SYMBOL(netfs_sreq); | 
|---|
| 22 |  | 
|---|
| 23 | unsigned netfs_debug; | 
|---|
| 24 | module_param_named(debug, netfs_debug, uint, S_IWUSR | S_IRUGO); | 
|---|
| 25 | MODULE_PARM_DESC(netfs_debug, "Netfs support debugging mask"); | 
|---|
| 26 |  | 
|---|
| 27 | static struct kmem_cache *netfs_request_slab; | 
|---|
| 28 | static struct kmem_cache *netfs_subrequest_slab; | 
|---|
| 29 | mempool_t netfs_request_pool; | 
|---|
| 30 | mempool_t netfs_subrequest_pool; | 
|---|
| 31 |  | 
|---|
| 32 | #ifdef CONFIG_PROC_FS | 
|---|
| 33 | LIST_HEAD(netfs_io_requests); | 
|---|
| 34 | DEFINE_SPINLOCK(netfs_proc_lock); | 
|---|
| 35 |  | 
|---|
| 36 | static const char *netfs_origins[nr__netfs_io_origin] = { | 
|---|
| 37 | [NETFS_READAHEAD]		= "RA", | 
|---|
| 38 | [NETFS_READPAGE]		= "RP", | 
|---|
| 39 | [NETFS_READ_GAPS]		= "RG", | 
|---|
| 40 | [NETFS_READ_SINGLE]		= "R1", | 
|---|
| 41 | [NETFS_READ_FOR_WRITE]		= "RW", | 
|---|
| 42 | [NETFS_UNBUFFERED_READ]		= "UR", | 
|---|
| 43 | [NETFS_DIO_READ]		= "DR", | 
|---|
| 44 | [NETFS_WRITEBACK]		= "WB", | 
|---|
| 45 | [NETFS_WRITEBACK_SINGLE]	= "W1", | 
|---|
| 46 | [NETFS_WRITETHROUGH]		= "WT", | 
|---|
| 47 | [NETFS_UNBUFFERED_WRITE]	= "UW", | 
|---|
| 48 | [NETFS_DIO_WRITE]		= "DW", | 
|---|
| 49 | [NETFS_PGPRIV2_COPY_TO_CACHE]	= "2C", | 
|---|
| 50 | }; | 
|---|
| 51 |  | 
|---|
| 52 | /* | 
|---|
| 53 | * Generate a list of I/O requests in /proc/fs/netfs/requests | 
|---|
| 54 | */ | 
|---|
| 55 | static int netfs_requests_seq_show(struct seq_file *m, void *v) | 
|---|
| 56 | { | 
|---|
| 57 | struct netfs_io_request *rreq; | 
|---|
| 58 |  | 
|---|
| 59 | if (v == &netfs_io_requests) { | 
|---|
| 60 | seq_puts(m, | 
|---|
| 61 | s: "REQUEST  OR REF FLAG ERR  OPS COVERAGE\n" | 
|---|
| 62 | "======== == === ==== ==== === =========\n" | 
|---|
| 63 | ); | 
|---|
| 64 | return 0; | 
|---|
| 65 | } | 
|---|
| 66 |  | 
|---|
| 67 | rreq = list_entry(v, struct netfs_io_request, proc_link); | 
|---|
| 68 | seq_printf(m, | 
|---|
| 69 | fmt: "%08x %s %3d %4lx %4ld %3d @%04llx %llx/%llx", | 
|---|
| 70 | rreq->debug_id, | 
|---|
| 71 | netfs_origins[rreq->origin], | 
|---|
| 72 | refcount_read(r: &rreq->ref), | 
|---|
| 73 | rreq->flags, | 
|---|
| 74 | rreq->error, | 
|---|
| 75 | 0, | 
|---|
| 76 | rreq->start, rreq->submitted, rreq->len); | 
|---|
| 77 | seq_putc(m, c: '\n'); | 
|---|
| 78 | return 0; | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | static void *netfs_requests_seq_start(struct seq_file *m, loff_t *_pos) | 
|---|
| 82 | __acquires(rcu) | 
|---|
| 83 | { | 
|---|
| 84 | rcu_read_lock(); | 
|---|
| 85 | return seq_list_start_head(head: &netfs_io_requests, pos: *_pos); | 
|---|
| 86 | } | 
|---|
| 87 |  | 
|---|
| 88 | static void *netfs_requests_seq_next(struct seq_file *m, void *v, loff_t *_pos) | 
|---|
| 89 | { | 
|---|
| 90 | return seq_list_next(v, head: &netfs_io_requests, ppos: _pos); | 
|---|
| 91 | } | 
|---|
| 92 |  | 
|---|
| 93 | static void netfs_requests_seq_stop(struct seq_file *m, void *v) | 
|---|
| 94 | __releases(rcu) | 
|---|
| 95 | { | 
|---|
| 96 | rcu_read_unlock(); | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | static const struct seq_operations netfs_requests_seq_ops = { | 
|---|
| 100 | .start  = netfs_requests_seq_start, | 
|---|
| 101 | .next   = netfs_requests_seq_next, | 
|---|
| 102 | .stop   = netfs_requests_seq_stop, | 
|---|
| 103 | .show   = netfs_requests_seq_show, | 
|---|
| 104 | }; | 
|---|
| 105 | #endif /* CONFIG_PROC_FS */ | 
|---|
| 106 |  | 
|---|
| 107 | static int __init netfs_init(void) | 
|---|
| 108 | { | 
|---|
| 109 | int ret = -ENOMEM; | 
|---|
| 110 |  | 
|---|
| 111 | netfs_request_slab = kmem_cache_create( "netfs_request", | 
|---|
| 112 | sizeof(struct netfs_io_request), 0, | 
|---|
| 113 | SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT, | 
|---|
| 114 | NULL); | 
|---|
| 115 | if (!netfs_request_slab) | 
|---|
| 116 | goto error_req; | 
|---|
| 117 |  | 
|---|
| 118 | if (mempool_init_slab_pool(&netfs_request_pool, 100, netfs_request_slab) < 0) | 
|---|
| 119 | goto error_reqpool; | 
|---|
| 120 |  | 
|---|
| 121 | netfs_subrequest_slab = kmem_cache_create( "netfs_subrequest", | 
|---|
| 122 | sizeof(struct netfs_io_subrequest) + 16, 0, | 
|---|
| 123 | SLAB_HWCACHE_ALIGN | SLAB_ACCOUNT, | 
|---|
| 124 | NULL); | 
|---|
| 125 | if (!netfs_subrequest_slab) | 
|---|
| 126 | goto error_subreq; | 
|---|
| 127 |  | 
|---|
| 128 | if (mempool_init_slab_pool(&netfs_subrequest_pool, 100, netfs_subrequest_slab) < 0) | 
|---|
| 129 | goto error_subreqpool; | 
|---|
| 130 |  | 
|---|
| 131 | #ifdef CONFIG_PROC_FS | 
|---|
| 132 | if (!proc_mkdir( "fs/netfs", NULL)) | 
|---|
| 133 | goto error_proc; | 
|---|
| 134 | if (!proc_create_seq( "fs/netfs/requests", S_IFREG | 0444, NULL, | 
|---|
| 135 | &netfs_requests_seq_ops)) | 
|---|
| 136 | goto error_procfile; | 
|---|
| 137 | #endif | 
|---|
| 138 | #ifdef CONFIG_FSCACHE_STATS | 
|---|
| 139 | if (!proc_create_single( "fs/netfs/stats", S_IFREG | 0444, NULL, | 
|---|
| 140 | netfs_stats_show)) | 
|---|
| 141 | goto error_procfile; | 
|---|
| 142 | #endif | 
|---|
| 143 |  | 
|---|
| 144 | ret = fscache_init(); | 
|---|
| 145 | if (ret < 0) | 
|---|
| 146 | goto error_fscache; | 
|---|
| 147 | return 0; | 
|---|
| 148 |  | 
|---|
| 149 | error_fscache: | 
|---|
| 150 | #ifdef CONFIG_PROC_FS | 
|---|
| 151 | error_procfile: | 
|---|
| 152 | remove_proc_subtree( "fs/netfs", NULL); | 
|---|
| 153 | error_proc: | 
|---|
| 154 | #endif | 
|---|
| 155 | mempool_exit(pool: &netfs_subrequest_pool); | 
|---|
| 156 | error_subreqpool: | 
|---|
| 157 | kmem_cache_destroy(s: netfs_subrequest_slab); | 
|---|
| 158 | error_subreq: | 
|---|
| 159 | mempool_exit(pool: &netfs_request_pool); | 
|---|
| 160 | error_reqpool: | 
|---|
| 161 | kmem_cache_destroy(s: netfs_request_slab); | 
|---|
| 162 | error_req: | 
|---|
| 163 | return ret; | 
|---|
| 164 | } | 
|---|
| 165 | fs_initcall(netfs_init); | 
|---|
| 166 |  | 
|---|
| 167 | static void __exit netfs_exit(void) | 
|---|
| 168 | { | 
|---|
| 169 | fscache_exit(); | 
|---|
| 170 | remove_proc_subtree( "fs/netfs", NULL); | 
|---|
| 171 | mempool_exit(pool: &netfs_subrequest_pool); | 
|---|
| 172 | kmem_cache_destroy(s: netfs_subrequest_slab); | 
|---|
| 173 | mempool_exit(pool: &netfs_request_pool); | 
|---|
| 174 | kmem_cache_destroy(s: netfs_request_slab); | 
|---|
| 175 | } | 
|---|
| 176 | module_exit(netfs_exit); | 
|---|
| 177 |  | 
|---|