| 1 | /* 
 | 
|---|
| 2 |    Unix SMB/CIFS implementation.
 | 
|---|
| 3 | 
 | 
|---|
| 4 |    ping pong test
 | 
|---|
| 5 | 
 | 
|---|
| 6 |    Copyright (C) Ronnie Sahlberg 2007
 | 
|---|
| 7 | 
 | 
|---|
| 8 |    Significantly based on and borrowed from lockbench.c by
 | 
|---|
| 9 |    Copyright (C) Andrew Tridgell 2006
 | 
|---|
| 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 | /*
 | 
|---|
| 26 |    filename is specified by
 | 
|---|
| 27 |          --option=torture:filename=...
 | 
|---|
| 28 | 
 | 
|---|
| 29 |    number of locks is specified by
 | 
|---|
| 30 |          --option=torture:num_locks=...
 | 
|---|
| 31 | 
 | 
|---|
| 32 |    locktimeout is specified in ms by
 | 
|---|
| 33 |          --option=torture:locktimeout=...
 | 
|---|
| 34 | 
 | 
|---|
| 35 |        default is 100 seconds
 | 
|---|
| 36 |        if set to 0 pingpong will instead loop trying the lock operation
 | 
|---|
| 37 |        over and over until it completes.
 | 
|---|
| 38 | 
 | 
|---|
| 39 |    reading from the file can be enabled with
 | 
|---|
| 40 |          --option=torture:read=true
 | 
|---|
| 41 | 
 | 
|---|
| 42 |    writing to the file can be enabled with
 | 
|---|
| 43 |          --option=torture:write=true
 | 
|---|
| 44 | 
 | 
|---|
| 45 | */
 | 
|---|
| 46 | #include "includes.h"
 | 
|---|
| 47 | #include "torture/torture.h"
 | 
|---|
| 48 | #include "libcli/raw/libcliraw.h"
 | 
|---|
| 49 | #include "system/time.h"
 | 
|---|
| 50 | #include "system/filesys.h"
 | 
|---|
| 51 | #include "libcli/libcli.h"
 | 
|---|
| 52 | #include "torture/util.h"
 | 
|---|
| 53 | 
 | 
|---|
| 54 | static void lock_byte(struct smbcli_state *cli, int fd, int offset, int lock_timeout)
 | 
|---|
| 55 | {
 | 
|---|
| 56 |         union smb_lock io;
 | 
|---|
| 57 |         struct smb_lock_entry lock;
 | 
|---|
| 58 |         NTSTATUS status;
 | 
|---|
| 59 | 
 | 
|---|
| 60 | try_again:
 | 
|---|
| 61 |         ZERO_STRUCT(lock);
 | 
|---|
| 62 |         io.lockx.in.ulock_cnt = 0;
 | 
|---|
| 63 |         io.lockx.in.lock_cnt = 1;
 | 
|---|
| 64 | 
 | 
|---|
| 65 |         lock.count = 1;
 | 
|---|
| 66 |         lock.offset = offset;
 | 
|---|
| 67 |         lock.pid = cli->tree->session->pid;
 | 
|---|
| 68 |         io.lockx.level = RAW_LOCK_LOCKX;
 | 
|---|
| 69 |         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
 | 
|---|
| 70 |         io.lockx.in.timeout = lock_timeout;
 | 
|---|
| 71 |         io.lockx.in.locks = &lock;
 | 
|---|
| 72 |         io.lockx.in.file.fnum = fd;
 | 
|---|
| 73 | 
 | 
|---|
| 74 |         status = smb_raw_lock(cli->tree, &io);
 | 
|---|
| 75 | 
 | 
|---|
| 76 |         /* If we dont use timeouts and we got file lock conflict
 | 
|---|
| 77 |            just try the lock again.
 | 
|---|
| 78 |         */
 | 
|---|
| 79 |         if (lock_timeout==0) {
 | 
|---|
| 80 |                 if ( (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status))
 | 
|---|
| 81 |                    ||(NT_STATUS_EQUAL(NT_STATUS_LOCK_NOT_GRANTED, status)) ) {
 | 
|---|
| 82 |                         goto try_again;
 | 
|---|
| 83 |                 }
 | 
|---|
| 84 |         }
 | 
|---|
| 85 | 
 | 
|---|
| 86 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 87 |                 DEBUG(0,("Lock failed\n"));
 | 
|---|
| 88 |                 exit(1);
 | 
|---|
| 89 |         }
 | 
|---|
| 90 | }
 | 
|---|
| 91 | 
 | 
|---|
| 92 | static void unlock_byte(struct smbcli_state *cli, int fd, int offset)
 | 
|---|
| 93 | {
 | 
|---|
| 94 |         union smb_lock io;
 | 
|---|
| 95 |         struct smb_lock_entry lock;
 | 
|---|
| 96 |         NTSTATUS status;
 | 
|---|
| 97 | 
 | 
|---|
| 98 |         ZERO_STRUCT(lock);
 | 
|---|
| 99 |         io.lockx.in.ulock_cnt = 1;
 | 
|---|
| 100 |         io.lockx.in.lock_cnt = 0;
 | 
|---|
| 101 | 
 | 
|---|
| 102 |         lock.count = 1;
 | 
|---|
| 103 |         lock.offset = offset;
 | 
|---|
| 104 |         lock.pid = cli->tree->session->pid;
 | 
|---|
| 105 |         io.lockx.level = RAW_LOCK_LOCKX;
 | 
|---|
| 106 |         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
 | 
|---|
| 107 |         io.lockx.in.timeout = 100000;
 | 
|---|
| 108 |         io.lockx.in.locks = &lock;
 | 
|---|
| 109 |         io.lockx.in.file.fnum = fd;
 | 
|---|
| 110 | 
 | 
|---|
| 111 |         status = smb_raw_lock(cli->tree, &io);
 | 
|---|
| 112 | 
 | 
|---|
| 113 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 114 |                 DEBUG(0,("Unlock failed\n"));
 | 
|---|
| 115 |                 exit(1);
 | 
|---|
| 116 |         }
 | 
|---|
| 117 | }
 | 
|---|
| 118 | 
 | 
|---|
| 119 | static void write_byte(struct smbcli_state *cli, int fd, uint8_t c, int offset)
 | 
|---|
| 120 | {
 | 
|---|
| 121 |         union smb_write io;
 | 
|---|
| 122 |         NTSTATUS status;
 | 
|---|
| 123 | 
 | 
|---|
| 124 |         io.generic.level = RAW_WRITE_WRITEX;
 | 
|---|
| 125 |         io.writex.in.file.fnum = fd;
 | 
|---|
| 126 |         io.writex.in.offset = offset;
 | 
|---|
| 127 |         io.writex.in.wmode = 0;
 | 
|---|
| 128 |         io.writex.in.remaining = 0;
 | 
|---|
| 129 |         io.writex.in.count = 1;
 | 
|---|
| 130 |         io.writex.in.data = &c;
 | 
|---|
| 131 | 
 | 
|---|
| 132 |         status = smb_raw_write(cli->tree, &io);
 | 
|---|
| 133 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 134 |                 printf("write failed\n");
 | 
|---|
| 135 |                 exit(1);
 | 
|---|
| 136 |         }
 | 
|---|
| 137 | }       
 | 
|---|
| 138 | 
 | 
|---|
| 139 | static void read_byte(struct smbcli_state *cli, int fd, uint8_t *c, int offset)
 | 
|---|
| 140 | {
 | 
|---|
| 141 |         union smb_read io;
 | 
|---|
| 142 |         NTSTATUS status;
 | 
|---|
| 143 | 
 | 
|---|
| 144 |         io.generic.level = RAW_READ_READX;
 | 
|---|
| 145 |         io.readx.in.file.fnum = fd;
 | 
|---|
| 146 |         io.readx.in.mincnt = 1;
 | 
|---|
| 147 |         io.readx.in.maxcnt = 1;
 | 
|---|
| 148 |         io.readx.in.offset = offset;
 | 
|---|
| 149 |         io.readx.in.remaining = 0;
 | 
|---|
| 150 |         io.readx.in.read_for_execute = false;
 | 
|---|
| 151 |         io.readx.out.data = c;
 | 
|---|
| 152 | 
 | 
|---|
| 153 |         status = smb_raw_read(cli->tree, &io);
 | 
|---|
| 154 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 155 |                 printf("read failed\n");
 | 
|---|
| 156 |                 exit(1);
 | 
|---|
| 157 |         }
 | 
|---|
| 158 | }       
 | 
|---|
| 159 | 
 | 
|---|
| 160 | 
 | 
|---|
| 161 | static struct timeval tp1, tp2;
 | 
|---|
| 162 | 
 | 
|---|
| 163 | static void start_timer(void)
 | 
|---|
| 164 | {
 | 
|---|
| 165 |         gettimeofday(&tp1, NULL);
 | 
|---|
| 166 | }
 | 
|---|
| 167 | 
 | 
|---|
| 168 | static double end_timer(void)
 | 
|---|
| 169 | {
 | 
|---|
| 170 |         gettimeofday(&tp2, NULL);
 | 
|---|
| 171 |         return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
 | 
|---|
| 172 |                 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
 | 
|---|
| 173 | }
 | 
|---|
| 174 | 
 | 
|---|
| 175 | /* 
 | 
|---|
| 176 |    ping pong
 | 
|---|
| 177 | */
 | 
|---|
| 178 | bool torture_ping_pong(struct torture_context *torture)
 | 
