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"
30 #include "ntvfs/ntvfs.h"
32 /* this is stored in ntvfs_private */
33 struct nbench_private {
38 log one request to the nbench log
40 static void nbench_log(struct ntvfs_request *req,
41 const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
43 static void nbench_log(struct ntvfs_request *req,
44 const char *format, ...)
46 struct nbench_private *private = req->async_states->ntvfs->private_data;
51 vasprintf(&s, format, ap);
54 write(private->log_fd, s, strlen(s));
59 this pass through macro operates on request contexts, and disables
62 async calls are a pain for the nbench module as it makes pulling the
63 status code and any result parameters much harder.
65 #define PASS_THRU_REQ_PRE_ASYNC(ntvfs, req, op, par1) do { \
66 status = ntvfs_async_state_push(ntvfs, req, par1, nbench_##op##_send); \
67 if (!NT_STATUS_IS_OK(status)) { \
72 #define PASS_THRU_REQ_POST_ASYNC(req) do { \
73 req->async_states->status = status; \
74 if (!(req->async_states->state & NTVFS_ASYNC_STATE_ASYNC)) { \
75 req->async_states->send_fn(req); \
79 #define PASS_THRU_REQ(ntvfs, req, op, par1, args) do { \
80 PASS_THRU_REQ_PRE_ASYNC(ntvfs, req, op, par1); \
81 status = ntvfs_next_##op args; \
82 PASS_THRU_REQ_POST_ASYNC(req); \
85 #define PASS_THRU_REP_POST(req) do { \
86 ntvfs_async_state_pop(req); \
87 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { \
88 req->async_states->send_fn(req); \
93 connect to a share - used when a tree_connect operation comes in.
95 static NTSTATUS nbench_connect(struct ntvfs_module_context *ntvfs,
96 struct ntvfs_request *req, const char *sharename)
98 struct nbench_private *nprivates;
100 char *logname = NULL;
102 nprivates = talloc(ntvfs, struct nbench_private);
104 return NT_STATUS_NO_MEMORY;
107 asprintf(&logname, "/tmp/nbenchlog%d.%u", ntvfs->depth, getpid());
108 nprivates->log_fd = open(logname, O_WRONLY|O_CREAT|O_APPEND, 0644);
111 if (nprivates->log_fd == -1) {
112 DEBUG(0,("Failed to open nbench log\n"));
113 return NT_STATUS_UNSUCCESSFUL;
116 ntvfs->private_data = nprivates;
118 status = ntvfs_next_connect(ntvfs, req, sharename);
124 disconnect from a share
126 static NTSTATUS nbench_disconnect(struct ntvfs_module_context *ntvfs)
128 struct nbench_private *nprivates = ntvfs->private_data;
131 close(nprivates->log_fd);
133 status = ntvfs_next_disconnect(ntvfs);
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 ntvfs_request *req)
144 union smb_unlink *unl = req->async_states->private_data;
146 nbench_log(req, "Unlink \"%s\" 0x%x %s\n",
147 unl->unlink.in.pattern, unl->unlink.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 ntvfs_request *req,
155 union smb_unlink *unl)
159 PASS_THRU_REQ(ntvfs, req, unlink, unl, (ntvfs, req, unl));
167 static void nbench_ioctl_send(struct ntvfs_request *req)
169 nbench_log(req, "Ioctl - NOT HANDLED\n");
171 PASS_THRU_REP_POST(req);
174 static NTSTATUS nbench_ioctl(struct ntvfs_module_context *ntvfs,
175 struct ntvfs_request *req, union smb_ioctl *io)
179 PASS_THRU_REQ(ntvfs, req, ioctl, io, (ntvfs, req, io));
185 check if a directory exists
187 static void nbench_chkpath_send(struct ntvfs_request *req)
189 union smb_chkpath *cp = req->async_states->private_data;
191 nbench_log(req, "Chkpath \"%s\" %s\n",
193 get_nt_error_c_code(req->async_states->status));
195 PASS_THRU_REP_POST(req);
198 static NTSTATUS nbench_chkpath(struct ntvfs_module_context *ntvfs,
199 struct ntvfs_request *req,
200 union smb_chkpath *cp)
204 PASS_THRU_REQ(ntvfs, req, chkpath, cp, (ntvfs, req, cp));
210 return info on a pathname
212 static void nbench_qpathinfo_send(struct ntvfs_request *req)
214 union smb_fileinfo *info = req->async_states->private_data;
216 nbench_log(req, "QUERY_PATH_INFORMATION \"%s\" %d %s\n",
217 info->generic.file.path,
219 get_nt_error_c_code(req->async_states->status));
221 PASS_THRU_REP_POST(req);
224 static NTSTATUS nbench_qpathinfo(struct ntvfs_module_context *ntvfs,
225 struct ntvfs_request *req, union smb_fileinfo *info)
229 PASS_THRU_REQ(ntvfs, req, qpathinfo, info, (ntvfs, req, info));
235 query info on a open file
237 static void nbench_qfileinfo_send(struct ntvfs_request *req)
239 union smb_fileinfo *info = req->async_states->private_data;
241 nbench_log(req, "QUERY_FILE_INFORMATION %d %d %s\n",
242 info->generic.file.fnum,
244 get_nt_error_c_code(req->async_states->status));
246 PASS_THRU_REP_POST(req);
249 static NTSTATUS nbench_qfileinfo(struct ntvfs_module_context *ntvfs,
250 struct ntvfs_request *req, union smb_fileinfo *info)
254 PASS_THRU_REQ(ntvfs, req, qfileinfo, info, (ntvfs, req, info));
260 set info on a pathname
262 static void nbench_setpathinfo_send(struct ntvfs_request *req)
264 union smb_setfileinfo *st = req->async_states->private_data;
266 nbench_log(req, "SET_PATH_INFORMATION \"%s\" %d %s\n",
267 st->generic.file.path,
269 get_nt_error_c_code(req->async_states->status));
271 PASS_THRU_REP_POST(req);
274 static NTSTATUS nbench_setpathinfo(struct ntvfs_module_context *ntvfs,
275 struct ntvfs_request *req, union smb_setfileinfo *st)
279 PASS_THRU_REQ(ntvfs, req, setpathinfo, st, (ntvfs, req, st));
287 static void nbench_open_send(struct ntvfs_request *req)
289 union smb_open *io = req->async_states->private_data;
291 switch (io->generic.level) {
292 case RAW_OPEN_NTCREATEX:
293 if (!NT_STATUS_IS_OK(req->async_states->status)) {
294 ZERO_STRUCT(io->ntcreatex.out);
296 nbench_log(req, "NTCreateX \"%s\" 0x%x 0x%x %d %s\n",
297 io->ntcreatex.in.fname,
298 io->ntcreatex.in.create_options,
299 io->ntcreatex.in.open_disposition,
300 io->ntcreatex.file.fnum,
301 get_nt_error_c_code(req->async_states->status));
305 nbench_log(req, "Open-%d - NOT HANDLED\n",
310 PASS_THRU_REP_POST(req);
313 static NTSTATUS nbench_open(struct ntvfs_module_context *ntvfs,
314 struct ntvfs_request *req, union smb_open *io)
318 PASS_THRU_REQ(ntvfs, req, open, io, (ntvfs, req, io));
326 static void nbench_mkdir_send(struct ntvfs_request *req)
328 nbench_log(req, "Mkdir - NOT HANDLED\n");
330 PASS_THRU_REP_POST(req);
333 static NTSTATUS nbench_mkdir(struct ntvfs_module_context *ntvfs,
334 struct ntvfs_request *req, union smb_mkdir *md)
338 PASS_THRU_REQ(ntvfs, req, mkdir, md, (ntvfs, req, md));
346 static void nbench_rmdir_send(struct ntvfs_request *req)
348 struct smb_rmdir *rd = req->async_states->private_data;
350 nbench_log(req, "Rmdir \"%s\" %s\n",
352 get_nt_error_c_code(req->async_states->status));
354 PASS_THRU_REP_POST(req);
357 static NTSTATUS nbench_rmdir(struct ntvfs_module_context *ntvfs,
358 struct ntvfs_request *req, struct smb_rmdir *rd)
362 PASS_THRU_REQ(ntvfs, req, rmdir, rd, (ntvfs, req, rd));
368 rename a set of files
370 static void nbench_rename_send(struct ntvfs_request *req)
372 union smb_rename *ren = req->async_states->private_data;
374 switch (ren->generic.level) {
375 case RAW_RENAME_RENAME:
376 nbench_log(req, "Rename \"%s\" \"%s\" %s\n",
377 ren->rename.in.pattern1,
378 ren->rename.in.pattern2,
379 get_nt_error_c_code(req->async_states->status));
383 nbench_log(req, "Rename-%d - NOT HANDLED\n",
388 PASS_THRU_REP_POST(req);
391 static NTSTATUS nbench_rename(struct ntvfs_module_context *ntvfs,
392 struct ntvfs_request *req, union smb_rename *ren)
396 PASS_THRU_REQ(ntvfs, req, rename, ren, (ntvfs, req, ren));
404 static void nbench_copy_send(struct ntvfs_request *req)
406 nbench_log(req, "Copy - NOT HANDLED\n");
408 PASS_THRU_REP_POST(req);
411 static NTSTATUS nbench_copy(struct ntvfs_module_context *ntvfs,
412 struct ntvfs_request *req, struct smb_copy *cp)
416 PASS_THRU_REQ(ntvfs, req, copy, cp, (ntvfs, req, cp));
424 static void nbench_read_send(struct ntvfs_request *req)
426 union smb_read *rd = req->async_states->private_data;
428 switch (rd->generic.level) {
430 if (!NT_STATUS_IS_OK(req->async_states->status)) {
431 ZERO_STRUCT(rd->readx.out);
433 nbench_log(req, "ReadX %d %d %d %d %s\n",
435 (int)rd->readx.in.offset,
438 get_nt_error_c_code(req->async_states->status));
441 nbench_log(req, "Read-%d - NOT HANDLED\n",
446 PASS_THRU_REP_POST(req);
449 static NTSTATUS nbench_read(struct ntvfs_module_context *ntvfs,
450 struct ntvfs_request *req, union smb_read *rd)
454 PASS_THRU_REQ(ntvfs, req, read, rd, (ntvfs, req, rd));
462 static void nbench_write_send(struct ntvfs_request *req)
464 union smb_write *wr = req->async_states->private_data;
466 switch (wr->generic.level) {
467 case RAW_WRITE_WRITEX:
468 if (!NT_STATUS_IS_OK(req->async_states->status)) {
469 ZERO_STRUCT(wr->writex.out);
471 nbench_log(req, "WriteX %d %d %d %d %s\n",
472 wr->writex.file.fnum,
473 (int)wr->writex.in.offset,
475 wr->writex.out.nwritten,
476 get_nt_error_c_code(req->async_states->status));
479 case RAW_WRITE_WRITE:
480 if (!NT_STATUS_IS_OK(req->async_states->status)) {
481 ZERO_STRUCT(wr->write.out);
483 nbench_log(req, "Write %d %d %d %d %s\n",
487 wr->write.out.nwritten,
488 get_nt_error_c_code(req->async_states->status));
492 nbench_log(req, "Write-%d - NOT HANDLED\n",
497 PASS_THRU_REP_POST(req);
500 static NTSTATUS nbench_write(struct ntvfs_module_context *ntvfs,
501 struct ntvfs_request *req, union smb_write *wr)
505 PASS_THRU_REQ(ntvfs, req, write, wr, (ntvfs, req, wr));
513 static void nbench_seek_send(struct ntvfs_request *req)
515 nbench_log(req, "Seek - NOT HANDLED\n");
517 PASS_THRU_REP_POST(req);
520 static NTSTATUS nbench_seek(struct ntvfs_module_context *ntvfs,
521 struct ntvfs_request *req,
526 PASS_THRU_REQ(ntvfs, req, seek, io, (ntvfs, req, io));
534 static void nbench_flush_send(struct ntvfs_request *req)
536 union smb_flush *io = req->async_states->private_data;
538 nbench_log(req, "Flush %d %s\n",
540 get_nt_error_c_code(req->async_states->status));
542 PASS_THRU_REP_POST(req);
545 static NTSTATUS nbench_flush(struct ntvfs_module_context *ntvfs,
546 struct ntvfs_request *req,
551 PASS_THRU_REQ(ntvfs, req, flush, io, (ntvfs, req, io));
559 static void nbench_close_send(struct ntvfs_request *req)
561 union smb_close *io = req->async_states->private_data;
563 switch (io->generic.level) {
564 case RAW_CLOSE_CLOSE:
565 nbench_log(req, "Close %d %s\n",
567 get_nt_error_c_code(req->async_states->status));
571 nbench_log(req, "Close-%d - NOT HANDLED\n",
576 PASS_THRU_REP_POST(req);
579 static NTSTATUS nbench_close(struct ntvfs_module_context *ntvfs,
580 struct ntvfs_request *req, union smb_close *io)
584 PASS_THRU_REQ(ntvfs, req, close, io, (ntvfs, req, io));
592 static void nbench_exit_send(struct ntvfs_request *req)
594 nbench_log(req, "Exit - NOT HANDLED\n");
596 PASS_THRU_REP_POST(req);
599 static NTSTATUS nbench_exit(struct ntvfs_module_context *ntvfs,
600 struct ntvfs_request *req)
604 PASS_THRU_REQ(ntvfs, req, exit, NULL, (ntvfs, req));
610 logoff - closing files
612 static void nbench_logoff_send(struct ntvfs_request *req)
614 nbench_log(req, "Logoff - NOT HANDLED\n");
616 PASS_THRU_REP_POST(req);
619 static NTSTATUS nbench_logoff(struct ntvfs_module_context *ntvfs,
620 struct ntvfs_request *req)
624 PASS_THRU_REQ(ntvfs, req, logoff, NULL, (ntvfs, req));
630 async_setup - send fn
632 static void nbench_async_setup_send(struct ntvfs_request *req)
634 PASS_THRU_REP_POST(req);
640 static NTSTATUS nbench_async_setup(struct ntvfs_module_context *ntvfs,
641 struct ntvfs_request *req,
646 PASS_THRU_REQ(ntvfs, req, async_setup, NULL, (ntvfs, req, private));
652 static void nbench_cancel_send(struct ntvfs_request *req)
654 PASS_THRU_REP_POST(req);
658 cancel an existing async request
660 static NTSTATUS nbench_cancel(struct ntvfs_module_context *ntvfs,
661 struct ntvfs_request *req)
665 PASS_THRU_REQ(ntvfs, req, cancel, NULL, (ntvfs, req));
673 static void nbench_lock_send(struct ntvfs_request *req)
675 union smb_lock *lck = req->async_states->private_data;
677 if (lck->generic.level == RAW_LOCK_LOCKX &&
678 lck->lockx.in.lock_cnt == 1 &&
679 lck->lockx.in.ulock_cnt == 0) {
680 nbench_log(req, "LockX %d %d %d %s\n",
681 lck->lockx.file.fnum,
682 (int)lck->lockx.in.locks[0].offset,
683 (int)lck->lockx.in.locks[0].count,
684 get_nt_error_c_code(req->async_states->status));
685 } else if (lck->generic.level == RAW_LOCK_LOCKX &&
686 lck->lockx.in.ulock_cnt == 1) {
687 nbench_log(req, "UnlockX %d %d %d %s\n",
688 lck->lockx.file.fnum,
689 (int)lck->lockx.in.locks[0].offset,
690 (int)lck->lockx.in.locks[0].count,
691 get_nt_error_c_code(req->async_states->status));
693 nbench_log(req, "Lock-%d - NOT HANDLED\n", lck->generic.level);
696 PASS_THRU_REP_POST(req);
699 static NTSTATUS nbench_lock(struct ntvfs_module_context *ntvfs,
700 struct ntvfs_request *req, union smb_lock *lck)
704 PASS_THRU_REQ(ntvfs, req, lock, lck, (ntvfs, req, lck));
710 set info on a open file
712 static void nbench_setfileinfo_send(struct ntvfs_request *req)
714 union smb_setfileinfo *info = req->async_states->private_data;
716 nbench_log(req, "SET_FILE_INFORMATION %d %d %s\n",
717 info->generic.file.fnum,
719 get_nt_error_c_code(req->async_states->status));
721 PASS_THRU_REP_POST(req);
724 static NTSTATUS nbench_setfileinfo(struct ntvfs_module_context *ntvfs,
725 struct ntvfs_request *req,
726 union smb_setfileinfo *info)
730 PASS_THRU_REQ(ntvfs, req, setfileinfo, info, (ntvfs, req, info));
736 return filesystem space info
738 static void nbench_fsinfo_send(struct ntvfs_request *req)
740 union smb_fsinfo *fs = req->async_states->private_data;
742 nbench_log(req, "QUERY_FS_INFORMATION %d %s\n",
744 get_nt_error_c_code(req->async_states->status));
746 PASS_THRU_REP_POST(req);
749 static NTSTATUS nbench_fsinfo(struct ntvfs_module_context *ntvfs,
750 struct ntvfs_request *req, union smb_fsinfo *fs)
754 PASS_THRU_REQ(ntvfs, req, fsinfo, fs, (ntvfs, req, fs));
760 return print queue info
762 static void nbench_lpq_send(struct ntvfs_request *req)
764 union smb_lpq *lpq = req->async_states->private_data;
766 nbench_log(req, "Lpq-%d - NOT HANDLED\n", lpq->generic.level);
768 PASS_THRU_REP_POST(req);
771 static NTSTATUS nbench_lpq(struct ntvfs_module_context *ntvfs,
772 struct ntvfs_request *req, union smb_lpq *lpq)
776 PASS_THRU_REQ(ntvfs, req, lpq, lpq, (ntvfs, req, lpq));
782 list files in a directory matching a wildcard pattern
784 static void nbench_search_first_send(struct ntvfs_request *req)
786 union smb_search_first *io = req->async_states->private_data;
788 switch (io->generic.level) {
789 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
790 if (NT_STATUS_IS_ERR(req->async_states->status)) {
791 ZERO_STRUCT(io->t2ffirst.out);
793 nbench_log(req, "FIND_FIRST \"%s\" %d %d %d %s\n",
794 io->t2ffirst.in.pattern,
796 io->t2ffirst.in.max_count,
797 io->t2ffirst.out.count,
798 get_nt_error_c_code(req->async_states->status));
802 nbench_log(req, "Search-%d - NOT HANDLED\n", io->generic.level);
806 PASS_THRU_REP_POST(req);
809 static NTSTATUS nbench_search_first(struct ntvfs_module_context *ntvfs,
810 struct ntvfs_request *req, union smb_search_first *io,
811 void *search_private,
812 BOOL (*callback)(void *, union smb_search_data *))
816 PASS_THRU_REQ(ntvfs, req, search_first, io, (ntvfs, req, io, search_private, callback));
821 /* continue a search */
822 static void nbench_search_next_send(struct ntvfs_request *req)
824 union smb_search_next *io = req->async_states->private_data;
826 nbench_log(req, "Searchnext-%d - NOT HANDLED\n", io->generic.level);
828 PASS_THRU_REP_POST(req);
831 static NTSTATUS nbench_search_next(struct ntvfs_module_context *ntvfs,
832 struct ntvfs_request *req, union smb_search_next *io,
833 void *search_private,
834 BOOL (*callback)(void *, union smb_search_data *))
838 PASS_THRU_REQ(ntvfs, req, search_next, io, (ntvfs, req, io, search_private, callback));
844 static void nbench_search_close_send(struct ntvfs_request *req)
846 union smb_search_close *io = req->async_states->private_data;
848 nbench_log(req, "Searchclose-%d - NOT HANDLED\n", io->generic.level);
850 PASS_THRU_REP_POST(req);
853 static NTSTATUS nbench_search_close(struct ntvfs_module_context *ntvfs,
854 struct ntvfs_request *req, union smb_search_close *io)
858 PASS_THRU_REQ(ntvfs, req, search_close, io, (ntvfs, req, io));
863 /* SMBtrans - not used on file shares */
864 static void nbench_trans_send(struct ntvfs_request *req)
866 nbench_log(req, "Trans - NOT HANDLED\n");
868 PASS_THRU_REP_POST(req);
871 static NTSTATUS nbench_trans(struct ntvfs_module_context *ntvfs,
872 struct ntvfs_request *req, struct smb_trans2 *trans2)
876 PASS_THRU_REQ(ntvfs, req, trans, trans2, (ntvfs, req, trans2));
882 initialise the nbench backend, registering ourselves with the ntvfs subsystem
884 NTSTATUS ntvfs_nbench_init(void)
887 struct ntvfs_ops ops;
891 /* fill in the name and type */
893 ops.type = NTVFS_DISK;
895 /* fill in all the operations */
896 ops.connect = nbench_connect;
897 ops.disconnect = nbench_disconnect;
898 ops.unlink = nbench_unlink;
899 ops.chkpath = nbench_chkpath;
900 ops.qpathinfo = nbench_qpathinfo;
901 ops.setpathinfo = nbench_setpathinfo;
902 ops.open = nbench_open;
903 ops.mkdir = nbench_mkdir;
904 ops.rmdir = nbench_rmdir;
905 ops.rename = nbench_rename;
906 ops.copy = nbench_copy;
907 ops.ioctl = nbench_ioctl;
908 ops.read = nbench_read;
909 ops.write = nbench_write;
910 ops.seek = nbench_seek;
911 ops.flush = nbench_flush;
912 ops.close = nbench_close;
913 ops.exit = nbench_exit;
914 ops.lock = nbench_lock;
915 ops.setfileinfo = nbench_setfileinfo;
916 ops.qfileinfo = nbench_qfileinfo;
917 ops.fsinfo = nbench_fsinfo;
918 ops.lpq = nbench_lpq;
919 ops.search_first = nbench_search_first;
920 ops.search_next = nbench_search_next;
921 ops.search_close = nbench_search_close;
922 ops.trans = nbench_trans;
923 ops.logoff = nbench_logoff;
924 ops.async_setup = nbench_async_setup;
925 ops.cancel = nbench_cancel;
927 /* we don't register a trans2 handler as we want to be able to
928 log individual trans2 requests */
931 /* register ourselves with the NTVFS subsystem. */
932 ret = ntvfs_register(&ops);
934 if (!NT_STATUS_IS_OK(ret)) {
935 DEBUG(0,("Failed to register nbench backend!\n"));