#undef DBGC_CLASS
#define DBGC_CLASS DBGC_LOCKING
-/****************************************************************************
- Determine if this is a secondary element of a chained SMB.
- **************************************************************************/
-
static void received_unlock_msg(struct messaging_context *msg,
void *private_data,
uint32_t msg_type,
(int)from_now.tv_sec, (int)from_now.tv_usec));
}
- sconn->smb1.locks.brl_timeout = tevent_add_timer(sconn->ev_ctx,
+ /*
+ * brl_timeout_fn() calls change_to_root_user()
+ * so we can use sconn->root_ev_ctx.
+ */
+ sconn->smb1.locks.brl_timeout = tevent_add_timer(sconn->root_ev_ctx,
NULL, next_timeout,
brl_timeout_fn, sconn);
if (sconn->smb1.locks.brl_timeout == NULL) {
lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
blr->lock_flav,
True,
- NULL,
- blr);
+ NULL);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd);
blr->req = talloc_move(blr, &req);
- DLIST_ADD_END(sconn->smb1.locks.blocking_lock_queue, blr, struct blocking_lock_record *);
+ DLIST_ADD_END(sconn->smb1.locks.blocking_lock_queue, blr);
recalc_brl_timeout(sconn);
/* Ensure we'll receive messages when this is unlocked. */
* that here and must set up the chain info manually.
*/
- if (!srv_send_smb(req->sconn,
+ if (!srv_send_smb(req->xconn,
(char *)req->outbuf,
true, req->seqnum+1,
IS_CONN_ENCRYPTED(req->conn)||req->encrypted,
}
reply_nterror(blr->req, status);
- if (!srv_send_smb(blr->req->sconn, (char *)blr->req->outbuf,
+ if (!srv_send_smb(blr->req->xconn, (char *)blr->req->outbuf,
true, blr->req->seqnum+1,
blr->req->encrypted, NULL)) {
exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
static void undo_locks_obtained(struct blocking_lock_record *blr)
{
files_struct *fsp = blr->fsp;
- uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
+ uint16_t num_ulocks = SVAL(blr->req->vwv+6, 0);
uint64_t count = (uint64_t)0, offset = (uint64_t) 0;
uint64_t smblctx;
unsigned char locktype = CVAL(blr->req->vwv+3, 0);
*/
for(i = blr->lock_num - 1; i >= 0; i--) {
- bool err;
smblctx = get_lock_pid( data, i, large_file_format);
count = get_lock_count( data, i, large_file_format);
- offset = get_lock_offset( data, i, large_file_format, &err);
+ offset = get_lock_offset( data, i, large_file_format);
/*
* We know err cannot be set as if it was the lock
*/
SCVAL(blr->req->outbuf,smb_com,SMBtrans2);
- if (!srv_send_smb(blr->req->sconn,
+ if (!srv_send_smb(blr->req->xconn,
(char *)blr->req->outbuf,
true, blr->req->seqnum+1,
IS_CONN_ENCRYPTED(blr->fsp->conn),
}
}
+/****************************************************************************
+ Utility function that returns true if a lock timed out.
+*****************************************************************************/
+
+static bool lock_timed_out(const struct blocking_lock_record *blr)
+{
+ struct timeval tv_curr;
+
+ if (timeval_is_zero(&blr->expire_time)) {
+ return false; /* Never times out. */
+ }
+
+ tv_curr = timeval_current();
+ if (timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
+ return true;
+ }
+ return false;
+}
+
/****************************************************************************
Attempt to finish off getting all pending blocking locks for a lockingX call.
Returns True if we want to be removed from the list.
{
unsigned char locktype = CVAL(blr->req->vwv+3, 0);
files_struct *fsp = blr->fsp;
- uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
- uint16 num_locks = SVAL(blr->req->vwv+7, 0);
- uint64_t count = (uint64_t)0, offset = (uint64_t)0;
- uint64_t smblctx;
+ uint16_t num_ulocks = SVAL(blr->req->vwv+6, 0);
+ uint16_t num_locks = SVAL(blr->req->vwv+7, 0);
bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
uint8_t *data;
NTSTATUS status = NT_STATUS_OK;
+ bool lock_timeout = lock_timed_out(blr);
data = discard_const_p(uint8_t, blr->req->buf)
+ ((large_file_format ? 20 : 10)*num_ulocks);
for(; blr->lock_num < num_locks; blr->lock_num++) {
struct byte_range_lock *br_lck = NULL;
- bool err;
- smblctx = get_lock_pid( data, blr->lock_num, large_file_format);
- count = get_lock_count( data, blr->lock_num, large_file_format);
- offset = get_lock_offset( data, blr->lock_num, large_file_format, &err);
+ /*
+ * Ensure the blr record gets updated with
+ * any lock we might end up blocked on.
+ */
+
+ blr->smblctx = get_lock_pid( data, blr->lock_num, large_file_format);
+ blr->count = get_lock_count( data, blr->lock_num, large_file_format);
+ blr->offset = get_lock_offset( data, blr->lock_num, large_file_format);
/*
* We know err cannot be set as if it was the lock
errno = 0;
br_lck = do_lock(fsp->conn->sconn->msg_ctx,
fsp,
- smblctx,
- count,
- offset,
+ blr->smblctx,
+ blr->count,
+ blr->offset,
((locktype & LOCKING_ANDX_SHARED_LOCK) ?
READ_LOCK : WRITE_LOCK),
WINDOWS_LOCK,
True,
&status,
- &blr->blocking_smblctx,
- blr);
+ &blr->blocking_smblctx);
+
+ if (ERROR_WAS_LOCK_DENIED(status) && !lock_timeout) {
+ /*
+ * If we didn't timeout, but still need to wait,
+ * re-add the pending lock entry whilst holding
+ * the brlock db lock.
+ */
+ NTSTATUS status1 =
+ brl_lock(blr->fsp->conn->sconn->msg_ctx,
+ br_lck,
+ blr->smblctx,
+ messaging_server_id(
+ blr->fsp->conn->sconn->msg_ctx),
+ blr->offset,
+ blr->count,
+ blr->lock_type == READ_LOCK ?
+ PENDING_READ_LOCK :
+ PENDING_WRITE_LOCK,
+ blr->lock_flav,
+ true, /* Blocking lock. */
+ NULL);
+
+ if (!NT_STATUS_IS_OK(status1)) {
+ DEBUG(0,("failed to add PENDING_LOCK "
+ "record.\n"));
+ }
+ }
TALLOC_FREE(br_lck);
return True;
}
- if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
- !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
+ if (!ERROR_WAS_LOCK_DENIED(status)) {
/*
* We have other than a "can't get lock"
* error. Free any locks we had and return an error.
return True;
}
+ /*
+ * Return an error to the client if we timed out.
+ */
+ if (lock_timeout) {
+ blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
+ return true;
+ }
+
/*
* Still can't get all the locks - keep waiting.
*/
{
char params[2];
NTSTATUS status;
+ bool lock_timeout = lock_timed_out(blr);
+
struct byte_range_lock *br_lck = do_lock(
blr->fsp->conn->sconn->msg_ctx,
blr->fsp,
blr->lock_flav,
True,
&status,
- &blr->blocking_smblctx,
- blr);
+ &blr->blocking_smblctx);
+ if (ERROR_WAS_LOCK_DENIED(status) && !lock_timeout) {
+ /*
+ * If we didn't timeout, but still need to wait,
+ * re-add the pending lock entry whilst holding
+ * the brlock db lock.
+ */
+ NTSTATUS status1 =
+ brl_lock(blr->fsp->conn->sconn->msg_ctx,
+ br_lck,
+ blr->smblctx,
+ messaging_server_id(
+ blr->fsp->conn->sconn->msg_ctx),
+ blr->offset,
+ blr->count,
+ blr->lock_type == READ_LOCK ?
+ PENDING_READ_LOCK :
+ PENDING_WRITE_LOCK,
+ blr->lock_flav,
+ true, /* Blocking lock. */
+ NULL);
+
+ if (!NT_STATUS_IS_OK(status1)) {
+ DEBUG(0,("failed to add PENDING_LOCK record.\n"));
+ }
+ }
+
TALLOC_FREE(br_lck);
if (!NT_STATUS_IS_OK(status)) {
if (ERROR_WAS_LOCK_DENIED(status)) {
+ if (lock_timeout) {
+ /*
+ * Return an error if we timed out
+ * and return true to get dequeued.
+ */
+ blocking_lock_reply_error(blr,
+ NT_STATUS_FILE_LOCK_CONFLICT);
+ return true;
+ }
/* Still can't get the lock, just keep waiting. */
return False;
}
messaging_server_id(sconn->msg_ctx),
blr->offset,
blr->count,
- blr->lock_flav,
- blr);
+ blr->lock_flav);
/* We're closing the file fsp here, so ensure
* we don't have a dangling pointer. */
messaging_server_id(sconn->msg_ctx),
blr->offset,
blr->count,
- blr->lock_flav,
- blr);
+ blr->lock_flav);
TALLOC_FREE(br_lck);
}
void process_blocking_lock_queue(struct smbd_server_connection *sconn)
{
- struct timeval tv_curr = timeval_current();
struct blocking_lock_record *blr, *next = NULL;
if (sconn->using_smb2) {
- process_blocking_lock_queue_smb2(sconn, tv_curr);
+ process_blocking_lock_queue_smb2(sconn, timeval_current());
return;
}
*/
for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) {
+ struct byte_range_lock *br_lck = NULL;
next = blr->next;
DEBUG(10, ("Processing BLR = %p\n", blr));
- /* We use set_current_service so connections with
- * pending locks are not marked as idle.
+ /*
+ * Connections with pending locks are not marked as idle.
*/
-
- set_current_service(blr->fsp->conn,
- SVAL(blr->req->inbuf,smb_flg),
- false);
-
- 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->smblctx,
- messaging_server_id(sconn->msg_ctx),
- blr->offset,
- blr->count,
- blr->lock_flav,
- blr);
- TALLOC_FREE(br_lck);
- }
-
- DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
- TALLOC_FREE(blr);
- continue;
- }
+ blr->fsp->conn->lastused_count++;
/*
- * We couldn't get the locks for this record on the list.
- * If the time has expired, return a lock error.
+ * Remove the pending lock we're waiting on.
+ * If we need to keep waiting blocking_lock_record_process()
+ * will re-add it.
*/
- if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
- 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.
- */
+ br_lck = brl_get_locks(talloc_tos(), blr->fsp);
+ if (br_lck) {
+ brl_lock_cancel(br_lck,
+ blr->smblctx,
+ messaging_server_id(sconn->msg_ctx),
+ blr->offset,
+ blr->count,
+ blr->lock_flav);
+ }
+ TALLOC_FREE(br_lck);
- if (br_lck) {
- DEBUG(5,("process_blocking_lock_queue: "
- "pending lock for %s, file %s "
- "timed out.\n", fsp_fnum_dbg(blr->fsp),
- fsp_str_dbg(blr->fsp)));
+ if(!blocking_lock_record_process(blr)) {
+ DEBUG(10, ("still waiting for lock. BLR = %p\n", blr));
+ continue;
+ }
- brl_lock_cancel(br_lck,
- blr->smblctx,
- messaging_server_id(sconn->msg_ctx),
- blr->offset,
- blr->count,
- blr->lock_flav,
- blr);
- TALLOC_FREE(br_lck);
- }
+ DEBUG(10, ("BLR_process returned true: removing BLR = %p\n",
+ blr));
- blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
- DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
- TALLOC_FREE(blr);
- }
+ DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr);
+ TALLOC_FREE(blr);
}
recalc_brl_timeout(sconn);
messaging_send_buf(sconn->msg_ctx, messaging_server_id(sconn->msg_ctx),
MSG_SMB_BLOCKING_LOCK_CANCEL,
- (uint8 *)&msg, sizeof(msg));
+ (uint8_t *)&msg, sizeof(msg));
return blr;
}