summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-11-04 11:28:38 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:05:28 -0500
commitc870ae8b898d3bcc81ed9fd1afd505d78dea52cc (patch)
tree6e83b98a6c0a1ce2ac594f9f84ad539ee436a9d7
parent92cac50045398b2d45ac45dd0d53eed3c41d4d00 (diff)
downloadsamba-c870ae8b898d3bcc81ed9fd1afd505d78dea52cc.tar.gz
samba-c870ae8b898d3bcc81ed9fd1afd505d78dea52cc.tar.bz2
samba-c870ae8b898d3bcc81ed9fd1afd505d78dea52cc.zip
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)
-rw-r--r--source4/ntvfs/cifs/vfs_cifs.c10
-rw-r--r--source4/ntvfs/common/brlock.c15
-rw-r--r--source4/ntvfs/ipc/vfs_ipc.c10
-rw-r--r--source4/ntvfs/nbench/vfs_nbench.c20
-rw-r--r--source4/ntvfs/ntvfs.h4
-rw-r--r--source4/ntvfs/ntvfs_generic.c3
-rw-r--r--source4/ntvfs/ntvfs_interface.c24
-rw-r--r--source4/ntvfs/posix/pvfs_open.c1
-rw-r--r--source4/ntvfs/posix/pvfs_wait.c31
-rw-r--r--source4/ntvfs/posix/vfs_posix.c1
-rw-r--r--source4/ntvfs/posix/vfs_posix.h4
-rw-r--r--source4/ntvfs/simple/vfs_simple.c13
-rw-r--r--source4/ntvfs/unixuid/vfs_unixuid.c14
-rwxr-xr-xsource4/script/tests/test_posix.sh4
-rw-r--r--source4/smb_server/reply.c4
-rw-r--r--source4/torture/raw/mux.c4
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
@@ -651,6 +651,15 @@ static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
}
/*
+ 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
*/
static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
@@ -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
@@ -520,6 +520,15 @@ static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs,
}
/*
+ 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
*/
static NTSTATUS ipc_lock(struct ntvfs_module_context *ntvfs,
@@ -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
@@ -609,6 +609,14 @@ static NTSTATUS svfs_async_setup(struct ntvfs_module_context *ntvfs,
}
/*
+ 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
*/
static NTSTATUS svfs_lock(struct ntvfs_module_context *ntvfs,
@@ -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
@@ -641,6 +641,19 @@ static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
}
/*
+ 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
*/
static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
@@ -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;