2 Unix SMB/CIFS implementation.
4 a pass-thru NTVFS module to record a NBENCH load file
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 "passthru" in this module refers to the next level of NTVFS being used
28 #include "system/filesys.h"
29 #include "smb_server/smb_server.h"
31 /* this is stored in ntvfs_private */
32 struct nbench_private {
37 log one request to the nbench log
39 static void nbench_log(struct smbsrv_request *req,
40 const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
42 static void nbench_log(struct smbsrv_request *req,
43 const char *format, ...)
45 struct nbench_private *private = req->async_states->ntvfs->private_data;
50 vasprintf(&s, format, ap);
53 write(private->log_fd, s, strlen(s));
58 this pass through macro operates on request contexts, and disables
61 async calls are a pain for the nbench module as it makes pulling the
62 status code and any result parameters much harder.
64 #define PASS_THRU_REQ_PRE_ASYNC(ntvfs, req, op, par1) do { \
65 status = ntvfs_async_state_push(req, par1, nbench_##op##_send, ntvfs); \
66 if (!NT_STATUS_IS_OK(status)) { \
71 #define PASS_THRU_REQ_POST_ASYNC(req) do { \
72 req->async_states->status = status; \
73 if (!(req->async_states->state & NTVFS_ASYNC_STATE_ASYNC)) { \
74 req->async_states->send_fn(req); \
78 #define PASS_THRU_REQ(ntvfs, req, op, par1, args) do { \
79 PASS_THRU_REQ_PRE_ASYNC(ntvfs, req, op, par1); \
80 status = ntvfs_next_##op args; \
81 PASS_THRU_REQ_POST_ASYNC(req); \
84 #define PASS_THRU_REP_POST(req) do { \
85 ntvfs_async_state_pop(req); \
86 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { \
87 req->async_states->send_fn(req); \
92 connect to a share - used when a tree_connect operation comes in.
94 static NTSTATUS nbench_connect(struct ntvfs_module_context *ntvfs,
95 struct smbsrv_request *req, const char *sharename)
97 struct nbench_private *nprivates;
101 nprivates = talloc(req->tcon, struct nbench_private);
103 return NT_STATUS_NO_MEMORY;
106 asprintf(&logname, "/tmp/nbenchlog%d.%u", ntvfs->depth, getpid());
107 nprivates->log_fd = open(logname, O_WRONLY|O_CREAT|O_APPEND, 0644);
110 if (nprivates->log_fd == -1) {
111 DEBUG(0,("Failed to open nbench log\n"));
112 return NT_STATUS_UNSUCCESSFUL;
115 ntvfs->private_data = nprivates;
117 status = ntvfs_next_connect(ntvfs, req, sharename);
123 disconnect from a share
125 static NTSTATUS nbench_disconnect(struct ntvfs_module_context *ntvfs,
126 struct smbsrv_tcon *tcon)
128 struct nbench_private *nprivates = ntvfs->private_data;
131 close(nprivates->log_fd);
133 status = ntvfs_next_disconnect(ntvfs, tcon);
139 delete a file - the dirtype specifies the file types to include in the search.
140 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
142 static void nbench_unlink_send(struct smbsrv_request *req)
144 struct smb_unlink *unl = req->async_states->private_data;
146 nbench_log(req, "Unlink \"%s\" 0x%x %s\n",
147 unl->in.pattern, unl->in.attrib,
148 get_nt_error_c_code(req->async_states->status));
150 PASS_THRU_REP_POST(req);
153 static NTSTATUS nbench_unlink(struct ntvfs_module_context *ntvfs,
154 struct smbsrv_request *req, struct smb_unlink *unl)
158 PASS_THRU_REQ(ntvfs, req, unlink, unl, (ntvfs, req, unl));
166 static void nbench_ioctl_send(struct smbsrv_request *req)
168 nbench_log(req, "Ioctl - NOT HANDLED\n");
170 PASS_THRU_REP_POST(req);
173 static NTSTATUS nbench_ioctl(struct ntvfs_module_context *ntvfs,
174 struct smbsrv_request *req, union smb_ioctl *io)
178 PASS_THRU_REQ(ntvfs, req, ioctl, io, (ntvfs, req, io));
184 check if a directory exists
186 static void nbench_chkpath_send(struct smbsrv_request *req)
188 struct smb_chkpath *cp = req->async_states->private_data;
190 nbench_log(req, "Chkpath \"%s\" %s\n",
192 get_nt_error_c_code(req->async_states->status));
194 PASS_THRU_REP_POST(req);
197 static NTSTATUS nbench_chkpath(struct ntvfs_module_context *ntvfs,
198 struct smbsrv_request *req, struct smb_chkpath *cp)
202 PASS_THRU_REQ(ntvfs, req, chkpath, cp, (ntvfs, req, cp));
208 return info on a pathname
210 static void nbench_qpathinfo_send(struct smbsrv_request *req)
212 union smb_fileinfo *info = req->async_states->private_data;
214 nbench_log(req, "QUERY_PATH_INFORMATION \"%s\" %d %s\n",
215 info->generic.in.fname,
217 get_nt_error_c_code(req->async_states->status));
219 PASS_THRU_REP_POST(req);
222 static NTSTATUS nbench_qpathinfo(struct ntvfs_module_context *ntvfs,
223 struct smbsrv_request *req, union smb_fileinfo *info)
227 PASS_THRU_REQ(ntvfs, req, qpathinfo, info, (ntvfs, req, info));
233 query info on a open file
235 static void nbench_qfileinfo_send(struct smbsrv_request *req)
237 union smb_fileinfo *info = req->async_states->private_data;
239 nbench_log(req, "QUERY_FILE_INFORMATION %d %d %s\n",
240 info->generic.in.fnum,
242 get_nt_error_c_code(req->async_states->status));
244 PASS_THRU_REP_POST(req);
247 static NTSTATUS nbench_qfileinfo(struct ntvfs_module_context *ntvfs,
248 struct smbsrv_request *req, union smb_fileinfo *info)
252 PASS_THRU_REQ(ntvfs, req, qfileinfo, info, (ntvfs, req, info));
258 set info on a pathname
260 static void nbench_setpathinfo_send(struct smbsrv_request *req)
262 union smb_setfileinfo *st = req->async_states->private_data;
264 nbench_log(req, "SET_PATH_INFORMATION \"%s\" %d %s\n",
265 st->generic.file.fname,
267 get_nt_error_c_code(req->async_states->status));
269 PASS_THRU_REP_POST(req);
272 static NTSTATUS nbench_setpathinfo(struct ntvfs_module_context *ntvfs,
273 struct smbsrv_request *req, union smb_setfileinfo *st)
277 PASS_THRU_REQ(ntvfs, req, setpathinfo, st, (ntvfs, req, st));
285 static void nbench_openfile_send(struct smbsrv_request *req)
287 union smb_open *io = req->async_states->private_data;
289 switch (io->generic.level) {
290 case RAW_OPEN_NTCREATEX:
291 if (!NT_STATUS_IS_OK(req->async_states->status)) {
292 ZERO_STRUCT(io->ntcreatex.out);
294 nbench_log(req, "NTCreateX \"%s\" 0x%x 0x%x %d %s\n",
295 io->ntcreatex.in.fname,
296 io->ntcreatex.in.create_options,
297 io->ntcreatex.in.open_disposition,
298 io->ntcreatex.out.fnum,
299 get_nt_error_c_code(req->async_states->status));
303 nbench_log(req, "Open-%d - NOT HANDLED\n",
308 PASS_THRU_REP_POST(req);
311 static NTSTATUS nbench_openfile(struct ntvfs_module_context *ntvfs,
312 struct smbsrv_request *req, union smb_open *io)
316 PASS_THRU_REQ(ntvfs, req, openfile, io, (ntvfs, req, io));
324 static void nbench_mkdir_send(struct smbsrv_request *req)
326 nbench_log(req, "Mkdir - NOT HANDLED\n");
328 PASS_THRU_REP_POST(req);
331 static NTSTATUS nbench_mkdir(struct ntvfs_module_context *ntvfs,
332 struct smbsrv_request *req, union smb_mkdir *md)
336 PASS_THRU_REQ(ntvfs, req, mkdir, md, (ntvfs, req, md));
344 static void nbench_rmdir_send(struct smbsrv_request *req)
346 struct smb_rmdir *rd = req->async_states->private_data;
348 nbench_log(req, "Rmdir \"%s\" %s\n",
350 get_nt_error_c_code(req->async_states->status));
352 PASS_THRU_REP_POST(req);
355 static NTSTATUS nbench_rmdir(struct ntvfs_module_context *ntvfs,
356 struct smbsrv_request *req, struct smb_rmdir *rd)
360 PASS_THRU_REQ(ntvfs, req, rmdir, rd, (ntvfs, req, rd));
366 rename a set of files
368 static void nbench_rename_send(struct smbsrv_request *req)
370 union smb_rename *ren = req->async_states->private_data;
372 switch (ren->generic.level) {
373 case RAW_RENAME_RENAME:
374 nbench_log(req, "Rename \"%s\" \"%s\" %s\n",
375 ren->rename.in.pattern1,
376 ren->rename.in.pattern2,
377 get_nt_error_c_code(req->async_states->status));
381 nbench_log(req, "Rename-%d - NOT HANDLED\n",
386 PASS_THRU_REP_POST(req);
389 static NTSTATUS nbench_rename(struct ntvfs_module_context *ntvfs,
390 struct smbsrv_request *req, union smb_rename *ren)
394 PASS_THRU_REQ(ntvfs, req, rename, ren, (ntvfs, req, ren));
402 static void nbench_copy_send(struct smbsrv_request *req)
404 nbench_log(req, "Copy - NOT HANDLED\n");
406 PASS_THRU_REP_POST(req);
409 static NTSTATUS nbench_copy(struct ntvfs_module_context *ntvfs,
410 struct smbsrv_request *req, struct smb_copy *cp)
414 PASS_THRU_REQ(ntvfs, req, copy, cp, (ntvfs, req, cp));
422 static void nbench_read_send(struct smbsrv_request *req)
424 union smb_read *rd = req->async_states->private_data;
426 switch (rd->generic.level) {
428 if (!NT_STATUS_IS_OK(req->async_states->status)) {
429 ZERO_STRUCT(rd->readx.out);
431 nbench_log(req, "ReadX %d %d %d %d %s\n",
433 (int)rd->readx.in.offset,
436 get_nt_error_c_code(req->async_states->status));
439 nbench_log(req, "Read-%d - NOT HANDLED\n",
444 PASS_THRU_REP_POST(req);
447 static NTSTATUS nbench_read(struct ntvfs_module_context *ntvfs,
448 struct smbsrv_request *req, union smb_read *rd)
452 PASS_THRU_REQ(ntvfs, req, read, rd, (ntvfs, req, rd));
460 static void nbench_write_send(struct smbsrv_request *req)
462 union smb_write *wr = req->async_states->private_data;
464 switch (wr->generic.level) {
465 case RAW_WRITE_WRITEX:
466 if (!NT_STATUS_IS_OK(req->async_states->status)) {
467 ZERO_STRUCT(wr->writex.out);
469 nbench_log(req, "WriteX %d %d %d %d %s\n",
471 (int)wr->writex.in.offset,
473 wr->writex.out.nwritten,
474 get_nt_error_c_code(req->async_states->status));
477 case RAW_WRITE_WRITE:
478 if (!NT_STATUS_IS_OK(req->async_states->status)) {
479 ZERO_STRUCT(wr->write.out);
481 nbench_log(req, "Write %d %d %d %d %s\n",
485 wr->write.out.nwritten,
486 get_nt_error_c_code(req->async_states->status));
490 nbench_log(req, "Write-%d - NOT HANDLED\n",
495 PASS_THRU_REP_POST(req);
498 static NTSTATUS nbench_write(struct ntvfs_module_context *ntvfs,
499 struct smbsrv_request *req, union smb_write *wr)
503 PASS_THRU_REQ(ntvfs, req, write, wr, (ntvfs, req, wr));
511 static void nbench_seek_send(struct smbsrv_request *req)
513 nbench_log(req, "Seek - NOT HANDLED\n");
515 PASS_THRU_REP_POST(req);
518 static NTSTATUS nbench_seek(struct ntvfs_module_context *ntvfs,
519 struct smbsrv_request *req, struct smb_seek *io)
523 PASS_THRU_REQ(ntvfs, req, seek, io, (ntvfs, req, io));
531 static void nbench_flush_send(struct smbsrv_request *req)
533 struct smb_flush *io = req->async_states->private_data;
535 nbench_log(req, "Flush %d %s\n",
537 get_nt_error_c_code(req->async_states->status));
539 PASS_THRU_REP_POST(req);
542 static NTSTATUS nbench_flush(struct ntvfs_module_context *ntvfs,
543 struct smbsrv_request *req, struct smb_flush *io)
547 PASS_THRU_REQ(ntvfs, req, flush, io, (ntvfs, req, io));
555 static void nbench_close_send(struct smbsrv_request *req)
557 union smb_close *io = req->async_states->private_data;
559 switch (io->generic.level) {
560 case RAW_CLOSE_CLOSE:
561 nbench_log(req, "Close %d %s\n",
563 get_nt_error_c_code(req->async_states->status));
567 nbench_log(req, "Close-%d - NOT HANDLED\n",
572 PASS_THRU_REP_POST(req);
575 static NTSTATUS nbench_close(struct ntvfs_module_context *ntvfs,
576 struct smbsrv_request *req, union smb_close *io)
580 PASS_THRU_REQ(ntvfs, req, close, io, (ntvfs, req, io));
588 static void nbench_exit_send(struct smbsrv_request *req)
590 nbench_log(req, "Exit - NOT HANDLED\n");
592 PASS_THRU_REP_POST(req);
595 static NTSTATUS nbench_exit(struct ntvfs_module_context *ntvfs,
596 struct smbsrv_request *req)
600 PASS_THRU_REQ(ntvfs, req, exit, NULL, (ntvfs, req));
606 logoff - closing files
608 static void nbench_logoff_send(struct smbsrv_request *req)
610 nbench_log(req, "Logoff - NOT HANDLED\n");
612 PASS_THRU_REP_POST(req);
615 static NTSTATUS nbench_logoff(struct ntvfs_module_context *ntvfs,
616 struct smbsrv_request *req)
620 PASS_THRU_REQ(ntvfs, req, logoff, NULL, (ntvfs, req));
626 async_setup - send fn
628 static void nbench_async_setup_send(struct smbsrv_request *req)
630 PASS_THRU_REP_POST(req);
636 static NTSTATUS nbench_async_setup(struct ntvfs_module_context *ntvfs,
637 struct smbsrv_request *req,
642 PASS_THRU_REQ(ntvfs, req, async_setup, NULL, (ntvfs, req, private));
648 static void nbench_cancel_send(struct smbsrv_request *req)
650 PASS_THRU_REP_POST(req);
654 cancel an existing async request
656 static NTSTATUS nbench_cancel(struct ntvfs_module_context *ntvfs,
657 struct smbsrv_request *req)
661 PASS_THRU_REQ(ntvfs, req, cancel, NULL, (ntvfs, req));
669 static void nbench_lock_send(struct smbsrv_request *req)
671 union smb_lock *lck = req->async_states->private_data;
673 if (lck->generic.level == RAW_LOCK_LOCKX &&
674 lck->lockx.in.lock_cnt == 1 &&
675 lck->lockx.in.ulock_cnt == 0) {
676 nbench_log(req, "LockX %d %d %d %s\n",
678 (int)lck->lockx.in.locks[0].offset,
679 (int)lck->lockx.in.locks[0].count,
680 get_nt_error_c_code(req->async_states->status));
681 } else if (lck->generic.level == RAW_LOCK_LOCKX &&
682 lck->lockx.in.ulock_cnt == 1) {
683 nbench_log(req, "UnlockX %d %d %d %s\n",
685 (int)lck->lockx.in.locks[0].offset,
686 (int)lck->lockx.in.locks[0].count,
687 get_nt_error_c_code(req->async_states->status));
689 nbench_log(req, "Lock-%d - NOT HANDLED\n", lck->generic.level);
692 PASS_THRU_REP_POST(req);
695 static NTSTATUS nbench_lock(struct ntvfs_module_context *ntvfs,
696 struct smbsrv_request *req, union smb_lock *lck)
700 PASS_THRU_REQ(ntvfs, req, lock, lck, (ntvfs, req, lck));
706 set info on a open file
708 static void nbench_setfileinfo_send(struct smbsrv_request *req)
710 union smb_setfileinfo *info = req->async_states->private_data;
712 nbench_log(req, "SET_FILE_INFORMATION %d %d %s\n",
713 info->generic.file.fnum,
715 get_nt_error_c_code(req->async_states->status));
717 PASS_THRU_REP_POST(req);
720 static NTSTATUS nbench_setfileinfo(struct ntvfs_module_context *ntvfs,
721 struct smbsrv_request *req,
722 union smb_setfileinfo *info)
726 PASS_THRU_REQ(ntvfs, req, setfileinfo, info, (ntvfs, req, info));
732 return filesystem space info
734 static void nbench_fsinfo_send(struct smbsrv_request *req)
736 union smb_fsinfo *fs = req->async_states->private_data;
738 nbench_log(req, "QUERY_FS_INFORMATION %d %s\n",
740 get_nt_error_c_code(req->async_states->status));
742 PASS_THRU_REP_POST(req);
745 static NTSTATUS nbench_fsinfo(struct ntvfs_module_context *ntvfs,
746 struct smbsrv_request *req, union smb_fsinfo *fs)
750 PASS_THRU_REQ(ntvfs, req, fsinfo, fs, (ntvfs, req, fs));
756 return print queue info
758 static void nbench_lpq_send(struct smbsrv_request *req)
760 union smb_lpq *lpq = req->async_states->private_data;
762 nbench_log(req, "Lpq-%d - NOT HANDLED\n", lpq->generic.level);
764 PASS_THRU_REP_POST(req);
767 static NTSTATUS nbench_lpq(struct ntvfs_module_context *ntvfs,
768 struct smbsrv_request *req, union smb_lpq *lpq)
772 PASS_THRU_REQ(ntvfs, req, lpq, lpq, (ntvfs, req, lpq));
778 list files in a directory matching a wildcard pattern
780 static void nbench_search_first_send(struct smbsrv_request *req)
782 union smb_search_first *io = req->async_states->private_data;
784 switch (io->generic.level) {
785 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
786 if (NT_STATUS_IS_ERR(req->async_states->status)) {
787 ZERO_STRUCT(io->t2ffirst.out);
789 nbench_log(req, "FIND_FIRST \"%s\" %d %d %d %s\n",
790 io->t2ffirst.in.pattern,
792 io->t2ffirst.in.max_count,
793 io->t2ffirst.out.count,
794 get_nt_error_c_code(req->async_states->status));
798 nbench_log(req, "Search-%d - NOT HANDLED\n", io->generic.level);
802 PASS_THRU_REP_POST(req);
805 static NTSTATUS nbench_search_first(struct ntvfs_module_context *ntvfs,
806 struct smbsrv_request *req, union smb_search_first *io,
807 void *search_private,
808 BOOL (*callback)(void *, union smb_search_data *))
812 PASS_THRU_REQ(ntvfs, req, search_first, io, (ntvfs, req, io, search_private, callback));
817 /* continue a search */
818 static void nbench_search_next_send(struct smbsrv_request *req)
820 union smb_search_next *io = req->async_states->private_data;
822 nbench_log(req, "Searchnext-%d - NOT HANDLED\n", io->generic.level);
824 PASS_THRU_REP_POST(req);
827 static NTSTATUS nbench_search_next(struct ntvfs_module_context *ntvfs,
828 struct smbsrv_request *req, union smb_search_next *io,
829 void *search_private,
830 BOOL (*callback)(void *, union smb_search_data *))
834 PASS_THRU_REQ(ntvfs, req, search_next, io, (ntvfs, req, io, search_private, callback));
840 static void nbench_search_close_send(struct smbsrv_request *req)
842 union smb_search_close *io = req->async_states->private_data;
844 nbench_log(req, "Searchclose-%d - NOT HANDLED\n", io->generic.level);
846 PASS_THRU_REP_POST(req);
849 static NTSTATUS nbench_search_close(struct ntvfs_module_context *ntvfs,
850 struct smbsrv_request *req, union smb_search_close *io)
854 PASS_THRU_REQ(ntvfs, req, search_close, io, (ntvfs, req, io));
859 /* SMBtrans - not used on file shares */
860 static void nbench_trans_send(struct smbsrv_request *req)
862 nbench_log(req, "Trans - NOT HANDLED\n");
864 PASS_THRU_REP_POST(req);
867 static NTSTATUS nbench_trans(struct ntvfs_module_context *ntvfs,
868 struct smbsrv_request *req, struct smb_trans2 *trans2)
872 PASS_THRU_REQ(ntvfs, req, trans, trans2, (ntvfs, req, trans2));
878 initialise the nbench backend, registering ourselves with the ntvfs subsystem
880 NTSTATUS ntvfs_nbench_init(void)
883 struct ntvfs_ops ops;
887 /* fill in the name and type */
889 ops.type = NTVFS_DISK;
891 /* fill in all the operations */
892 ops.connect = nbench_connect;
893 ops.disconnect = nbench_disconnect;
894 ops.unlink = nbench_unlink;
895 ops.chkpath = nbench_chkpath;
896 ops.qpathinfo = nbench_qpathinfo;
897 ops.setpathinfo = nbench_setpathinfo;
898 ops.openfile = nbench_openfile;
899 ops.mkdir = nbench_mkdir;
900 ops.rmdir = nbench_rmdir;
901 ops.rename = nbench_rename;
902 ops.copy = nbench_copy;
903 ops.ioctl = nbench_ioctl;
904 ops.read = nbench_read;
905 ops.write = nbench_write;
906 ops.seek = nbench_seek;
907 ops.flush = nbench_flush;
908 ops.close = nbench_close;
909 ops.exit = nbench_exit;
910 ops.lock = nbench_lock;
911 ops.setfileinfo = nbench_setfileinfo;
912 ops.qfileinfo = nbench_qfileinfo;
913 ops.fsinfo = nbench_fsinfo;
914 ops.lpq = nbench_lpq;
915 ops.search_first = nbench_search_first;
916 ops.search_next = nbench_search_next;
917 ops.search_close = nbench_search_close;
918 ops.trans = nbench_trans;
919 ops.logoff = nbench_logoff;
920 ops.async_setup = nbench_async_setup;
921 ops.cancel = nbench_cancel;
923 /* we don't register a trans2 handler as we want to be able to
924 log individual trans2 requests */
927 /* register ourselves with the NTVFS subsystem. */
928 ret = ntvfs_register(&ops);
930 if (!NT_STATUS_IS_OK(ret)) {
931 DEBUG(0,("Failed to register nbench backend!\n"));