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;
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;
/*
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;
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);
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;
};
/*
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;
}
*(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
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);
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;
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;
}
}
/* 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_ */
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;
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);
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);
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);
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: