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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_LOCKING
+extern int max_send;
+
/****************************************************************************
This is the structure to queue to implement blocking locks.
notify. It consists of the requesting SMB and the expiry time.
SMB_BIG_UINT offset;
SMB_BIG_UINT count;
uint32 lock_pid;
+ uint32 blocking_pid; /* PID that blocks us. */
enum brl_flavour lock_flav;
enum brl_type lock_type;
char *inbuf;
/* dlink list we move cancelled lock records onto. */
static blocking_lock_record *blocking_lock_cancelled_queue;
+/* The event that makes us process our blocking lock queue */
+static struct timed_event *brl_timeout;
+
/****************************************************************************
Destructor for the above structure.
****************************************************************************/
return (chain_size != 0);
}
-static void received_unlock_msg(int msg_type, struct process_id src,
- void *buf, size_t len);
+static void received_unlock_msg(struct messaging_context *msg,
+ void *private_data,
+ 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,
+ const struct timeval *now,
+ void *private_data)
+{
+ SMB_ASSERT(brl_timeout == te);
+ TALLOC_FREE(brl_timeout);
+
+ change_to_root_user(); /* TODO: Possibly run all timed events as
+ * root */
+
+ process_blocking_lock_queue();
+}
+
+/****************************************************************************
+ After a change to blocking_lock_queue, recalculate the timed_event for the
+ next processing.
+****************************************************************************/
+
+static BOOL recalc_brl_timeout(void)
+{
+ blocking_lock_record *brl;
+ struct timeval next_timeout;
+
+ TALLOC_FREE(brl_timeout);
+
+ next_timeout = timeval_zero();
+
+ for (brl = blocking_lock_queue; brl; brl = brl->next) {
+ if (timeval_is_zero(&brl->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) {
+ struct timeval psx_to = timeval_current_ofs(10, 0);
+ next_timeout = timeval_min(&next_timeout, &psx_to);
+ }
+
+ continue;
+ }
+
+ if (timeval_is_zero(&next_timeout)) {
+ next_timeout = brl->expire_time;
+ }
+ else {
+ next_timeout = timeval_min(&next_timeout,
+ &brl->expire_time);
+ }
+ }
+
+ if (timeval_is_zero(&next_timeout)) {
+ return True;
+ }
+
+ if (!(brl_timeout = event_add_timed(smbd_event_context(), NULL,
+ next_timeout, "brl_timeout",
+ brl_timeout_fn, NULL))) {
+ return False;
+ }
+
+ return True;
+}
+
/****************************************************************************
Function to push a blocking lock request onto the lock queue.
uint32 lock_pid,
enum brl_type lock_type,
enum brl_flavour lock_flav,
- SMB_BIG_UINT offset, SMB_BIG_UINT count)
+ SMB_BIG_UINT offset,
+ SMB_BIG_UINT count,
+ uint32 blocking_pid)
{
static BOOL set_lock_msg;
blocking_lock_record *blr;
}
blr->lock_num = lock_num;
blr->lock_pid = lock_pid;
+ blr->blocking_pid = blocking_pid;
blr->lock_flav = lock_flav;
blr->lock_type = lock_type;
blr->offset = offset;
blr->length = length;
/* Add a pending lock record for this. */
- status = brl_lock(br_lck,
+ status = brl_lock(smbd_messaging_context(), br_lck,
lock_pid,
procid_self(),
offset,
count,
lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
blr->lock_flav,
- lock_timeout ? True : False); /* blocking_lock. */
+ lock_timeout ? True : False, /* blocking_lock. */
+ NULL);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
}
DLIST_ADD_END(blocking_lock_queue, blr, blocking_lock_record *);
+ recalc_brl_timeout();
/* Ensure we'll receive messages when this is unlocked. */
if (!set_lock_msg) {
- message_register(MSG_SMB_UNLOCK, received_unlock_msg);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_UNLOCK, received_unlock_msg);
set_lock_msg = True;
}
Return a smd with a given size.
*****************************************************************************/
-static void send_blocking_reply(char *outbuf, int outsize)
+static void send_blocking_reply(char *outbuf, int outsize, const char *inbuf)
{
- if(outsize > 4)
- smb_setlen(outbuf,outsize - 4);
+ if(outsize > 4) {
+ smb_setlen(inbuf, outbuf,outsize - 4);
+ }
- if (!send_smb(smbd_server_fd(),outbuf))
- exit_server("send_blocking_reply: send_smb failed.");
+ if (!send_smb(smbd_server_fd(),outbuf)) {
+ exit_server_cleanly("send_blocking_reply: send_smb failed.");
+ }
}
/****************************************************************************
int outsize = 0;
construct_reply_common(inbuf, outbuf);
- set_message(outbuf,2,0,True);
+ set_message(inbuf,outbuf,2,0,True);
/*
* As this message is a lockingX call we must handle
outsize += chain_size;
- send_blocking_reply(outbuf,outsize);
+ send_blocking_reply(outbuf,outsize,inbuf);
}
/****************************************************************************
ERROR_NT(status);
if (!send_smb(smbd_server_fd(),outbuf)) {
- exit_server("generic_blocking_lock_error: send_smb failed.");
+ exit_server_cleanly("generic_blocking_lock_error: send_smb failed.");
}
}
* request would never have been queued. JRA.
*/
- do_unlock(fsp,
+ do_unlock(smbd_messaging_context(),
+ fsp,
lock_pid,
count,
offset,
SCVAL(outbuf,smb_com,SMBtrans2);
ERROR_NT(status);
if (!send_smb(smbd_server_fd(),outbuf)) {
- exit_server("blocking_lock_reply_error: send_smb failed.");
+ exit_server_cleanly("blocking_lock_reply_error: send_smb failed.");
}
break;
}
* request would never have been queued. JRA.
*/
errno = 0;
- br_lck = do_lock(fsp,
+ br_lck = do_lock(smbd_messaging_context(),
+ fsp,
lock_pid,
count,
offset,
READ_LOCK : WRITE_LOCK),
WINDOWS_LOCK,
True,
- &status);
+ &status,
+ &blr->blocking_pid);
TALLOC_FREE(br_lck);
static BOOL process_trans2(blocking_lock_record *blr)
{
- extern int max_send;
char *inbuf = blr->inbuf;
char *outbuf;
char params[2];
NTSTATUS status;
- struct byte_range_lock *br_lck = do_lock(blr->fsp,
+ struct byte_range_lock *br_lck = do_lock(smbd_messaging_context(),
+ blr->fsp,
blr->lock_pid,
blr->count,
blr->offset,
blr->lock_type,
blr->lock_flav,
True,
- &status);
+ &status,
+ &blr->blocking_pid);
TALLOC_FREE(br_lck);
if (!NT_STATUS_IS_OK(status)) {
SCVAL(outbuf,smb_com,SMBtrans2);
SSVAL(params,0,0);
/* Fake up max_data_bytes here - we know it fits. */
- send_trans2_replies(outbuf, max_send, params, 2, NULL, 0, 0xffff);
+ send_trans2_replies(inbuf, outbuf, max_send, params, 2, NULL, 0, 0xffff);
return True;
}
}
/****************************************************************************
- Set a flag as an unlock request affects one of our pending locks.
+ Is this mid a blocking lock request on the queue ?
*****************************************************************************/
-static void received_unlock_msg(int msg_type, struct process_id src,
- void *buf, size_t len)
+BOOL blocking_lock_was_deferred(int mid)
{
- DEBUG(10,("received_unlock_msg\n"));
- process_blocking_lock_queue();
+ blocking_lock_record *blr, *next = NULL;
+
+ for(blr = blocking_lock_queue; blr; blr = next) {
+ next = blr->next;
+ if(SVAL(blr->inbuf,smb_mid) == mid) {
+ return True;
+ }
+ }
+ return False;
}
/****************************************************************************
- Return the number of milliseconds to the next blocking locks timeout, or default_timeout
+ Set a flag as an unlock request affects one of our pending locks.
*****************************************************************************/
-unsigned int blocking_locks_timeout_ms(unsigned int default_timeout_ms)
+static void received_unlock_msg(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
{
- unsigned int timeout_ms = default_timeout_ms;
- struct timeval tv_curr;
- SMB_BIG_INT min_tv_dif_us = 0x7FFFFFFF; /* A large +ve number. */
- blocking_lock_record *blr = blocking_lock_queue;
-
- /* note that we avoid the GetTimeOfDay() syscall if there are no blocking locks */
- if (!blr) {
- return timeout_ms;
- }
-
- tv_curr = timeval_current();
-
- for (; blr; blr = blr->next) {
- SMB_BIG_INT tv_dif_us;
-
- if (timeval_is_zero(&blr->expire_time)) {
- continue; /* Never timeout. */
- }
-
- tv_dif_us = usec_time_diff(&blr->expire_time, &tv_curr);
- min_tv_dif_us = MIN(min_tv_dif_us, tv_dif_us);
- }
-
- if (min_tv_dif_us < 0) {
- min_tv_dif_us = 0;
- }
-
- timeout_ms = (unsigned int)(min_tv_dif_us / (SMB_BIG_INT)1000);
-
- if (timeout_ms < 1) {
- timeout_ms = 1;
- }
-
- DEBUG(10,("blocking_locks_timeout_ms: returning %u\n", timeout_ms));
-
- return timeout_ms;
+ DEBUG(10,("received_unlock_msg\n"));
+ process_blocking_lock_queue();
}
/****************************************************************************
Process the blocking lock queue. Note that this is only called as root.
*****************************************************************************/
-void process_blocking_lock_queue(void)
+static void process_blocking_lock_queue(void)
{
struct timeval tv_curr = timeval_current();
blocking_lock_record *blr, *next = NULL;
+ BOOL recalc_timeout = False;
/*
* Go through the queue and see if we can get any of the locks.
blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT);
DLIST_REMOVE(blocking_lock_queue, blr);
free_blocking_lock_record(blr);
+ recalc_timeout = True;
continue;
}
blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
DLIST_REMOVE(blocking_lock_queue, blr);
free_blocking_lock_record(blr);
+ recalc_timeout = True;
continue;
}
blocking_lock_reply_error(blr,NT_STATUS_ACCESS_DENIED);
DLIST_REMOVE(blocking_lock_queue, blr);
free_blocking_lock_record(blr);
+ recalc_timeout = True;
change_to_root_user();
continue;
}
DLIST_REMOVE(blocking_lock_queue, blr);
free_blocking_lock_record(blr);
+ recalc_timeout = True;
}
change_to_root_user();
}
+
+ if (recalc_timeout) {
+ recalc_brl_timeout();
+ }
}
/****************************************************************************
#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS))
-static void process_blocking_lock_cancel_message(int msg_type, struct process_id src,
- void *buf, size_t len)
+static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
{
NTSTATUS err;
- const char *msg = (const char *)buf;
+ const char *msg = (const char *)data->data;
blocking_lock_record *blr;
- if (buf == NULL) {
- smb_panic("process_blocking_lock_cancel_message: null msg\n");
+ if (data->data == NULL) {
+ smb_panic("process_blocking_lock_cancel_message: null msg");
}
- if (len != MSG_BLOCKING_LOCK_CANCEL_SIZE) {
+ if (data->length != MSG_BLOCKING_LOCK_CANCEL_SIZE) {
DEBUG(0, ("process_blocking_lock_cancel_message: "
- "Got invalid msg len %d\n", (int)len));
- smb_panic("process_blocking_lock_cancel_message: bad msg\n");
+ "Got invalid msg len %d\n", (int)data->length));
+ smb_panic("process_blocking_lock_cancel_message: bad msg");
}
memcpy(&blr, msg, sizeof(blr));
if (!initialized) {
/* Register our message. */
- message_register(MSG_SMB_BLOCKING_LOCK_CANCEL,
- process_blocking_lock_cancel_message);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_SMB_BLOCKING_LOCK_CANCEL,
+ process_blocking_lock_cancel_message);
initialized = True;
}
memcpy(msg, &blr, sizeof(blr));
memcpy(&msg[sizeof(blr)], &err, sizeof(NTSTATUS));
- message_send_pid(pid_to_procid(sys_getpid()),
- MSG_SMB_BLOCKING_LOCK_CANCEL,
- &msg, sizeof(msg), True);
+ messaging_send_buf(smbd_messaging_context(), procid_self(),
+ MSG_SMB_BLOCKING_LOCK_CANCEL,
+ (uint8 *)&msg, sizeof(msg));
return True;
}