if oplock set.
****************************************************************************/
-bool set_file_oplock(files_struct *fsp, int oplock_type)
+NTSTATUS set_file_oplock(files_struct *fsp, int oplock_type)
{
struct smbd_server_connection *sconn = fsp->conn->sconn;
+ struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
bool use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks;
if (fsp->oplock_type == LEVEL_II_OPLOCK) {
!(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) {
DEBUG(10, ("Refusing level2 oplock, kernel oplocks "
"don't support them\n"));
- return false;
+ return NT_STATUS_NOT_SUPPORTED;
}
}
if ((fsp->oplock_type != NO_OPLOCK) &&
(fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
use_kernel &&
- !koplocks->ops->set_oplock(koplocks, fsp, oplock_type)) {
- return False;
+ !koplocks->ops->set_oplock(koplocks, fsp, oplock_type))
+ {
+ return map_nt_error_from_unix(errno);
}
fsp->oplock_type = oplock_type;
fsp->fh->gen_id, (int)fsp->open_time.tv_sec,
(int)fsp->open_time.tv_usec ));
- return True;
+ return NT_STATUS_OK;
}
/****************************************************************************
void release_file_oplock(files_struct *fsp)
{
struct smbd_server_connection *sconn = fsp->conn->sconn;
+ struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
if ((fsp->oplock_type != NO_OPLOCK) &&
(fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) &&
static void downgrade_file_oplock(files_struct *fsp)
{
struct smbd_server_connection *sconn = fsp->conn->sconn;
+ struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
if (!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
DEBUG(0, ("trying to downgrade an already-downgraded oplock!\n"));
sconn->oplocks.exclusive_open--;
sconn->oplocks.level_II_open++;
fsp->sent_oplock_break = NO_BREAK_SENT;
+
+ TALLOC_FREE(fsp->oplock_timeout);
}
/****************************************************************************
ret = remove_share_oplock(lck, fsp);
if (!ret) {
DEBUG(0,("remove_oplock: failed to remove share oplock for "
- "file %s fnum %d, %s\n",
- fsp_str_dbg(fsp), fsp->fnum,
+ "file %s, %s, %s\n",
+ fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
file_id_string_tos(&fsp->file_id)));
}
release_file_oplock(fsp);
ret = downgrade_share_oplock(lck, fsp);
if (!ret) {
DEBUG(0,("downgrade_oplock: failed to downgrade share oplock "
- "for file %s fnum %d, file_id %s\n",
- fsp_str_dbg(fsp), fsp->fnum,
+ "for file %s, %s, file_id %s\n",
+ fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
file_id_string_tos(&fsp->file_id)));
}
return ret;
}
-/*
- * Some kernel oplock implementations handle the notification themselves.
- */
-bool should_notify_deferred_opens()
-{
- return !(koplocks &&
- (koplocks->flags & KOPLOCKS_DEFERRED_OPEN_NOTIFICATION));
-}
-
/****************************************************************************
Set up an oplock break message.
****************************************************************************/
-static char *new_break_message_smb1(TALLOC_CTX *mem_ctx,
- files_struct *fsp, int cmd)
-{
- char *result = talloc_array(mem_ctx, char, smb_size + 8*2 + 0);
-
- if (result == NULL) {
- DEBUG(0, ("talloc failed\n"));
- return NULL;
- }
+#define SMB1_BREAK_MESSAGE_LENGTH (smb_size + 8*2)
+static void new_break_message_smb1(files_struct *fsp, int cmd,
+ char result[SMB1_BREAK_MESSAGE_LENGTH])
+{
memset(result,'\0',smb_size);
srv_set_message(result,8,0,true);
SCVAL(result,smb_com,SMBlockingX);
SSVAL(result,smb_vwv2,fsp->fnum);
SCVAL(result,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE);
SCVAL(result,smb_vwv3+1,cmd);
- return result;
}
/****************************************************************************
/* The file could have been closed in the meantime - return success. */
if( DEBUGLVL( 3 ) ) {
dbgtext( "initial_break_processing: cannot find open file with " );
- dbgtext( "file_id %s gen_id = %lu", file_id_string_tos(&id), file_id);
+ dbgtext( "file_id %s gen_id = %lu, ", file_id_string_tos(&id), file_id);
dbgtext( "allowing break to succeed.\n" );
}
return NULL;
return fsp;
}
-static void oplock_timeout_handler(struct event_context *ctx,
- struct timed_event *te,
+static void oplock_timeout_handler(struct tevent_context *ctx,
+ struct tevent_timer *te,
struct timeval now,
void *private_data)
{
files_struct *fsp = (files_struct *)private_data;
+ SMB_ASSERT(fsp->sent_oplock_break != NO_BREAK_SENT);
+
/* Remove the timed event handler. */
TALLOC_FREE(fsp->oplock_timeout);
DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n",
fsp_str_dbg(fsp)));
remove_oplock(fsp);
- reply_to_oplock_break_requests(fsp);
}
/*******************************************************************
static void add_oplock_timeout_handler(files_struct *fsp)
{
+ struct smbd_server_connection *sconn = fsp->conn->sconn;
+ struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
+
/*
* If kernel oplocks already notifies smbds when an oplock break times
* out, just return.
static void send_break_message_smb1(files_struct *fsp, int level)
{
- char *break_msg = new_break_message_smb1(talloc_tos(),
- fsp,
- level);
- if (break_msg == NULL) {
- exit_server("Could not talloc break_msg\n");
- }
+ char break_msg[SMB1_BREAK_MESSAGE_LENGTH];
+
+ new_break_message_smb1(fsp, level, break_msg);
show_msg(break_msg);
if (!srv_send_smb(fsp->conn->sconn,
exit_server_cleanly("send_break_message_smb1: "
"srv_send_smb failed.");
}
-
- TALLOC_FREE(break_msg);
}
-void break_level2_to_none_async(files_struct *fsp)
+static void break_level2_to_none_async(files_struct *fsp)
{
struct smbd_server_connection *sconn = fsp->conn->sconn;
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,
+ "to none message for %s, file %s\n", fsp_fnum_dbg(fsp),
fsp_str_dbg(fsp)));
/* Now send a break to none message to our client. */
struct smbd_server_connection *sconn =
talloc_get_type_abort(private_data,
struct smbd_server_connection);
+ struct server_id self = messaging_server_id(sconn->msg_ctx);
+ struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
if (data->data == NULL) {
DEBUG(0, ("Got NULL buffer\n"));
if (fsp == NULL) {
/* We hit a race here. Break messages are sent, and before we
- * get to process this message, we have closed the file. Reply
- * with 'ok, oplock broken' */
+ * get to process this message, we have closed the file. */
DEBUG(3, ("Did not find fsp\n"));
-
- /* We just send the same message back. */
- messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE,
- (uint8 *)data->data,
- MSG_SMB_SHARE_MODE_ENTRY_SIZE);
return;
}
if (fsp->sent_oplock_break != NO_BREAK_SENT) {
- /* Remember we have to inform the requesting PID when the
- * client replies */
- msg.pid = src;
- ADD_TO_ARRAY(NULL, struct share_mode_entry, msg,
- &fsp->pending_break_messages,
- &fsp->num_pending_break_messages);
+ /*
+ * Nothing to do anymore
+ */
return;
}
DEBUG(3, ("Already downgraded oplock on %s: %s\n",
file_id_string_tos(&fsp->file_id),
fsp_str_dbg(fsp)));
- /* We just send the same message back. */
- messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE,
- (uint8 *)data->data,
- MSG_SMB_SHARE_MODE_ENTRY_SIZE);
return;
}
use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks;
if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
- !(msg.op_type & FORCE_OPLOCK_BREAK_TO_NONE) &&
!(use_kernel && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) &&
lp_level2_oplocks(SNUM(fsp->conn))) {
break_to_level2 = True;
/* Need to wait before sending a break
message if we sent ourselves this message. */
- if (procid_is_me(&src)) {
+ if (serverid_equal(&self, &src)) {
wait_before_sending_break();
}
fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
- msg.pid = src;
- ADD_TO_ARRAY(NULL, struct share_mode_entry, msg,
- &fsp->pending_break_messages,
- &fsp->num_pending_break_messages);
-
add_oplock_timeout_handler(fsp);
}
add_oplock_timeout_handler(fsp);
}
-void reply_to_oplock_break_requests(files_struct *fsp)
-{
- int i;
-
- /*
- * If kernel oplocks already notifies smbds when oplocks are
- * broken/removed, just return.
- */
- if (koplocks &&
- (koplocks->flags & KOPLOCKS_OPLOCK_BROKEN_NOTIFICATION)) {
- return;
- }
-
- for (i=0; i<fsp->num_pending_break_messages; i++) {
- struct share_mode_entry *e = &fsp->pending_break_messages[i];
- char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
-
- share_mode_entry_to_message(msg, e);
-
- messaging_send_buf(fsp->conn->sconn->msg_ctx, e->pid,
- MSG_SMB_BREAK_RESPONSE,
- (uint8 *)msg,
- MSG_SMB_SHARE_MODE_ENTRY_SIZE);
- }
-
- SAFE_FREE(fsp->pending_break_messages);
- fsp->num_pending_break_messages = 0;
- TALLOC_FREE(fsp->oplock_timeout);
- return;
-}
-
-static void process_oplock_break_response(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id src,
- DATA_BLOB *data)
-{
- struct share_mode_entry msg;
- struct smbd_server_connection *sconn =
- talloc_get_type_abort(private_data,
- struct smbd_server_connection);
-
- if (data->data == NULL) {
- DEBUG(0, ("Got NULL buffer\n"));
- return;
- }
-
- if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
- DEBUG(0, ("Got invalid msg len %u\n",
- (unsigned int)data->length));
- return;
- }
-
- /* De-linearize incoming message. */
- message_to_share_mode_entry(&msg, (char *)data->data);
-
- DEBUG(10, ("Got oplock break response from pid %s: %s/%llu mid %llu\n",
- server_id_str(talloc_tos(), &src),
- file_id_string_tos(&msg.id),
- (unsigned long long)msg.share_file_id,
- (unsigned long long)msg.op_mid));
-
- schedule_deferred_open_message_smb(sconn, msg.op_mid);
-}
-
-static void process_open_retry_message(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id src,
- DATA_BLOB *data)
-{
- struct share_mode_entry msg;
- struct smbd_server_connection *sconn =
- talloc_get_type_abort(private_data,
- struct smbd_server_connection);
-
- if (data->data == NULL) {
- DEBUG(0, ("Got NULL buffer\n"));
- return;
- }
-
- if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) {
- DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
- return;
- }
-
- /* De-linearize incoming message. */
- message_to_share_mode_entry(&msg, (char *)data->data);
-
- DEBUG(10, ("Got open retry msg from pid %s: %s mid %llu\n",
- server_id_str(talloc_tos(), &src), file_id_string_tos(&msg.id),
- (unsigned long long)msg.op_mid));
-
- schedule_deferred_open_message_smb(sconn, msg.op_mid);
-}
-
struct break_to_none_state {
struct smbd_server_connection *sconn;
struct file_id id;
};
-static void do_break_to_none(struct tevent_req *req);
+static void do_break_to_none(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
/****************************************************************************
This function is called on any file modification or lock request. If a file
enum level2_contention_type type)
{
struct smbd_server_connection *sconn = fsp->conn->sconn;
- struct tevent_req *req;
+ struct tevent_immediate *im;
struct break_to_none_state *state;
/*
state->sconn = sconn;
state->id = fsp->file_id;
- req = tevent_wakeup_send(state, sconn->ev_ctx, timeval_set(0, 0));
- if (req == NULL) {
- DEBUG(1, ("tevent_wakeup_send failed\n"));
+ im = tevent_create_immediate(state);
+ if (im == NULL) {
+ DEBUG(1, ("tevent_create_immediate failed\n"));
TALLOC_FREE(state);
return;
}
- tevent_req_set_callback(req, do_break_to_none, state);
- return;
+ tevent_schedule_immediate(im, sconn->ev_ctx, do_break_to_none, state);
}
-static void do_break_to_none(struct tevent_req *req)
+static void do_break_to_none(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
{
- struct break_to_none_state *state = tevent_req_callback_data(
- req, struct break_to_none_state);
- bool ret;
+ struct break_to_none_state *state = talloc_get_type_abort(
+ private_data, struct break_to_none_state);
+ struct server_id self = messaging_server_id(state->sconn->msg_ctx);
int i;
struct share_mode_lock *lck;
- ret = tevent_wakeup_recv(req);
- TALLOC_FREE(req);
- if (!ret) {
- DEBUG(1, ("tevent_wakeup_recv failed\n"));
- goto done;
- }
lck = get_existing_share_mode_lock(talloc_tos(), state->id);
if (lck == NULL) {
DEBUG(1, ("release_level_2_oplocks_on_change: failed to lock "
* Bugid #5980.
*/
- if (procid_is_me(&share_entry->pid)) {
+ if (serverid_equal(&self, &share_entry->pid)) {
struct files_struct *cur_fsp =
initial_break_processing(state->sconn,
share_entry->id,
share_entry->share_file_id);
- wait_before_sending_break();
if (cur_fsp != NULL) {
+ wait_before_sending_break();
break_level2_to_none_async(cur_fsp);
} else {
DEBUG(3, ("release_level_2_oplocks_on_change: "
void smbd_contend_level2_oplocks_begin(files_struct *fsp,
enum level2_contention_type type)
{
+ struct smbd_server_connection *sconn = fsp->conn->sconn;
+ struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
+
if (koplocks && koplocks->ops->contend_level2_oplocks_begin) {
koplocks->ops->contend_level2_oplocks_begin(fsp, type);
return;
void smbd_contend_level2_oplocks_end(files_struct *fsp,
enum level2_contention_type type)
{
+ struct smbd_server_connection *sconn = fsp->conn->sconn;
+ struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
+
/* Only kernel oplocks implement this so far */
if (koplocks && koplocks->ops->contend_level2_oplocks_end) {
koplocks->ops->contend_level2_oplocks_end(fsp, type);
process_oplock_break_message);
messaging_register(sconn->msg_ctx, sconn, MSG_SMB_ASYNC_LEVEL2_BREAK,
process_oplock_async_level2_break_message);
- messaging_register(sconn->msg_ctx, sconn, MSG_SMB_BREAK_RESPONSE,
- process_oplock_break_response);
messaging_register(sconn->msg_ctx, sconn, MSG_SMB_KERNEL_BREAK,
process_kernel_oplock_break);
- messaging_register(sconn->msg_ctx, sconn, MSG_SMB_OPEN_RETRY,
- process_open_retry_message);
-
return true;
}
void init_kernel_oplocks(struct smbd_server_connection *sconn)
{
+ struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
+
/* only initialize once */
if (koplocks == NULL) {
#if HAVE_KERNEL_OPLOCKS_IRIX
#elif HAVE_KERNEL_OPLOCKS_LINUX
koplocks = linux_init_kernel_oplocks(sconn);
#endif
+ sconn->oplocks.kernel_ops = koplocks;
}
}