r3034: - fixed a bug in message dispatch, when the dispatch function called messagin...
authorAndrew Tridgell <tridge@samba.org>
Mon, 18 Oct 2004 11:47:13 +0000 (11:47 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:00:00 +0000 (13:00 -0500)
 - 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

source/lib/messaging/messaging.c
source/ntvfs/posix/pvfs_lock.c
source/ntvfs/posix/pvfs_open.c
source/ntvfs/posix/pvfs_wait.c
source/torture/raw/lock.c

index e78ec83b4b1a757d5e2e5eb746a0c5cae4c1ac33..b0ca9cc41e3c7f9800fd75e32fde37159d660ef2 100644 (file)
@@ -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);
                }
index 100fc50e55609932ec7b4115268e2b00e68644ec..ead1371ebc1e58b5e29521ef51f840d1381b3cac 100644 (file)
@@ -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;i<lck->lockx.in.lock_cnt;i++) {            
+       for (i=pending->pending_lock+1;i<lck->lockx.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;
        }
 
index 05c2bdda28b9876f7be78784b33e76580ee3372f..429f519bcad21b5fcbc20efce0a0ba9a50d9f6e0 100644 (file)
@@ -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;
index 1d6da6aaf815157afb5d7dac88d1bc972b343d93..5815b8eddead4cd9d34b56981965b9e26a854b82 100644 (file)
@@ -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;
 }
index 005984618073c6bfd8c1ac51d8d09f5e0760df3a..9e7a15f1dcf815bfd3a0de11eb4489db2e2b9e58 100644 (file)
@@ -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);