r3540: added testing of SMBntcancel in the open/open/close mux
authorAndrew Tridgell <tridge@samba.org>
Fri, 5 Nov 2004 02:22:07 +0000 (02:22 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:05:30 +0000 (13:05 -0500)
testing. Interestingly, w2k3 does not allow the cancel of an
outstanding async open request, whereas it does allow the cancel of an
outstanding async lock request. To support this I have changed the
pvfs_wait interface to provide a enum on why the event is happening,
so the callback can decide what to do.
(This used to be commit f23d6a28008a13588cde24b5012ec21e488ac47a)

source4/ntvfs/posix/pvfs_lock.c
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_wait.c
source4/ntvfs/posix/vfs_posix.h
source4/torture/raw/mux.c

index 82ac9ebad574adb240f151274b8ace4eb56c9f85..f778b59d950eb02c3ed5a85cad7ac5e173fcec07 100644 (file)
@@ -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;
 
index 73b1949acbdcba07cc9102d09901e8043a45c570..c8f96849ecece53089bf5516e60a84abd46a5247 100644 (file)
@@ -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);
index df7f045e00d33f945aceb06436ed9abf6d985f81..dd7afaf6532bfb0191927427bee1ee69c8b7679c 100644 (file)
 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;
                }
        }
index e0d8e7fe3796b5837495fd7821ca844e7f73956c..4ee06723ac50109205ada990e3d95e76d0d1f775 100644 (file)
@@ -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_ */
index 6f9426490eb8c9ba9cc871071142e37f3370ddf0..39eb5c1d5e0734855f38e9cd5cf1bd867d42b03b 100644 (file)
@@ -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: