diff options
Diffstat (limited to 'source4/ntvfs')
-rw-r--r-- | source4/ntvfs/common/brlock.c | 272 | ||||
-rw-r--r-- | source4/ntvfs/posix/config.mk | 1 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_lock.c | 186 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 6 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_wait.c | 128 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.c | 3 |
6 files changed, 561 insertions, 35 deletions
diff --git a/source4/ntvfs/common/brlock.c b/source4/ntvfs/common/brlock.c index 0eb644e943..792ee52ad5 100644 --- a/source4/ntvfs/common/brlock.c +++ b/source4/ntvfs/common/brlock.c @@ -27,12 +27,6 @@ #include "includes.h" -struct brl_context { - struct tdb_wrap *w; - servid_t server; - uint16_t tid; -}; - /* in this module a "DATA_BLOB *file_key" is a blob that uniquely identifies a file. For a local posix filesystem this will usually be a combination @@ -60,13 +54,25 @@ struct lock_struct { uint64_t size; uint16_t fnum; enum brl_type lock_type; + void *notify_ptr; +}; + +struct brl_context { + struct tdb_wrap *w; + servid_t server; + uint16_t tid; + void *messaging_ctx; + struct lock_struct last_lock_failure; }; + /* Open up the brlock.tdb database. Close it down using - talloc_free() + talloc_free(). We need the messaging_ctx to allow for + pending lock notifications. */ -void *brl_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid) +void *brl_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid, + void *messaging_ctx) { char *path; struct brl_context *brl; @@ -88,6 +94,8 @@ void *brl_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid) brl->server = server; brl->tid = tid; + brl->messaging_ctx = messaging_ctx; + ZERO_STRUCT(brl->last_lock_failure); return (void *)brl; } @@ -104,11 +112,30 @@ static BOOL brl_same_context(struct lock_context *ctx1, struct lock_context *ctx } /* + see if lck1 and lck2 overlap +*/ +static BOOL brl_overlap(struct lock_struct *lck1, + struct lock_struct *lck2) +{ + if (lck1->start >= (lck2->start + lck2->size) || + lck2->start >= (lck1->start + lck1->size)) { + return False; + } + return True; +} + +/* See if lock2 can be added when lock1 is in place. */ static BOOL brl_conflict(struct lock_struct *lck1, struct lock_struct *lck2) { + /* pending locks don't conflict with anything */ + if (lck1->lock_type >= PENDING_READ_LOCK || + lck2->lock_type >= PENDING_READ_LOCK) { + return False; + } + if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) { return False; } @@ -118,12 +145,7 @@ static BOOL brl_conflict(struct lock_struct *lck1, return False; } - if (lck1->start >= (lck2->start + lck2->size) || - lck2->start >= (lck1->start + lck1->size)) { - return False; - } - - return True; + return brl_overlap(lck1, lck2); } @@ -133,32 +155,68 @@ static BOOL brl_conflict(struct lock_struct *lck1, */ static BOOL brl_conflict_other(struct lock_struct *lck1, struct lock_struct *lck2) { + /* pending locks don't conflict with anything */ + if (lck1->lock_type >= PENDING_READ_LOCK || + lck2->lock_type >= PENDING_READ_LOCK) { + return False; + } + if (lck1->lock_type == READ_LOCK && lck2->lock_type == READ_LOCK) return False; + /* + * note that incoming write calls conflict with existing READ + * locks even if the context is the same. JRA. See LOCKTEST7 + * in smbtorture. + */ if (brl_same_context(&lck1->context, &lck2->context) && - lck1->fnum == lck2->fnum) { + lck1->fnum == lck2->fnum && + (lck2->lock_type == READ_LOCK || lck1->lock_type == WRITE_LOCK)) { return False; } - if (lck1->start >= (lck2->start + lck2->size) || - lck2->start >= (lck1->start + lck1->size)) - return False; - - return True; + return brl_overlap(lck1, lck2); } +/* + amazingly enough, w2k3 "remembers" whether the last lock failure + is the same as this one and changes its error code. I wonder if any + app depends on this? +*/ +static NTSTATUS brl_lock_failed(struct brl_context *brl, struct lock_struct *lock) +{ + if (brl_same_context(&lock->context, &brl->last_lock_failure.context) && + lock->fnum == brl->last_lock_failure.fnum && + lock->start == brl->last_lock_failure.start && + lock->size == brl->last_lock_failure.size) { + return NT_STATUS_FILE_LOCK_CONFLICT; + } + brl->last_lock_failure = *lock; + if (lock->start >= 0xEF000000) { + /* amazing the little things you learn with a test + suite. Locks beyond this offset (as a 64 bit + number!) always generate the conflict error + code. */ + return NT_STATUS_FILE_LOCK_CONFLICT; + } + return NT_STATUS_LOCK_NOT_GRANTED; +} /* - Lock a range of bytes. + Lock a range of bytes. The lock_type can be a PENDING_*_LOCK, in + which case a real lock is first tried, and if that fails then a + pending lock is created. When the pending lock is triggered (by + someone else closing an overlapping lock range) a messaging + notification is sent, identified by the notify_ptr */ NTSTATUS brl_lock(void *brl_ctx, DATA_BLOB *file_key, uint16_t smbpid, uint16_t fnum, uint64_t start, uint64_t size, - enum brl_type lock_type) + enum brl_type lock_type, + void *notify_ptr) { struct brl_context *brl = brl_ctx; TDB_DATA kbuf, dbuf; @@ -174,6 +232,20 @@ NTSTATUS brl_lock(void *brl_ctx, return NT_STATUS_INTERNAL_DB_CORRUPTION; } + /* if this is a pending lock, then with the chainlock held we + try to get the real lock. If we succeed then we don't need + to make it pending. This prevents a possible race condition + where the pending lock gets created after the lock that is + preventing the real lock gets removed */ + if (lock_type >= PENDING_READ_LOCK) { + enum brl_type rw = (lock_type==PENDING_READ_LOCK? READ_LOCK : WRITE_LOCK); + status = brl_lock(brl_ctx, file_key, smbpid, fnum, start, size, rw, NULL); + if (NT_STATUS_IS_OK(status)) { + tdb_chainunlock(brl->w->tdb, kbuf); + return NT_STATUS_OK; + } + } + dbuf = tdb_fetch(brl->w->tdb, kbuf); lock.context.smbpid = smbpid; @@ -183,6 +255,7 @@ NTSTATUS brl_lock(void *brl_ctx, lock.size = size; lock.fnum = fnum; lock.lock_type = lock_type; + lock.notify_ptr = notify_ptr; if (dbuf.dptr) { /* there are existing locks - make sure they don't conflict */ @@ -190,7 +263,7 @@ NTSTATUS brl_lock(void *brl_ctx, count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { if (brl_conflict(&locks[i], &lock)) { - status = NT_STATUS_LOCK_NOT_GRANTED; + status = brl_lock_failed(brl, &lock); goto fail; } } @@ -214,6 +287,14 @@ NTSTATUS brl_lock(void *brl_ctx, free(dbuf.dptr); tdb_chainunlock(brl->w->tdb, kbuf); + + /* the caller needs to know if the real lock was granted. If + we have reached here then it must be a pending lock that + was granted, so tell them the lock failed */ + if (lock_type >= PENDING_READ_LOCK) { + return brl_lock_failed(brl, &lock); + } + return NT_STATUS_OK; fail: @@ -225,6 +306,57 @@ NTSTATUS brl_lock(void *brl_ctx, /* + we are removing a lock that might be holding up a pending lock. Scan for pending + locks that cover this range and if we find any then notify the server that it should + retry the lock +*/ +static void brl_notify_unlock(struct brl_context *brl, + struct lock_struct *locks, int count, + struct lock_struct *removed_lock) +{ + int i, last_notice; + + /* the last_notice logic is to prevent stampeding on a lock + range. It prevents us sending hundreds of notifies on the + same range of bytes. It doesn't prevent all possible + stampedes, but it does prevent the most common problem */ + last_notice = -1; + + for (i=0;i<count;i++) { + if (locks[i].lock_type >= PENDING_READ_LOCK && + brl_overlap(&locks[i], removed_lock)) { + DATA_BLOB data; + + if (last_notice != -1 && brl_overlap(&locks[i], &locks[last_notice])) { + continue; + } + last_notice = i; + data.data = (void *)&locks[i].notify_ptr; + data.length = sizeof(void *); + messaging_send(brl->messaging_ctx, locks[i].context.server, MSG_BRL_RETRY, &data); + } + } +} + + +/* + send notifications for all pending locks - the file is being closed by this + user +*/ +static void brl_notify_all(struct brl_context *brl, + struct lock_struct *locks, int count) +{ + int i; + for (i=0;i<count;i++) { + if (locks->lock_type >= PENDING_READ_LOCK) { + brl_notify_unlock(brl, locks, count, &locks[i]); + } + } +} + + + +/* Unlock a range of bytes. */ NTSTATUS brl_unlock(void *brl_ctx, @@ -261,15 +393,92 @@ NTSTATUS brl_unlock(void *brl_ctx, locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); - locks = (struct lock_struct *)dbuf.dptr; - count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (brl_same_context(&lock->context, &context) && lock->fnum == fnum && lock->start == start && - lock->size == size) { + lock->size == size && + lock->notify_ptr == NULL) { + /* found it - delete it */ + if (count == 1) { + if (tdb_delete(brl->w->tdb, kbuf) != 0) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto fail; + } + } else { + struct lock_struct removed_lock = *lock; + if (i < count-1) { + memmove(&locks[i], &locks[i+1], + sizeof(*locks)*((count-1) - i)); + } + count--; + + /* send notifications for any relevant pending locks */ + brl_notify_unlock(brl, locks, count, &removed_lock); + + dbuf.dsize = count * sizeof(*locks); + + if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto fail; + } + } + + free(dbuf.dptr); + tdb_chainunlock(brl->w->tdb, kbuf); + return NT_STATUS_OK; + } + } + + /* we didn't find it */ + status = NT_STATUS_RANGE_NOT_LOCKED; + + fail: + free(dbuf.dptr); + tdb_chainunlock(brl->w->tdb, kbuf); + return status; +} + + +/* + remove a pending lock. This is called when the caller has either + given up trying to establish a lock or when they have succeeded in + getting it. In either case they no longer need to be notified. +*/ +NTSTATUS brl_remove_pending(void *brl_ctx, + DATA_BLOB *file_key, + void *notify_ptr) +{ + struct brl_context *brl = brl_ctx; + TDB_DATA kbuf, dbuf; + int count, i; + struct lock_struct *locks; + NTSTATUS status; + + kbuf.dptr = file_key->data; + kbuf.dsize = file_key->length; + + if (tdb_chainlock(brl->w->tdb, kbuf) != 0) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + dbuf = tdb_fetch(brl->w->tdb, kbuf); + if (!dbuf.dptr) { + tdb_chainunlock(brl->w->tdb, kbuf); + return NT_STATUS_RANGE_NOT_LOCKED; + } + + /* there are existing locks - find a match */ + locks = (struct lock_struct *)dbuf.dptr; + count = dbuf.dsize / sizeof(*locks); + + for (i=0; i<count; i++) { + struct lock_struct *lock = &locks[i]; + + if (lock->notify_ptr == notify_ptr && + lock->context.server == brl->server) { /* found it - delete it */ if (count == 1) { if (tdb_delete(brl->w->tdb, kbuf) != 0) { @@ -281,7 +490,8 @@ NTSTATUS brl_unlock(void *brl_ctx, memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } - dbuf.dsize -= sizeof(*locks); + count--; + dbuf.dsize = count * sizeof(*locks); if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) { status = NT_STATUS_INTERNAL_DB_CORRUPTION; goto fail; @@ -404,7 +614,13 @@ NTSTATUS brl_close(void *brl_ctx, status = NT_STATUS_INTERNAL_DB_CORRUPTION; } } else if (dcount != 0) { - dbuf.dsize -= dcount * sizeof(*locks); + /* tell all pending lock holders for this file that + they have a chance now. This is a bit indiscriminant, + but works OK */ + brl_notify_all(brl, locks, count); + + dbuf.dsize = count * sizeof(*locks); + if (tdb_store(brl->w->tdb, kbuf, dbuf, TDB_REPLACE) != 0) { status = NT_STATUS_INTERNAL_DB_CORRUPTION; } diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk index 8ca5ad7b0b..b6ba073a99 100644 --- a/source4/ntvfs/posix/config.mk +++ b/source4/ntvfs/posix/config.mk @@ -21,6 +21,7 @@ ADD_OBJ_FILES = \ ntvfs/posix/pvfs_resolve.o \ ntvfs/posix/pvfs_shortname.o \ ntvfs/posix/pvfs_lock.o \ + ntvfs/posix/pvfs_wait.o \ ntvfs/common/brlock.o # End MODULE ntvfs_posix ################################################ diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c index d7aca9df8b..548c5bd82c 100644 --- a/source4/ntvfs/posix/pvfs_lock.c +++ b/source4/ntvfs/posix/pvfs_lock.c @@ -44,6 +44,153 @@ NTSTATUS pvfs_check_lock(struct pvfs_state *pvfs, offset, count, rw); } +/* this state structure holds information about a lock we are waiting on */ +struct pending_state { + struct pvfs_state *pvfs; + union smb_lock *lck; + struct pvfs_file *f; + struct smbsrv_request *req; + int pending_lock; + void *wait_handle; + time_t end_time; +}; + + +/* + a secondary attempt to setup a lock has failed - back out + the locks we did get and send an error +*/ +static void pvfs_lock_async_failed(struct pvfs_state *pvfs, + struct smbsrv_request *req, + struct pvfs_file *f, + struct smb_lock_entry *locks, + int i, + NTSTATUS status) +{ + /* undo the locks we just did */ + for (i=i-1;i>=0;i--) { + brl_unlock(pvfs->brl_context, + &f->locking_key, + locks[i].pid, + f->fnum, + locks[i].offset, + locks[i].count); + } + req->async.status = status; + req->async.send_fn(req); +} + + +/* + called when we receive a pending lock notification. It means that + either our lock timed out or somoene else has unlocked a overlapping + 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) +{ + struct pending_state *pending = private; + struct pvfs_state *pvfs = pending->pvfs; + struct pvfs_file *f = pending->f; + struct smbsrv_request *req = pending->req; + union smb_lock *lck = pending->lck; + struct smb_lock_entry *locks; + enum brl_type rw; + NTSTATUS status; + int i; + + locks = lck->lockx.in.locks + lck->lockx.in.ulock_cnt; + + if (lck->lockx.in.mode & LOCKING_ANDX_SHARED_LOCK) { + rw = READ_LOCK; + } else { + rw = WRITE_LOCK; + } + + status = brl_lock(pvfs->brl_context, + &f->locking_key, + req->smbpid, + f->fnum, + locks[pending->pending_lock].offset, + locks[pending->pending_lock].count, + rw, NULL); + + /* if we have failed and timed out, or succeeded, then we + don't need the pending lock any more */ + if (NT_STATUS_IS_OK(status) || timed_out) { + NTSTATUS status2; + status2 = brl_remove_pending(pvfs->brl_context, &f->locking_key, pending); + if (!NT_STATUS_IS_OK(status2)) { + DEBUG(0,("pvfs_lock: failed to remove pending lock - %s\n", nt_errstr(status2))); + } + talloc_free(pending->wait_handle); + } + + if (!NT_STATUS_IS_OK(status)) { + if (timed_out) { + /* no more chances */ + pvfs_lock_async_failed(pvfs, req, f, locks, pending->pending_lock, status); + } + /* we can try again */ + return; + } + + /* if we haven't timed out yet, then we can do more pending locks */ + if (timed_out) { + pending = NULL; + } else { + if (rw == READ_LOCK) { + rw = PENDING_READ_LOCK; + } else { + rw = PENDING_WRITE_LOCK; + } + } + + /* 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++) { + if (pending) { + pending->pending_lock = i; + } + + status = brl_lock(pvfs->brl_context, + &f->locking_key, + req->smbpid, + f->fnum, + locks[i].offset, + locks[i].count, + rw, pending); + if (!NT_STATUS_IS_OK(status)) { + if (pending) { + /* a timed lock failed - setup a wait message to handle + the pending lock notification or a timeout */ + pending->wait_handle = pvfs_wait_message(pvfs, req, MSG_BRL_RETRY, + pending->end_time, + pvfs_pending_lock_continue, + pending); + if (pending->wait_handle == NULL) { + pvfs_lock_async_failed(pvfs, req, f, locks, i, NT_STATUS_NO_MEMORY); + } + return; + } + pvfs_lock_async_failed(pvfs, req, f, locks, i, status); + return; + } + } + + 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); +} + + /* lock or unlock a byte range */ @@ -55,6 +202,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, struct smb_lock_entry *locks; int i; enum brl_type rw; + struct pending_state *pending = NULL; f = pvfs_find_fd(pvfs, req, lck->generic.in.fnum); if (!f) { @@ -69,7 +217,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, f->fnum, lck->lock.in.offset, lck->lock.in.count, - WRITE_LOCK); + WRITE_LOCK, NULL); case RAW_LOCK_UNLOCK: return brl_unlock(pvfs->brl_context, @@ -88,11 +236,25 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, } /* now the lockingX case, most common and also most complex */ + if (lck->lockx.in.timeout != 0) { + pending = talloc_p(req, struct pending_state); + if (pending == NULL) { + return NT_STATUS_NO_MEMORY; + } + + pending->pvfs = pvfs; + pending->lck = lck; + pending->f = f; + pending->req = req; + + /* round up to the nearest second */ + pending->end_time = time(NULL) + ((lck->lockx.in.timeout+999)/1000); + } if (lck->lockx.in.mode & LOCKING_ANDX_SHARED_LOCK) { - rw = READ_LOCK; + rw = pending? PENDING_READ_LOCK : READ_LOCK; } else { - rw = WRITE_LOCK; + rw = pending? PENDING_WRITE_LOCK : WRITE_LOCK; } if (lck->lockx.in.mode & @@ -125,14 +287,30 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, for (i=0;i<lck->lockx.in.lock_cnt;i++) { NTSTATUS status; + if (pending) { + pending->pending_lock = i; + } + status = brl_lock(pvfs->brl_context, &f->locking_key, locks[i].pid, f->fnum, locks[i].offset, locks[i].count, - rw); + rw, pending); if (!NT_STATUS_IS_OK(status)) { + if (pending) { + /* a timed lock failed - setup a wait message to handle + the pending lock notification or a timeout */ + pending->wait_handle = pvfs_wait_message(pvfs, req, MSG_BRL_RETRY, + pending->end_time, + pvfs_pending_lock_continue, + pending); + if (pending->wait_handle == NULL) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; + } /* undo the locks we just did */ for (i=i-1;i>=0;i--) { brl_unlock(pvfs->brl_context, diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 51526461e0..5798aa782f 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -96,9 +96,11 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, flags = O_CREAT | O_TRUNC; break; case NTCREATEX_DISP_OPEN: - case NTCREATEX_DISP_OVERWRITE: flags = 0; break; + case NTCREATEX_DISP_OVERWRITE: + flags = O_TRUNC; + break; case NTCREATEX_DISP_CREATE: flags = O_CREAT | O_EXCL; break; @@ -222,7 +224,7 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs, if (!NT_STATUS_IS_OK(status)) { return status; } - + if (close(f->fd) != 0) { status = pvfs_map_errno(pvfs, errno); } else { diff --git a/source4/ntvfs/posix/pvfs_wait.c b/source4/ntvfs/posix/pvfs_wait.c new file mode 100644 index 0000000000..1d6da6aaf8 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_wait.c @@ -0,0 +1,128 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - async request wait routines + + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "include/includes.h" +#include "vfs_posix.h" + +/* the context for a single wait instance */ +struct pvfs_wait { + void (*handler)(void *, BOOL); + void *private; + struct timed_event *te; + int msg_type; + void *msg_ctx; + struct event_context *ev; +}; + + +/* + receive a completion message for a wait +*/ +static void pvfs_wait_dispatch(void *msg_ctx, void *private, uint32_t msg_type, + servid_t src, DATA_BLOB *data) +{ + struct pvfs_wait *pwait = private; + + /* we need to check that this one is for us. This sender sends + the private pointer as the body of the message. This might + seem a little unusual, but as the pointer is guaranteed + unique for this server, it is a good token */ + if (data->length != sizeof(void *) || + *(void **)data->data != pwait->private) { + return; + } + + pwait->handler(pwait->private, False); +} + + +/* + receive a timeout on a message wait +*/ +static void pvfs_wait_timeout(struct event_context *ev, struct timed_event *te, time_t t) +{ + struct pvfs_wait *pwait = te->private; + pwait->handler(pwait->private, True); +} + + +/* + destroy a pending wait + */ +static int pvfs_wait_destructor(void *ptr) +{ + struct pvfs_wait *pwait = ptr; + messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait->private); + event_remove_timed(pwait->ev, pwait->te); + return 0; +} + +/* + setup a request to wait on a message of type msg_type, with a + timeout (given as an expiry time) + + the return value is a handle. To stop waiting talloc_free this + handle. +*/ +void *pvfs_wait_message(struct pvfs_state *pvfs, + struct smbsrv_request *req, + int msg_type, + time_t end_time, + void (*fn)(void *, BOOL), + void *private) +{ + struct timed_event te; + struct pvfs_wait *pwait; + + pwait = talloc_p(req, struct pvfs_wait); + if (pwait == NULL) { + return NULL; + } + + pwait->private = private; + pwait->handler = fn; + pwait->msg_ctx = pvfs->tcon->smb_conn->connection->messaging_ctx; + pwait->ev = req->tcon->smb_conn->connection->event.ctx; + pwait->msg_type = msg_type; + + /* setup a timer */ + te.next_event = end_time; + te.handler = pvfs_wait_timeout; + te.private = pwait; + pwait->te = event_add_timed(pwait->ev, &te); + + /* register with the messaging subsystem for this message + type */ + messaging_register(pwait->msg_ctx, + pwait, + msg_type, + pvfs_wait_dispatch); + + /* tell the main smb server layer that we will be replying + asynchronously */ + req->control_flags |= REQ_CONTROL_ASYNC; + + /* make sure we cleanup the timer and message handler */ + talloc_set_destructor(pwait, pvfs_wait_destructor); + + return pwait; +} diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index 5e7a605c9f..6e6c8b4275 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -89,7 +89,8 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, pvfs->brl_context = brl_init(pvfs, pvfs->tcon->smb_conn->connection->server_id, - pvfs->tcon->service); + pvfs->tcon->service, + pvfs->tcon->smb_conn->connection->messaging_ctx); if (pvfs->brl_context == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } |