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 {
31 const struct ntvfs_ops *passthru_ops;
32 void *passthru_private;
33 const struct ntvfs_ops *nbench_ops;
39 log one request to the nbench log
41 static void nbench_log(struct nbench_private *private,
42 const char *format, ...)
48 vasprintf(&s, format, ap);
51 write(private->log_fd, s, strlen(s));
57 when we call the next stacked level of NTVFS module we need
58 to give it its own private pointer, plus its own NTVFS operations structure.
59 Then we need to restore both of these after the call, as the next level could
60 modify either of these
62 #define PASS_THRU(conn, op, args) do { \
63 conn->ntvfs_private = private->passthru_private; \
64 conn->ntvfs_ops = private->passthru_ops; \
66 status = private->passthru_ops->op args; \
68 private->passthru_private = conn->ntvfs_private; \
69 private->passthru_ops = conn->ntvfs_ops; \
71 conn->ntvfs_private = private; \
72 conn->ntvfs_ops = private->nbench_ops; \
76 this pass through macro operates on request contexts, and disables
79 async calls are a pain for the nbench module as it makes pulling the
80 status code and any result parameters much harder.
82 #define PASS_THRU_REQ(req, op, args) do { \
83 void *send_fn_saved = req->async.send_fn; \
84 req->async.send_fn = NULL; \
85 PASS_THRU(req->conn, op, args); \
86 req->async.send_fn = send_fn_saved; \
91 connect to a share - used when a tree_connect operation comes in.
93 static NTSTATUS nbench_connect(struct request_context *req, const char *sharename)
95 struct nbench_private *private;
100 private = talloc_p(req->conn->mem_ctx, struct nbench_private);
102 return NT_STATUS_NO_MEMORY;
105 asprintf(&logname, "/tmp/nbenchlog.%u", getpid());
106 private->log_fd = open(logname, O_WRONLY|O_CREAT|O_APPEND, 0644);
109 if (private->log_fd == -1) {
110 DEBUG(0,("Failed to open nbench log\n"));
111 return NT_STATUS_UNSUCCESSFUL;
114 passthru = lp_parm_string(req->conn->service, "nbench", "passthru");
116 private->passthru_private = NULL;
117 private->nbench_ops = req->conn->ntvfs_ops;
118 private->passthru_ops = ntvfs_backend_byname(passthru, NTVFS_DISK);
120 if (!private->passthru_ops) {
121 DEBUG(0,("Unable to connect to '%s' pass through backend\n", passthru));
122 return NT_STATUS_UNSUCCESSFUL;
125 PASS_THRU(req->conn, connect, (req, sharename));
131 disconnect from a share
133 static NTSTATUS nbench_disconnect(struct tcon_context *conn)
135 struct nbench_private *private = conn->ntvfs_private;
138 PASS_THRU(conn, disconnect, (conn));
140 close(private->log_fd);
146 delete a file - the dirtype specifies the file types to include in the search.
147 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
149 static NTSTATUS nbench_unlink(struct request_context *req, struct smb_unlink *unl)
151 struct nbench_private *private = req->conn->ntvfs_private;
154 PASS_THRU_REQ(req, unlink, (req, unl));
156 nbench_log(private, "Unlink \"%s\" 0x%x %s\n",
157 unl->in.pattern, unl->in.attrib,
158 get_nt_error_c_code(status));
166 static NTSTATUS nbench_ioctl(struct request_context *req, union smb_ioctl *io)
168 struct nbench_private *private = req->conn->ntvfs_private;
171 PASS_THRU_REQ(req, ioctl, (req, io));
173 nbench_log(private, "Ioctl - NOT HANDLED\n");
179 check if a directory exists
181 static NTSTATUS nbench_chkpath(struct request_context *req, struct smb_chkpath *cp)
183 struct nbench_private *private = req->conn->ntvfs_private;
186 PASS_THRU_REQ(req, chkpath, (req, cp));
188 nbench_log(private, "Chkpath \"%s\" %s\n",
190 get_nt_error_c_code(status));
196 return info on a pathname
198 static NTSTATUS nbench_qpathinfo(struct request_context *req, union smb_fileinfo *info)
200 struct nbench_private *private = req->conn->ntvfs_private;
203 PASS_THRU_REQ(req, qpathinfo, (req, info));
205 nbench_log(private, "QUERY_PATH_INFORMATION \"%s\" %d %s\n",
206 info->generic.in.fname,
208 get_nt_error_c_code(status));
214 query info on a open file
216 static NTSTATUS nbench_qfileinfo(struct request_context *req, union smb_fileinfo *info)
218 struct nbench_private *private = req->conn->ntvfs_private;
221 PASS_THRU_REQ(req, qfileinfo, (req, info));
223 nbench_log(private, "QUERY_FILE_INFORMATION %d %d %s\n",
224 info->generic.in.fnum,
226 get_nt_error_c_code(status));
233 set info on a pathname
235 static NTSTATUS nbench_setpathinfo(struct request_context *req, union smb_setfileinfo *st)
237 struct nbench_private *private = req->conn->ntvfs_private;
240 PASS_THRU_REQ(req, setpathinfo, (req, st));
242 nbench_log(private, "SET_PATH_INFORMATION \"%s\" %d %s\n",
243 st->generic.file.fname,
245 get_nt_error_c_code(status));
253 static NTSTATUS nbench_open(struct request_context *req, union smb_open *io)
255 struct nbench_private *private = req->conn->ntvfs_private;
258 PASS_THRU_REQ(req, open, (req, io));
260 switch (io->generic.level) {
261 case RAW_OPEN_NTCREATEX:
262 nbench_log(private, "NTCreateX \"%s\" 0x%x 0x%x %d %s\n",
263 io->ntcreatex.in.fname,
264 io->ntcreatex.in.create_options,
265 io->ntcreatex.in.open_disposition,
266 io->ntcreatex.out.fnum,
267 get_nt_error_c_code(status));
271 nbench_log(private, "Open-%d - NOT HANDLED\n",
282 static NTSTATUS nbench_mkdir(struct request_context *req, union smb_mkdir *md)
284 struct nbench_private *private = req->conn->ntvfs_private;
287 PASS_THRU_REQ(req, mkdir, (req, md));
289 nbench_log(private, "Mkdir - NOT HANDLED\n");
297 static NTSTATUS nbench_rmdir(struct request_context *req, struct smb_rmdir *rd)
299 struct nbench_private *private = req->conn->ntvfs_private;
302 PASS_THRU_REQ(req, rmdir, (req, rd));
304 nbench_log(private, "Rmdir \"%s\" %s\n",
306 get_nt_error_c_code(status));
312 rename a set of files
314 static NTSTATUS nbench_rename(struct request_context *req, union smb_rename *ren)
316 struct nbench_private *private = req->conn->ntvfs_private;
319 PASS_THRU_REQ(req, rename, (req, ren));
321 switch (ren->generic.level) {
322 case RAW_RENAME_RENAME:
323 nbench_log(private, "Rename \"%s\" \"%s\" %s\n",
324 ren->rename.in.pattern1,
325 ren->rename.in.pattern2,
326 get_nt_error_c_code(status));
330 nbench_log(private, "Rename-%d - NOT HANDLED\n",
341 static NTSTATUS nbench_copy(struct request_context *req, struct smb_copy *cp)
343 struct nbench_private *private = req->conn->ntvfs_private;
346 PASS_THRU_REQ(req, copy, (req, cp));
348 nbench_log(private, "Copy - NOT HANDLED\n");
356 static NTSTATUS nbench_read(struct request_context *req, union smb_read *rd)
358 struct nbench_private *private = req->conn->ntvfs_private;
361 PASS_THRU_REQ(req, read, (req, rd));
363 switch (rd->generic.level) {
365 nbench_log(private, "ReadX %d %d %d %d %s\n",
367 (int)rd->readx.in.offset,
370 get_nt_error_c_code(status));
373 nbench_log(private, "Read-%d - NOT HANDLED\n",
384 static NTSTATUS nbench_write(struct request_context *req, union smb_write *wr)
386 struct nbench_private *private = req->conn->ntvfs_private;
389 PASS_THRU_REQ(req, write, (req, wr));
391 switch (wr->generic.level) {
392 case RAW_WRITE_WRITEX:
393 nbench_log(private, "WriteX %d %d %d %d %s\n",
395 (int)wr->writex.in.offset,
397 wr->writex.out.nwritten,
398 get_nt_error_c_code(status));
401 case RAW_WRITE_WRITE:
402 nbench_log(private, "Write %d %d %d %d %s\n",
406 wr->write.out.nwritten,
407 get_nt_error_c_code(status));
411 nbench_log(private, "Write-%d - NOT HANDLED\n",
422 static NTSTATUS nbench_seek(struct request_context *req, struct smb_seek *io)
424 struct nbench_private *private = req->conn->ntvfs_private;
427 PASS_THRU_REQ(req, seek, (req, io));
429 nbench_log(private, "Seek - NOT HANDLED\n");
437 static NTSTATUS nbench_flush(struct request_context *req, struct smb_flush *io)
439 struct nbench_private *private = req->conn->ntvfs_private;
442 PASS_THRU_REQ(req, flush, (req, io));
444 nbench_log(private, "Flush %d %s\n",
446 get_nt_error_c_code(status));
454 static NTSTATUS nbench_close(struct request_context *req, union smb_close *io)
456 struct nbench_private *private = req->conn->ntvfs_private;
459 PASS_THRU_REQ(req, close, (req, io));
461 switch (io->generic.level) {
462 case RAW_CLOSE_CLOSE:
463 nbench_log(private, "Close %d %s\n",
465 get_nt_error_c_code(status));
469 nbench_log(private, "Close-%d - NOT HANDLED\n",
480 static NTSTATUS nbench_exit(struct request_context *req)
482 struct nbench_private *private = req->conn->ntvfs_private;
485 PASS_THRU_REQ(req, exit, (req));
493 static NTSTATUS nbench_lock(struct request_context *req, union smb_lock *lck)
495 struct nbench_private *private = req->conn->ntvfs_private;
498 PASS_THRU_REQ(req, lock, (req, lck));
500 if (lck->generic.level == RAW_LOCK_LOCKX &&
501 lck->lockx.in.lock_cnt == 1 &&
502 lck->lockx.in.ulock_cnt == 0) {
503 nbench_log(private, "LockX %d %d %d %s\n",
505 (int)lck->lockx.in.locks[0].offset,
506 (int)lck->lockx.in.locks[0].count,
507 get_nt_error_c_code(status));
508 } else if (lck->generic.level == RAW_LOCK_LOCKX &&
509 lck->lockx.in.ulock_cnt == 1) {
510 nbench_log(private, "UnlockX %d %d %d %s\n",
512 (int)lck->lockx.in.locks[0].offset,
513 (int)lck->lockx.in.locks[0].count,
514 get_nt_error_c_code(status));
516 nbench_log(private, "Lock-%d - NOT HANDLED\n", lck->generic.level);
523 set info on a open file
525 static NTSTATUS nbench_setfileinfo(struct request_context *req,
526 union smb_setfileinfo *info)
528 struct nbench_private *private = req->conn->ntvfs_private;
531 PASS_THRU_REQ(req, setfileinfo, (req, info));
533 nbench_log(private, "SET_FILE_INFORMATION %d %d %s\n",
534 info->generic.file.fnum,
536 get_nt_error_c_code(status));
543 return filesystem space info
545 static NTSTATUS nbench_fsinfo(struct request_context *req, union smb_fsinfo *fs)
547 struct nbench_private *private = req->conn->ntvfs_private;
550 PASS_THRU_REQ(req, fsinfo, (req, fs));
552 nbench_log(private, "QUERY_FS_INFORMATION %d %s\n",
554 get_nt_error_c_code(status));
560 return print queue info
562 static NTSTATUS nbench_lpq(struct request_context *req, union smb_lpq *lpq)
564 struct nbench_private *private = req->conn->ntvfs_private;
567 PASS_THRU_REQ(req, lpq, (req, lpq));
569 nbench_log(private, "Lpq-%d - NOT HANDLED\n", lpq->generic.level);
575 list files in a directory matching a wildcard pattern
577 static NTSTATUS nbench_search_first(struct request_context *req, union smb_search_first *io,
578 void *search_private,
579 BOOL (*callback)(void *, union smb_search_data *))
581 struct nbench_private *private = req->conn->ntvfs_private;
584 PASS_THRU_REQ(req, search_first, (req, io, search_private, callback));
586 switch (io->generic.level) {
587 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
588 nbench_log(private, "FIND_FIRST \"%s\" %d %d %d %s\n",
589 io->t2ffirst.in.pattern,
591 io->t2ffirst.in.max_count,
592 io->t2ffirst.out.count,
593 get_nt_error_c_code(status));
597 nbench_log(private, "Search-%d - NOT HANDLED\n", io->generic.level);
604 /* continue a search */
605 static NTSTATUS nbench_search_next(struct request_context *req, union smb_search_next *io,
606 void *search_private,
607 BOOL (*callback)(void *, union smb_search_data *))
609 struct nbench_private *private = req->conn->ntvfs_private;
612 PASS_THRU_REQ(req, search_next, (req, io, search_private, callback));
614 nbench_log(private, "Searchnext-%d - NOT HANDLED\n", io->generic.level);
620 static NTSTATUS nbench_search_close(struct request_context *req, union smb_search_close *io)
622 struct nbench_private *private = req->conn->ntvfs_private;
625 PASS_THRU_REQ(req, search_close, (req, io));
627 nbench_log(private, "Searchclose-%d - NOT HANDLED\n", io->generic.level);
632 /* SMBtrans - not used on file shares */
633 static NTSTATUS nbench_trans(struct request_context *req, struct smb_trans2 *trans2)
635 struct nbench_private *private = req->conn->ntvfs_private;
638 PASS_THRU_REQ(req, trans, (req,trans2));
640 nbench_log(private, "Trans - NOT HANDLED\n");
646 initialise the nbench backend, registering ourselves with the ntvfs subsystem
648 NTSTATUS ntvfs_nbench_init(void)
651 struct ntvfs_ops ops;
655 /* fill in the name and type */
657 ops.type = NTVFS_DISK;
659 /* fill in all the operations */
660 ops.connect = nbench_connect;
661 ops.disconnect = nbench_disconnect;
662 ops.unlink = nbench_unlink;
663 ops.chkpath = nbench_chkpath;
664 ops.qpathinfo = nbench_qpathinfo;
665 ops.setpathinfo = nbench_setpathinfo;
666 ops.open = nbench_open;
667 ops.mkdir = nbench_mkdir;
668 ops.rmdir = nbench_rmdir;
669 ops.rename = nbench_rename;
670 ops.copy = nbench_copy;
671 ops.ioctl = nbench_ioctl;
672 ops.read = nbench_read;
673 ops.write = nbench_write;
674 ops.seek = nbench_seek;
675 ops.flush = nbench_flush;
676 ops.close = nbench_close;
677 ops.exit = nbench_exit;
678 ops.lock = nbench_lock;
679 ops.setfileinfo = nbench_setfileinfo;
680 ops.qfileinfo = nbench_qfileinfo;
681 ops.fsinfo = nbench_fsinfo;
682 ops.lpq = nbench_lpq;
683 ops.search_first = nbench_search_first;
684 ops.search_next = nbench_search_next;
685 ops.search_close = nbench_search_close;
686 ops.trans = nbench_trans;
688 /* we don't register a trans2 handler as we want to be able to
689 log individual trans2 requests */
692 /* register ourselves with the NTVFS subsystem. */
693 ret = register_backend("ntvfs", &ops);
695 if (!NT_STATUS_IS_OK(ret)) {
696 DEBUG(0,("Failed to register nbench backend!\n"));