#define DBGC_CLASS DBGC_LOCKING
#include "includes.h"
-
-/* Current number of oplocks we have outstanding. */
-static int32 exclusive_oplocks_open = 0;
-static int32 level_II_oplocks_open = 0;
-bool global_client_failed_oplock_break = False;
-
-extern uint32 global_client_caps;
-
-static struct kernel_oplocks *koplocks;
+#include "smbd/globals.h"
/****************************************************************************
Get the number of current exclusive oplocks.
bool set_file_oplock(files_struct *fsp, int oplock_type)
{
- if (koplocks && !koplocks->set_oplock(fsp, oplock_type)) {
+ if ((fsp->oplock_type != NO_OPLOCK) &&
+ (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
+ koplocks &&
+ !koplocks->set_oplock(fsp, oplock_type)) {
return False;
}
fsp->sent_oplock_break = NO_BREAK_SENT;
if (oplock_type == LEVEL_II_OPLOCK) {
level_II_oplocks_open++;
- } else {
+ } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
exclusive_oplocks_open++;
}
SMB_ASSERT(exclusive_oplocks_open>=0);
SMB_ASSERT(level_II_oplocks_open>=0);
-
- fsp->oplock_type = NO_OPLOCK;
+
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
+ /* This doesn't matter for close. */
+ fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+ } else {
+ fsp->oplock_type = NO_OPLOCK;
+ }
fsp->sent_oplock_break = NO_BREAK_SENT;
-
+
flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH);
TALLOC_FREE(fsp->oplock_timeout);
struct share_mode_lock *lck;
/* Remove the oplock flag from the sharemode. */
- lck = get_share_mode_lock(NULL, fsp->file_id, NULL, NULL);
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
if (lck == NULL) {
DEBUG(0,("remove_oplock: failed to lock share entry for "
"file %s\n", fsp->fsp_name ));
bool ret;
struct share_mode_lock *lck;
- lck = get_share_mode_lock(NULL, fsp->file_id, NULL, NULL);
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
if (lck == NULL) {
DEBUG(0,("downgrade_oplock: failed to lock share entry for "
"file %s\n", fsp->fsp_name ));
}
memset(result,'\0',smb_size);
- set_message(result,8,0,True);
+ srv_set_message(result,8,0,true);
SCVAL(result,smb_com,SMBlockingX);
SSVAL(result,smb_tid,fsp->conn->cnum);
SSVAL(result,smb_pid,0xFFFF);
static void oplock_timeout_handler(struct event_context *ctx,
struct timed_event *te,
- const struct timeval *now,
+ struct timeval now,
void *private_data)
{
files_struct *fsp = (files_struct *)private_data;
fsp->oplock_timeout =
event_add_timed(smbd_event_context(), NULL,
timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
- "oplock_timeout_handler",
oplock_timeout_handler, fsp);
if (fsp->oplock_timeout == NULL) {
/* Ensure we're really at level2 state. */
SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK);
+ DEBUG(10,("process_oplock_async_level2_break_message: sending break to "
+ "none message for fid %d, file %s\n",
+ fsp->fnum,
+ fsp->fsp_name));
+
/* Now send a break to none message to our client. */
break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE);
sign_state = srv_oplock_set_signing(False);
show_msg(break_msg);
- if (!send_smb(smbd_server_fd(), break_msg)) {
- exit_server_cleanly("oplock_break: send_smb failed.");
+ if (!srv_send_smb(smbd_server_fd(),
+ break_msg,
+ IS_CONN_ENCRYPTED(fsp->conn))) {
+ exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
/* Restore the sign state to what it was. */
sign_state = srv_oplock_set_signing(False);
show_msg(break_msg);
- if (!send_smb(smbd_server_fd(), break_msg)) {
- exit_server_cleanly("oplock_break: send_smb failed.");
+ if (!srv_send_smb(smbd_server_fd(),
+ break_msg,
+ IS_CONN_ENCRYPTED(fsp->conn))) {
+ exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
/* Restore the sign state to what it was. */
sign_state = srv_oplock_set_signing(False);
show_msg(break_msg);
- if (!send_smb(smbd_server_fd(), break_msg)) {
- exit_server_cleanly("oplock_break: send_smb failed.");
+ if (!srv_send_smb(smbd_server_fd(),
+ break_msg,
+ IS_CONN_ENCRYPTED(fsp->conn))) {
+ exit_server_cleanly("oplock_break: srv_send_smb failed.");
}
/* Restore the sign state to what it was. */
if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
return;
- lck = get_share_mode_lock(NULL, fsp->file_id, NULL, NULL);
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
if (lck == NULL) {
DEBUG(0,("release_level_2_oplocks_on_change: failed to lock "
"share mode entry for file %s.\n", fsp->fsp_name ));
share_mode_entry_to_message(msg, share_entry);
- messaging_send_buf(smbd_messaging_context(), share_entry->pid,
- MSG_SMB_ASYNC_LEVEL2_BREAK,
- (uint8 *)msg,
- MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ /*
+ * Deal with a race condition when breaking level2
+ * oplocks. Don't send all the messages and release
+ * the lock, this allows someone else to come in and
+ * get a level2 lock before any of the messages are
+ * processed, and thus miss getting a break message.
+ * Ensure at least one entry (the one we're breaking)
+ * is processed immediately under the lock and becomes
+ * set as NO_OPLOCK to stop any waiter getting a level2.
+ * Bugid #5980.
+ */
+
+ if (procid_is_me(&share_entry->pid)) {
+ DATA_BLOB blob = data_blob_const(msg,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ process_oplock_async_level2_break_message(smbd_messaging_context(),
+ NULL,
+ MSG_SMB_ASYNC_LEVEL2_BREAK,
+ share_entry->pid,
+ &blob);
+ } else {
+ messaging_send_buf(smbd_messaging_context(),
+ share_entry->pid,
+ MSG_SMB_ASYNC_LEVEL2_BREAK,
+ (uint8 *)msg,
+ MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+ }
}
/* We let the message receivers handle removing the oplock state
Linearize a share mode entry struct to an internal oplock break message.
****************************************************************************/
-void share_mode_entry_to_message(char *msg, struct share_mode_entry *e)
+void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e)
{
SIVAL(msg,0,(uint32)e->pid.pid);
SSVAL(msg,4,e->op_mid);