Line data Source code
1 : /*
2 : TODO: add splitting of writes for servers with signing
3 : */
4 :
5 :
6 : /*
7 : Unix SMB/CIFS implementation.
8 : SMB torture tester
9 : Copyright (C) Andrew Tridgell 1997-1998
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "includes.h"
26 : #include "system/time.h"
27 : #include "system/filesys.h"
28 : #include "../lib/util/dlinklist.h"
29 : #include "libcli/libcli.h"
30 : #include "torture/util.h"
31 : #include "torture/nbench/proto.h"
32 :
33 : extern int nbench_line_count;
34 : static int nbio_id = -1;
35 : static int nprocs;
36 : static bool bypass_io;
37 : static struct timeval tv_start, tv_end;
38 : static int warmup, timelimit;
39 : static int in_cleanup;
40 :
41 : struct lock_info {
42 : struct lock_info *next, *prev;
43 : off_t offset;
44 : int size;
45 : };
46 :
47 : struct createx_params {
48 : char *fname;
49 : unsigned int create_options;
50 : unsigned int create_disposition;
51 : int handle;
52 : };
53 :
54 : struct ftable {
55 : struct ftable *next, *prev;
56 : int fd; /* the fd that we got back from the server */
57 : int handle; /* the handle in the load file */
58 : struct createx_params cp;
59 : struct lock_info *locks;
60 : };
61 :
62 : static struct ftable *ftable;
63 :
64 : static struct {
65 : double bytes, warmup_bytes;
66 : int line;
67 : int done;
68 : bool connected;
69 : double max_latency;
70 : struct timeval starttime;
71 : } *children;
72 :
73 : static bool nb_do_createx(struct ftable *f,
74 : const char *fname,
75 : unsigned int create_options,
76 : unsigned int create_disposition,
77 : int handle,
78 : NTSTATUS status,
79 : bool retry);
80 :
81 : static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status);
82 :
83 0 : static void nb_set_createx_params(struct ftable *f,
84 : const char *fname,
85 : unsigned int create_options,
86 : unsigned int create_disposition,
87 : int handle)
88 : {
89 0 : struct createx_params *cp = &f->cp;
90 :
91 0 : if (fname != NULL) {
92 0 : cp->fname = talloc_strdup(f, fname);
93 0 : if (cp->fname == NULL) {
94 0 : perror("nb_set_createx_params: strdup");
95 0 : nb_exit(1);
96 : }
97 : } else {
98 0 : cp->fname = NULL;
99 : }
100 :
101 0 : cp->create_options = create_options;
102 0 : cp->create_disposition = create_disposition;
103 0 : cp->handle = handle;
104 0 : }
105 :
106 0 : static bool nb_reestablish_locks(struct ftable *f)
107 : {
108 0 : struct lock_info *linfo = f->locks;
109 :
110 0 : while (linfo != NULL) {
111 0 : DEBUG(1,("nb_reestablish_locks: lock for file %d at %lu\n",
112 : f->handle, (unsigned long) linfo->offset));
113 :
114 0 : if (!nb_do_lockx(true, f->handle, linfo->offset, linfo->size, NT_STATUS_OK)) {
115 0 : printf("nb_reestablish_locks: failed to get lock for file %s at %lu\n",
116 0 : f->cp.fname, (unsigned long) linfo->offset);
117 0 : return false;
118 : }
119 :
120 0 : linfo = linfo->next;
121 : }
122 :
123 0 : return true;
124 : }
125 :
126 0 : static bool nb_reopen_all_files(void)
127 : {
128 0 : struct ftable *f = ftable;
129 :
130 0 : while (f != NULL) {
131 0 : DEBUG(1,("-- nb_reopen_all_files: opening %s (handle %d)\n",
132 : f->cp.fname, f->cp.handle));
133 :
134 0 : if (!nb_do_createx(f,
135 0 : f->cp.fname,
136 : f->cp.create_options,
137 : f->cp.create_disposition,
138 : f->cp.handle,
139 0 : NT_STATUS_OK,
140 : true))
141 : {
142 0 : printf("-- nb_reopen_all_files: failed to open file %s\n", f->cp.fname);
143 0 : return false;
144 : }
145 :
146 0 : if (!nb_reestablish_locks(f)) {
147 0 : printf("--nb_reopen_all_files: failed to reestablish locks\n");
148 0 : return false;
149 : }
150 :
151 0 : f = f->next;
152 : }
153 :
154 0 : return true;
155 : }
156 :
157 0 : bool nb_reconnect(struct smbcli_state **cli, struct torture_context *tctx, int client)
158 : {
159 0 : children[client].connected = false;
160 :
161 0 : if (*cli != NULL) {
162 0 : talloc_free(*cli);
163 : }
164 :
165 0 : if (!torture_open_connection(cli, tctx, client)) {
166 0 : printf("nb_reconnect: failed to connect\n");
167 0 : *cli = NULL;
168 0 : return false;
169 : }
170 :
171 0 : nb_setup(*cli, client);
172 :
173 0 : if (!nb_reopen_all_files()) {
174 0 : printf("nb_reconnect: failed to reopen files in client %d\n", client);
175 0 : return false;
176 : }
177 :
178 0 : return true;
179 : }
180 :
181 0 : void nbio_target_rate(double rate)
182 : {
183 0 : static double last_bytes;
184 0 : static struct timeval last_time;
185 0 : double tdelay;
186 :
187 0 : if (last_bytes == 0) {
188 0 : last_bytes = children[nbio_id].bytes;
189 0 : last_time = timeval_current();
190 0 : return;
191 : }
192 :
193 0 : tdelay = (children[nbio_id].bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
194 0 : if (tdelay > 0) {
195 0 : smb_msleep(tdelay*1000);
196 : } else {
197 0 : children[nbio_id].max_latency = MAX(children[nbio_id].max_latency, -tdelay);
198 : }
199 :
200 0 : last_time = timeval_current();
201 0 : last_bytes = children[nbio_id].bytes;
202 : }
203 :
204 0 : void nbio_time_reset(void)
205 : {
206 0 : children[nbio_id].starttime = timeval_current();
207 0 : }
208 :
209 0 : void nbio_time_delay(double targett)
210 : {
211 0 : double elapsed = timeval_elapsed(&children[nbio_id].starttime);
212 0 : if (targett > elapsed) {
213 0 : smb_msleep(1000*(targett - elapsed));
214 0 : } else if (elapsed - targett > children[nbio_id].max_latency) {
215 0 : children[nbio_id].max_latency = MAX(elapsed - targett, children[nbio_id].max_latency);
216 : }
217 0 : }
218 :
219 0 : double nbio_result(void)
220 : {
221 0 : int i;
222 0 : double total = 0;
223 0 : for (i=0;i<nprocs;i++) {
224 0 : total += children[i].bytes - children[i].warmup_bytes;
225 : }
226 0 : return 1.0e-6 * total / timeval_elapsed2(&tv_start, &tv_end);
227 : }
228 :
229 0 : double nbio_latency(void)
230 : {
231 0 : int i;
232 0 : double max_latency = 0;
233 0 : for (i=0;i<nprocs;i++) {
234 0 : if (children[i].max_latency > max_latency) {
235 0 : max_latency = children[i].max_latency;
236 0 : children[i].max_latency = 0;
237 : }
238 : }
239 0 : return max_latency;
240 : }
241 :
242 0 : bool nb_tick(void)
243 : {
244 0 : return children[nbio_id].done;
245 : }
246 :
247 :
248 0 : void nb_alarm(int sig)
249 : {
250 0 : int i;
251 0 : int lines=0;
252 0 : double t;
253 0 : int in_warmup = 0;
254 0 : int num_connected = 0;
255 :
256 0 : if (nbio_id != -1) return;
257 :
258 0 : for (i=0;i<nprocs;i++) {
259 0 : if (children[i].connected) {
260 0 : num_connected++;
261 : }
262 0 : if (children[i].bytes == 0) {
263 0 : in_warmup = 1;
264 : }
265 0 : lines += children[i].line;
266 : }
267 :
268 0 : t = timeval_elapsed(&tv_start);
269 :
270 0 : if (!in_warmup && warmup>0 && t > warmup) {
271 0 : tv_start = timeval_current();
272 0 : warmup = 0;
273 0 : for (i=0;i<nprocs;i++) {
274 0 : children[i].warmup_bytes = children[i].bytes;
275 : }
276 0 : goto next;
277 : }
278 0 : if (t < warmup) {
279 0 : in_warmup = 1;
280 0 : } else if (!in_warmup && !in_cleanup && t > timelimit) {
281 0 : for (i=0;i<nprocs;i++) {
282 0 : children[i].done = 1;
283 : }
284 0 : tv_end = timeval_current();
285 0 : in_cleanup = 1;
286 : }
287 0 : if (t < 1) {
288 0 : goto next;
289 : }
290 0 : if (!in_cleanup) {
291 0 : tv_end = timeval_current();
292 : }
293 :
294 0 : if (in_warmup) {
295 0 : printf("%4d %8d %.2f MB/sec warmup %.0f sec \n",
296 : num_connected, lines/nprocs,
297 : nbio_result(), t);
298 0 : } else if (in_cleanup) {
299 0 : printf("%4d %8d %.2f MB/sec cleanup %.0f sec \n",
300 : num_connected, lines/nprocs,
301 : nbio_result(), t);
302 : } else {
303 0 : printf("%4d %8d %.2f MB/sec execute %.0f sec latency %.2f msec \n",
304 : num_connected, lines/nprocs,
305 0 : nbio_result(), t, nbio_latency() * 1.0e3);
306 : }
307 :
308 0 : fflush(stdout);
309 0 : next:
310 0 : signal(SIGALRM, nb_alarm);
311 0 : alarm(1);
312 : }
313 :
314 0 : void nbio_shmem(int n, int t_timelimit, int t_warmup)
315 : {
316 0 : nprocs = n;
317 0 : children = anonymous_shared_allocate(sizeof(*children) * nprocs);
318 0 : if (!children) {
319 0 : printf("Failed to setup shared memory!\n");
320 0 : nb_exit(1);
321 : }
322 0 : memset(children, 0, sizeof(*children) * nprocs);
323 0 : timelimit = t_timelimit;
324 0 : warmup = t_warmup;
325 0 : in_cleanup = 0;
326 0 : tv_start = timeval_current();
327 0 : }
328 :
329 0 : static struct lock_info* find_lock(struct lock_info *linfo, off_t offset, int size)
330 : {
331 0 : while (linfo != NULL) {
332 0 : if (linfo->offset == offset &&
333 0 : linfo->size == size)
334 : {
335 0 : return linfo;
336 : }
337 :
338 0 : linfo = linfo->next;
339 : }
340 :
341 0 : return NULL;
342 : }
343 :
344 0 : static struct ftable *find_ftable(int handle)
345 : {
346 0 : struct ftable *f;
347 :
348 0 : for (f=ftable;f;f=f->next) {
349 0 : if (f->handle == handle) return f;
350 : }
351 0 : return NULL;
352 : }
353 :
354 0 : static int find_handle(int handle, struct ftable **f_ret)
355 : {
356 0 : struct ftable *f;
357 :
358 0 : if (f_ret != NULL)
359 0 : *f_ret = NULL;
360 :
361 0 : children[nbio_id].line = nbench_line_count;
362 :
363 0 : f = find_ftable(handle);
364 0 : if (f) {
365 0 : if (f_ret != NULL)
366 0 : *f_ret = f;
367 0 : return f->fd;
368 : }
369 0 : printf("(%d) ERROR: handle %d was not found\n",
370 : nbench_line_count, handle);
371 0 : nb_exit(1);
372 :
373 0 : return -1; /* Not reached */
374 : }
375 :
376 :
377 :
378 : static struct smbcli_state *c;
379 :
380 : /*
381 : a handler function for oplock break requests
382 : */
383 0 : static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid,
384 : uint16_t fnum, uint8_t level, void *private_data)
385 : {
386 0 : struct smbcli_tree *tree = (struct smbcli_tree *)private_data;
387 0 : return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
388 : }
389 :
390 0 : void nb_setup(struct smbcli_state *cli, int id)
391 : {
392 0 : nbio_id = id;
393 0 : c = cli;
394 0 : if (bypass_io)
395 0 : printf("skipping I/O\n");
396 :
397 0 : if (cli) {
398 0 : smbcli_oplock_handler(cli->transport, oplock_handler, cli->tree);
399 : }
400 :
401 0 : children[id].connected = true;
402 0 : }
403 :
404 :
405 0 : static bool check_status(const char *op, NTSTATUS status, NTSTATUS ret)
406 : {
407 0 : if ((NT_STATUS_EQUAL(ret, NT_STATUS_END_OF_FILE) ||
408 0 : NT_STATUS_EQUAL(ret, NT_STATUS_NET_WRITE_FAULT) ||
409 0 : NT_STATUS_EQUAL(ret, NT_STATUS_CONNECTION_RESET))
410 0 : && !NT_STATUS_EQUAL (status, ret))
411 : {
412 0 : return false;
413 : }
414 :
415 0 : if (!NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(ret)) {
416 0 : printf("[%d] Error: %s should have failed with %s\n",
417 : nbench_line_count, op, nt_errstr(status));
418 0 : nb_exit(1);
419 : }
420 :
421 0 : if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ret)) {
422 0 : printf("[%d] Error: %s should have succeeded - %s\n",
423 : nbench_line_count, op, nt_errstr(ret));
424 0 : nb_exit(1);
425 : }
426 :
427 0 : if (!NT_STATUS_EQUAL(status, ret)) {
428 0 : printf("[%d] Warning: got status %s but expected %s\n",
429 : nbench_line_count, nt_errstr(ret), nt_errstr(status));
430 : }
431 :
432 0 : return true;
433 : }
434 :
435 :
436 0 : bool nb_unlink(const char *fname, int attr, NTSTATUS status, bool retry)
437 : {
438 0 : union smb_unlink io;
439 0 : NTSTATUS ret;
440 :
441 0 : io.unlink.in.pattern = fname;
442 :
443 0 : io.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
444 0 : if (strchr(fname, '*') == 0) {
445 0 : io.unlink.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
446 : }
447 :
448 0 : ret = smb_raw_unlink(c->tree, &io);
449 :
450 0 : if (!retry)
451 0 : return check_status("Unlink", status, ret);
452 :
453 0 : return true;
454 : }
455 :
456 0 : static bool nb_do_createx(struct ftable *f,
457 : const char *fname,
458 : unsigned int create_options,
459 : unsigned int create_disposition,
460 : int handle,
461 : NTSTATUS status,
462 : bool retry)
463 : {
464 0 : union smb_open io;
465 0 : uint32_t desired_access;
466 0 : NTSTATUS ret;
467 0 : TALLOC_CTX *mem_ctx;
468 0 : unsigned int flags = 0;
469 :
470 0 : mem_ctx = talloc_init("raw_open");
471 :
472 0 : if (create_options & NTCREATEX_OPTIONS_DIRECTORY) {
473 0 : desired_access = SEC_FILE_READ_DATA;
474 : } else {
475 0 : desired_access =
476 : SEC_FILE_READ_DATA |
477 : SEC_FILE_WRITE_DATA |
478 : SEC_FILE_READ_ATTRIBUTE |
479 : SEC_FILE_WRITE_ATTRIBUTE;
480 0 : flags = NTCREATEX_FLAGS_EXTENDED |
481 : NTCREATEX_FLAGS_REQUEST_OPLOCK |
482 : NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
483 : }
484 :
485 0 : io.ntcreatex.level = RAW_OPEN_NTCREATEX;
486 0 : io.ntcreatex.in.flags = flags;
487 0 : io.ntcreatex.in.root_fid.fnum = 0;
488 0 : io.ntcreatex.in.access_mask = desired_access;
489 0 : io.ntcreatex.in.file_attr = 0;
490 0 : io.ntcreatex.in.alloc_size = 0;
491 0 : io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE;
492 0 : io.ntcreatex.in.open_disposition = create_disposition;
493 0 : io.ntcreatex.in.create_options = create_options;
494 0 : io.ntcreatex.in.impersonation = 0;
495 0 : io.ntcreatex.in.security_flags = 0;
496 0 : io.ntcreatex.in.fname = fname;
497 :
498 0 : if (retry) {
499 : /* Reopening after a disconnect. */
500 0 : io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
501 : } else
502 0 : if (f != NULL &&
503 0 : f->cp.create_disposition == NTCREATEX_DISP_CREATE &&
504 0 : NT_STATUS_IS_OK(status))
505 : {
506 : /* Reopening after nb_createx() error. */
507 0 : io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
508 : }
509 :
510 0 : ret = smb_raw_open(c->tree, mem_ctx, &io);
511 :
512 0 : talloc_free(mem_ctx);
513 :
514 0 : if (!check_status("NTCreateX", status, ret))
515 0 : return false;
516 :
517 0 : if (!NT_STATUS_IS_OK(ret))
518 0 : return true;
519 :
520 0 : if (f == NULL) {
521 0 : f = talloc (NULL, struct ftable);
522 0 : f->locks = NULL;
523 0 : nb_set_createx_params(f, fname, create_options, create_disposition, handle);
524 0 : DLIST_ADD_END(ftable, f);
525 : }
526 :
527 0 : f->handle = handle;
528 0 : f->fd = io.ntcreatex.out.file.fnum;
529 :
530 0 : return true;
531 : }
532 :
533 0 : bool nb_createx(const char *fname,
534 : unsigned int create_options, unsigned int create_disposition, int handle,
535 : NTSTATUS status)
536 : {
537 0 : return nb_do_createx(NULL, fname, create_options, create_disposition, handle, status, false);
538 : }
539 :
540 0 : bool nb_writex(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
541 : {
542 0 : union smb_write io;
543 0 : int i;
544 0 : NTSTATUS ret;
545 0 : uint8_t *buf;
546 :
547 0 : i = find_handle(handle, NULL);
548 :
549 0 : if (bypass_io)
550 0 : return true;
551 :
552 0 : buf = malloc(size);
553 0 : memset(buf, 0xab, size);
554 :
555 0 : io.writex.level = RAW_WRITE_WRITEX;
556 0 : io.writex.in.file.fnum = i;
557 0 : io.writex.in.wmode = 0;
558 0 : io.writex.in.remaining = 0;
559 0 : io.writex.in.offset = offset;
560 0 : io.writex.in.count = size;
561 0 : io.writex.in.data = buf;
562 :
563 0 : ret = smb_raw_write(c->tree, &io);
564 :
565 0 : free(buf);
566 :
567 0 : if (!check_status("WriteX", status, ret))
568 0 : return false;
569 :
570 0 : if (NT_STATUS_IS_OK(ret) && io.writex.out.nwritten != ret_size) {
571 0 : printf("[%d] Warning: WriteX got count %d expected %d\n",
572 : nbench_line_count,
573 : io.writex.out.nwritten, ret_size);
574 : }
575 :
576 0 : children[nbio_id].bytes += ret_size;
577 :
578 0 : return true;
579 : }
580 :
581 0 : bool nb_write(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
582 : {
583 0 : union smb_write io;
584 0 : int i;
585 0 : NTSTATUS ret;
586 0 : uint8_t *buf;
587 :
588 0 : i = find_handle(handle, NULL);
589 :
590 0 : if (bypass_io)
591 0 : return true;
592 :
593 0 : buf = malloc(size);
594 :
595 0 : memset(buf, 0x12, size);
596 :
597 0 : io.write.level = RAW_WRITE_WRITE;
598 0 : io.write.in.file.fnum = i;
599 0 : io.write.in.remaining = 0;
600 0 : io.write.in.offset = offset;
601 0 : io.write.in.count = size;
602 0 : io.write.in.data = buf;
603 :
604 0 : ret = smb_raw_write(c->tree, &io);
605 :
606 0 : free(buf);
607 :
608 0 : if (!check_status("Write", status, ret))
609 0 : return false;
610 :
611 0 : if (NT_STATUS_IS_OK(ret) && io.write.out.nwritten != ret_size) {
612 0 : printf("[%d] Warning: Write got count %d expected %d\n",
613 : nbench_line_count,
614 0 : io.write.out.nwritten, ret_size);
615 : }
616 :
617 0 : children[nbio_id].bytes += ret_size;
618 :
619 0 : return true;
620 : }
621 :
622 0 : static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status)
623 : {
624 0 : union smb_lock io;
625 0 : int i;
626 0 : NTSTATUS ret;
627 0 : struct smb_lock_entry lck;
628 0 : struct ftable *f;
629 :
630 0 : i = find_handle(handle, &f);
631 :
632 0 : lck.pid = getpid();
633 0 : lck.offset = offset;
634 0 : lck.count = size;
635 :
636 0 : io.lockx.level = RAW_LOCK_LOCKX;
637 0 : io.lockx.in.file.fnum = i;
638 0 : io.lockx.in.mode = 0;
639 0 : io.lockx.in.timeout = 0;
640 0 : io.lockx.in.ulock_cnt = 0;
641 0 : io.lockx.in.lock_cnt = 1;
642 0 : io.lockx.in.locks = &lck;
643 :
644 0 : ret = smb_raw_lock(c->tree, &io);
645 :
646 0 : if (!check_status("LockX", status, ret))
647 0 : return false;
648 :
649 0 : if (f != NULL &&
650 0 : !relock)
651 : {
652 0 : struct lock_info *linfo;
653 0 : linfo = talloc (f, struct lock_info);
654 0 : linfo->offset = offset;
655 0 : linfo->size = size;
656 0 : DLIST_ADD_END(f->locks, linfo);
657 : }
658 :
659 0 : return true;
660 : }
661 :
662 0 : bool nb_lockx(int handle, off_t offset, int size, NTSTATUS status)
663 : {
664 0 : return nb_do_lockx(false, handle, offset, size, status);
665 : }
666 :
667 0 : bool nb_unlockx(int handle, unsigned int offset, int size, NTSTATUS status)
668 : {
669 0 : union smb_lock io;
670 0 : int i;
671 0 : NTSTATUS ret;
672 0 : struct smb_lock_entry lck;
673 0 : struct ftable *f;
674 :
675 0 : i = find_handle(handle, &f);
676 :
677 0 : lck.pid = getpid();
678 0 : lck.offset = offset;
679 0 : lck.count = size;
680 :
681 0 : io.lockx.level = RAW_LOCK_LOCKX;
682 0 : io.lockx.in.file.fnum = i;
683 0 : io.lockx.in.mode = 0;
684 0 : io.lockx.in.timeout = 0;
685 0 : io.lockx.in.ulock_cnt = 1;
686 0 : io.lockx.in.lock_cnt = 0;
687 0 : io.lockx.in.locks = &lck;
688 :
689 0 : ret = smb_raw_lock(c->tree, &io);
690 :
691 0 : if (!check_status("UnlockX", status, ret))
692 0 : return false;
693 :
694 0 : if (f != NULL) {
695 0 : struct lock_info *linfo;
696 0 : linfo = find_lock(f->locks, offset, size);
697 0 : if (linfo != NULL)
698 0 : DLIST_REMOVE(f->locks, linfo);
699 : else
700 0 : printf("nb_unlockx: unknown lock (%d)\n", handle);
701 : }
702 :
703 0 : return true;
704 : }
705 :
706 0 : bool nb_readx(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
707 : {
708 0 : union smb_read io;
709 0 : int i;
710 0 : NTSTATUS ret;
711 0 : uint8_t *buf;
712 :
713 0 : i = find_handle(handle, NULL);
714 :
715 0 : if (bypass_io)
716 0 : return true;
717 :
718 0 : buf = malloc(size);
719 :
720 0 : io.readx.level = RAW_READ_READX;
721 0 : io.readx.in.file.fnum = i;
722 0 : io.readx.in.offset = offset;
723 0 : io.readx.in.mincnt = size;
724 0 : io.readx.in.maxcnt = size;
725 0 : io.readx.in.remaining = 0;
726 0 : io.readx.in.read_for_execute = false;
727 0 : io.readx.out.data = buf;
728 :
729 0 : ret = smb_raw_read(c->tree, &io);
730 :
731 0 : free(buf);
732 :
733 0 : if (!check_status("ReadX", status, ret))
734 0 : return false;
735 :
736 0 : if (NT_STATUS_IS_OK(ret) && io.readx.out.nread != ret_size) {
737 0 : printf("[%d] ERROR: ReadX got count %d expected %d\n",
738 : nbench_line_count,
739 : io.readx.out.nread, ret_size);
740 0 : nb_exit(1);
741 : }
742 :
743 0 : children[nbio_id].bytes += ret_size;
744 :
745 0 : return true;
746 : }
747 :
748 0 : bool nb_close(int handle, NTSTATUS status)
749 : {
750 0 : NTSTATUS ret;
751 0 : union smb_close io;
752 0 : int i;
753 :
754 0 : i = find_handle(handle, NULL);
755 :
756 0 : io.close.level = RAW_CLOSE_CLOSE;
757 0 : io.close.in.file.fnum = i;
758 0 : io.close.in.write_time = 0;
759 :
760 0 : ret = smb_raw_close(c->tree, &io);
761 :
762 0 : if (!check_status("Close", status, ret))
763 0 : return false;
764 :
765 0 : if (NT_STATUS_IS_OK(ret)) {
766 0 : struct ftable *f = find_ftable(handle);
767 0 : DLIST_REMOVE(ftable, f);
768 0 : talloc_free(f);
769 : }
770 :
771 0 : return true;
772 : }
773 :
774 0 : bool nb_rmdir(const char *dname, NTSTATUS status, bool retry)
775 : {
776 0 : NTSTATUS ret;
777 0 : struct smb_rmdir io;
778 :
779 0 : io.in.path = dname;
780 :
781 0 : ret = smb_raw_rmdir(c->tree, &io);
782 :
783 0 : if (!retry)
784 0 : return check_status("Rmdir", status, ret);
785 :
786 0 : return true;
787 : }
788 :
789 0 : bool nb_mkdir(const char *dname, NTSTATUS status, bool retry)
790 : {
791 0 : union smb_mkdir io;
792 :
793 0 : io.mkdir.level = RAW_MKDIR_MKDIR;
794 0 : io.mkdir.in.path = dname;
795 :
796 : /* NOTE! no error checking. Used for base fileset creation */
797 0 : smb_raw_mkdir(c->tree, &io);
798 :
799 0 : return true;
800 : }
801 :
802 0 : bool nb_rename(const char *o, const char *n, NTSTATUS status, bool retry)
803 : {
804 0 : NTSTATUS ret;
805 0 : union smb_rename io;
806 :
807 0 : io.generic.level = RAW_RENAME_RENAME;
808 0 : io.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
809 0 : io.rename.in.pattern1 = o;
810 0 : io.rename.in.pattern2 = n;
811 :
812 0 : ret = smb_raw_rename(c->tree, &io);
813 :
814 0 : if (!retry)
815 0 : return check_status("Rename", status, ret);
816 :
817 0 : return true;
818 : }
819 :
820 :
821 0 : bool nb_qpathinfo(const char *fname, int level, NTSTATUS status)
822 : {
823 0 : union smb_fileinfo io;
824 0 : TALLOC_CTX *mem_ctx;
825 0 : NTSTATUS ret;
826 :
827 0 : mem_ctx = talloc_init("nb_qpathinfo");
828 :
829 0 : io.generic.level = level;
830 0 : io.generic.in.file.path = fname;
831 :
832 0 : ret = smb_raw_pathinfo(c->tree, mem_ctx, &io);
833 :
834 0 : talloc_free(mem_ctx);
835 :
836 0 : return check_status("Pathinfo", status, ret);
837 : }
838 :
839 :
840 0 : bool nb_qfileinfo(int fnum, int level, NTSTATUS status)
841 : {
842 0 : union smb_fileinfo io;
843 0 : TALLOC_CTX *mem_ctx;
844 0 : NTSTATUS ret;
845 0 : int i;
846 :
847 0 : i = find_handle(fnum, NULL);
848 :
849 0 : mem_ctx = talloc_init("nb_qfileinfo");
850 :
851 0 : io.generic.level = level;
852 0 : io.generic.in.file.fnum = i;
853 :
854 0 : ret = smb_raw_fileinfo(c->tree, mem_ctx, &io);
855 :
856 0 : talloc_free(mem_ctx);
857 :
858 0 : return check_status("Fileinfo", status, ret);
859 : }
860 :
861 0 : bool nb_sfileinfo(int fnum, int level, NTSTATUS status)
862 : {
863 0 : union smb_setfileinfo io;
864 0 : NTSTATUS ret;
865 0 : int i;
866 :
867 0 : if (level != RAW_SFILEINFO_BASIC_INFORMATION) {
868 0 : printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level);
869 0 : return true;
870 : }
871 :
872 0 : ZERO_STRUCT(io);
873 :
874 0 : i = find_handle(fnum, NULL);
875 :
876 0 : io.generic.level = level;
877 0 : io.generic.in.file.fnum = i;
878 0 : unix_to_nt_time(&io.basic_info.in.create_time, time(NULL));
879 0 : unix_to_nt_time(&io.basic_info.in.access_time, 0);
880 0 : unix_to_nt_time(&io.basic_info.in.write_time, 0);
881 0 : unix_to_nt_time(&io.basic_info.in.change_time, 0);
882 0 : io.basic_info.in.attrib = 0;
883 :
884 0 : ret = smb_raw_setfileinfo(c->tree, &io);
885 :
886 0 : return check_status("Setfileinfo", status, ret);
887 : }
888 :
889 0 : bool nb_qfsinfo(int level, NTSTATUS status)
890 : {
891 0 : union smb_fsinfo io;
892 0 : TALLOC_CTX *mem_ctx;
893 0 : NTSTATUS ret;
894 :
895 0 : mem_ctx = talloc_init("smbcli_dskattr");
896 :
897 0 : io.generic.level = level;
898 0 : ret = smb_raw_fsinfo(c->tree, mem_ctx, &io);
899 :
900 0 : talloc_free(mem_ctx);
901 :
902 0 : return check_status("Fsinfo", status, ret);
903 : }
904 :
905 : /* callback function used for trans2 search */
906 0 : static bool findfirst_callback(void *private_data, const union smb_search_data *file)
907 : {
908 0 : return true;
909 : }
910 :
911 0 : bool nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
912 : {
913 0 : union smb_search_first io;
914 0 : TALLOC_CTX *mem_ctx;
915 0 : NTSTATUS ret;
916 :
917 0 : mem_ctx = talloc_init("smbcli_dskattr");
918 :
919 0 : io.t2ffirst.level = RAW_SEARCH_TRANS2;
920 0 : io.t2ffirst.data_level = level;
921 0 : io.t2ffirst.in.max_count = maxcnt;
922 0 : io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY;
923 0 : io.t2ffirst.in.pattern = mask;
924 0 : io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
925 0 : io.t2ffirst.in.storage_type = 0;
926 :
927 0 : ret = smb_raw_search_first(c->tree, mem_ctx, &io, NULL, findfirst_callback);
928 :
929 0 : talloc_free(mem_ctx);
930 :
931 0 : if (!check_status("Search", status, ret))
932 0 : return false;
933 :
934 0 : if (NT_STATUS_IS_OK(ret) && io.t2ffirst.out.count != count) {
935 0 : printf("[%d] Warning: got count %d expected %d\n",
936 : nbench_line_count,
937 0 : io.t2ffirst.out.count, count);
938 : }
939 :
940 0 : return true;
941 : }
942 :
943 0 : bool nb_flush(int fnum, NTSTATUS status)
944 : {
945 0 : union smb_flush io;
946 0 : NTSTATUS ret;
947 0 : int i;
948 0 : i = find_handle(fnum, NULL);
949 :
950 0 : io.flush.level = RAW_FLUSH_FLUSH;
951 0 : io.flush.in.file.fnum = i;
952 :
953 0 : ret = smb_raw_flush(c->tree, &io);
954 :
955 0 : return check_status("Flush", status, ret);
956 : }
957 :
958 0 : void nb_sleep(int usec, NTSTATUS status)
959 : {
960 0 : usleep(usec);
961 0 : }
962 :
963 0 : bool nb_deltree(const char *dname, bool retry)
964 : {
965 0 : int total_deleted;
966 :
967 0 : smb_raw_exit(c->session);
968 :
969 0 : while (ftable) {
970 0 : struct ftable *f = ftable;
971 0 : DLIST_REMOVE(ftable, f);
972 0 : talloc_free (f);
973 : }
974 :
975 0 : total_deleted = smbcli_deltree(c->tree, dname);
976 :
977 0 : if (total_deleted == -1) {
978 0 : printf("Failed to cleanup tree %s - exiting\n", dname);
979 0 : nb_exit(1);
980 : }
981 :
982 0 : smbcli_rmdir(c->tree, dname);
983 :
984 0 : return true;
985 : }
986 :
987 :
988 0 : void nb_exit(int status)
989 : {
990 0 : children[nbio_id].connected = false;
991 0 : printf("[%d] client %d exiting with status %d\n",
992 : nbench_line_count, nbio_id, status);
993 0 : exit(status);
994 : }
|