From c870ae8b898d3bcc81ed9fd1afd505d78dea52cc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 4 Nov 2004 11:28:38 +0000 Subject: r3528: added support for the SMBntcancel() operation, which cancels any outstanding async operation (triggering an immediate timeout). pvfs now passes the RAW-MUX test (This used to be commit 3423e2f41461d054067ef168b9b986f62cc8f77c) --- source4/ntvfs/cifs/vfs_cifs.c | 10 ++++++++++ source4/ntvfs/common/brlock.c | 15 ++++++++------- source4/ntvfs/ipc/vfs_ipc.c | 10 ++++++++++ source4/ntvfs/nbench/vfs_nbench.c | 20 ++++++++++++++++++++ source4/ntvfs/ntvfs.h | 4 ++++ source4/ntvfs/ntvfs_generic.c | 3 +++ source4/ntvfs/ntvfs_interface.c | 24 ++++++++++++++++++++++++ source4/ntvfs/posix/pvfs_open.c | 1 - source4/ntvfs/posix/pvfs_wait.c | 31 +++++++++++++++++++++++++++++++ source4/ntvfs/posix/vfs_posix.c | 1 + source4/ntvfs/posix/vfs_posix.h | 4 ++++ source4/ntvfs/simple/vfs_simple.c | 13 +++++++++++++ source4/ntvfs/unixuid/vfs_unixuid.c | 14 ++++++++++++++ source4/script/tests/test_posix.sh | 4 ++-- source4/smb_server/reply.c | 4 +++- source4/torture/raw/mux.c | 4 ++++ 16 files changed, 151 insertions(+), 11 deletions(-) diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c index 3e9899cb8c..ea169b7ee6 100644 --- a/source4/ntvfs/cifs/vfs_cifs.c +++ b/source4/ntvfs/cifs/vfs_cifs.c @@ -650,6 +650,15 @@ static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, return NT_STATUS_OK; } +/* + cancel an async call +*/ +static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + /* lock a byte range */ @@ -855,6 +864,7 @@ NTSTATUS ntvfs_cifs_init(void) ops.trans = cvfs_trans; ops.logoff = cvfs_logoff; ops.async_setup = cvfs_async_setup; + ops.cancel = cvfs_cancel; if (lp_parm_bool(-1, "cifs", "maptrans2", False)) { ops.trans2 = cvfs_trans2; diff --git a/source4/ntvfs/common/brlock.c b/source4/ntvfs/common/brlock.c index 6fae7c6e4c..2b30270eff 100644 --- a/source4/ntvfs/common/brlock.c +++ b/source4/ntvfs/common/brlock.c @@ -63,7 +63,7 @@ struct brl_context { servid_t server; uint16_t tid; struct messaging_context *messaging_ctx; - struct lock_struct last_lock_failure; + struct lock_struct last_lock; }; @@ -95,7 +95,7 @@ struct brl_context *brl_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid, brl->server = server; brl->tid = tid; brl->messaging_ctx = messaging_ctx; - ZERO_STRUCT(brl->last_lock_failure); + ZERO_STRUCT(brl->last_lock); return brl; } @@ -194,13 +194,14 @@ static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck */ static NTSTATUS brl_lock_failed(struct brl_context *brl, struct lock_struct *lock) { - if (brl_same_context(&lock->context, &brl->last_lock_failure.context) && - lock->fnum == brl->last_lock_failure.fnum && - lock->start == brl->last_lock_failure.start && - lock->size == brl->last_lock_failure.size) { + if (lock->context.server == brl->last_lock.context.server && + lock->context.tid == brl->last_lock.context.tid && + lock->fnum == brl->last_lock.fnum && + lock->start == brl->last_lock.start && + lock->size == brl->last_lock.size) { return NT_STATUS_FILE_LOCK_CONFLICT; } - brl->last_lock_failure = *lock; + brl->last_lock = *lock; if (lock->start >= 0xEF000000 && (lock->start >> 63) == 0) { /* amazing the little things you learn with a test diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c index dc43dff3aa..271be09ac3 100644 --- a/source4/ntvfs/ipc/vfs_ipc.c +++ b/source4/ntvfs/ipc/vfs_ipc.c @@ -519,6 +519,15 @@ static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs, return NT_STATUS_OK; } +/* + cancel an async call +*/ +static NTSTATUS ipc_cancel(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req) +{ + return NT_STATUS_UNSUCCESSFUL; +} + /* lock a byte range */ @@ -744,6 +753,7 @@ NTSTATUS ntvfs_ipc_init(void) ops.trans = ipc_trans; ops.logoff = ipc_logoff; ops.async_setup = ipc_async_setup; + ops.cancel = ipc_cancel; /* register ourselves with the NTVFS subsystem. */ ret = register_backend("ntvfs", &ops); diff --git a/source4/ntvfs/nbench/vfs_nbench.c b/source4/ntvfs/nbench/vfs_nbench.c index ef435c5d75..1bcfda1371 100644 --- a/source4/ntvfs/nbench/vfs_nbench.c +++ b/source4/ntvfs/nbench/vfs_nbench.c @@ -643,6 +643,25 @@ static NTSTATUS nbench_async_setup(struct ntvfs_module_context *ntvfs, return status; } + +static void nbench_cancel_send(struct smbsrv_request *req) +{ + PASS_THRU_REP_POST(req); +} + +/* + cancel an existing async request +*/ +static NTSTATUS nbench_cancel(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req) +{ + NTSTATUS status; + + PASS_THRU_REQ(ntvfs, req, cancel, NULL, (ntvfs, req)); + + return status; +} + /* lock a byte range */ @@ -898,6 +917,7 @@ NTSTATUS ntvfs_nbench_init(void) ops.trans = nbench_trans; ops.logoff = nbench_logoff; ops.async_setup = nbench_async_setup; + ops.cancel = nbench_cancel; /* we don't register a trans2 handler as we want to be able to log individual trans2 requests */ diff --git a/source4/ntvfs/ntvfs.h b/source4/ntvfs/ntvfs.h index 62a735774c..3a6a78c032 100644 --- a/source4/ntvfs/ntvfs.h +++ b/source4/ntvfs/ntvfs.h @@ -117,6 +117,10 @@ struct ntvfs_ops { /* async_setup - called when a backend is processing a async request */ NTSTATUS (*async_setup)(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req, void *private); + + /* cancel - cancels any pending async request */ + NTSTATUS (*cancel)(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req); }; struct ntvfs_module_context { diff --git a/source4/ntvfs/ntvfs_generic.c b/source4/ntvfs/ntvfs_generic.c index 01a1a2dc60..885eb9719e 100644 --- a/source4/ntvfs/ntvfs_generic.c +++ b/source4/ntvfs/ntvfs_generic.c @@ -942,6 +942,9 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, status = ntvfs_map_async_setup(req, ntvfs, wr, wr2, (second_stage_t)ntvfs_map_write_finish); + if (!NT_STATUS_IS_OK(status)) { + return status; + } wr2->writex.level = RAW_WRITE_GENERIC; diff --git a/source4/ntvfs/ntvfs_interface.c b/source4/ntvfs/ntvfs_interface.c index f1ab217533..6ab5aad790 100644 --- a/source4/ntvfs/ntvfs_interface.c +++ b/source4/ntvfs/ntvfs_interface.c @@ -306,6 +306,20 @@ NTSTATUS ntvfs_async_setup(struct smbsrv_request *req, void *private) return ntvfs->ops->async_setup(ntvfs, req, private); } + +/* + cancel an outstanding async request +*/ +NTSTATUS ntvfs_cancel(struct smbsrv_request *req) +{ + struct ntvfs_module_context *ntvfs = req->tcon->ntvfs_ctx->modules; + if (!ntvfs->ops->cancel) { + return NT_STATUS_NOT_IMPLEMENTED; + } + return ntvfs->ops->cancel(ntvfs, req); +} + + /* initial setup */ NTSTATUS ntvfs_next_connect(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req, const char *sharename) @@ -588,3 +602,13 @@ NTSTATUS ntvfs_next_async_setup(struct ntvfs_module_context *ntvfs, } return ntvfs->next->ops->async_setup(ntvfs->next, req, private); } + +/* cancel - called to cancel an outstanding async request */ +NTSTATUS ntvfs_next_cancel(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req) +{ + if (!ntvfs->next || !ntvfs->next->ops->cancel) { + return NT_STATUS_NOT_IMPLEMENTED; + } + return ntvfs->next->ops->cancel(ntvfs->next, req); +} diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 8ad6ad0389..2c0f55cf22 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -556,7 +556,6 @@ static NTSTATUS pvfs_open_setup_retry(struct smbsrv_request *req, } talloc_free(lck); - talloc_steal(pvfs, req); talloc_set_destructor(r, pvfs_retry_destructor); diff --git a/source4/ntvfs/posix/pvfs_wait.c b/source4/ntvfs/posix/pvfs_wait.c index 0faab8ef55..df7f045e00 100644 --- a/source4/ntvfs/posix/pvfs_wait.c +++ b/source4/ntvfs/posix/pvfs_wait.c @@ -22,10 +22,13 @@ #include "include/includes.h" #include "events.h" +#include "dlinklist.h" #include "vfs_posix.h" /* the context for a single wait instance */ struct pvfs_wait { + struct pvfs_wait *next, *prev; + struct pvfs_state *pvfs; void (*handler)(void *, BOOL); void *private; struct timed_event *te; @@ -103,6 +106,7 @@ static int pvfs_wait_destructor(void *ptr) struct pvfs_wait *pwait = ptr; messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait); event_remove_timed(pwait->ev, pwait->te); + DLIST_REMOVE(pwait->pvfs->wait_list, pwait); return 0; } @@ -134,6 +138,7 @@ void *pvfs_wait_message(struct pvfs_state *pvfs, pwait->ev = req->tcon->smb_conn->connection->event.ctx; pwait->msg_type = msg_type; pwait->req = req; + pwait->pvfs = pvfs; /* setup a timer */ te.next_event = end_time; @@ -152,8 +157,34 @@ void *pvfs_wait_message(struct pvfs_state *pvfs, asynchronously */ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; + DLIST_ADD(pvfs->wait_list, pwait); + /* make sure we cleanup the timer and message handler */ talloc_set_destructor(pwait, pvfs_wait_destructor); + /* make sure that on a disconnect the request is not destroyed + before pvfs */ + talloc_steal(pvfs, req); + return pwait; } + + +/* + cancel an outstanding async request +*/ +NTSTATUS pvfs_cancel(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req) +{ + struct pvfs_state *pvfs = ntvfs->private_data; + struct pvfs_wait *pwait; + 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()); + return NT_STATUS_OK; + } + } + + return NT_STATUS_UNSUCCESSFUL; +} diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index 7ebea2ea9a..9ad1d3cb35 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -236,6 +236,7 @@ NTSTATUS ntvfs_posix_init(void) ops.trans = pvfs_trans; ops.logoff = pvfs_logoff; ops.async_setup = pvfs_async_setup; + ops.cancel = pvfs_cancel; /* register ourselves with the NTVFS subsystem. We register under the name 'default' as we wish to be the default diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index 265649f5a3..ce6e7ad24d 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -46,6 +46,10 @@ struct pvfs_state { /* an id tree mapping open file handle -> struct pvfs_file */ struct idr_context *idtree_fnum; + + /* a list of pending async requests. Needed to support + ntcancel */ + struct pvfs_wait *wait_list; }; diff --git a/source4/ntvfs/simple/vfs_simple.c b/source4/ntvfs/simple/vfs_simple.c index 97dd8a7d60..807f51a43d 100644 --- a/source4/ntvfs/simple/vfs_simple.c +++ b/source4/ntvfs/simple/vfs_simple.c @@ -608,6 +608,14 @@ static NTSTATUS svfs_async_setup(struct ntvfs_module_context *ntvfs, return NT_STATUS_OK; } +/* + cancel an async call +*/ +static NTSTATUS svfs_cancel(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req) +{ + return NT_STATUS_UNSUCCESSFUL; +} + /* lock a byte range */ @@ -668,6 +676,10 @@ static NTSTATUS svfs_setfileinfo(struct ntvfs_module_context *ntvfs, return NT_STATUS_ACCESS_DENIED; } break; + default: + DEBUG(2,("svfs_setfileinfo: level %d not implemented\n", + info->generic.level)); + return NT_STATUS_NOT_IMPLEMENTED; } return NT_STATUS_OK; } @@ -986,6 +998,7 @@ NTSTATUS ntvfs_simple_init(void) ops.trans = svfs_trans; ops.logoff = svfs_logoff; ops.async_setup = svfs_async_setup; + ops.cancel = svfs_cancel; /* register ourselves with the NTVFS subsystem. We register under names 'simple' diff --git a/source4/ntvfs/unixuid/vfs_unixuid.c b/source4/ntvfs/unixuid/vfs_unixuid.c index 9b62c38e13..7f8f8acf99 100644 --- a/source4/ntvfs/unixuid/vfs_unixuid.c +++ b/source4/ntvfs/unixuid/vfs_unixuid.c @@ -640,6 +640,19 @@ static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs, return status; } +/* + cancel an async request +*/ +static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req) +{ + NTSTATUS status; + + PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req)); + + return status; +} + /* lock a byte range */ @@ -784,6 +797,7 @@ NTSTATUS ntvfs_unixuid_init(void) ops.trans = unixuid_trans; ops.logoff = unixuid_logoff; ops.async_setup = unixuid_async_setup; + ops.cancel = unixuid_cancel; ops.name = "unixuid"; diff --git a/source4/script/tests/test_posix.sh b/source4/script/tests/test_posix.sh index e2cad84306..c31d4b70ea 100755 --- a/source4/script/tests/test_posix.sh +++ b/source4/script/tests/test_posix.sh @@ -37,12 +37,12 @@ tests="$tests BASE-DELETE BASE-PROPERTIES BASE-MANGLE" tests="$tests BASE-CHKPATH BASE-SECLEAK BASE-TRANS2" tests="$tests BASE-NTDENY1 BASE-NTDENY2 BASE-RENAME" tests="$tests RAW-QFSINFO RAW-QFILEINFO RAW-SFILEINFO-BUG" -tests="$tests RAW-LOCK RAW-MKDIR RAW-SEEK RAW-CONTEXT" +tests="$tests RAW-LOCK RAW-MKDIR RAW-SEEK RAW-CONTEXT RAW-MUX" tests="$tests RAW-UNLINK RAW-READ RAW-CLOSE RAW-IOCTL RAW-SEARCH RAW-CHKPATH" tests="$tests LOCAL-ICONV LOCAL-TALLOC LOCAL-MESSAGING LOCAL-BINDING LOCAL-IDTREE" soon="BASE-DENY1 BASE-DEFER_OPEN BASE-OPENATTR BASE-CHARSET" -soon="$soon RAW-SFILEINFO RAW-OPEN RAW-OPLOCK RAW-NOTIFY RAW-MUX" +soon="$soon RAW-SFILEINFO RAW-OPEN RAW-OPLOCK RAW-NOTIFY" soon="$soon RAW-WRITE RAW-RENAME" for t in $tests; do diff --git a/source4/smb_server/reply.c b/source4/smb_server/reply.c index 9c7d027f4a..615dd692a1 100644 --- a/source4/smb_server/reply.c +++ b/source4/smb_server/reply.c @@ -2319,7 +2319,9 @@ void reply_ntcreate_and_X(struct smbsrv_request *req) ****************************************************************************/ void reply_ntcancel(struct smbsrv_request *req) { - req_reply_error(req, NT_STATUS_FOOBAR); + /* NOTE: this request does not generate a reply */ + ntvfs_cancel(req); + req_destroy(req); } /**************************************************************************** diff --git a/source4/torture/raw/mux.c b/source4/torture/raw/mux.c index c02045817e..7dddd0602c 100644 --- a/source4/torture/raw/mux.c +++ b/source4/torture/raw/mux.c @@ -252,6 +252,10 @@ static BOOL test_mux_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) /* cancel the blocking lock */ smb_raw_ntcancel(req); + /* the 2nd cancel is totally harmless, but tests the server trying to + cancel an already cancelled request */ + smb_raw_ntcancel(req); + lock[0].pid = 1; io.lockx.in.ulock_cnt = 1; io.lockx.in.lock_cnt = 0; -- cgit