mirror of
https://github.com/samba-team/samba.git
synced 2025-08-03 04:22:09 +03:00
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 5ef80f034d
)
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
a03a7d0aea
commit
384f87bd38
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user