diff options
-rw-r--r-- | source4/ntvfs/posix/pvfs_lock.c | 6 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 10 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_wait.c | 19 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 13 | ||||
-rw-r--r-- | source4/torture/raw/mux.c | 47 |
5 files changed, 69 insertions, 26 deletions
diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c index 82ac9ebad5..f778b59d95 100644 --- a/source4/ntvfs/posix/pvfs_lock.c +++ b/source4/ntvfs/posix/pvfs_lock.c @@ -91,7 +91,7 @@ static void pvfs_lock_async_failed(struct pvfs_state *pvfs, range, so we should try the lock again. Note that on timeout we do retry the lock, giving it a last chance. */ -static void pvfs_pending_lock_continue(void *private, BOOL timed_out) +static void pvfs_pending_lock_continue(void *private, enum pvfs_wait_notice reason) { struct pvfs_pending_lock *pending = private; struct pvfs_state *pvfs = pending->pvfs; @@ -102,6 +102,10 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out) enum brl_type rw; NTSTATUS status; int i; + BOOL timed_out; + + /* we consider a cancel to be a timeout */ + timed_out = (reason != PVFS_WAIT_EVENT); locks = lck->lockx.in.locks + lck->lockx.in.ulock_cnt; diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 73b1949acb..c8f96849ec 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -430,7 +430,7 @@ static int pvfs_retry_destructor(void *ptr) /* retry an open */ -static void pvfs_open_retry(void *private, BOOL timed_out) +static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason) { struct pvfs_open_retry *r = private; struct ntvfs_module_context *ntvfs = r->ntvfs; @@ -438,9 +438,15 @@ static void pvfs_open_retry(void *private, BOOL timed_out) union smb_open *io = r->io; NTSTATUS status; + /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably + just a bug in their server, but we better do the same */ + if (reason == PVFS_WAIT_CANCEL) { + return; + } + talloc_free(r->wait_handle); - if (timed_out) { + if (reason == PVFS_WAIT_TIMEOUT) { /* if it timed out, then give the failure immediately */ talloc_free(r); diff --git a/source4/ntvfs/posix/pvfs_wait.c b/source4/ntvfs/posix/pvfs_wait.c index df7f045e00..dd7afaf653 100644 --- a/source4/ntvfs/posix/pvfs_wait.c +++ b/source4/ntvfs/posix/pvfs_wait.c @@ -29,14 +29,14 @@ struct pvfs_wait { struct pvfs_wait *next, *prev; struct pvfs_state *pvfs; - void (*handler)(void *, BOOL); + void (*handler)(void *, enum pvfs_wait_notice); void *private; struct timed_event *te; int msg_type; struct messaging_context *msg_ctx; struct event_context *ev; struct smbsrv_request *req; - BOOL timed_out; + enum pvfs_wait_notice reason; }; /* @@ -48,7 +48,7 @@ NTSTATUS pvfs_async_setup(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req, void *private) { struct pvfs_wait *pwait = private; - pwait->handler(pwait->private, pwait->timed_out); + pwait->handler(pwait->private, pwait->reason); return NT_STATUS_OK; } @@ -68,7 +68,7 @@ static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uin *(void **)data->data != pwait->private) { return; } - pwait->timed_out = False; + pwait->reason = PVFS_WAIT_EVENT; req = pwait->req; /* the extra reference here is to ensure that the req @@ -90,7 +90,7 @@ static void pvfs_wait_timeout(struct event_context *ev, struct pvfs_wait *pwait = te->private; struct smbsrv_request *req = pwait->req; - pwait->timed_out = True; + pwait->reason = PVFS_WAIT_TIMEOUT; talloc_increase_ref_count(req); ntvfs_async_setup(pwait->req, pwait); @@ -117,11 +117,11 @@ static int pvfs_wait_destructor(void *ptr) the return value is a handle. To stop waiting talloc_free this handle. */ -void *pvfs_wait_message(struct pvfs_state *pvfs, + void *pvfs_wait_message(struct pvfs_state *pvfs, struct smbsrv_request *req, int msg_type, struct timeval end_time, - void (*fn)(void *, BOOL), + void (*fn)(void *, enum pvfs_wait_notice), void *private) { struct timed_event te; @@ -180,8 +180,9 @@ NTSTATUS pvfs_cancel(struct ntvfs_module_context *ntvfs, struct smbsrv_request * for (pwait=pvfs->wait_list;pwait;pwait=pwait->next) { if (SVAL(req->in.hdr, HDR_MID) == SVAL(pwait->req->in.hdr, HDR_MID) && req->smbpid == pwait->req->smbpid) { - /* trigger an early timeout */ - pvfs_wait_timeout(pwait->ev, pwait->te, timeval_current()); + /* trigger a cancel on the request */ + pwait->reason = PVFS_WAIT_CANCEL; + ntvfs_async_setup(pwait->req, pwait); return NT_STATUS_OK; } } diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index e0d8e7fe37..4ee06723ac 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -165,4 +165,17 @@ struct pvfs_mangle_context { /* forward declare some anonymous structures */ struct pvfs_dir; +/* types of notification for pvfs wait events */ +enum pvfs_wait_notice {PVFS_WAIT_EVENT, PVFS_WAIT_TIMEOUT, PVFS_WAIT_CANCEL}; + + +/* putting this prototype here avoids us having to expose this whole header in the + rest of Samba */ +void *pvfs_wait_message(struct pvfs_state *pvfs, + struct smbsrv_request *req, + int msg_type, + struct timeval end_time, + void (*fn)(void *, enum pvfs_wait_notice), + void *private); + #endif /* _VFS_POSIX_H_ */ diff --git a/source4/torture/raw/mux.c b/source4/torture/raw/mux.c index 6f9426490e..39eb5c1d5e 100644 --- a/source4/torture/raw/mux.c +++ b/source4/torture/raw/mux.c @@ -41,15 +41,13 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) NTSTATUS status; int fnum1, fnum2; BOOL ret = True; - struct smbcli_request *req; + struct smbcli_request *req1, *req2; struct timeval tv; double d; printf("testing multiplexed open/open/close\n"); - /* - file open with no share access - */ + printf("send first open\n"); io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.flags = 0; @@ -66,7 +64,7 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) CHECK_STATUS(status, NT_STATUS_OK); fnum1 = io.ntcreatex.out.fnum; - /* and a 2nd open, this will not conflict */ + printf("send 2nd open, non-conflicting\n"); io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); @@ -74,7 +72,7 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) tv = timeval_current(); - /* send an open that will conflict */ + printf("send 3rd open, conflicting\n"); io.ntcreatex.in.share_access = 0; status = smb_raw_open(cli->tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); @@ -87,20 +85,31 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) printf("open delay %.2f\n", d); } - /* - same request, but async - */ + printf("send async open, conflicting\n"); + tv = timeval_current(); + req1 = smb_raw_open_send(cli->tree, &io); + + printf("send 2nd async open, conflicting\n"); tv = timeval_current(); - req = smb_raw_open_send(cli->tree, &io); + req2 = smb_raw_open_send(cli->tree, &io); - /* and close the first file */ + printf("close first sync open\n"); smbcli_close(cli->tree, fnum1); - /* then the 2nd file */ + printf("cancel 2nd async open (should be ignored)\n"); + smb_raw_ntcancel(req2); + + d = timeval_elapsed(&tv); + if (d > 0.25) { + printf("bad timeout after cancel - %.2f should be <0.25\n", d); + ret = False; + } + + printf("close the 2nd sync open\n"); smbcli_close(cli->tree, fnum2); - /* see if the async open succeeded */ - status = smb_raw_open_recv(req, mem_ctx, &io); + printf("see if the 1st async open now succeeded\n"); + status = smb_raw_open_recv(req1, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); d = timeval_elapsed(&tv); @@ -111,6 +120,16 @@ static BOOL test_mux_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) printf("async open delay %.2f\n", d); } + printf("2nd async open should have timed out\n"); + status = smb_raw_open_recv(req2, mem_ctx, &io); + CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION); + d = timeval_elapsed(&tv); + if (d < 0.8) { + printf("bad timeout for async conflict - %.2f should be 1.0\n", d); + ret = False; + } + + printf("close the 1st async open\n"); smbcli_close(cli->tree, io.ntcreatex.out.fnum); done: |