diff options
-rw-r--r-- | docs-xml/smbdotconf/misc/perfcountmodule.xml | 13 | ||||
-rw-r--r-- | source3/Makefile.in | 8 | ||||
-rw-r--r-- | source3/configure.in | 3 | ||||
-rw-r--r-- | source3/include/includes.h | 1 | ||||
-rw-r--r-- | source3/include/proto.h | 5 | ||||
-rw-r--r-- | source3/include/smb.h | 3 | ||||
-rw-r--r-- | source3/include/smb_perfcount.h | 106 | ||||
-rw-r--r-- | source3/param/loadparm.c | 11 | ||||
-rw-r--r-- | source3/smbd/aio.c | 8 | ||||
-rw-r--r-- | source3/smbd/blocking.c | 6 | ||||
-rw-r--r-- | source3/smbd/ipc.c | 9 | ||||
-rw-r--r-- | source3/smbd/notify.c | 2 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 8 | ||||
-rw-r--r-- | source3/smbd/oplock.c | 9 | ||||
-rw-r--r-- | source3/smbd/perfcount.c | 192 | ||||
-rw-r--r-- | source3/smbd/pipes.c | 3 | ||||
-rw-r--r-- | source3/smbd/process.c | 61 | ||||
-rw-r--r-- | source3/smbd/reply.c | 10 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 5 |
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: |