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
29 /* this is stored in ntvfs_private */
30 struct nbench_private {
35 log one request to the nbench log
37 static void nbench_log(struct smbsrv_request *req,
38 const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
40 static void nbench_log(struct smbsrv_request *req,
41 const char *format, ...)
43 struct nbench_private *private = req->async_states->ntvfs->private_data;
48 vasprintf(&s, format, ap);
51 write(private->log_fd, s, strlen(s));
56 this pass through macro operates on request contexts, and disables
59 async calls are a pain for the nbench module as it makes pulling the
60 status code and any result parameters much harder.
62 #define PASS_THRU_REQ_PRE_ASYNC(ntvfs, req, op, par1) do { \
63 status = ntvfs_async_state_push(req, par1, nbench_##op##_send, ntvfs); \
64 if (!NT_STATUS_IS_OK(status)) { \
69 #define PASS_THRU_REQ_POST_ASYNC(req) do { \
70 req->async_states->status = status; \
71 if (!(req->async_states->state & NTVFS_ASYNC_STATE_ASYNC)) { \
72 req->async_states->send_fn(req); \
76 #define PASS_THRU_REQ(ntvfs, req, op, par1, args) do { \
77 PASS_THRU_REQ_PRE_ASYNC(ntvfs, req, op, par1); \
78 status = ntvfs_next_##op args; \
79 PASS_THRU_REQ_POST_ASYNC(req); \
82 #define PASS_THRU_REP_POST(req) do { \
83 ntvfs_async_state_pop(req); \
84 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { \
85 req->async_states->send_fn(req); \
90 connect to a share - used when a tree_connect operation comes in.
92 static NTSTATUS nbench_connect(struct ntvfs_module_context *ntvfs,
93 struct smbsrv_request *req, const char *sharename)
95 struct nbench_private *nprivates;
99 nprivates = talloc_p(req->tcon, struct nbench_private);
101 return NT_STATUS_NO_MEMORY;
104 asprintf(&logname, "/tmp/nbenchlog%d.%u", ntvfs->depth, getpid());
105 nprivates->log_fd = open(logname, O_WRONLY|O_CREAT|O_APPEND, 0644);
108 if (nprivates->log_fd == -1) {
109 DEBUG(0,("Failed to open nbench log\n"));
110 return NT_STATUS_UNSUCCESSFUL;
113 ntvfs->private_data = nprivates;
115 status = ntvfs_next_connect(ntvfs, req, sharename);
121 disconnect from a share
123 static NTSTATUS nbench_disconnect(struct ntvfs_module_context *ntvfs,
124 struct smbsrv_tcon *tcon)
126 struct nbench_private *nprivates = ntvfs->private_data;
129 close(nprivates->log_fd);
131 status = ntvfs_next_disconnect(ntvfs, tcon);
137 delete a file - the dirtype specifies the file types to include in the search.
138 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
140 static void nbench_unlink_send(struct smbsrv_request *req)
142 struct smb_unlink *unl = req->async_states->private_data;
144 nbench_log(req, "Unlink \"%s\" 0x%x %s\n",
145 unl->in.pattern, unl->in.attrib,
146 get_nt_error_c_code(req->async_states->status));
148 PASS_THRU_REP_POST(req);
151 static NTSTATUS nbench_unlink(struct ntvfs_module_context *ntvfs,
152 struct smbsrv_request *req, struct smb_unlink *unl)
156 PASS_THRU_REQ(ntvfs, req, unlink, unl, (ntvfs, req, unl));
164 static void nbench_ioctl_send(struct smbsrv_request *req)
166 nbench_log(req, "Ioctl - NOT HANDLED\n");
168 PASS_THRU_REP_POST(req);
171 static NTSTATUS nbench_ioctl(struct ntvfs_module_context *ntvfs,
172 struct smbsrv_request *req, union smb_ioctl *io)
176 PASS_THRU_REQ(ntvfs, req, ioctl, io, (ntvfs, req, io));
182 check if a directory exists
184 static void nbench_chkpath_send(struct smbsrv_request *req)
186 struct smb_chkpath *cp = req->async_states->private_data;
188 nbench_log(req, "Chkpath \"%s\" %s\n",
190 get_nt_error_c_code(req->async_states->status));
192 PASS_THRU_REP_POST(req);
195 static NTSTATUS nbench_chkpath(struct ntvfs_module_context *ntvfs,
196 struct smbsrv_request *req, struct smb_chkpath *cp)
200 PASS_THRU_REQ(ntvfs, req, chkpath, cp, (ntvfs, req, cp));
206 return info on a pathname
208 static void nbench_qpathinfo_send(struct smbsrv_request *req)
210 union smb_fileinfo *info = req->async_states->private_data;
212 nbench_log(req, "QUERY_PATH_INFORMATION \"%s\" %d %s\n",
213 info->generic.in.fname,
215 get_nt_error_c_code(req->async_states->status));
217 PASS_THRU_REP_POST(req);
220 static NTSTATUS nbench_qpathinfo(struct ntvfs_module_context *ntvfs,
221 struct smbsrv_request *req, union smb_fileinfo *info)
225 PASS_THRU_REQ(ntvfs, req, qpathinfo, info, (ntvfs, req, info));
231 query info on a open file
233 static void nbench_qfileinfo_send(struct smbsrv_request *req)
235 union smb_fileinfo *info = req->async_states->private_data;
237 nbench_log(req, "QUERY_FILE_INFORMATION %d %d %s\n",
238 info->generic.in.fnum,
240 get_nt_error_c_code(req->async_states->status));
242 PASS_THRU_REP_POST(req);
245 static NTSTATUS nbench_qfileinfo(struct ntvfs_module_context *ntvfs,
246 struct smbsrv_request *req, union smb_fileinfo *info)
250 PASS_THRU_REQ(ntvfs, req, qfileinfo, info, (ntvfs, req, info));
256 set info on a pathname
258 static void nbench_setpathinfo_send(struct smbsrv_request *req)
260 union smb_setfileinfo *st = req->async_states->private_data;
262 nbench_log(req, "SET_PATH_INFORMATION \"%s\" %d %s\n",
263 st->generic.file.fname,
265 get_nt_error_c_code(req->async_states->status));
267 PASS_THRU_REP_POST(req);
270 static NTSTATUS nbench_setpathinfo(struct ntvfs_module_context *ntvfs,
271 struct smbsrv_request *req, union smb_setfileinfo *st)
275 PASS_THRU_REQ(ntvfs, req, setpathinfo, st, (ntvfs, req, st));
283 static void nbench_openfile_send(struct smbsrv_request *req)
285 union smb_open *io = req->async_states->private_data;
287 switch (io->generic.level) {
288 case RAW_OPEN_NTCREATEX:
289 if (!NT_STATUS_IS_OK(req->async_states->status)) {
290 ZERO_STRUCT(io->ntcreatex.out);
292 nbench_log(req, "NTCreateX \"%s\" 0x%x 0x%x %d %s\n",
293 io->ntcreatex.in.fname,
294 io->ntcreatex.in.create_options,
295 io->ntcreatex.in.open_disposition,
296 io->ntcreatex.out.fnum,
297 get_nt_error_c_code(req->async_states->status));
301 nbench_log(req, "Open-%d - NOT HANDLED\n",
306 PASS_THRU_REP_POST(req);
309 static NTSTATUS nbench_openfile(struct ntvfs_module_context *ntvfs,
310 struct smbsrv_request *req, union smb_open *io)
314 PASS_THRU_REQ(ntvfs, req, openfile, io, (ntvfs, req, io));
322 static void nbench_mkdir_send(struct smbsrv_request *req)
324 nbench_log(req, "Mkdir - NOT HANDLED\n");
326 PASS_THRU_REP_POST(req);
329 static NTSTATUS nbench_mkdir(struct ntvfs_module_context *ntvfs,
330 struct smbsrv_request *req, union smb_mkdir *md)
334 PASS_THRU_REQ(ntvfs, req, mkdir, md, (ntvfs, req, md));
342 static void nbench_rmdir_send(struct smbsrv_request *req)
344 struct smb_rmdir *rd = req->async_states->private_data;
346 nbench_log(req, "Rmdir \"%s\" %s\n",
348 get_nt_error_c_code(req->async_states->status));
350 PASS_THRU_REP_POST(req);
353 static NTSTATUS nbench_rmdir(struct ntvfs_module_context *ntvfs,
354 struct smbsrv_request *req, struct smb_rmdir *rd)
358 PASS_THRU_REQ(ntvfs, req, rmdir, rd, (ntvfs, req, rd));
364 rename a set of files
366 static void nbench_rename_send(struct smbsrv_request *req)
368 union smb_rename *ren = req->async_states->private_data;
370 switch (ren->generic.level) {
371 case RAW_RENAME_RENAME:
372 nbench_log(req, "Rename \"%s\" \"%s\" %s\n",
373 ren->rename.in.pattern1,
374 ren->rename.in.pattern2,
375 get_nt_error_c_code(req->async_states->status));
379 nbench_log(req, "Rename-%d - NOT HANDLED\n",
384 PASS_THRU_REP_POST(req);
387 static NTSTATUS nbench_rename(struct ntvfs_module_context *ntvfs,
388 struct smbsrv_request *req, union smb_rename *ren)
392 PASS_THRU_REQ(ntvfs, req, rename, ren, (ntvfs, req, ren));
400 static void nbench_copy_send(struct smbsrv_request *req)
402 nbench_log(req, "Copy - NOT HANDLED\n");
404 PASS_THRU_REP_POST(req);
407 static NTSTATUS nbench_copy(struct ntvfs_module_context *ntvfs,
408 struct smbsrv_request *req, struct smb_copy *cp)
412 PASS_THRU_REQ(ntvfs, req, copy, cp, (ntvfs, req, cp));
420 static void nbench_read_send(struct smbsrv_request *req)
422 union smb_read *rd = req->async_states->private_data;
424 switch (rd->generic.level) {
426 if (!NT_STATUS_IS_OK(req->async_states->status)) {
427 ZERO_STRUCT(rd->readx.out);
429 nbench_log(req, "ReadX %d %d %d %d %s\n",
431 (int)rd->readx.in.offset,
434 get_nt_error_c_code(req->async_states->status));
437 nbench_log(req, "Read-%d - NOT HANDLED\n",
442 PASS_THRU_REP_POST(req);
445 static NTSTATUS nbench_read(struct ntvfs_module_context *ntvfs,
446 struct smbsrv_request *req, union smb_read *rd)
450 PASS_THRU_REQ(ntvfs, req, read, rd, (ntvfs, req, rd));
458 static void nbench_write_send(struct smbsrv_request *req)
460 union smb_write *wr = req->async_states->private_data;
462 switch (wr->generic.level) {
463 case RAW_WRITE_WRITEX:
464 if (!NT_STATUS_IS_OK(req->async_states->status)) {
465 ZERO_STRUCT(wr->writex.out);
467 nbench_log(req, "WriteX %d %d %d %d %s\n",
469 (int)wr->writex.in.offset,
471 wr->writex.out.nwritten,
472 get_nt_error_c_code(req->async_states->status));
475 case RAW_WRITE_WRITE:
476 if (!NT_STATUS_IS_OK(req->async_states->status)) {
477 ZERO_STRUCT(wr->write.out);
479 nbench_log(req, "Write %d %d %d %d %s\n",
483 wr->write.out.nwritten,
484 get_nt_error_c_code(req->async_states->status));
488 nbench_log(req, "Write-%d - NOT HANDLED\n",
493 PASS_THRU_REP_POST(req);
496 static NTSTATUS nbench_write(struct ntvfs_module_context *ntvfs,
497 struct smbsrv_request *req, union smb_write *wr)
501 PASS_THRU_REQ(ntvfs, req, write, wr, (ntvfs, req, wr));
509 static void nbench_seek_send(struct smbsrv_request *req)
511 nbench_log(req, "Seek - NOT HANDLED\n");
513 PASS_THRU_REP_POST(req);
516 static NTSTATUS nbench_seek(struct ntvfs_module_context *ntvfs,
517 struct smbsrv_request *req, struct smb_seek *io)
521 PASS_THRU_REQ(ntvfs, req, seek, io, (ntvfs, req, io));
529 static void nbench_flush_send(struct smbsrv_request *req)
531 struct smb_flush *io = req->async_states->private_data;
533 nbench_log(req, "Flush %d %s\n",
535 get_nt_error_c_code(req->async_states->status));
537 PASS_THRU_REP_POST(req);
540 static NTSTATUS nbench_flush(struct ntvfs_module_context *ntvfs,
541 struct smbsrv_request *req, struct smb_flush *io)
545 PASS_THRU_REQ(ntvfs, req, flush, io, (ntvfs, req, io));
553 static void nbench_close_send(struct smbsrv_request *req)
555 union smb_close *io = req->async_states->private_data;
557 switch (io->generic.level) {
558 case RAW_CLOSE_CLOSE:
559 nbench_log(req, "Close %d %s\n",
561 get_nt_error_c_code(req->async_states->status));
565 nbench_log(req, "Close-%d - NOT HANDLED\n",
570 PASS_THRU_REP_POST(req);
573 static NTSTATUS nbench_close(struct ntvfs_module_context *ntvfs,
574 struct smbsrv_request *req, union smb_close *io)
578 PASS_THRU_REQ(ntvfs, req, close, io, (ntvfs, req, io));
586 static void nbench_exit_send(struct smbsrv_request *req)
588 nbench_log(req, "Exit - NOT HANDLED\n");
590 PASS_THRU_REP_POST(req);
593 static NTSTATUS nbench_exit(struct ntvfs_module_context *ntvfs,
594 struct smbsrv_request *req)
598 PASS_THRU_REQ(ntvfs, req, exit, NULL, (ntvfs, req));
604 logoff - closing files
606 static void nbench_logoff_send(struct smbsrv_request *req)
608 nbench_log(req, "Logoff - NOT HANDLED\n");
610 PASS_THRU_REP_POST(req);
613 static NTSTATUS nbench_logoff(struct ntvfs_module_context *ntvfs,
614 struct smbsrv_request *req)
618 PASS_THRU_REQ(ntvfs, req, logoff, NULL, (ntvfs, req));
624 async_setup - send fn
626 static void nbench_async_setup_send(struct smbsrv_request *req)
628 PASS_THRU_REP_POST(req);
634 static NTSTATUS nbench_async_setup(struct ntvfs_module_context *ntvfs,
635 struct smbsrv_request *req,
640 PASS_THRU_REQ(ntvfs, req, async_setup, NULL, (ntvfs, req, private));
648 static void nbench_lock_send(struct smbsrv_request *req)
650 union smb_lock *lck = req->async_states->private_data;
652 if (lck->generic.level == RAW_LOCK_LOCKX &&
653 lck->lockx.in.lock_cnt == 1 &&
654 lck->lockx.in.ulock_cnt == 0) {
655 nbench_log(req, "LockX %d %d %d %s\n",
657 (int)lck->lockx.in.locks[0].offset,
658 (int)lck->lockx.in.locks[0].count,
659 get_nt_error_c_code(req->async_states->status));
660 } else if (lck->generic.level == RAW_LOCK_LOCKX &&
661 lck->lockx.in.ulock_cnt == 1) {
662 nbench_log(req, "UnlockX %d %d %d %s\n",
664 (int)lck->lockx.in.locks[0].offset,
665 (int)lck->lockx.in.locks[0].count,
666 get_nt_error_c_code(req->async_states->status));
668 nbench_log(req, "Lock-%d - NOT HANDLED\n", lck->generic.level);
671 PASS_THRU_REP_POST(req);
674 static NTSTATUS nbench_lock(struct ntvfs_module_context *ntvfs,
675 struct smbsrv_request *req, union smb_lock *lck)
679 PASS_THRU_REQ(ntvfs, req, lock, lck, (ntvfs, req, lck));
685 set info on a open file
687 static void nbench_setfileinfo_send(struct smbsrv_request *req)
689 union smb_setfileinfo *info = req->async_states->private_data;
691 nbench_log(req, "SET_FILE_INFORMATION %d %d %s\n",
692 info->generic.file.fnum,
694 get_nt_error_c_code(req->async_states->status));
696 PASS_THRU_REP_POST(req);
699 static NTSTATUS nbench_setfileinfo(struct ntvfs_module_context *ntvfs,
700 struct smbsrv_request *req,
701 union smb_setfileinfo *info)
705 PASS_THRU_REQ(ntvfs, req, setfileinfo, info, (ntvfs, req, info));
711 return filesystem space info
713 static void nbench_fsinfo_send(struct smbsrv_request *req)
715 union smb_fsinfo *fs = req->async_states->private_data;
717 nbench_log(req, "QUERY_FS_INFORMATION %d %s\n",
719 get_nt_error_c_code(req->async_states->status));
721 PASS_THRU_REP_POST(req);
724 static NTSTATUS nbench_fsinfo(struct ntvfs_module_context *ntvfs,
725 struct smbsrv_request *req, union smb_fsinfo *fs)
729 PASS_THRU_REQ(ntvfs, req, fsinfo, fs, (ntvfs, req, fs));
735 return print queue info
737 static void nbench_lpq_send(struct smbsrv_request *req)
739 union smb_lpq *lpq = req->async_states->private_data;
741 nbench_log(req, "Lpq-%d - NOT HANDLED\n", lpq->generic.level);
743 PASS_THRU_REP_POST(req);
746 static NTSTATUS nbench_lpq(struct ntvfs_module_context *ntvfs,
747 struct smbsrv_request *req, union smb_lpq *lpq)
751 PASS_THRU_REQ(ntvfs, req, lpq, lpq, (ntvfs, req, lpq));
757 list files in a directory matching a wildcard pattern
759 static void nbench_search_first_send(struct smbsrv_request *req)
761 union smb_search_first *io = req->async_states->private_data;
763 switch (io->generic.level) {
764 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
765 if (NT_STATUS_IS_ERR(req->async_states->status)) {
766 ZERO_STRUCT(io->t2ffirst.out);
768 nbench_log(req, "FIND_FIRST \"%s\" %d %d %d %s\n",
769 io->t2ffirst.in.pattern,
771 io->t2ffirst.in.max_count,
772 io->t2ffirst.out.count,
773 get_nt_error_c_code(req->async_states->status));
777 nbench_log(req, "Search-%d - NOT HANDLED\n", io->generic.level);
781 PASS_THRU_REP_POST(req);
784 static NTSTATUS nbench_search_first(struct ntvfs_module_context *ntvfs,
785 struct smbsrv_request *req, union smb_search_first *io,
786 void *search_private,
787 BOOL (*callback)(void *, union smb_search_data *))
791 PASS_THRU_REQ(ntvfs, req, search_first, io, (ntvfs, req, io, search_private, callback));
796 /* continue a search */
797 static void nbench_search_next_send(struct smbsrv_request *req)
799 union smb_search_next *io = req->async_states->private_data;
801 nbench_log(req, "Searchnext-%d - NOT HANDLED\n", io->generic.level);
803 PASS_THRU_REP_POST(req);
806 static NTSTATUS nbench_search_next(struct ntvfs_module_context *ntvfs,
807 struct smbsrv_request *req, union smb_search_next *io,
808 void *search_private,
809 BOOL (*callback)(void *, union smb_search_data *))
813 PASS_THRU_REQ(ntvfs, req, search_next, io, (ntvfs, req, io, search_private, callback));
819 static void nbench_search_close_send(struct smbsrv_request *req)
821 union smb_search_close *io = req->async_states->private_data;
823 nbench_log(req, "Searchclose-%d - NOT HANDLED\n", io->generic.level);
825 PASS_THRU_REP_POST(req);
828 static NTSTATUS nbench_search_close(struct ntvfs_module_context *ntvfs,
829 struct smbsrv_request *req, union smb_search_close *io)
833 PASS_THRU_REQ(ntvfs, req, search_close, io, (ntvfs, req, io));
838 /* SMBtrans - not used on file shares */
839 static void nbench_trans_send(struct smbsrv_request *req)
841 nbench_log(req, "Trans - NOT HANDLED\n");
843 PASS_THRU_REP_POST(req);
846 static NTSTATUS nbench_trans(struct ntvfs_module_context *ntvfs,
847 struct smbsrv_request *req, struct smb_trans2 *trans2)
851 PASS_THRU_REQ(ntvfs, req, trans, trans2, (ntvfs, req, trans2));
857 initialise the nbench backend, registering ourselves with the ntvfs subsystem
859 NTSTATUS ntvfs_nbench_init(void)
862 struct ntvfs_ops ops;
866 /* fill in the name and type */
868 ops.type = NTVFS_DISK;
870 /* fill in all the operations */
871 ops.connect = nbench_connect;
872 ops.disconnect = nbench_disconnect;
873 ops.unlink = nbench_unlink;
874 ops.chkpath = nbench_chkpath;
875 ops.qpathinfo = nbench_qpathinfo;
876 ops.setpathinfo = nbench_setpathinfo;
877 ops.openfile = nbench_openfile;
878 ops.mkdir = nbench_mkdir;
879 ops.rmdir = nbench_rmdir;
880 ops.rename = nbench_rename;
881 ops.copy = nbench_copy;
882 ops.ioctl = nbench_ioctl;
883 ops.read = nbench_read;
884 ops.write = nbench_write;
885 ops.seek = nbench_seek;
886 ops.flush = nbench_flush;
887 ops.close = nbench_close;
888 ops.exit = nbench_exit;
889 ops.lock = nbench_lock;
890 ops.setfileinfo = nbench_setfileinfo;
891 ops.qfileinfo = nbench_qfileinfo;
892 ops.fsinfo = nbench_fsinfo;
893 ops.lpq = nbench_lpq;
894 ops.search_first = nbench_search_first;
895 ops.search_next = nbench_search_next;
896 ops.search_close = nbench_search_close;
897 ops.trans = nbench_trans;
898 ops.logoff = nbench_logoff;
899 ops.async_setup = nbench_async_setup;
901 /* we don't register a trans2 handler as we want to be able to
902 log individual trans2 requests */
905 /* register ourselves with the NTVFS subsystem. */
906 ret = register_backend("ntvfs", &ops);
908 if (!NT_STATUS_IS_OK(ret)) {
909 DEBUG(0,("Failed to register nbench backend!\n"));