summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs-xml/smbdotconf/misc/perfcountmodule.xml13
-rw-r--r--source3/Makefile.in8
-rw-r--r--source3/configure.in3
-rw-r--r--source3/include/includes.h1
-rw-r--r--source3/include/proto.h5
-rw-r--r--source3/include/smb.h3
-rw-r--r--source3/include/smb_perfcount.h106
-rw-r--r--source3/param/loadparm.c11
-rw-r--r--source3/smbd/aio.c8
-rw-r--r--source3/smbd/blocking.c6
-rw-r--r--source3/smbd/ipc.c9
-rw-r--r--source3/smbd/notify.c2
-rw-r--r--source3/smbd/nttrans.c8
-rw-r--r--source3/smbd/oplock.c9
-rw-r--r--source3/smbd/perfcount.c192
-rw-r--r--source3/smbd/pipes.c3
-rw-r--r--source3/smbd/process.c61
-rw-r--r--source3/smbd/reply.c10
-rw-r--r--source3/smbd/trans2.c5
19 files changed, 424 insertions, 39 deletions
diff --git a/docs-xml/smbdotconf/misc/perfcountmodule.xml b/docs-xml/smbdotconf/misc/perfcountmodule.xml
new file mode 100644
index 0000000000..f22c399642
--- /dev/null
+++ b/docs-xml/smbdotconf/misc/perfcountmodule.xml
@@ -0,0 +1,13 @@
+<samba:parameter name="perfcount module"
+ context="G"
+ type="string"
+ advanced="1"
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+ <para>This parameter specifies the perfcount backend to be used when monitoring SMB
+ operations. Only one perfcount module may be used, and it must implement all of the
+ apis contained in the smb_perfcount_handler structure defined in smb.h.
+ </para>
+</description>
+
+</samba:parameter>
diff --git a/source3/Makefile.in b/source3/Makefile.in
index ee75eb30e6..a775eafe05 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -108,6 +108,7 @@ MODULESDIR = @modulesdir@
INCLUDEDIR=@includedir@
PAMMODULESDIR = @pammodulesdir@
VFSLIBDIR = $(MODULESDIR)/vfs
+PERFCOUNTLIBDIR = $(MODULESDIR)/perfcount
PDBLIBDIR = $(MODULESDIR)/pdb
RPCLIBDIR = $(MODULESDIR)/rpc
IDMAPLIBDIR = $(MODULESDIR)/idmap
@@ -220,6 +221,7 @@ NSS_MODULES = @NSS_MODULES@
SCRIPTS = $(srcdir)/script/smbtar $(builddir)/script/findsmb
VFS_MODULES = @VFS_MODULES@
+PERFCOUNT_MODULES = @PERFCOUNT_MODULES@
PDB_MODULES = @PDB_MODULES@
RPC_MODULES = @RPC_MODULES@
IDMAP_MODULES = @IDMAP_MODULES@
@@ -229,7 +231,7 @@ NSS_INFO_MODULES = @NSS_INFO_MODULES@
GPEXT_MODULES = @GPEXT_MODULES@
MODULES = $(VFS_MODULES) $(PDB_MODULES) $(RPC_MODULES) $(IDMAP_MODULES) \
$(CHARSET_MODULES) $(AUTH_MODULES) $(NSS_INFO_MODULES) \
- $(GPEXT_MODULES)
+ $(GPEXT_MODULES) $(PERFCOUNT_MODULES)
EXTRA_ALL_TARGETS = @EXTRA_ALL_TARGETS@
@@ -698,7 +700,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
smbd/reply.o smbd/sesssetup.o smbd/trans2.o smbd/uid.o \
smbd/dosmode.o smbd/filename.o smbd/open.o smbd/close.o \
smbd/blocking.o smbd/sec_ctx.o smbd/srvstr.o \
- smbd/vfs.o smbd/statcache.o smbd/seal.o \
+ smbd/vfs.o smbd/perfcount.o smbd/statcache.o smbd/seal.o \
smbd/posix_acls.o lib/sysacls.o $(SERVER_MUTEX_OBJ) \
smbd/process.o smbd/service.o smbd/error.o \
printing/printfsp.o lib/sysquotas.o lib/sysquotas_linux.o \
@@ -2689,6 +2691,7 @@ installmodules:: modules installdirs
@$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(CHARSETLIBDIR) $(CHARSET_MODULES)
@$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(AUTHLIBDIR) $(AUTH_MODULES)
@$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(GPEXTLIBDIR) $(GPEXT_MODULES)
+ @$(SHELL) $(srcdir)/script/installmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(PERFCOUNTLIBDIR) $(PERFCOUNT_MODULES)
@$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(PDBLIBDIR) ldapsam.@SHLIBEXT@ NDS_ldapsam.@SHLIBEXT@
@$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(PDBLIBDIR) ldapsam.@SHLIBEXT@ NDS_ldapsam_compat.@SHLIBEXT@
@$(SHELL) $(srcdir)/script/linkmodules.sh $(DESTDIR)$(PDBLIBDIR) ldapsam.@SHLIBEXT@ ldapsam_compat.@SHLIBEXT@
@@ -2780,6 +2783,7 @@ uninstallmodules::
@$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(CHARSETLIBDIR) $(CHARSET_MODULES)
@$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(AUTHLIBDIR) $(AUTH_MODULES)
@$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(GPEXTLIBDIR) $(GPEXT_MODULES)
+ @$(SHELL) $(srcdir)/script/uninstallmodules.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(PERFCOUNTLIBDIR) $(PERFCOUNT_MODULES)
uninstallscripts::
@$(SHELL) $(srcdir)/script/uninstallscripts.sh $(INSTALLPERMS_BIN) $(DESTDIR)$(BINDIR) $(SCRIPTS)
diff --git a/source3/configure.in b/source3/configure.in
index 37ee9a131f..86fb84c37e 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -6416,9 +6416,10 @@ SMB_MODULE(vfs_acl_xattr, \$(VFS_ACL_XATTR_OBJ), "bin/acl_xattr.$SHLIBEXT", VFS)
SMB_MODULE(vfs_acl_tdb, \$(VFS_ACL_TDB_OBJ), "bin/acl_tdb.$SHLIBEXT", VFS)
SMB_MODULE(vfs_smb_traffic_analyzer, \$(VFS_SMB_TRAFFIC_ANALYZER_OBJ), "bin/smb_traffic_analyzer.$SHLIBEXT", VFS)
SMB_MODULE(vfs_onefs, \$(VFS_ONEFS), "bin/onefs.$SHLIBEXT", VFS)
-
SMB_SUBSYSTEM(VFS,smbd/vfs.o)
+SMB_SUBSYSTEM(PERFCOUNT,smbd/perfcount.o)
+
SMB_MODULE(gpext_registry, libgpo/gpext/registry.o, "bin/registry.$SHLIBEXT", GPEXT)
SMB_MODULE(gpext_scripts, libgpo/gpext/scripts.o, "bin/scripts.$SHLIBEXT", GPEXT)
SMB_MODULE(gpext_security, libgpo/gpext/security.o, "bin/security.$SHLIBEXT", GPEXT)
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 930df6e36c..095fcaa3da 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -597,6 +597,7 @@ struct smb_iconv_convenience *lp_iconv_convenience(void *lp_ctx);
#include "privileges.h"
#include "messages.h"
#include "locking.h"
+#include "smb_perfcount.h"
#include "smb.h"
#include "nameserv.h"
#include "secrets.h"
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 537eb98ffc..7deaff3e19 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -4358,6 +4358,8 @@ void lp_set_posix_pathnames(void);
enum brl_flavour lp_posix_cifsu_locktype(files_struct *fsp);
void lp_set_posix_default_cifsx_readwrite_locktype(enum brl_flavour val);
int lp_min_receive_file_size(void);
+char* lp_smb_perfcount_module(void);
+
/* The following definitions come from param/params.c */
@@ -6978,7 +6980,8 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname);
void smbd_setup_sig_term_handler(void);
void smbd_setup_sig_hup_handler(void);
-bool srv_send_smb(int fd, char *buffer, bool do_encrypt);
+bool srv_send_smb(int fd, char *buffer, bool do_encrypt,
+ struct smb_perfcount_data *pcd);
int srv_set_message(char *buf,
int num_words,
int num_bytes,
diff --git a/source3/include/smb.h b/source3/include/smb.h
index eaf09dd09c..3da63cfc2b 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -613,6 +613,7 @@ struct current_user {
NT_USER_TOKEN *nt_user_token;
};
+
struct smb_request {
uint8_t cmd;
uint16 flags2;
@@ -640,6 +641,7 @@ struct smb_request {
size_t unread_bytes;
bool encrypted;
connection_struct *conn;
+ struct smb_perfcount_data pcd;
/*
* Chained request handling
@@ -717,6 +719,7 @@ struct pending_message_list {
struct pending_message_list *next, *prev;
struct timeval request_time; /* When was this first issued? */
struct timed_event *te;
+ struct smb_perfcount_data pcd;
bool encrypted;
DATA_BLOB buf;
DATA_BLOB private_data;
diff --git a/source3/include/smb_perfcount.h b/source3/include/smb_perfcount.h
new file mode 100644
index 0000000000..218045be88
--- /dev/null
+++ b/source3/include/smb_perfcount.h
@@ -0,0 +1,106 @@
+/*
+ Unix SMB/CIFS implementation.
+ Portable SMB Messaging statistics interfaces
+ Copyright (C) Todd Stecher (2008)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SMB_PERFCOUNT_H_
+#define _SMB_PERFCOUNT_H_
+
+#define SMB_PERFCOUNTER_INTERFACE_VERSION 1
+
+struct smb_perfcount_data{
+ struct smb_perfcount_handlers *handlers;
+ void *context;
+};
+
+struct smb_perfcount_handlers {
+ void (*perfcount_start) (struct smb_perfcount_data *pcd);
+ void (*perfcount_add) (struct smb_perfcount_data *pcd);
+ void (*perfcount_set_op) (struct smb_perfcount_data *pcd, int op);
+ void (*perfcount_set_subop) (struct smb_perfcount_data *pcd, int subop);
+ void (*perfcount_set_ioctl) (struct smb_perfcount_data *pcd, int io_ctl);
+ void (*perfcount_set_msglen_in) (struct smb_perfcount_data *pcd,
+ uint64_t in_bytes);
+ void (*perfcount_set_msglen_out) (struct smb_perfcount_data *pcd,
+ uint64_t out_bytes);
+ void (*perfcount_set_client) (struct smb_perfcount_data *pcd, uid_t uid,
+ const char *user, const char *domain);
+ void (*perfcount_defer_op) (struct smb_perfcount_data *pcd,
+ struct smb_perfcount_data *def_pcd);
+ void (*perfcount_end) (struct smb_perfcount_data *pcd);
+};
+
+bool smb_perfcount_init(void);
+
+NTSTATUS smb_register_perfcounter(int interface_version, const char *name,
+ const struct smb_perfcount_handlers *handlers);
+
+void smb_init_perfcount_data(struct smb_perfcount_data *pcd);
+
+#define SMB_PERFCOUNT_START(_pcd_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_start((_pcd_)); \
+ } while (0)
+
+#define SMB_PERFCOUNT_ADD(_pcd_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_add((_pcd_)); \
+ } while (0)
+
+#define SMB_PERFCOUNT_SET_OP(_pcd_,_op_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_set_op((_pcd_), (_op_)); \
+ } while (0)
+
+#define SMB_PERFCOUNT_SET_SUBOP(_pcd_,_subop_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_set_subop((_pcd_), (_subop_)); \
+ } while (0)
+
+#define SMB_PERFCOUNT_SET_IOCTL(_pcd_,_subop_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_set_ioctl((_pcd_), (_subop_)); \
+ } while (0)
+
+#define SMB_PERFCOUNT_SET_MSGLEN_IN(_pcd_,_in_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_set_msglen_in((_pcd_), (_in_));\
+ } while (0)
+
+#define SMB_PERFCOUNT_SET_MSGLEN_OUT(_pcd_,_out_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_set_msglen_out((_pcd_), (_out_));\
+ } while (0)
+
+
+#define SMB_PERFCOUNT_SET_CLIENT(_pcd_,_uid_, _user_, _domain_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_set_client((_pcd_), (_uid_), \
+ (_user_), (_domain_)); \
+ } while (0)
+
+#define SMB_PERFCOUNT_DEFER_OP(_pcd_, _def_pcd_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_defer_op((_pcd_), (_def_pcd_)); \
+ } while (0)
+
+#define SMB_PERFCOUNT_END(_pcd_) \
+ do {if((_pcd_) && (_pcd_)->handlers) \
+ (_pcd_)->handlers->perfcount_end((_pcd_));\
+ } while (0)
+
+#endif /* _SMB_PERFCOUNT_H_ */
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index bc7d9974f4..0dfbb09331 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -344,6 +344,7 @@ struct global {
int iminreceivefile;
struct param_opt_struct *param_opt;
int cups_connection_timeout;
+ char *szSMBPerfcountModule;
};
static struct global Globals;
@@ -4258,6 +4259,15 @@ static struct parm_struct parm_table[] = {
.enum_list = NULL,
.flags = FLAG_ADVANCED,
},
+ {
+ .label = "perfcount module",
+ .type = P_STRING,
+ .p_class = P_GLOBAL,
+ .ptr = &Globals.szSMBPerfcountModule,
+ .special = NULL,
+ .enum_list = NULL,
+ .flags = FLAG_ADVANCED,
+ },
{N_("VFS module options"), P_SEP, P_SEPARATOR},
@@ -5163,6 +5173,7 @@ FN_GLOBAL_STRING(lp_utmpdir, &Globals.szUtmpDir)
FN_GLOBAL_STRING(lp_wtmpdir, &Globals.szWtmpDir)
FN_GLOBAL_BOOL(lp_utmp, &Globals.bUtmp)
FN_GLOBAL_STRING(lp_rootdir, &Globals.szRootdir)
+FN_GLOBAL_STRING(lp_smb_perfcount_module, &Globals.szSMBPerfcountModule)
FN_GLOBAL_STRING(lp_defaultservice, &Globals.szDefaultService)
FN_GLOBAL_STRING(lp_msg_command, &Globals.szMsgCommand)
FN_GLOBAL_STRING(lp_get_quota_command, &Globals.szGetQuota)
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index 64d512d675..75ce07d41a 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -301,7 +301,8 @@ bool schedule_aio_write_and_X(connection_struct *conn,
SSVAL(aio_ex->outbuf,smb_vwv4,(numtowrite>>16)&1);
show_msg(aio_ex->outbuf);
if (!srv_send_smb(smbd_server_fd(),aio_ex->outbuf,
- IS_CONN_ENCRYPTED(fsp->conn))) {
+ IS_CONN_ENCRYPTED(fsp->conn),
+ &req->pcd)) {
exit_server_cleanly("handle_aio_write: srv_send_smb "
"failed.");
}
@@ -375,7 +376,7 @@ static int handle_aio_read_complete(struct aio_extra *aio_ex)
smb_setlen(outbuf,outsize - 4);
show_msg(outbuf);
if (!srv_send_smb(smbd_server_fd(),outbuf,
- IS_CONN_ENCRYPTED(aio_ex->fsp->conn))) {
+ IS_CONN_ENCRYPTED(aio_ex->fsp->conn), NULL)) {
exit_server_cleanly("handle_aio_read_complete: srv_send_smb "
"failed.");
}
@@ -472,7 +473,8 @@ static int handle_aio_write_complete(struct aio_extra *aio_ex)
}
show_msg(outbuf);
- if (!srv_send_smb(smbd_server_fd(),outbuf,IS_CONN_ENCRYPTED(fsp->conn))) {
+ if (!srv_send_smb(smbd_server_fd(),outbuf,IS_CONN_ENCRYPTED(fsp->conn),
+ NULL)) {
exit_server_cleanly("handle_aio_write: srv_send_smb failed.");
}
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index ac1ff00858..659ef700cb 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -192,6 +192,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
return False;
}
+ SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd);
blr->req = talloc_move(blr, &req);
DLIST_ADD_END(blocking_lock_queue, blr, blocking_lock_record *);
@@ -266,7 +267,7 @@ static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS stat
reply_nterror(blr->req, status);
if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf,
- blr->req->encrypted)) {
+ blr->req->encrypted, NULL)) {
exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
}
TALLOC_FREE(blr->req->outbuf);
@@ -347,7 +348,8 @@ static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status
if (!srv_send_smb(smbd_server_fd(),
(char *)blr->req->outbuf,
- IS_CONN_ENCRYPTED(blr->fsp->conn))) {
+ IS_CONN_ENCRYPTED(blr->fsp->conn),
+ NULL)) {
exit_server_cleanly("blocking_lock_reply_error: "
"srv_send_smb failed.");
}
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c
index 9c7528dfa7..d18b5debe0 100644
--- a/source3/smbd/ipc.c
+++ b/source3/smbd/ipc.c
@@ -134,7 +134,7 @@ void send_trans_reply(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
- IS_CONN_ENCRYPTED(conn))) {
+ IS_CONN_ENCRYPTED(conn), &req->pcd)) {
exit_server_cleanly("send_trans_reply: srv_send_smb failed.");
}
@@ -190,7 +190,7 @@ void send_trans_reply(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
- IS_CONN_ENCRYPTED(conn)))
+ IS_CONN_ENCRYPTED(conn), &req->pcd))
exit_server_cleanly("send_trans_reply: srv_send_smb "
"failed.");
@@ -298,7 +298,8 @@ static void api_dcerpc_cmd_write_done(struct async_req *subreq)
send:
if (!srv_send_smb(
smbd_server_fd(), (char *)req->outbuf,
- IS_CONN_ENCRYPTED(req->conn) || req->encrypted)) {
+ IS_CONN_ENCRYPTED(req->conn) || req->encrypted,
+ &req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb failed.");
}
TALLOC_FREE(req);
@@ -324,7 +325,7 @@ static void api_dcerpc_cmd_read_done(struct async_req *subreq)
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
IS_CONN_ENCRYPTED(req->conn)
- ||req->encrypted)) {
+ ||req->encrypted, &req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb "
"failed.");
}
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 7ffe62058c..1d4f5e8c5b 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -144,7 +144,7 @@ static void change_notify_reply_packet(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
- req->encrypted)) {
+ req->encrypted, &req->pcd)) {
exit_server_cleanly("change_notify_reply_packet: srv_send_smb "
"failed.");
}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 0ad4df6e90..ad2366efae 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -230,7 +230,8 @@ void send_nt_replies(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(),
(char *)req->outbuf,
- IS_CONN_ENCRYPTED(conn))) {
+ IS_CONN_ENCRYPTED(conn),
+ &req->pcd)) {
exit_server_cleanly("send_nt_replies: srv_send_smb failed.");
}
@@ -1823,6 +1824,8 @@ static void call_nt_transact_ioctl(connection_struct *conn,
because I don't want to break anything... --metze
FSP_BELONGS_CONN(fsp,conn);*/
+ SMB_PERFCOUNT_SET_IOCTL(&req->pcd, function);
+
switch (function) {
case FSCTL_SET_SPARSE:
/* pretend this succeeded - tho strictly we should
@@ -2489,6 +2492,9 @@ static void handle_nttrans(connection_struct *conn,
SSVAL(req->inbuf,smb_flg2,req->flags2);
}
+
+ SMB_PERFCOUNT_SET_SUBOP(&req->pcd, state->call);
+
/* Now we must call the relevant NT_TRANS function */
switch(state->call) {
case NT_TRANSACT_CREATE:
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 788d2f7238..3dac674c17 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -406,7 +406,8 @@ static void process_oplock_async_level2_break_message(struct messaging_context *
show_msg(break_msg);
if (!srv_send_smb(smbd_server_fd(),
break_msg,
- IS_CONN_ENCRYPTED(fsp->conn))) {
+ IS_CONN_ENCRYPTED(fsp->conn),
+ NULL)) {
exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
@@ -513,7 +514,8 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx,
show_msg(break_msg);
if (!srv_send_smb(smbd_server_fd(),
break_msg,
- IS_CONN_ENCRYPTED(fsp->conn))) {
+ IS_CONN_ENCRYPTED(fsp->conn),
+ NULL)) {
exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
@@ -592,7 +594,8 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx,
show_msg(break_msg);
if (!srv_send_smb(smbd_server_fd(),
break_msg,
- IS_CONN_ENCRYPTED(fsp->conn))) {
+ IS_CONN_ENCRYPTED(fsp->conn),
+ NULL)) {
exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
diff --git a/source3/smbd/perfcount.c b/source3/smbd/perfcount.c
new file mode 100644
index 0000000000..0ad706c46d
--- /dev/null
+++ b/source3/smbd/perfcount.c
@@ -0,0 +1,192 @@
+/*
+ Unix SMB/Netbios implementation.
+ Perfcounter initialization and support functions
+ Copyright (C) Todd Stecher 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "includes.h"
+
+struct smb_perfcount_handlers *g_smb_perfcount_handlers = NULL;
+
+struct smb_perfcount_module {
+ char *name;
+ struct smb_perfcount_handlers *handlers;
+ struct smb_perfcount_module *prev, *next;
+};
+
+struct smb_perfcount_module *modules = NULL;
+
+
+/*
+ * a module is registered before it is actually loaded - keep a list
+ *
+ * @todo - currently perfcount modules are globally configured, so
+ * building the list is not strictly required.
+ * However, its a proven concept in VFS, and is here to allow a
+ * move to eventual per-service perfcount configuration.
+ *
+ * Note many pre-connection statistics are interesting
+ * (e.g. before binding to an individual share).
+ *
+ */
+static struct smb_perfcount_module *smb_perfcount_find_module(const char *name)
+{
+ struct smb_perfcount_module *entry = modules;
+
+ while (entry) {
+ if (strcmp(entry->name, name)==0)
+ return entry;
+
+ entry = entry->next;
+ }
+
+ return NULL;
+}
+NTSTATUS smb_register_perfcounter(int interface_version, const char *name,
+ const struct smb_perfcount_handlers *handlers)
+{
+ struct smb_perfcount_module *entry = modules;
+
+ if ((interface_version != SMB_PERFCOUNTER_INTERFACE_VERSION)) {
+ DEBUG(0, ("Failed to register perfcount module.\n"
+ "The module was compiled against "
+ "SMB_PERFCOUNTER_INTERFACE_VERSION %d,\n"
+ "current SMB_PERFCOUNTER_INTERFACE_VERSION is %d.\n"
+ "Please recompile against the current Samba Version!\n",
+ interface_version, SMB_PERFCOUNTER_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!name || !name[0] || !handlers) {
+ DEBUG(0,("smb_register_perfcounter() called with NULL pointer "
+ "or empty name!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (smb_perfcount_find_module(name)) {
+ DEBUG(0,("Perfcount Module %s already loaded!\n", name));
+ return NT_STATUS_OK;
+ }
+
+ entry = SMB_XMALLOC_P(struct smb_perfcount_module);
+ entry->name = smb_xstrdup(name);
+ entry->handlers = (struct smb_perfcount_handlers*) handlers;
+
+ DLIST_ADD(modules, entry);
+ DEBUG(0, ("Successfully added perfcounter module '%s'\n", name));
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ initialise smb perf counters
+ ****************************************************************************/
+bool smb_load_perfcount_module(const char *name)
+{
+ char *module_path = NULL;
+ char *module_name = NULL;
+ char *module_param = NULL, *p;
+
+ const struct smb_perfcount_module *entry;
+
+ DEBUG(3, ("Initialising perfcounter module [%s]\n", name));
+
+ if (g_smb_perfcount_handlers) {
+ DEBUG(0,("Only 1 perfcount handler may be registered in "
+ "smb.conf\n"));
+ return true;
+ }
+
+ module_path = smb_xstrdup(name);
+
+ p = strchr_m(module_path, ':');
+
+ if (p) {
+ *p = 0;
+ module_param = p+1;
+ trim_char(module_param, ' ', ' ');
+ }
+
+ trim_char(module_path, ' ', ' ');
+
+ module_name = smb_xstrdup(module_path);
+
+ if (module_name[0] == '/') {
+
+ /*
+ * Extract the module name from the path. Just use the base
+ * name of the last path component.
+ */
+
+ SAFE_FREE(module_name);
+ module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
+
+ p = strchr_m(module_name, '.');
+
+ if (p != NULL) {
+ *p = '\0';
+ }
+ }
+
+ /* load the perfcounter module */
+ if((entry = smb_perfcount_find_module(module_name)) ||
+ (NT_STATUS_IS_OK(smb_probe_module("perfcount", module_path)) &&
+ (entry = smb_perfcount_find_module(module_name)))) {
+
+ DEBUG(0,("Successfully loaded perfcounter module [%s] \n", name));
+ } else {
+ DEBUG(0,("Can't find a perfcounter module [%s]\n",name));
+ goto fail;
+ }
+
+ g_smb_perfcount_handlers = entry->handlers;
+
+ SAFE_FREE(module_path);
+ SAFE_FREE(module_name);
+ return True;
+
+ fail:
+ SAFE_FREE(module_path);
+ SAFE_FREE(module_name);
+ return False;
+}
+
+void smb_init_perfcount_data(struct smb_perfcount_data *pcd)
+{
+
+ ZERO_STRUCTP(pcd);
+ pcd->handlers = g_smb_perfcount_handlers;
+}
+
+bool smb_perfcount_init(void)
+{
+ char *perfcount_object;
+
+ perfcount_object = lp_smb_perfcount_module();
+
+ /* don't init */
+ if (!perfcount_object || !perfcount_object[0])
+ return True;
+
+ if (!smb_load_perfcount_module(perfcount_object)) {
+ DEBUG(0, ("smbd_load_percount_module failed for %s\n",
+ perfcount_object));
+ return False;
+ }
+
+
+ return True;
+}
diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c
index f287adc92d..6fd4031f3d 100644
--- a/source3/smbd/pipes.c
+++ b/source3/smbd/pipes.c
@@ -216,7 +216,8 @@ static void pipe_write_done(struct async_req *subreq)
send:
if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
- IS_CONN_ENCRYPTED(req->conn)||req->encrypted)) {
+ IS_CONN_ENCRYPTED(req->conn)||req->encrypted,
+ &req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb failed.");
}
TALLOC_FREE(req);
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 8539e04bd5..1262d01840 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -32,9 +32,10 @@ static void construct_reply_common(struct smb_request *req, const char *inbuf,
Send an smb to a fd.
****************************************************************************/
-bool srv_send_smb(int fd, char *buffer, bool do_encrypt)
+bool srv_send_smb(int fd, char *buffer, bool do_encrypt,
+ struct smb_perfcount_data *pcd)
{
- size_t len;
+ size_t len = 0;
size_t nwritten=0;
ssize_t ret;
char *buf_out = buffer;
@@ -48,7 +49,7 @@ bool srv_send_smb(int fd, char *buffer, bool do_encrypt)
DEBUG(0, ("send_smb: SMB encryption failed "
"on outgoing packet! Error %s\n",
nt_errstr(status) ));
- return false;
+ goto out;
}
}
@@ -60,12 +61,15 @@ bool srv_send_smb(int fd, char *buffer, bool do_encrypt)
DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
(int)len,(int)ret, strerror(errno) ));
srv_free_enc_buffer(buf_out);
- return false;
+ goto out;
}
nwritten += ret;
}
+ SMB_PERFCOUNT_SET_MSGLEN_OUT(pcd, len);
srv_free_enc_buffer(buf_out);
+out:
+ SMB_PERFCOUNT_END(pcd);
return true;
}
@@ -373,6 +377,7 @@ void init_smb_request(struct smb_request *req,
req->conn = conn_find(req->tid);
req->chain_fsp = NULL;
req->chain_outbuf = NULL;
+ smb_init_perfcount_data(&req->pcd);
/* Ensure we have at least wct words and 2 bytes of bcc. */
if (smb_size + req->wct*2 > req_size) {
@@ -390,12 +395,13 @@ void init_smb_request(struct smb_request *req,
(unsigned int)req_size));
exit_server_cleanly("Invalid SMB request");
}
+
req->outbuf = NULL;
}
static void process_smb(struct smbd_server_connection *conn,
uint8_t *inbuf, size_t nread, size_t unread_bytes,
- bool encrypted);
+ bool encrypted, struct smb_perfcount_data *deferred_pcd);
static void smbd_deferred_open_timer(struct event_context *ev,
struct timed_event *te,
@@ -421,7 +427,7 @@ static void smbd_deferred_open_timer(struct event_context *ev,
process_smb(smbd_server_conn, inbuf,
msg->buf.length, 0,
- msg->encrypted);
+ msg->encrypted, &msg->pcd);
}
/****************************************************************************
@@ -453,6 +459,7 @@ static bool push_queued_message(struct smb_request *req,
msg->request_time = request_time;
msg->encrypted = req->encrypted;
+ SMB_PERFCOUNT_DEFER_OP(&req->pcd, &msg->pcd);
if (private_data) {
msg->private_data = data_blob_talloc(msg, private_data,
@@ -1354,7 +1361,9 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req, in
Construct a reply to the incoming packet.
****************************************************************************/
-static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool encrypted)
+static void construct_reply(char *inbuf, int size, size_t unread_bytes,
+ bool encrypted,
+ struct smb_perfcount_data *deferred_pcd)
{
connection_struct *conn;
struct smb_request *req;
@@ -1362,9 +1371,19 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool enc
if (!(req = talloc(talloc_tos(), struct smb_request))) {
smb_panic("could not allocate smb_request");
}
+
init_smb_request(req, (uint8 *)inbuf, unread_bytes, encrypted);
req->inbuf = (uint8_t *)talloc_move(req, &inbuf);
+ /* we popped this message off the queue - keep original perf data */
+ if (deferred_pcd)
+ req->pcd = *deferred_pcd;
+ else {
+ SMB_PERFCOUNT_START(&req->pcd);
+ SMB_PERFCOUNT_SET_OP(&req->pcd, req->cmd);
+ SMB_PERFCOUNT_SET_MSGLEN_IN(&req->pcd, size);
+ }
+
conn = switch_message(req->cmd, req, size);
if (req->unread_bytes) {
@@ -1386,7 +1405,8 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool enc
if (!srv_send_smb(smbd_server_fd(),
(char *)req->outbuf,
- IS_CONN_ENCRYPTED(conn)||req->encrypted)) {
+ IS_CONN_ENCRYPTED(conn)||req->encrypted,
+ &req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb failed.");
}
@@ -1398,10 +1418,9 @@ static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool enc
/****************************************************************************
Process an smb from the client
****************************************************************************/
-
static void process_smb(struct smbd_server_connection *conn,
uint8_t *inbuf, size_t nread, size_t unread_bytes,
- bool encrypted)
+ bool encrypted, struct smb_perfcount_data *deferred_pcd)
{
int msg_type = CVAL(inbuf,0);
@@ -1423,8 +1442,7 @@ static void process_smb(struct smbd_server_connection *conn,
show_msg((char *)inbuf);
- construct_reply((char *)inbuf,nread,unread_bytes,encrypted);
-
+ construct_reply((char *)inbuf,nread,unread_bytes,encrypted,deferred_pcd);
trans_num++;
done:
@@ -1617,16 +1635,24 @@ void chain_reply(struct smb_request *req)
*/
smb_setlen((char *)(req->chain_outbuf),
talloc_get_size(req->chain_outbuf) - 4);
+
if (!srv_send_smb(smbd_server_fd(), (char *)req->chain_outbuf,
IS_CONN_ENCRYPTED(req->conn)
- ||req->encrypted)) {
+ ||req->encrypted,
+ &req->pcd)) {
exit_server_cleanly("chain_reply: srv_send_smb "
"failed.");
}
TALLOC_FREE(req);
+
return;
}
+ /* add a new perfcounter for this element of chain */
+ SMB_PERFCOUNT_ADD(&req->pcd);
+ SMB_PERFCOUNT_SET_OP(&req->pcd, chain_cmd);
+ SMB_PERFCOUNT_SET_MSGLEN_IN(&req->pcd, smblen);
+
/*
* Check if the client tries to fool us. The request so far uses the
* space to the end of the byte buffer in the request just
@@ -1735,7 +1761,8 @@ void chain_reply(struct smb_request *req)
show_msg((char *)(req->chain_outbuf));
if (!srv_send_smb(smbd_server_fd(), (char *)req->chain_outbuf,
- IS_CONN_ENCRYPTED(req->conn)||req->encrypted)) {
+ IS_CONN_ENCRYPTED(req->conn)||req->encrypted,
+ &req->pcd)) {
exit_server_cleanly("construct_reply: srv_send_smb failed.");
}
TALLOC_FREE(req);
@@ -1823,7 +1850,7 @@ static void smbd_server_connection_read_handler(struct smbd_server_connection *c
}
process:
- process_smb(conn, inbuf, inbuf_len, unread_bytes, encrypted);
+ process_smb(conn, inbuf, inbuf_len, unread_bytes, encrypted, NULL);
}
static void smbd_server_connection_handler(struct event_context *ev,
@@ -1988,7 +2015,7 @@ void smbd_process(void)
unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
DEBUG( 1, ("Connection denied from %s\n",
client_addr(get_client_fd(),addr,sizeof(addr)) ) );
- (void)srv_send_smb(smbd_server_fd(),(char *)buf,false);
+ (void)srv_send_smb(smbd_server_fd(),(char *)buf,false, NULL);
exit_server_cleanly("connection denied");
}
@@ -1996,6 +2023,8 @@ void smbd_process(void)
init_modules();
+ smb_perfcount_init();
+
if (!init_account_policy()) {
exit_server("Could not open account policy tdb.\n");
}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index bb5fadd465..60e2e5dc7a 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -492,7 +492,7 @@ void reply_special(char *inbuf)
DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
msg_type, msg_flags));
- srv_send_smb(smbd_server_fd(), outbuf, false);
+ srv_send_smb(smbd_server_fd(), outbuf, false, NULL);
return;
}
@@ -3293,6 +3293,8 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
/* No outbuf here means successful sendfile. */
TALLOC_FREE(req->outbuf);
+ SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
+ SMB_PERFCOUNT_END(&req->pcd);
return;
}
#endif
@@ -3590,7 +3592,8 @@ void reply_writebraw(struct smb_request *req)
show_msg(buf);
if (!srv_send_smb(smbd_server_fd(),
buf,
- IS_CONN_ENCRYPTED(conn))) {
+ IS_CONN_ENCRYPTED(conn),
+ &req->pcd)) {
exit_server_cleanly("reply_writebraw: srv_send_smb "
"failed.");
}
@@ -4647,7 +4650,8 @@ void reply_echo(struct smb_request *req)
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(),
(char *)req->outbuf,
- IS_CONN_ENCRYPTED(conn)||req->encrypted))
+ IS_CONN_ENCRYPTED(conn)||req->encrypted,
+ &req->pcd))
exit_server_cleanly("reply_echo: srv_send_smb failed.");
}
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 6c082a8273..6a6e59a581 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -832,7 +832,8 @@ void send_trans2_replies(connection_struct *conn,
show_msg((char *)req->outbuf);
if (!srv_send_smb(smbd_server_fd(),
(char *)req->outbuf,
- IS_CONN_ENCRYPTED(conn)))
+ IS_CONN_ENCRYPTED(conn),
+ &req->pcd))
exit_server_cleanly("send_trans2_replies: srv_send_smb failed.");
TALLOC_FREE(req->outbuf);
@@ -7468,6 +7469,8 @@ static void handle_trans2(connection_struct *conn, struct smb_request *req,
}
}
+ SMB_PERFCOUNT_SET_SUBOP(&req->pcd, state->call);
+
/* Now we must call the relevant TRANS2 function */
switch(state->call) {
case TRANSACT2_OPEN: