From 384f87bd38c1133c90e2a57775f139532574e3cc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 18 Oct 2004 11:47:13 +0000 Subject: r3034: - fixed a bug in message dispatch, when the dispatch function called messaging_deregister() - added a pvfs_lock_close_pending() hook to remove pending locks on file close - fixed the private ptr argument to messaging_deregister() in pvfs_wait - fixed a bug in continuing lock requests after a lock that is blocking a pending lock is removed - removed bogus brl_unlock() call in lock continue - corrected error code for LOCKING_ANDX_CHANGE_LOCKTYPE - expanded the lock cancel test suite to test lock cancel by unlock and by close - added a testsuite for LOCKING_ANDX_CHANGE_LOCKTYPE (This used to be commit 5ef80f034d4aa4dd6810532c63ad041bfc019cb8) --- source4/lib/messaging/messaging.c | 5 +- source4/ntvfs/posix/pvfs_lock.c | 46 +++++++++---- source4/ntvfs/posix/pvfs_open.c | 4 ++ source4/ntvfs/posix/pvfs_wait.c | 2 +- source4/torture/raw/lock.c | 131 +++++++++++++++++++++++++++++++++++++- 5 files changed, 171 insertions(+), 17 deletions(-) (limited to 'source4') diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c index e78ec83b4b..b0ca9cc41e 100644 --- a/source4/lib/messaging/messaging.c +++ b/source4/lib/messaging/messaging.c @@ -95,8 +95,9 @@ static char *messaging_path(TALLOC_CTX *mem_ctx, servid_t server_id) */ static void messaging_dispatch(struct messaging_state *msg, struct messaging_rec *rec) { - struct dispatch_fn *d; - for (d=msg->dispatch;d;d=d->next) { + struct dispatch_fn *d, *next; + for (d=msg->dispatch;d;d=next) { + next = d->next; if (d->msg_type == rec->header.msg_type) { d->fn(msg, d->private, d->msg_type, rec->header.from, &rec->data); } diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c index 100fc50e55..ead1371ebc 100644 --- a/source4/ntvfs/posix/pvfs_lock.c +++ b/source4/ntvfs/posix/pvfs_lock.c @@ -152,7 +152,7 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out) /* we've now got the pending lock. try and get the rest, which might lead to more pending locks */ - for (i=pending->pending_lock;ilockx.in.lock_cnt;i++) { + for (i=pending->pending_lock+1;ilockx.in.lock_cnt;i++) { if (pending) { pending->pending_lock = i; } @@ -184,19 +184,36 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out) } } - brl_unlock(pvfs->brl_context, - &f->locking_key, - req->smbpid, - f->fnum, - lck->lock.in.offset, - lck->lock.in.count); - /* we've managed to get all the locks. Tell the client */ req->async.status = NT_STATUS_OK; req->async.send_fn(req); } +/* + called when we close a file that might have pending locks +*/ +void pvfs_lock_close_pending(struct pvfs_state *pvfs, struct pvfs_file *f) +{ + struct pvfs_pending_lock *p, *next; + NTSTATUS status; + + for (p=f->pending_list;p;p=next) { + next = p->next; + DLIST_REMOVE(f->pending_list, p); + status = brl_remove_pending(pvfs->brl_context, &f->locking_key, p); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("pvfs_lock_close_pending: failed to remove pending lock - %s\n", + nt_errstr(status))); + } + talloc_free(p->wait_handle); + p->req->async.status = NT_STATUS_RANGE_NOT_LOCKED; + p->req->async.send_fn(p->req); + } + +} + + /* cancel a set of locks */ @@ -303,11 +320,14 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, return pvfs_lock_cancel(pvfs, req, lck, f); } - if (lck->lockx.in.mode & - (LOCKING_ANDX_OPLOCK_RELEASE | - LOCKING_ANDX_CHANGE_LOCKTYPE | - LOCKING_ANDX_CANCEL_LOCK)) { - /* todo: need to add support for these */ + if (lck->lockx.in.mode & LOCKING_ANDX_CHANGE_LOCKTYPE) { + /* this seems to not be supported by any windows server, + or used by any clients */ + return NT_STATUS_UNSUCCESSFUL; + } + + if (lck->lockx.in.mode & LOCKING_ANDX_OPLOCK_RELEASE) { + DEBUG(0,("received unexpected oplock break\n")); return NT_STATUS_NOT_IMPLEMENTED; } diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 05c2bdda28..429f519bca 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -52,6 +52,8 @@ static int pvfs_fd_destructor(void *p) { struct pvfs_file *f = p; + pvfs_lock_close_pending(f->pvfs, f); + brl_close(f->pvfs->brl_context, &f->locking_key, f->fnum); if (f->fd != -1) { @@ -221,6 +223,8 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } + pvfs_lock_close_pending(pvfs, f); + status = brl_close(pvfs->brl_context, &f->locking_key, f->fnum); if (!NT_STATUS_IS_OK(status)) { return status; diff --git a/source4/ntvfs/posix/pvfs_wait.c b/source4/ntvfs/posix/pvfs_wait.c index 1d6da6aaf8..5815b8edde 100644 --- a/source4/ntvfs/posix/pvfs_wait.c +++ b/source4/ntvfs/posix/pvfs_wait.c @@ -71,7 +71,7 @@ static void pvfs_wait_timeout(struct event_context *ev, struct timed_event *te, static int pvfs_wait_destructor(void *ptr) { struct pvfs_wait *pwait = ptr; - messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait->private); + messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait); event_remove_timed(pwait->ev, pwait->te); return 0; } diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c index 0059846180..9e7a15f1dc 100644 --- a/source4/torture/raw/lock.c +++ b/source4/torture/raw/lock.c @@ -460,7 +460,7 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) return False; } - printf("Testing lock cancel\n"); + printf("Testing LOCKING_ANDX_CANCEL_LOCK\n"); io.generic.level = RAW_LOCK_LOCKX; fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); @@ -485,6 +485,8 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) t = time(NULL); + printf("testing cancel by CANCEL_LOCK\n"); + /* setup a timed lock */ io.lockx.in.timeout = 10000; req = smb_raw_lock_send(cli->tree, &io); @@ -525,6 +527,132 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) goto done; } + printf("testing cancel by unlock\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.timeout = 5000; + req = smb_raw_lock_send(cli->tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = False; + goto done; + } + + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_OK); + + if (time(NULL) > t+2) { + printf("lock cancel by unlock was not immediate (%s)\n", __location__); + ret = False; + goto done; + } + + + printf("testing cancel by close\n"); + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + io.lockx.in.timeout = 10000; + req = smb_raw_lock_send(cli->tree, &io); + if (req == NULL) { + printf("Failed to setup timed lock (%s)\n", __location__); + ret = False; + goto done; + } + + smbcli_close(cli->tree, fnum); + + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED); + + if (time(NULL) > t+2) { + printf("lock cancel by unlock was not immediate (%s)\n", __location__); + ret = False; + goto done; + } + + +done: + smbcli_close(cli->tree, fnum); + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + + +/* + test LOCKING_ANDX_CHANGE_LOCKTYPE +*/ +static BOOL test_changetype(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) +{ + union smb_lock io; + struct smb_lock_entry lock[2]; + NTSTATUS status; + BOOL ret = True; + int fnum; + char c = 0; + const char *fname = BASEDIR "\\test.txt"; + + if (smbcli_deltree(cli->tree, BASEDIR) == -1 || + NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) { + printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree)); + return False; + } + + printf("Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n"); + io.generic.level = RAW_LOCK_LOCKX; + + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + if (fnum == -1) { + printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); + ret = False; + goto done; + } + + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) { + printf("allowed write on read locked region (%s)\n", __location__); + ret = False; + goto done; + } + + /* windows server don't seem to support this */ + io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL); + + if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) { + printf("allowed write after lock change (%s)\n", __location__); + ret = False; + goto done; + } + done: smbcli_close(cli->tree, fnum); smb_raw_exit(cli->session); @@ -552,6 +680,7 @@ BOOL torture_raw_lock(int dummy) ret &= test_lock(cli, mem_ctx); ret &= test_pidhigh(cli, mem_ctx); ret &= test_async(cli, mem_ctx); + ret &= test_changetype(cli, mem_ctx); torture_close_connection(cli); talloc_destroy(mem_ctx); -- cgit