summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorZack Kirsch <zack.kirsch@isilon.com>2009-02-09 21:51:29 -0800
committerJeremy Allison <jra@samba.org>2009-02-13 10:08:40 -0800
commit813273c87e4f48d7d8415c8ee9a1a553ed369429 (patch)
tree2f6140e3f75d987f437ff93a291a4e8e14117d1b /source3/smbd
parenteb3d964f20f44deaf2b4f07adba64785875710e0 (diff)
downloadsamba-813273c87e4f48d7d8415c8ee9a1a553ed369429.tar.gz
samba-813273c87e4f48d7d8415c8ee9a1a553ed369429.tar.bz2
samba-813273c87e4f48d7d8415c8ee9a1a553ed369429.zip
Add VFS ops for Windows BRL: Lock, Unlock and Cancel:
This patch adds 3 new VFS OPs for Windows byte range locking: BRL_LOCK_WINDOWS, BRL_UNLOCK_WINDOWS and BRL_CANCEL_WINDOWS. Specifically: * I renamed brl_lock_windows, brl_unlock_windows and brl_lock_cancel to *_default as the default implementations of the VFS ops. * The blocking_lock_record (BLR) is now passed into the brl_lock_windows and brl_cancel_windows paths. The Onefs implementation uses it - future implementations may find it useful too. * Created brl_lock_cancel to do what brl_lock/brl_unlock do: set up a lock_struct and call either the Posix or Windows lock function. These happen to be the same for the default implementation. * Added helper functions: increment_current_lock_count() and decrement_current_lock_count(). * Minor spelling correction in brl_timeout_fn: brl -> blr. * Changed blocking_lock_cancel() to return the BLR that it has cancelled. This allows us to assert its the lock that we wanted to cancel. If this assert ever fires, this path will need to take in the BLR to cancel, rather than choosing on its own. * Adds a small helper function: find_blocking_lock_record_by_id(). Used by the OneFS implementation, but could be useful for others.
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/blocking.c107
-rw-r--r--source3/smbd/reply.c18
-rw-r--r--source3/smbd/trans2.c3
3 files changed, 75 insertions, 53 deletions
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c
index 33aa748cdc..42849931f3 100644
--- a/source3/smbd/blocking.c
+++ b/source3/smbd/blocking.c
@@ -24,26 +24,6 @@
#define DBGC_CLASS DBGC_LOCKING
/****************************************************************************
- This is the structure to queue to implement blocking locks.
- notify. It consists of the requesting SMB and the expiry time.
-*****************************************************************************/
-
-struct blocking_lock_record {
- struct blocking_lock_record *next;
- struct blocking_lock_record *prev;
- files_struct *fsp;
- struct timeval expire_time;
- int lock_num;
- uint64_t offset;
- uint64_t count;
- uint32_t lock_pid;
- uint32_t blocking_pid; /* PID that blocks us. */
- enum brl_flavour lock_flav;
- enum brl_type lock_type;
- struct smb_request *req;
-};
-
-/****************************************************************************
Determine if this is a secondary element of a chained SMB.
**************************************************************************/
@@ -52,7 +32,6 @@ static void received_unlock_msg(struct messaging_context *msg,
uint32_t msg_type,
struct server_id server_id,
DATA_BLOB *data);
-static void process_blocking_lock_queue(void);
static void brl_timeout_fn(struct event_context *event_ctx,
struct timed_event *te,
@@ -82,14 +61,14 @@ static bool recalc_brl_timeout(void)
next_timeout = timeval_zero();
- for (brl = blocking_lock_queue; brl; brl = brl->next) {
- if (timeval_is_zero(&brl->expire_time)) {
+ for (blr = blocking_lock_queue; blr; blr = blr->next) {
+ if (timeval_is_zero(&blr->expire_time)) {
/*
* If we're blocked on pid 0xFFFFFFFF this is
* a POSIX lock, so calculate a timeout of
* 10 seconds into the future.
*/
- if (brl->blocking_pid == 0xFFFFFFFF) {
+ if (blr->blocking_pid == 0xFFFFFFFF) {
struct timeval psx_to = timeval_current_ofs(10, 0);
next_timeout = timeval_min(&next_timeout, &psx_to);
}
@@ -98,18 +77,28 @@ static bool recalc_brl_timeout(void)
}
if (timeval_is_zero(&next_timeout)) {
- next_timeout = brl->expire_time;
+ next_timeout = blr->expire_time;
}
else {
next_timeout = timeval_min(&next_timeout,
- &brl->expire_time);
+ &blr->expire_time);
}
}
if (timeval_is_zero(&next_timeout)) {
+ DEBUG(10, ("Next timeout = Infinite.\n"));
return True;
}
+ if (DEBUGLVL(10)) {
+ struct timeval cur, from_now;
+
+ cur = timeval_current();
+ from_now = timeval_until(&cur, &next_timeout);
+ DEBUG(10, ("Next timeout = %d.%d seconds from now.\n",
+ (int)from_now.tv_sec, (int)from_now.tv_usec));
+ }
+
if (!(brl_timeout = event_add_timed(smbd_event_context(), NULL,
next_timeout,
brl_timeout_fn, NULL))) {
@@ -173,9 +162,13 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
blr->lock_type = lock_type;
blr->offset = offset;
blr->count = count;
+
+ /* Specific brl_lock() implementations can fill this in. */
+ blr->blr_private = NULL;
/* Add a pending lock record for this. */
- status = brl_lock(smbd_messaging_context(), br_lck,
+ status = brl_lock(smbd_messaging_context(),
+ br_lck,
lock_pid,
procid_self(),
offset,
@@ -183,11 +176,11 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck,
lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
blr->lock_flav,
lock_timeout ? True : False, /* blocking_lock. */
- NULL);
+ NULL,
+ blr);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
- DLIST_REMOVE(blocking_lock_queue, blr);
TALLOC_FREE(blr);
return False;
}
@@ -332,6 +325,8 @@ static void reply_lockingX_error(struct blocking_lock_record *blr, NTSTATUS stat
static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status)
{
+ DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr));
+
switch(blr->req->cmd) {
case SMBlockingX:
reply_lockingX_error(blr, status);
@@ -409,7 +404,8 @@ static bool process_lockingX(struct blocking_lock_record *blr)
WINDOWS_LOCK,
True,
&status,
- &blr->blocking_pid);
+ &blr->blocking_pid,
+ blr);
TALLOC_FREE(br_lck);
@@ -470,7 +466,8 @@ static bool process_trans2(struct blocking_lock_record *blr)
blr->lock_flav,
True,
&status,
- &blr->blocking_pid);
+ &blr->blocking_pid,
+ blr);
TALLOC_FREE(br_lck);
if (!NT_STATUS_IS_OK(status)) {
@@ -521,7 +518,7 @@ static bool blocking_lock_record_process(struct blocking_lock_record *blr)
void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
{
- struct blocking_lock_record *blr, *next = NULL;
+ struct blocking_lock_record *blr, *blr_cancelled, *next = NULL;
for(blr = blocking_lock_queue; blr; blr = next) {
unsigned char locktype = 0;
@@ -539,14 +536,7 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo
"request type %d for file %s fnum = %d\n",
blr->req->cmd, fsp->fsp_name, fsp->fnum));
- brl_lock_cancel(br_lck,
- blr->lock_pid,
- procid_self(),
- blr->offset,
- blr->count,
- blr->lock_flav);
-
- blocking_lock_cancel(fsp,
+ blr_cancelled = blocking_lock_cancel(fsp,
blr->lock_pid,
blr->offset,
blr->count,
@@ -554,6 +544,16 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo
locktype,
NT_STATUS_RANGE_NOT_LOCKED);
+ SMB_ASSERT(blr_cancelled == blr);
+
+ brl_lock_cancel(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav,
+ blr);
+
/* We're closing the file fsp here, so ensure
* we don't have a dangling pointer. */
blr->fsp = NULL;
@@ -592,7 +592,8 @@ void remove_pending_lock_requests_by_mid(int mid)
procid_self(),
blr->offset,
blr->count,
- blr->lock_flav);
+ blr->lock_flav,
+ blr);
TALLOC_FREE(br_lck);
}
@@ -637,7 +638,7 @@ static void received_unlock_msg(struct messaging_context *msg,
Process the blocking lock queue. Note that this is only called as root.
*****************************************************************************/
-static void process_blocking_lock_queue(void)
+void process_blocking_lock_queue(void)
{
struct timeval tv_curr = timeval_current();
struct blocking_lock_record *blr, *next = NULL;
@@ -657,17 +658,23 @@ static void process_blocking_lock_queue(void)
* and False if we still need to wait.
*/
+ DEBUG(10, ("Processing BLR = %p\n", blr));
+
if(blocking_lock_record_process(blr)) {
struct byte_range_lock *br_lck = brl_get_locks(
talloc_tos(), blr->fsp);
+ DEBUG(10, ("BLR_process returned true: cancelling and "
+ "removing lock. BLR = %p\n", blr));
+
if (br_lck) {
brl_lock_cancel(br_lck,
blr->lock_pid,
procid_self(),
blr->offset,
blr->count,
- blr->lock_flav);
+ blr->lock_flav,
+ blr);
TALLOC_FREE(br_lck);
}
@@ -686,6 +693,8 @@ static void process_blocking_lock_queue(void)
struct byte_range_lock *br_lck = brl_get_locks(
talloc_tos(), blr->fsp);
+ DEBUG(10, ("Lock timed out! BLR = %p\n", blr));
+
/*
* Lock expired - throw away all previously
* obtained locks and return lock error.
@@ -702,7 +711,8 @@ static void process_blocking_lock_queue(void)
procid_self(),
blr->offset,
blr->count,
- blr->lock_flav);
+ blr->lock_flav,
+ blr);
TALLOC_FREE(br_lck);
}
@@ -757,9 +767,10 @@ static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
/****************************************************************************
Send ourselves a blocking lock cancelled message. Handled asynchronously above.
+ Returns the blocking_lock_record that is being cancelled.
*****************************************************************************/
-bool blocking_lock_cancel(files_struct *fsp,
+struct blocking_lock_record *blocking_lock_cancel(files_struct *fsp,
uint32 lock_pid,
uint64_t offset,
uint64_t count,
@@ -790,14 +801,14 @@ bool blocking_lock_cancel(files_struct *fsp,
}
if (!blr) {
- return False;
+ return NULL;
}
/* Check the flags are right. */
if (blr->req->cmd == SMBlockingX &&
(locktype & LOCKING_ANDX_LARGE_FILES) !=
(CVAL(blr->req->vwv+3, 0) & LOCKING_ANDX_LARGE_FILES)) {
- return False;
+ return NULL;
}
/* Move to cancelled queue. */
@@ -812,5 +823,5 @@ bool blocking_lock_cancel(files_struct *fsp,
MSG_SMB_BLOCKING_LOCK_CANCEL,
(uint8 *)&msg, sizeof(msg));
- return True;
+ return blr;
}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 256160c402..1ed5e7229e 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3040,6 +3040,7 @@ void reply_lockread(struct smb_request *req)
WINDOWS_LOCK,
False, /* Non-blocking lock. */
&status,
+ NULL,
NULL);
TALLOC_FREE(br_lck);
@@ -4514,6 +4515,7 @@ void reply_lock(struct smb_request *req)
WINDOWS_LOCK,
False, /* Non-blocking lock. */
&status,
+ NULL,
NULL);
TALLOC_FREE(br_lck);
@@ -6904,6 +6906,9 @@ void reply_lockingX(struct smb_request *req)
offset,
WINDOWS_LOCK);
+ DEBUG(10, ("reply_lockingX: unlock returned %s\n",
+ nt_errstr(status)));
+
if (NT_STATUS_V(status)) {
END_PROFILE(SMBlockingX);
reply_nterror(req, status);
@@ -6945,19 +6950,22 @@ void reply_lockingX(struct smb_request *req)
fsp->fsp_name, (int)lock_timeout ));
if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
+ struct blocking_lock_record *blr;
+
if (lp_blocking_locks(SNUM(conn))) {
/* Schedule a message to ourselves to
remove the blocking lock record and
return the right error. */
- if (!blocking_lock_cancel(fsp,
+ blr = blocking_lock_cancel(fsp,
lock_pid,
offset,
count,
WINDOWS_LOCK,
locktype,
- NT_STATUS_FILE_LOCK_CONFLICT)) {
+ NT_STATUS_FILE_LOCK_CONFLICT);
+ if (blr == NULL) {
END_PROFILE(SMBlockingX);
reply_nterror(
req,
@@ -6972,7 +6980,8 @@ void reply_lockingX(struct smb_request *req)
lock_pid,
count,
offset,
- WINDOWS_LOCK);
+ WINDOWS_LOCK,
+ blr);
} else {
bool blocking_lock = lock_timeout ? True : False;
bool defer_lock = False;
@@ -6988,7 +6997,8 @@ void reply_lockingX(struct smb_request *req)
WINDOWS_LOCK,
blocking_lock,
&status,
- &block_smbpid);
+ &block_smbpid,
+ NULL);
if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
/* Windows internal resolution for blocking locks seems
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index cea066e97f..759e520866 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -5628,7 +5628,8 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
POSIX_LOCK,
blocking_lock,
&status,
- &block_smbpid);
+ &block_smbpid,
+ NULL);
if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
/*