|---|
| 179 | {
 | 
|---|
| 180 |         const char *fn;
 | 
|---|
| 181 |         int num_locks;
 | 
|---|
| 182 |         TALLOC_CTX *mem_ctx = talloc_new(torture);
 | 
|---|
| 183 |         static bool do_reads;
 | 
|---|
| 184 |         static bool do_writes;
 | 
|---|
| 185 |         int lock_timeout;
 | 
|---|
| 186 |         int fd;
 | 
|---|
| 187 |         struct smbcli_state *cli;
 | 
|---|
| 188 |         int i;
 | 
|---|
| 189 |         uint8_t incr=0, last_incr=0;
 | 
|---|
| 190 |         uint8_t *val;
 | 
|---|
| 191 |         int count, loops;
 | 
|---|
| 192 | 
 | 
|---|
| 193 |         fn = torture_setting_string(torture, "filename", NULL);
 | 
|---|
| 194 |         if (fn == NULL) {
 | 
|---|
| 195 |                 DEBUG(0,("You must specify the filename using --option=torture:filename=...\n"));
 | 
|---|
| 196 |                 return false;
 | 
|---|
| 197 |         }
 | 
|---|
| 198 | 
 | 
|---|
| 199 |         num_locks = torture_setting_int(torture, "num_locks", -1);
 | 
|---|
| 200 |         if (num_locks == -1) {
 | 
|---|
| 201 |                 DEBUG(0,("You must specify num_locks using --option=torture:num_locks=...\n"));
 | 
|---|
| 202 |                 return false;
 | 
|---|
| 203 |         }
 | 
|---|
| 204 | 
 | 
|---|
| 205 |         do_reads     = torture_setting_bool(torture, "read", false);
 | 
|---|
| 206 |         do_writes    = torture_setting_bool(torture, "write", false);
 | 
|---|
| 207 |         lock_timeout =  torture_setting_int(torture, "lock_timeout", 100000);
 | 
|---|
| 208 | 
 | 
|---|
| 209 |         if (!torture_open_connection(&cli, torture, 0)) {
 | 
|---|
| 210 |                 DEBUG(0,("Could not open connection\n"));
 | 
|---|
| 211 |                 return false;
 | 
|---|
| 212 |         }
 | 
|---|
| 213 | 
 | 
|---|
| 214 |         fd = smbcli_open(cli->tree, fn, O_RDWR|O_CREAT, DENY_NONE);
 | 
|---|
| 215 |         if (fd == -1) {
 | 
|---|
| 216 |                 printf("Failed to open %s\n", fn);
 | 
|---|
| 217 |                 exit(1);
 | 
|---|
| 218 |         }
 | 
|---|
| 219 | 
 | 
|---|
| 220 |         write_byte(cli, fd, 0, num_locks);
 | 
|---|
| 221 |         lock_byte(cli, fd, 0, lock_timeout);
 | 
|---|
| 222 | 
 | 
|---|
| 223 | 
 | 
|---|
| 224 |         start_timer();
 | 
|---|
| 225 |         val = talloc_zero_array(mem_ctx, uint8_t, num_locks);
 | 
|---|
| 226 |         i = 0;
 | 
|---|
| 227 |         count = 0;
 | 
|---|
| 228 |         loops = 0;
 | 
|---|
| 229 |         while (1) {
 | 
|---|
| 230 |                 lock_byte(cli, fd, (i+1)%num_locks, lock_timeout);
 | 
|---|
| 231 | 
 | 
|---|
| 232 |                 if (do_reads) {
 | 
|---|
| 233 |                         uint8_t c;
 | 
|---|
| 234 |                         read_byte(cli, fd, &c, i);
 | 
|---|
| 235 |                         incr   = c-val[i];
 | 
|---|
| 236 |                         val[i] = c;                     
 | 
|---|
| 237 |                 }
 | 
|---|
| 238 | 
 | 
|---|
| 239 |                 if (do_writes) {
 | 
|---|
| 240 |                         uint8_t c = val[i] + 1;
 | 
|---|
| 241 |                         write_byte(cli, fd, c, i);
 | 
|---|
| 242 |                 }
 | 
|---|
| 243 | 
 | 
|---|
| 244 |                 unlock_byte(cli, fd, i);
 | 
|---|
| 245 | 
 | 
|---|
| 246 |                 i = (i+1)%num_locks;
 | 
|---|
| 247 |                 count++;
 | 
|---|
| 248 |                 if (loops>num_locks && incr!=last_incr) {
 | 
|---|
| 249 |                         last_incr = incr;
 | 
|---|
| 250 |                         printf("data increment = %u\n", incr);
 | 
|---|
| 251 |                         fflush(stdout);
 | 
|---|
| 252 |                 }
 | 
|---|
| 253 |                 if (end_timer() > 1.0) {
 | 
|---|
| 254 |                         printf("%8u locks/sec\r", 
 | 
|---|
| 255 |                                (unsigned)(2*count/end_timer()));
 | 
|---|
| 256 |                         fflush(stdout);
 | 
|---|
| 257 |                         start_timer();
 | 
|---|
| 258 |                         count=0;
 | 
|---|
| 259 |                 }
 | 
|---|
| 260 |                 loops++;
 | 
|---|
| 261 |         }
 | 
|---|
| 262 | 
 | 
|---|
| 263 |         talloc_free(mem_ctx);
 | 
|---|
| 264 |         return true;
 | 
|---|
| 265 | }
 | 
|---|
| 266 | 
 | 
|---|