/* test disconnect with timed lock */ static bool test_disconnect_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_lock io; NTSTATUS status; int fnum; struct smbcli_request *req; struct smb_lock_entry lock[1]; printf("trying disconnect with async lock\n"); fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree)); return false; } io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.file.fnum = fnum; io.lockx.in.mode = 0; io.lockx.in.timeout = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.ulock_cnt = 0; lock[0].pid = 1; lock[0].offset = 0; lock[0].count = 4; io.lockx.in.locks = &lock[0]; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); lock[0].pid = 2; io.lockx.in.timeout = 3000; req = smb_raw_lock_send(cli->tree, &io); if (!req) { printf("test_disconnect_lock: smb_raw_lock_send() " "returned NULL\n"); return false; } status = smbcli_chkpath(cli->tree, "\\"); CHECK_STATUS(status, NT_STATUS_OK); talloc_free(cli); return true; }
/* send the next lock request */ static void lock_send(struct benchlock_state *state) { union smb_lock io; struct smb_lock_entry lock; switch (state->stage) { case LOCK_INITIAL: io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; state->lock_offset = 0; state->unlock_offset = 0; lock.offset = state->lock_offset; break; case LOCK_LOCK: io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; state->lock_offset = (state->lock_offset+1)%(nprocs+1); lock.offset = state->lock_offset; break; case LOCK_UNLOCK: io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; lock.offset = state->unlock_offset; state->unlock_offset = (state->unlock_offset+1)%(nprocs+1); break; } lock.count = 1; lock.pid = state->tree->session->pid; io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; io.lockx.in.timeout = 100000; io.lockx.in.locks = &lock; io.lockx.in.file.fnum = state->fnum; state->req = smb_raw_lock_send(state->tree, &io); if (state->req == NULL) { DEBUG(0,("Failed to setup lock\n")); lock_failed++; } state->req->async.private_data = state; state->req->async.fn = lock_completion; }
/* lock a byte range */ static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, union smb_lock *io) { struct cvfs_private *p = ntvfs->private_data; struct smbcli_request *c_req; SETUP_PID; if (io->generic.level != RAW_LOCK_GENERIC && p->map_generic) { return ntvfs_map_lock(ntvfs, req, io); } SETUP_FILE; if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { return smb_raw_lock(p->tree, io); } c_req = smb_raw_lock_send(p->tree, io); SIMPLE_ASYNC_TAIL; }
/* test a lock that conflicts with an existing lock */ static bool test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { union smb_lock io; NTSTATUS status; int fnum; bool ret = true; struct smbcli_request *req; struct smb_lock_entry lock[1]; struct timeval t; printf("TESTING MULTIPLEXED LOCK/LOCK/UNLOCK\n"); fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { printf("open failed in mux_write - %s\n", smbcli_errstr(cli->tree)); ret = false; goto done; } printf("establishing a lock\n"); io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.file.fnum = fnum; io.lockx.in.mode = 0; io.lockx.in.timeout = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.ulock_cnt = 0; lock[0].pid = 1; lock[0].offset = 0; lock[0].count = 4; io.lockx.in.locks = &lock[0]; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); printf("the second lock will conflict with the first\n"); lock[0].pid = 2; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); printf("this will too, but we'll unlock while waiting\n"); t = timeval_current(); req = smb_raw_lock_send(cli->tree, &io); printf("unlock the first range\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; io.lockx.in.timeout = 0; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); printf("recv the async reply\n"); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_OK); printf("async lock took %.2f msec\n", timeval_elapsed(&t) * 1000); if (timeval_elapsed(&t) > 0.1) { printf("failed to trigger early lock retry\n"); return false; } printf("reopening with an exit\n"); smb_raw_exit(cli->session); fnum = smbcli_open(cli->tree, BASEDIR "\\write.dat", O_RDWR | O_CREAT, DENY_NONE); printf("Now trying with a cancel\n"); io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.file.fnum = fnum; io.lockx.in.mode = 0; io.lockx.in.timeout = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.ulock_cnt = 0; lock[0].pid = 1; lock[0].offset = 0; lock[0].count = 4; io.lockx.in.locks = &lock[0]; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); lock[0].pid = 2; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); req = smb_raw_lock_send(cli->tree, &io); /* cancel the blocking lock */ smb_raw_ntcancel(req); printf("sending 2nd cancel\n"); /* the 2nd cancel is totally harmless, but tests the server trying to cancel an already cancelled request */ smb_raw_ntcancel(req); printf("sent 2nd cancel\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; io.lockx.in.timeout = 0; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); printf("cancel a lock using exit to close file\n"); lock[0].pid = 1; io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; io.lockx.in.timeout = 1000; status = smb_raw_lock(cli->tree, &io); CHECK_STATUS(status, NT_STATUS_OK); t = timeval_current(); lock[0].pid = 2; req = smb_raw_lock_send(cli->tree, &io); smb_raw_exit(cli->session); smb_raw_exit(cli->session); smb_raw_exit(cli->session); smb_raw_exit(cli->session); printf("recv the async reply\n"); status = smbcli_request_simple_recv(req); CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); printf("async lock exit took %.2f msec\n", timeval_elapsed(&t) * 1000); if (timeval_elapsed(&t) > 0.1) { printf("failed to trigger early lock failure\n"); return false; } done: return ret; }
bool torture_samba3_posixtimedlock(struct torture_context *tctx, struct smbcli_state *cli) { NTSTATUS status; bool ret = true; const char *dirname = "posixlock"; const char *fname = "locked"; const char *fpath; const char *localdir; const char *localname; int fnum = -1; int fd = -1; struct flock posix_lock; union smb_lock io; struct smb_lock_entry lock_entry; struct smbcli_request *req; struct lock_result_state lock_result; struct tevent_timer *te; torture_assert(tctx, torture_setup_dir(cli, dirname), "creating test directory"); if (!(fpath = talloc_asprintf(tctx, "%s\\%s", dirname, fname))) { torture_warning(tctx, "talloc failed\n"); ret = false; goto done; } fnum = smbcli_open(cli->tree, fpath, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { torture_warning(tctx, "Could not create file %s: %s\n", fpath, smbcli_errstr(cli->tree)); ret = false; goto done; } if (!(localdir = torture_setting_string(tctx, "localdir", NULL))) { torture_warning(tctx, "Need 'localdir' setting\n"); ret = false; goto done; } if (!(localname = talloc_asprintf(tctx, "%s/%s/%s", localdir, dirname, fname))) { torture_warning(tctx, "talloc failed\n"); ret = false; goto done; } /* * Lock a byte range from posix */ fd = open(localname, O_RDWR); if (fd == -1) { torture_warning(tctx, "open(%s) failed: %s\n", localname, strerror(errno)); goto done; } posix_lock.l_type = F_WRLCK; posix_lock.l_whence = SEEK_SET; posix_lock.l_start = 0; posix_lock.l_len = 1; if (fcntl(fd, F_SETLK, &posix_lock) == -1) { torture_warning(tctx, "fcntl failed: %s\n", strerror(errno)); ret = false; goto done; } /* * Try a cifs brlock without timeout to see if posix locking = yes */ io.lockx.in.ulock_cnt = 0; io.lockx.in.lock_cnt = 1; lock_entry.count = 1; lock_entry.offset = 0; lock_entry.pid = cli->tree->session->pid; io.lockx.level = RAW_LOCK_LOCKX; io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; io.lockx.in.timeout = 0; io.lockx.in.locks = &lock_entry; io.lockx.in.file.fnum = fnum; status = smb_raw_lock(cli->tree, &io); ret = true; CHECK_STATUS(tctx, status, NT_STATUS_FILE_LOCK_CONFLICT); if (!ret) { goto done; } /* * Now fire off a timed brlock, unlock the posix lock and see if the * timed lock gets through. */ io.lockx.in.timeout = 5000; req = smb_raw_lock_send(cli->tree, &io); if (req == NULL) { torture_warning(tctx, "smb_raw_lock_send failed\n"); ret = false; goto done; } lock_result.done = false; req->async.fn = receive_lock_result; req->async.private_data = &lock_result; te = tevent_add_timer(tctx->ev, tctx, timeval_current_ofs(1, 0), close_locked_file, &fd); if (te == NULL) { torture_warning(tctx, "tevent_add_timer failed\n"); ret = false; goto done; } while ((fd != -1) || (!lock_result.done)) { if (tevent_loop_once(tctx->ev) == -1) { torture_warning(tctx, "tevent_loop_once failed: %s\n", strerror(errno)); ret = false; goto done; } } CHECK_STATUS(tctx, lock_result.status, NT_STATUS_OK); done: if (fnum != -1) { smbcli_close(cli->tree, fnum); } if (fd != -1) { close(fd); } smbcli_deltree(cli->tree, dirname); return ret; }