#undef DBGC_CLASS
#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.
-*****************************************************************************/
-
-typedef 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;
-} blocking_lock_record;
-
/****************************************************************************
Determine if this is a secondary element of a chained SMB.
**************************************************************************/
-static bool in_chained_smb(void)
-{
- return (chain_size != 0);
-}
-
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,
static bool recalc_brl_timeout(void)
{
- blocking_lock_record *brl;
+ struct blocking_lock_record *blr;
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)) {
+ 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);
}
}
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))) {
uint64_t count,
uint32_t blocking_pid)
{
- blocking_lock_record *blr;
+ struct blocking_lock_record *blr;
NTSTATUS status;
- if(in_chained_smb() ) {
+ if(req_is_in_chain(req)) {
DEBUG(0,("push_blocking_lock_request: cannot queue a chained request (currently).\n"));
return False;
}
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,
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;
}
+ SMB_PERFCOUNT_DEFER_OP(&req->pcd, &req->pcd);
blr->req = talloc_move(blr, &req);
- DLIST_ADD_END(blocking_lock_queue, blr, blocking_lock_record *);
+ DLIST_ADD_END(blocking_lock_queue, blr, struct blocking_lock_record *);
recalc_brl_timeout();
/* Ensure we'll receive messages when this is unlocked. */
(unsigned int)blr->expire_time.tv_usec, lock_timeout,
blr->fsp->fnum, blr->fsp->fsp_name ));
- /* Push the MID of this packet on the signing queue. */
- srv_defer_sign_response(blr->req->mid);
-
return True;
}
Return a lockingX success SMB.
*****************************************************************************/
-static void reply_lockingX_success(blocking_lock_record *blr)
+static void reply_lockingX_success(struct blocking_lock_record *blr)
{
reply_outbuf(blr->req, 2, 0);
*/
chain_reply(blr->req);
-
- if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf,
- IS_CONN_ENCRYPTED(blr->fsp->conn))) {
- exit_server_cleanly("send_blocking_reply: srv_send_smb failed.");
- }
-
TALLOC_FREE(blr->req->outbuf);
}
Return a generic lock fail error blocking call.
*****************************************************************************/
-static void generic_blocking_lock_error(blocking_lock_record *blr, NTSTATUS status)
+static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTATUS status)
{
/* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to
FILE_LOCK_CONFLICT! (tridge) */
reply_nterror(blr->req, status);
if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf,
- blr->req->encrypted)) {
+ true, blr->req->seqnum+1,
+ blr->req->encrypted, NULL)) {
exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed.");
}
TALLOC_FREE(blr->req->outbuf);
obtained first.
*****************************************************************************/
-static void reply_lockingX_error(blocking_lock_record *blr, NTSTATUS status)
+static void reply_lockingX_error(struct blocking_lock_record *blr, NTSTATUS status)
{
files_struct *fsp = blr->fsp;
uint16 num_ulocks = SVAL(blr->req->vwv+6, 0);
Return a lock fail error.
*****************************************************************************/
-static void blocking_lock_reply_error(blocking_lock_record *blr, NTSTATUS status)
+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);
if (!srv_send_smb(smbd_server_fd(),
(char *)blr->req->outbuf,
- IS_CONN_ENCRYPTED(blr->fsp->conn))) {
+ true, blr->req->seqnum+1,
+ IS_CONN_ENCRYPTED(blr->fsp->conn),
+ NULL)) {
exit_server_cleanly("blocking_lock_reply_error: "
"srv_send_smb failed.");
}
Returns True if we want to be removed from the list.
*****************************************************************************/
-static bool process_lockingX(blocking_lock_record *blr)
+static bool process_lockingX(struct blocking_lock_record *blr)
{
unsigned char locktype = CVAL(blr->req->vwv+3, 0);
files_struct *fsp = blr->fsp;
WINDOWS_LOCK,
True,
&status,
- &blr->blocking_pid);
+ &blr->blocking_pid,
+ blr);
TALLOC_FREE(br_lck);
Returns True if we want to be removed from the list.
*****************************************************************************/
-static bool process_trans2(blocking_lock_record *blr)
+static bool process_trans2(struct blocking_lock_record *blr)
{
char params[2];
NTSTATUS status;
blr->lock_flav,
True,
&status,
- &blr->blocking_pid);
+ &blr->blocking_pid,
+ blr);
TALLOC_FREE(br_lck);
if (!NT_STATUS_IS_OK(status)) {
Returns True if we want to be removed from the list.
*****************************************************************************/
-static bool blocking_lock_record_process(blocking_lock_record *blr)
+static bool blocking_lock_record_process(struct blocking_lock_record *blr)
{
switch(blr->req->cmd) {
case SMBlockingX:
void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
{
- 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;
"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,
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;
void remove_pending_lock_requests_by_mid(int mid)
{
- blocking_lock_record *blr, *next = NULL;
+ struct blocking_lock_record *blr, *next = NULL;
for(blr = blocking_lock_queue; blr; blr = next) {
files_struct *fsp;
procid_self(),
blr->offset,
blr->count,
- blr->lock_flav);
+ blr->lock_flav,
+ blr);
TALLOC_FREE(br_lck);
}
bool blocking_lock_was_deferred(int mid)
{
- blocking_lock_record *blr, *next = NULL;
+ struct blocking_lock_record *blr, *next = NULL;
for(blr = blocking_lock_queue; blr; blr = next) {
next = blr->next;
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();
- blocking_lock_record *blr, *next = NULL;
+ struct blocking_lock_record *blr, *next = NULL;
bool recalc_timeout = False;
/*
* 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);
}
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.
procid_self(),
blr->offset,
blr->count,
- blr->lock_flav);
+ blr->lock_flav,
+ blr);
TALLOC_FREE(br_lck);
}
Handle a cancel message. Lock already moved onto the cancel queue.
*****************************************************************************/
-#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS))
+#define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(struct blocking_lock_record *) + sizeof(NTSTATUS))
static void process_blocking_lock_cancel_message(struct messaging_context *ctx,
void *private_data,
{
NTSTATUS err;
const char *msg = (const char *)data->data;
- blocking_lock_record *blr;
+ struct blocking_lock_record *blr;
if (data->data == NULL) {
smb_panic("process_blocking_lock_cancel_message: null msg");
/****************************************************************************
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,
NTSTATUS err)
{
char msg[MSG_BLOCKING_LOCK_CANCEL_SIZE];
- blocking_lock_record *blr;
+ struct blocking_lock_record *blr;
if (!blocking_lock_cancel_state) {
/* Register our message. */
}
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. */
MSG_SMB_BLOCKING_LOCK_CANCEL,
(uint8 *)&msg, sizeof(msg));
- return True;
+ return blr;
}