| 1 | |
| 2 | |
| 3 | * Copyright (C) 2025, LG Electronics.
|
| 4 | * Author(s): Hyunchul Lee <[email protected]>
|
| 5 | * Copyright (C) 2025, Samsung Electronics.
|
| 6 | * Author(s): Vedansh Bhardwaj <[email protected]>
|
| 7 |
|
| 8 |
|
| 9 | #include <linux/module.h>
|
| 10 | #include <linux/proc_fs.h>
|
| 11 | #include <linux/seq_file.h>
|
| 12 |
|
| 13 | #include "misc.h"
|
| 14 | #include "connection.h"
|
| 15 | #include "server.h"
|
| 16 | #include "stats.h"
|
| 17 | #include "smb_common.h"
|
| 18 | #include "smb2pdu.h"
|
| 19 | #include "vfs_cache.h"
|
| 20 |
|
| 21 | static struct proc_dir_entry *ksmbd_proc_fs;
|
| 22 | struct ksmbd_counters ksmbd_counters;
|
| 23 |
|
| 24 | struct proc_dir_entry *ksmbd_proc_create(const char *name,
|
| 25 | int (*show)(struct seq_file *m, void *v),
|
| 26 | void *v)
|
| 27 | {
|
| 28 | return proc_create_single_data(name, 0400, ksmbd_proc_fs,
|
| 29 | show, v);
|
| 30 | }
|
| 31 |
|
| 32 | void ksmbd_proc_show_flag_names(struct seq_file *m,
|
| 33 | const struct ksmbd_const_name *table,
|
| 34 | int count, unsigned int flags)
|
| 35 | {
|
| 36 | unsigned int remaining = flags;
|
| 37 | bool separator = false;
|
| 38 | int i;
|
| 39 |
|
| 40 | for (i = 0; i < count; i++) {
|
| 41 | unsigned int flag = table[i].const_value;
|
| 42 |
|
| 43 | if (!flag || (remaining & flag) != flag)
|
| 44 | continue;
|
| 45 | seq_printf(m, "%s%s", separator ? "," : "", table[i].name);
|
| 46 | separator = true;
|
| 47 | remaining &= ~flag;
|
| 48 | }
|
| 49 |
|
| 50 | if (remaining)
|
| 51 | seq_printf(m, "%s0x%08x", separator ? "," : "", remaining);
|
| 52 | else if (!separator)
|
| 53 | seq_puts(m, "none");
|
| 54 | }
|
| 55 |
|
| 56 | const char *ksmbd_proc_const_name(const struct ksmbd_const_name *table,
|
| 57 | int count, unsigned int const_value)
|
| 58 | {
|
| 59 | int i;
|
| 60 |
|
| 61 | for (i = 0; i < count; i++) {
|
| 62 | if (table[i].const_value == const_value)
|
| 63 | return table[i].name;
|
| 64 | }
|
| 65 | return NULL;
|
| 66 | }
|
| 67 |
|
| 68 | struct ksmbd_const_smb2_process_req {
|
| 69 | unsigned int const_value;
|
| 70 | const char *name;
|
| 71 | };
|
| 72 |
|
| 73 | static const struct ksmbd_const_smb2_process_req smb2_process_req[KSMBD_COUNTER_MAX_REQS] = {
|
| 74 | {le16_to_cpu(SMB2_NEGOTIATE), "SMB2_NEGOTIATE"},
|
| 75 | {le16_to_cpu(SMB2_SESSION_SETUP), "SMB2_SESSION_SETUP"},
|
| 76 | {le16_to_cpu(SMB2_LOGOFF), "SMB2_LOGOFF"},
|
| 77 | {le16_to_cpu(SMB2_TREE_CONNECT), "SMB2_TREE_CONNECT"},
|
| 78 | {le16_to_cpu(SMB2_TREE_DISCONNECT), "SMB2_TREE_DISCONNECT"},
|
| 79 | {le16_to_cpu(SMB2_CREATE), "SMB2_CREATE"},
|
| 80 | {le16_to_cpu(SMB2_CLOSE), "SMB2_CLOSE"},
|
| 81 | {le16_to_cpu(SMB2_FLUSH), "SMB2_FLUSH"},
|
| 82 | {le16_to_cpu(SMB2_READ), "SMB2_READ"},
|
| 83 | {le16_to_cpu(SMB2_WRITE), "SMB2_WRITE"},
|
| 84 | {le16_to_cpu(SMB2_LOCK), "SMB2_LOCK"},
|
| 85 | {le16_to_cpu(SMB2_IOCTL), "SMB2_IOCTL"},
|
| 86 | {le16_to_cpu(SMB2_CANCEL), "SMB2_CANCEL"},
|
| 87 | {le16_to_cpu(SMB2_ECHO), "SMB2_ECHO"},
|
| 88 | {le16_to_cpu(SMB2_QUERY_DIRECTORY), "SMB2_QUERY_DIRECTORY"},
|
| 89 | {le16_to_cpu(SMB2_CHANGE_NOTIFY), "SMB2_CHANGE_NOTIFY"},
|
| 90 | {le16_to_cpu(SMB2_QUERY_INFO), "SMB2_QUERY_INFO"},
|
| 91 | {le16_to_cpu(SMB2_SET_INFO), "SMB2_SET_INFO"},
|
| 92 | {le16_to_cpu(SMB2_OPLOCK_BREAK), "SMB2_OPLOCK_BREAK"},
|
| 93 | };
|
| 94 |
|
| 95 | static const char *ksmbd_server_state_string(void)
|
| 96 | {
|
| 97 | switch (READ_ONCE(server_conf.state)) {
|
| 98 | case SERVER_STATE_STARTING_UP:
|
| 99 | return "starting";
|
| 100 | case SERVER_STATE_RUNNING:
|
| 101 | return "running";
|
| 102 | case SERVER_STATE_RESETTING:
|
| 103 | return "resetting";
|
| 104 | case SERVER_STATE_SHUTTING_DOWN:
|
| 105 | return "shutdown";
|
| 106 | default:
|
| 107 | return "unknown";
|
| 108 | }
|
| 109 | }
|
| 110 |
|
| 111 | static const char *ksmbd_signing_mode_string(void)
|
| 112 | {
|
| 113 | switch (server_conf.signing) {
|
| 114 | case KSMBD_CONFIG_OPT_DISABLED:
|
| 115 | return "disabled";
|
| 116 | case KSMBD_CONFIG_OPT_MANDATORY:
|
| 117 | return "mandatory";
|
| 118 | case KSMBD_CONFIG_OPT_AUTO:
|
| 119 | return "auto";
|
| 120 | default:
|
| 121 | return "unknown";
|
| 122 | }
|
| 123 | }
|
| 124 |
|
| 125 | static void proc_show_runtime_totals(struct seq_file *m)
|
| 126 | {
|
| 127 | struct ksmbd_conn *conn;
|
| 128 | unsigned int clients = 0;
|
| 129 | unsigned int open_files = 0;
|
| 130 | int i;
|
| 131 |
|
| 132 | down_read(&conn_list_lock);
|
| 133 | hash_for_each(conn_list, i, conn, hlist) {
|
| 134 | clients++;
|
| 135 | open_files += atomic_read(&conn->stats.open_files_count);
|
| 136 | }
|
| 137 | up_read(&conn_list_lock);
|
| 138 |
|
| 139 | seq_printf(m, "clients:\t%u\n", clients);
|
| 140 | seq_printf(m, "open_files:\t%u\n", open_files);
|
| 141 | }
|
| 142 |
|
| 143 | static int proc_show_ksmbd_stats(struct seq_file *m, void *v)
|
| 144 | {
|
| 145 | int i;
|
| 146 |
|
| 147 | seq_puts(m, "Server\n");
|
| 148 | seq_printf(m, "state:\t%s\n", ksmbd_server_state_string());
|
| 149 | seq_printf(m, "name:\t%s\n", ksmbd_server_string());
|
| 150 | seq_printf(m, "netbios:\t%s\n", ksmbd_netbios_name());
|
| 151 | seq_printf(m, "work_group:\t%s\n", ksmbd_work_group());
|
| 152 | seq_printf(m, "min_protocol:\t%s\n", ksmbd_get_protocol_string(server_conf.min_protocol));
|
| 153 | seq_printf(m, "max_protocol:\t%s\n", ksmbd_get_protocol_string(server_conf.max_protocol));
|
| 154 | seq_printf(m, "flags:\t0x%08x\n", server_conf.flags);
|
| 155 | seq_printf(m, "tcp_port:\t%u\n", server_conf.tcp_port);
|
| 156 | seq_printf(m, "signing:\t%s\n", ksmbd_signing_mode_string());
|
| 157 | seq_printf(m, "signing_enforced:\t%s\n",
|
| 158 | server_conf.enforced_signing ? "yes" : "no");
|
| 159 | seq_printf(m, "bind_interfaces_only:\t%s\n",
|
| 160 | server_conf.bind_interfaces_only ? "yes" : "no");
|
| 161 | seq_printf(m, "max_connections:\t%u\n", server_conf.max_connections);
|
| 162 | seq_printf(m, "max_connections_per_ip:\t%u\n",
|
| 163 | server_conf.max_ip_connections);
|
| 164 | seq_printf(m, "max_inflight_requests:\t%u\n",
|
| 165 | server_conf.max_inflight_req);
|
| 166 | seq_printf(m, "deadtime_seconds:\t%lu\n", server_conf.deadtime / HZ);
|
| 167 | seq_printf(m, "ipc_timeout_seconds:\t%u\n", server_conf.ipc_timeout / HZ);
|
| 168 | if (server_conf.ipc_last_active)
|
| 169 | seq_printf(m, "ipc_last_active_seconds:\t%lu\n",
|
| 170 | jiffies_to_msecs(jiffies - server_conf.ipc_last_active) /
|
| 171 | MSEC_PER_SEC);
|
| 172 | else
|
| 173 | seq_puts(m, "ipc_last_active_seconds:\tnever\n");
|
| 174 | seq_printf(m, "durable_scavenger:\t%s\n",
|
| 175 | ksmbd_durable_scavenger_active() ? "running" : "stopped");
|
| 176 | seq_printf(m, "share_fake_fscaps:\t0x%08x\n",
|
| 177 | server_conf.share_fake_fscaps);
|
| 178 | proc_show_runtime_totals(m);
|
| 179 | seq_printf(m, "sessions:\t%lld\n",
|
| 180 | ksmbd_counter_sum(KSMBD_COUNTER_SESSIONS));
|
| 181 | seq_printf(m, "session_timeouts:\t%lld\n",
|
| 182 | ksmbd_counter_sum(KSMBD_COUNTER_SESSION_TIMEOUTS));
|
| 183 | seq_printf(m, "tree_connects:\t%lld\n",
|
| 184 | ksmbd_counter_sum(KSMBD_COUNTER_TREE_CONNS));
|
| 185 | seq_printf(m, "requests:\t%lld\n",
|
| 186 | ksmbd_counter_sum(KSMBD_COUNTER_REQUESTS));
|
| 187 | seq_printf(m, "read_bytes:\t%lld\n",
|
| 188 | ksmbd_counter_sum(KSMBD_COUNTER_READ_BYTES));
|
| 189 | seq_printf(m, "written_bytes:\t%lld\n",
|
| 190 | ksmbd_counter_sum(KSMBD_COUNTER_WRITE_BYTES));
|
| 191 |
|
| 192 | seq_puts(m, "\nSMB2\n");
|
| 193 | for (i = 0; i < KSMBD_COUNTER_MAX_REQS; i++)
|
| 194 | seq_printf(m, "%s:\t%lld\n", smb2_process_req[i].name,
|
| 195 | ksmbd_counter_sum(KSMBD_COUNTER_FIRST_REQ + i));
|
| 196 |
|
| 197 | seq_puts(m, "\nSMB2 status\n");
|
| 198 | seq_printf(m, "success:\t%lld\n",
|
| 199 | ksmbd_counter_sum(KSMBD_COUNTER_STATUS_SUCCESS));
|
| 200 | seq_printf(m, "informational:\t%lld\n",
|
| 201 | ksmbd_counter_sum(KSMBD_COUNTER_STATUS_INFORMATIONAL));
|
| 202 | seq_printf(m, "warning:\t%lld\n",
|
| 203 | ksmbd_counter_sum(KSMBD_COUNTER_STATUS_WARNING));
|
| 204 | seq_printf(m, "error:\t%lld\n",
|
| 205 | ksmbd_counter_sum(KSMBD_COUNTER_STATUS_ERROR));
|
| 206 | seq_printf(m, "access_denied:\t%lld\n",
|
| 207 | ksmbd_counter_sum(KSMBD_COUNTER_ERROR_ACCESS_DENIED));
|
| 208 | seq_printf(m, "not_found:\t%lld\n",
|
| 209 | ksmbd_counter_sum(KSMBD_COUNTER_ERROR_NOT_FOUND));
|
| 210 | seq_printf(m, "invalid_parameter:\t%lld\n",
|
| 211 | ksmbd_counter_sum(KSMBD_COUNTER_ERROR_INVALID_PARAMETER));
|
| 212 | seq_printf(m, "sharing_violation:\t%lld\n",
|
| 213 | ksmbd_counter_sum(KSMBD_COUNTER_ERROR_SHARING_VIOLATION));
|
| 214 | seq_printf(m, "not_supported:\t%lld\n",
|
| 215 | ksmbd_counter_sum(KSMBD_COUNTER_ERROR_NOT_SUPPORTED));
|
| 216 | seq_printf(m, "other:\t%lld\n",
|
| 217 | ksmbd_counter_sum(KSMBD_COUNTER_ERROR_OTHER));
|
| 218 | return 0;
|
| 219 | }
|
| 220 |
|
| 221 | void ksmbd_proc_cleanup(void)
|
| 222 | {
|
| 223 | int i;
|
| 224 |
|
| 225 | if (!ksmbd_proc_fs)
|
| 226 | return;
|
| 227 |
|
| 228 | proc_remove(ksmbd_proc_fs);
|
| 229 |
|
| 230 | for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++)
|
| 231 | percpu_counter_destroy(&ksmbd_counters.counters[i]);
|
| 232 |
|
| 233 | ksmbd_proc_fs = NULL;
|
| 234 | }
|
| 235 |
|
| 236 | void ksmbd_proc_reset(void)
|
| 237 | {
|
| 238 | int i;
|
| 239 |
|
| 240 | for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++)
|
| 241 | percpu_counter_set(&ksmbd_counters.counters[i], 0);
|
| 242 | }
|
| 243 |
|
| 244 | int ksmbd_proc_init(void)
|
| 245 | {
|
| 246 | int i;
|
| 247 | int retval = -ENOMEM;
|
| 248 |
|
| 249 | ksmbd_proc_fs = proc_mkdir("fs/ksmbd", NULL);
|
| 250 | if (!ksmbd_proc_fs)
|
| 251 | return retval;
|
| 252 |
|
| 253 | if (!proc_mkdir_mode("sessions", 0400, ksmbd_proc_fs))
|
| 254 | goto err_out;
|
| 255 |
|
| 256 | for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++) {
|
| 257 | retval = percpu_counter_init(&ksmbd_counters.counters[i], 0, GFP_KERNEL);
|
| 258 | if (retval)
|
| 259 | goto err_out;
|
| 260 | }
|
| 261 |
|
| 262 | if (!ksmbd_proc_create("server", proc_show_ksmbd_stats, NULL)) {
|
| 263 | retval = -ENOMEM;
|
| 264 | goto err_out;
|
| 265 | }
|
| 266 |
|
| 267 | ksmbd_proc_reset();
|
| 268 | return 0;
|
| 269 | err_out:
|
| 270 | ksmbd_proc_cleanup();
|
| 271 | return retval;
|
| 272 | }
|