linux/fs/smb/server/proc.c
Bahubali B Gumaji b38f99c121 ksmbd: add procfs interface for runtime monitoring and statistics
This patch introduces a /proc filesystem interface to ksmbd, providing
visibility into the internal state of the SMB server. This allows
administrators and developers to monitor active connections, user
sessions, and opened files in real-time without relying on external
tools or heavy debugging.

Key changes include:
 - Connection Monitoring (/proc/fs/ksmbd/clients): Displays a list of
   active network connections, including client IP addresses, SMB dialects,
   credits, and last active timestamps.

 - Session Management (/proc/fs/ksmbd/sessions/): Adds a global sessions
   file to list all authenticated users and their session IDs.

 - Creates individual session entries (e.g., /proc/fs/ksmbd/sessions/<id>)
   detailing capabilities (DFS, Multi-channel, etc.), signing/encryption
   algorithms, and connected tree shares.

 - File Tracking (/proc/fs/ksmbd/files): Shows all currently opened files
   across the server, including tree IDs, process IDs (PID), access modes
   (daccess/saccess), and oplock/lease states.

 - Statistics & Counters: Implements internal counters for global server
   metrics, such as the number of tree connections, total sessions, and
   processed read/write bytes.

Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Bahubali B Gumaji <bahubali.bg@samsung.com>
Signed-off-by: Sang-Soo Lee  <constant.lee@samsung.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
2026-02-08 20:25:16 -06:00

134 lines
3.8 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2025, LG Electronics.
* Author(s): Hyunchul Lee <hyc.lee@gmail.com>
* Copyright (C) 2025, Samsung Electronics.
* Author(s): Vedansh Bhardwaj <v.bhardwaj@samsung.com>
*/
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include "misc.h"
#include "server.h"
#include "stats.h"
#include "smb_common.h"
#include "smb2pdu.h"
static struct proc_dir_entry *ksmbd_proc_fs;
struct ksmbd_counters ksmbd_counters;
struct proc_dir_entry *ksmbd_proc_create(const char *name,
int (*show)(struct seq_file *m, void *v),
void *v)
{
return proc_create_single_data(name, 0400, ksmbd_proc_fs,
show, v);
}
struct ksmbd_const_smb2_process_req {
unsigned int const_value;
const char *name;
};
static const struct ksmbd_const_smb2_process_req smb2_process_req[KSMBD_COUNTER_MAX_REQS] = {
{le16_to_cpu(SMB2_NEGOTIATE), "SMB2_NEGOTIATE"},
{le16_to_cpu(SMB2_SESSION_SETUP), "SMB2_SESSION_SETUP"},
{le16_to_cpu(SMB2_LOGOFF), "SMB2_LOGOFF"},
{le16_to_cpu(SMB2_TREE_CONNECT), "SMB2_TREE_CONNECT"},
{le16_to_cpu(SMB2_TREE_DISCONNECT), "SMB2_TREE_DISCONNECT"},
{le16_to_cpu(SMB2_CREATE), "SMB2_CREATE"},
{le16_to_cpu(SMB2_CLOSE), "SMB2_CLOSE"},
{le16_to_cpu(SMB2_FLUSH), "SMB2_FLUSH"},
{le16_to_cpu(SMB2_READ), "SMB2_READ"},
{le16_to_cpu(SMB2_WRITE), "SMB2_WRITE"},
{le16_to_cpu(SMB2_LOCK), "SMB2_LOCK"},
{le16_to_cpu(SMB2_IOCTL), "SMB2_IOCTL"},
{le16_to_cpu(SMB2_CANCEL), "SMB2_CANCEL"},
{le16_to_cpu(SMB2_ECHO), "SMB2_ECHO"},
{le16_to_cpu(SMB2_QUERY_DIRECTORY), "SMB2_QUERY_DIRECTORY"},
{le16_to_cpu(SMB2_CHANGE_NOTIFY), "SMB2_CHANGE_NOTIFY"},
{le16_to_cpu(SMB2_QUERY_INFO), "SMB2_QUERY_INFO"},
{le16_to_cpu(SMB2_SET_INFO), "SMB2_SET_INFO"},
{le16_to_cpu(SMB2_OPLOCK_BREAK), "SMB2_OPLOCK_BREAK"},
};
static int proc_show_ksmbd_stats(struct seq_file *m, void *v)
{
int i;
seq_puts(m, "Server\n");
seq_printf(m, "name: %s\n", ksmbd_server_string());
seq_printf(m, "netbios: %s\n", ksmbd_netbios_name());
seq_printf(m, "work group: %s\n", ksmbd_work_group());
seq_printf(m, "min protocol: %s\n", ksmbd_get_protocol_string(server_conf.min_protocol));
seq_printf(m, "max protocol: %s\n", ksmbd_get_protocol_string(server_conf.max_protocol));
seq_printf(m, "flags: 0x%08x\n", server_conf.flags);
seq_printf(m, "share_fake_fscaps: 0x%08x\n",
server_conf.share_fake_fscaps);
seq_printf(m, "sessions: %lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_SESSIONS));
seq_printf(m, "tree connects: %lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_TREE_CONNS));
seq_printf(m, "read bytes: %lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_READ_BYTES));
seq_printf(m, "written bytes: %lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_WRITE_BYTES));
seq_puts(m, "\nSMB2\n");
for (i = 0; i < KSMBD_COUNTER_MAX_REQS; i++)
seq_printf(m, "%-20s:\t%lld\n", smb2_process_req[i].name,
ksmbd_counter_sum(KSMBD_COUNTER_FIRST_REQ + i));
return 0;
}
void ksmbd_proc_cleanup(void)
{
int i;
if (!ksmbd_proc_fs)
return;
proc_remove(ksmbd_proc_fs);
for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++)
percpu_counter_destroy(&ksmbd_counters.counters[i]);
ksmbd_proc_fs = NULL;
}
void ksmbd_proc_reset(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++)
percpu_counter_set(&ksmbd_counters.counters[i], 0);
}
void ksmbd_proc_init(void)
{
int i;
int retval;
ksmbd_proc_fs = proc_mkdir("fs/ksmbd", NULL);
if (!ksmbd_proc_fs)
return;
if (!proc_mkdir_mode("sessions", 0400, ksmbd_proc_fs))
goto err_out;
for (i = 0; i < ARRAY_SIZE(ksmbd_counters.counters); i++) {
retval = percpu_counter_init(&ksmbd_counters.counters[i], 0, GFP_KERNEL);
if (retval)
goto err_out;
}
if (!ksmbd_proc_create("server", proc_show_ksmbd_stats, NULL))
goto err_out;
ksmbd_proc_reset();
return;
err_out:
ksmbd_proc_cleanup();
}