X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Foplock.c;h=e3f00a70ecc94aebaa03c61e2f12a2380e42a953;hb=70be41c772d69d36ea8f434187be8bfd6b5f38a0;hp=6add9f5fc1b787ae05e33730d5c54c5cf5b9cf45;hpb=7ee4f168d8b18eaeed9cbdbf2db17090b8d35961;p=samba.git diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 6add9f5fc1b..e3f00a70ecc 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -4,24 +4,27 @@ Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jeremy Allison 1998 - 2001 Copyright (C) Volker Lendecke 2005 - + 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 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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, see . */ #define DBGC_CLASS DBGC_LOCKING #include "includes.h" +#include "smbd/smbd.h" #include "smbd/globals.h" +#include "messages.h" +#include "../librpc/gen_ndr/open_files.h" /**************************************************************************** Get the number of current exclusive oplocks. @@ -46,21 +49,34 @@ void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp) /* Don't need to be root here as we're only ever sending to ourselves. */ - messaging_send_buf(msg_ctx, procid_self(), + messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx), MSG_SMB_KERNEL_BREAK, msg, MSG_SMB_KERNEL_BREAK_SIZE); } /**************************************************************************** - Attempt to set an oplock on a file. Always succeeds if kernel oplocks are - disabled (just sets flags). Returns True if oplock set. + Attempt to set an oplock on a file. Succeeds if kernel oplocks are + disabled (just sets flags) and no byte-range locks in the file. Returns True + if oplock set. ****************************************************************************/ bool set_file_oplock(files_struct *fsp, int oplock_type) { + + bool use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks; + + if (fsp->oplock_type == LEVEL_II_OPLOCK) { + if (use_kernel && + !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) { + DEBUG(10, ("Refusing level2 oplock, kernel oplocks " + "don't support them\n")); + return false; + } + } + if ((fsp->oplock_type != NO_OPLOCK) && (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK) && - koplocks && + use_kernel && !koplocks->ops->set_oplock(koplocks, fsp, oplock_type)) { return False; } @@ -75,7 +91,7 @@ bool set_file_oplock(files_struct *fsp, int oplock_type) DEBUG(5,("set_file_oplock: granted oplock on file %s, %s/%lu, " "tv_sec = %x, tv_usec = %x\n", - fsp->fsp_name, file_id_string_tos(&fsp->file_id), + fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), fsp->fh->gen_id, (int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec )); @@ -112,6 +128,7 @@ void release_file_oplock(files_struct *fsp) fsp->sent_oplock_break = NO_BREAK_SENT; flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH); + delete_write_cache(fsp); TALLOC_FREE(fsp->oplock_timeout); } @@ -148,18 +165,18 @@ bool remove_oplock(files_struct *fsp) struct share_mode_lock *lck; /* Remove the oplock flag from the sharemode. */ - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, - NULL); + lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); if (lck == NULL) { DEBUG(0,("remove_oplock: failed to lock share entry for " - "file %s\n", fsp->fsp_name )); + "file %s\n", fsp_str_dbg(fsp))); return False; } 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->fsp_name, fsp->fnum, file_id_string_tos(&fsp->file_id))); + fsp_str_dbg(fsp), fsp->fnum, + file_id_string_tos(&fsp->file_id))); } release_file_oplock(fsp); TALLOC_FREE(lck); @@ -174,18 +191,18 @@ bool downgrade_oplock(files_struct *fsp) bool ret; struct share_mode_lock *lck; - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, - NULL); + lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); if (lck == NULL) { DEBUG(0,("downgrade_oplock: failed to lock share entry for " - "file %s\n", fsp->fsp_name )); + "file %s\n", fsp_str_dbg(fsp))); return False; } 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->fsp_name, fsp->fnum, file_id_string_tos(&fsp->file_id))); + fsp_str_dbg(fsp), fsp->fnum, + file_id_string_tos(&fsp->file_id))); } downgrade_file_oplock(fsp); @@ -206,10 +223,10 @@ bool should_notify_deferred_opens() Set up an oplock break message. ****************************************************************************/ -static char *new_break_smb_message(TALLOC_CTX *mem_ctx, - files_struct *fsp, uint8 cmd) +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); + char *result = talloc_array(mem_ctx, char, smb_size + 8*2 + 0); if (result == NULL) { DEBUG(0, ("talloc failed\n")); @@ -247,7 +264,9 @@ static void wait_before_sending_break(void) Ensure that we have a valid oplock. ****************************************************************************/ -static files_struct *initial_break_processing(struct file_id id, unsigned long file_id) +static files_struct *initial_break_processing( + struct smbd_server_connection *sconn, struct file_id id, + unsigned long file_id) { files_struct *fsp = NULL; @@ -264,7 +283,7 @@ static files_struct *initial_break_processing(struct file_id id, unsigned long f * we have an oplock on it. */ - fsp = file_find_dif(id, file_id); + fsp = file_find_dif(sconn, id, file_id); if(fsp == NULL) { /* The file could have been closed in the meantime - return success. */ @@ -288,7 +307,8 @@ static files_struct *initial_break_processing(struct file_id id, unsigned long f if(fsp->oplock_type == NO_OPLOCK) { if( DEBUGLVL( 3 ) ) { - dbgtext( "initial_break_processing: file %s ", fsp->fsp_name ); + dbgtext( "initial_break_processing: file %s ", + fsp_str_dbg(fsp)); dbgtext( "(file_id = %s gen_id = %lu) has no oplock.\n", file_id_string_tos(&id), fsp->fh->gen_id ); dbgtext( "Allowing break to succeed regardless.\n" ); @@ -308,8 +328,8 @@ static void oplock_timeout_handler(struct event_context *ctx, /* Remove the timed event handler. */ TALLOC_FREE(fsp->oplock_timeout); - DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", fsp->fsp_name)); - global_client_failed_oplock_break = True; + DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n", + fsp_str_dbg(fsp))); remove_oplock(fsp); reply_to_oplock_break_requests(fsp); } @@ -335,15 +355,74 @@ static void add_oplock_timeout_handler(files_struct *fsp) } fsp->oplock_timeout = - event_add_timed(smbd_event_context(), NULL, - timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0), - oplock_timeout_handler, fsp); + tevent_add_timer(fsp->conn->sconn->ev_ctx, fsp, + timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0), + oplock_timeout_handler, fsp); if (fsp->oplock_timeout == NULL) { DEBUG(0, ("Could not add oplock timeout handler\n")); } } +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"); + } + + show_msg(break_msg); + if (!srv_send_smb(fsp->conn->sconn, + break_msg, false, 0, + IS_CONN_ENCRYPTED(fsp->conn), + NULL)) { + exit_server_cleanly("send_break_message_smb1: " + "srv_send_smb failed."); + } + + TALLOC_FREE(break_msg); +} + +void break_level2_to_none_async(files_struct *fsp) +{ + struct smbd_server_connection *sconn = fsp->conn->sconn; + + if (fsp->oplock_type == NO_OPLOCK) { + /* We already got a "break to none" message and we've handled + * it. just ignore. */ + DEBUG(3, ("process_oplock_async_level2_break_message: already " + "broken to none, ignoring.\n")); + return; + } + + if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) { + /* Don't tell the client, just downgrade. */ + DEBUG(3, ("process_oplock_async_level2_break_message: " + "downgrading fake level 2 oplock.\n")); + remove_oplock(fsp); + return; + } + + /* 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_str_dbg(fsp))); + + /* Now send a break to none message to our client. */ + if (sconn->using_smb2) { + send_break_message_smb2(fsp, OPLOCKLEVEL_NONE); + } else { + send_break_message_smb1(fsp, OPLOCKLEVEL_NONE); + } + + /* Async level2 request, don't send a reply, just remove the oplock. */ + remove_oplock(fsp); +} + /******************************************************************* This handles the case of a write triggering a break to none message on a level2 oplock. @@ -352,7 +431,7 @@ static void add_oplock_timeout_handler(files_struct *fsp) the client for LEVEL2. *******************************************************************/ -void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx, +static void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx, void *private_data, uint32_t msg_type, struct server_id src, @@ -360,7 +439,9 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx { struct share_mode_entry msg; files_struct *fsp; - char *break_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")); @@ -376,10 +457,11 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx message_to_share_mode_entry(&msg, (char *)data->data); DEBUG(10, ("Got oplock async level 2 break message from pid %s: " - "%s/%lu\n", procid_str(debug_ctx(), &src), - file_id_string_tos(&msg.id), msg.share_file_id)); + "%s/%llu\n", server_id_str(talloc_tos(), &src), + file_id_string_tos(&msg.id), + (unsigned long long)msg.share_file_id)); - fsp = initial_break_processing(msg.id, msg.share_file_id); + fsp = initial_break_processing(sconn, msg.id, msg.share_file_id); if (fsp == NULL) { /* We hit a race here. Break messages are sent, and before we @@ -389,52 +471,7 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx return; } - if (fsp->oplock_type == NO_OPLOCK) { - /* We already got a "break to none" message and we've handled it. - * just ignore. */ - DEBUG(3, ("process_oplock_async_level2_break_message: already broken to none, ignoring.\n")); - return; - } - - if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) { - /* Don't tell the client, just downgrade. */ - DEBUG(3, ("process_oplock_async_level2_break_message: downgrading fake level 2 oplock.\n")); - remove_oplock(fsp); - return; - } - - /* 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); - if (break_msg == NULL) { - exit_server("Could not talloc break_msg\n"); - } - - /* Need to wait before sending a break message if we sent ourselves this message. */ - if (procid_is_me(&src)) { - wait_before_sending_break(); - } - - show_msg(break_msg); - if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, - IS_CONN_ENCRYPTED(fsp->conn), - NULL)) { - exit_server_cleanly("oplock_break: srv_send_smb failed."); - } - - TALLOC_FREE(break_msg); - - /* Async level2 request, don't send a reply, just remove the oplock. */ - remove_oplock(fsp); + break_level2_to_none_async(fsp); } /******************************************************************* @@ -449,8 +486,11 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, { struct share_mode_entry msg; files_struct *fsp; - char *break_msg; bool break_to_level2 = False; + bool use_kernel; + 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")); @@ -465,14 +505,15 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got oplock break message from pid %s: %s/%lu\n", - procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), - msg.share_file_id)); + DEBUG(10, ("Got oplock break message from pid %s: %s/%llu\n", + server_id_str(talloc_tos(), &src), + file_id_string_tos(&msg.id), + (unsigned long long)msg.share_file_id)); - fsp = initial_break_processing(msg.id, msg.share_file_id); + fsp = initial_break_processing(sconn, msg.id, msg.share_file_id); if (fsp == NULL) { - /* a We hit race here. Break messages are sent, and before we + /* 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' */ DEBUG(3, ("Did not find fsp\n")); @@ -498,7 +539,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, !EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { DEBUG(3, ("Already downgraded oplock on %s: %s\n", file_id_string_tos(&fsp->file_id), - fsp->fsp_name)); + fsp_str_dbg(fsp))); /* We just send the same message back. */ messaging_send_buf(msg_ctx, src, MSG_SMB_BREAK_RESPONSE, (uint8 *)data->data, @@ -506,34 +547,29 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, return; } - if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && + 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) && - !(koplocks && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) && + !(use_kernel && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) && lp_level2_oplocks(SNUM(fsp->conn))) { break_to_level2 = True; } - break_msg = new_break_smb_message(NULL, fsp, break_to_level2 ? - OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); - if (break_msg == NULL) { - exit_server("Could not talloc break_msg\n"); - } - - /* Need to wait before sending a break message if we sent ourselves this message. */ + /* Need to wait before sending a break + message if we sent ourselves this message. */ if (procid_is_me(&src)) { wait_before_sending_break(); } - show_msg(break_msg); - if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, - IS_CONN_ENCRYPTED(fsp->conn), - NULL)) { - exit_server_cleanly("oplock_break: srv_send_smb failed."); + if (sconn->using_smb2) { + send_break_message_smb2(fsp, break_to_level2 ? + OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); + } else { + send_break_message_smb1(fsp, break_to_level2 ? + OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); } - TALLOC_FREE(break_msg); - fsp->sent_oplock_break = break_to_level2 ? LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT; msg.pid = src; @@ -557,7 +593,9 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, struct file_id id; unsigned long file_id; files_struct *fsp; - char *break_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")); @@ -574,10 +612,10 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, file_id = (unsigned long)IVAL(data->data, 24); DEBUG(10, ("Got kernel oplock break message from pid %s: %s/%u\n", - procid_str(debug_ctx(), &src), file_id_string_tos(&id), + server_id_str(talloc_tos(), &src), file_id_string_tos(&id), (unsigned int)file_id)); - fsp = initial_break_processing(id, file_id); + fsp = initial_break_processing(sconn, id, file_id); if (fsp == NULL) { DEBUG(3, ("Got a kernel oplock break message for a file " @@ -592,21 +630,12 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, return; } - break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); - if (break_msg == NULL) { - exit_server("Could not talloc break_msg\n"); - } - - show_msg(break_msg); - if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, - IS_CONN_ENCRYPTED(fsp->conn), - NULL)) { - exit_server_cleanly("oplock_break: srv_send_smb failed."); + if (sconn->using_smb2) { + send_break_message_smb2(fsp, OPLOCKLEVEL_NONE); + } else { + send_break_message_smb1(fsp, OPLOCKLEVEL_NONE); } - TALLOC_FREE(break_msg); - fsp->sent_oplock_break = BREAK_TO_NONE_SENT; add_oplock_timeout_handler(fsp); @@ -631,7 +660,7 @@ void reply_to_oplock_break_requests(files_struct *fsp) share_mode_entry_to_message(msg, e); - messaging_send_buf(smbd_messaging_context(), e->pid, + messaging_send_buf(fsp->conn->sconn->msg_ctx, e->pid, MSG_SMB_BREAK_RESPONSE, (uint8 *)msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE); @@ -639,11 +668,7 @@ void reply_to_oplock_break_requests(files_struct *fsp) SAFE_FREE(fsp->pending_break_messages); fsp->num_pending_break_messages = 0; - if (fsp->oplock_timeout != NULL) { - /* Remove the timed event handler. */ - TALLOC_FREE(fsp->oplock_timeout); - fsp->oplock_timeout = NULL; - } + TALLOC_FREE(fsp->oplock_timeout); return; } @@ -654,6 +679,9 @@ static void process_oplock_break_response(struct messaging_context *msg_ctx, 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")); @@ -669,12 +697,13 @@ static void process_oplock_break_response(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got oplock break response from pid %s: %s/%lu mid %u\n", - procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), - msg.share_file_id, (unsigned int)msg.op_mid)); + 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)); - /* Here's the hack from open.c, store the mid in the 'port' field */ - schedule_deferred_open_smb_message(msg.op_mid); + schedule_deferred_open_message_smb(sconn, msg.op_mid); } static void process_open_retry_message(struct messaging_context *msg_ctx, @@ -684,7 +713,10 @@ static void process_open_retry_message(struct messaging_context *msg_ctx, 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; @@ -698,13 +730,19 @@ static void process_open_retry_message(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got open retry msg from pid %s: %s mid %u\n", - procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), - (unsigned int)msg.op_mid)); + 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_smb_message(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); + /**************************************************************************** This function is called on any file modification or lock request. If a file is level 2 oplocked then it must tell all other level 2 holders to break to @@ -714,8 +752,9 @@ static void process_open_retry_message(struct messaging_context *msg_ctx, static void contend_level2_oplocks_begin_default(files_struct *fsp, enum level2_contention_type type) { - int i; - struct share_mode_lock *lck; + struct smbd_server_connection *sconn = fsp->conn->sconn; + struct tevent_req *req; + struct break_to_none_state *state; /* * If this file is level II oplocked then we need @@ -728,19 +767,58 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) return; - 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 )); + /* + * When we get here we might have a brlock entry locked. Also + * locking the share mode entry would violate the locking + * order. Breaking level2 oplocks to none is asynchronous + * anyway, so we postpone this into an immediate timed event. + */ + + state = talloc(sconn, struct break_to_none_state); + if (state == NULL) { + DEBUG(1, ("talloc failed\n")); return; } + 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")); + TALLOC_FREE(state); + return; + } + tevent_req_set_callback(req, do_break_to_none, state); + return; +} + +static void do_break_to_none(struct tevent_req *req) +{ + struct break_to_none_state *state = tevent_req_callback_data( + req, struct break_to_none_state); + bool ret; + 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 " + "share mode entry for file %s.\n", + file_id_string_tos(&state->id))); + goto done; + } DEBUG(10,("release_level_2_oplocks_on_change: num_share_modes = %d\n", - lck->num_share_modes )); + lck->data->num_share_modes )); - for(i = 0; i < lck->num_share_modes; i++) { - struct share_mode_entry *share_entry = &lck->share_modes[i]; + for(i = 0; i < lck->data->num_share_modes; i++) { + struct share_mode_entry *share_entry = &lck->data->share_modes[i]; char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; if (!is_valid_share_mode_entry(share_entry)) { @@ -790,15 +868,19 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, */ 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); + 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) { + break_level2_to_none_async(cur_fsp); + } else { + DEBUG(3, ("release_level_2_oplocks_on_change: " + "Did not find fsp, ignoring\n")); + } } else { - messaging_send_buf(smbd_messaging_context(), + messaging_send_buf(state->sconn->msg_ctx, share_entry->pid, MSG_SMB_ASYNC_LEVEL2_BREAK, (uint8 *)msg, @@ -810,9 +892,12 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, in the share mode lock db. */ TALLOC_FREE(lck); +done: + TALLOC_FREE(state); + return; } -void contend_level2_oplocks_begin(files_struct *fsp, +void smbd_contend_level2_oplocks_begin(files_struct *fsp, enum level2_contention_type type) { if (koplocks && koplocks->ops->contend_level2_oplocks_begin) { @@ -823,7 +908,7 @@ void contend_level2_oplocks_begin(files_struct *fsp, contend_level2_oplocks_begin_default(fsp, type); } -void contend_level2_oplocks_end(files_struct *fsp, +void smbd_contend_level2_oplocks_end(files_struct *fsp, enum level2_contention_type type) { /* Only kernel oplocks implement this so far */ @@ -838,21 +923,20 @@ void contend_level2_oplocks_end(files_struct *fsp, 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); - SSVAL(msg,6,e->op_type); - SIVAL(msg,8,e->access_mask); - SIVAL(msg,12,e->share_access); - SIVAL(msg,16,e->private_options); - SIVAL(msg,20,(uint32)e->time.tv_sec); - SIVAL(msg,24,(uint32)e->time.tv_usec); - push_file_id_24(msg+28, &e->id); - SIVAL(msg,52,e->share_file_id); - SIVAL(msg,56,e->uid); - SSVAL(msg,60,e->flags); -#ifdef CLUSTER_SUPPORT - SIVAL(msg,62,e->pid.vnn); -#endif + SIVAL(msg,OP_BREAK_MSG_PID_OFFSET,(uint32)e->pid.pid); + SBVAL(msg,OP_BREAK_MSG_MID_OFFSET,e->op_mid); + SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET,e->op_type); + SIVAL(msg,OP_BREAK_MSG_ACCESS_MASK_OFFSET,e->access_mask); + SIVAL(msg,OP_BREAK_MSG_SHARE_ACCESS_OFFSET,e->share_access); + SIVAL(msg,OP_BREAK_MSG_PRIV_OFFSET,e->private_options); + SIVAL(msg,OP_BREAK_MSG_TIME_SEC_OFFSET,(uint32_t)e->time.tv_sec); + SIVAL(msg,OP_BREAK_MSG_TIME_USEC_OFFSET,(uint32_t)e->time.tv_usec); + push_file_id_24(msg+OP_BREAK_MSG_DEV_OFFSET, &e->id); + SIVAL(msg,OP_BREAK_MSG_FILE_ID_OFFSET,e->share_file_id); + SIVAL(msg,OP_BREAK_MSG_UID_OFFSET,e->uid); + SSVAL(msg,OP_BREAK_MSG_FLAGS_OFFSET,e->flags); + SIVAL(msg,OP_BREAK_MSG_NAME_HASH_OFFSET,e->name_hash); + SIVAL(msg,OP_BREAK_MSG_VNN_OFFSET,e->pid.vnn); } /**************************************************************************** @@ -861,51 +945,52 @@ void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e) void message_to_share_mode_entry(struct share_mode_entry *e, char *msg) { - e->pid.pid = (pid_t)IVAL(msg,0); - e->op_mid = SVAL(msg,4); - e->op_type = SVAL(msg,6); - e->access_mask = IVAL(msg,8); - e->share_access = IVAL(msg,12); - e->private_options = IVAL(msg,16); - e->time.tv_sec = (time_t)IVAL(msg,20); - e->time.tv_usec = (int)IVAL(msg,24); - pull_file_id_24(msg+28, &e->id); - e->share_file_id = (unsigned long)IVAL(msg,52); - e->uid = (uint32)IVAL(msg,56); - e->flags = (uint16)SVAL(msg,60); -#ifdef CLUSTER_SUPPORT - e->pid.vnn = IVAL(msg,62); -#endif + e->pid.pid = (pid_t)IVAL(msg,OP_BREAK_MSG_PID_OFFSET); + e->op_mid = BVAL(msg,OP_BREAK_MSG_MID_OFFSET); + e->op_type = SVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET); + e->access_mask = IVAL(msg,OP_BREAK_MSG_ACCESS_MASK_OFFSET); + e->share_access = IVAL(msg,OP_BREAK_MSG_SHARE_ACCESS_OFFSET); + e->private_options = IVAL(msg,OP_BREAK_MSG_PRIV_OFFSET); + e->time.tv_sec = (time_t)IVAL(msg,OP_BREAK_MSG_TIME_SEC_OFFSET); + e->time.tv_usec = (int)IVAL(msg,OP_BREAK_MSG_TIME_USEC_OFFSET); + pull_file_id_24(msg+OP_BREAK_MSG_DEV_OFFSET, &e->id); + e->share_file_id = (unsigned long)IVAL(msg,OP_BREAK_MSG_FILE_ID_OFFSET); + e->uid = (uint32)IVAL(msg,OP_BREAK_MSG_UID_OFFSET); + e->flags = (uint16)SVAL(msg,OP_BREAK_MSG_FLAGS_OFFSET); + e->name_hash = IVAL(msg,OP_BREAK_MSG_NAME_HASH_OFFSET); + e->pid.vnn = IVAL(msg,OP_BREAK_MSG_VNN_OFFSET); } /**************************************************************************** Setup oplocks for this process. ****************************************************************************/ -bool init_oplocks(struct messaging_context *msg_ctx) +bool init_oplocks(struct smbd_server_connection *sconn) { DEBUG(3,("init_oplocks: initializing messages.\n")); - messaging_register(msg_ctx, NULL, MSG_SMB_BREAK_REQUEST, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_BREAK_REQUEST, process_oplock_break_message); - messaging_register(msg_ctx, NULL, MSG_SMB_ASYNC_LEVEL2_BREAK, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_ASYNC_LEVEL2_BREAK, process_oplock_async_level2_break_message); - messaging_register(msg_ctx, NULL, MSG_SMB_BREAK_RESPONSE, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_BREAK_RESPONSE, process_oplock_break_response); - messaging_register(msg_ctx, NULL, MSG_SMB_KERNEL_BREAK, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_KERNEL_BREAK, process_kernel_oplock_break); - messaging_register(msg_ctx, NULL, MSG_SMB_OPEN_RETRY, + messaging_register(sconn->msg_ctx, sconn, MSG_SMB_OPEN_RETRY, process_open_retry_message); - if (lp_kernel_oplocks()) { + return true; +} + +void init_kernel_oplocks(struct smbd_server_connection *sconn) +{ + /* only initialize once */ + if (koplocks == NULL) { #if HAVE_KERNEL_OPLOCKS_IRIX - koplocks = irix_init_kernel_oplocks(talloc_autofree_context()); + koplocks = irix_init_kernel_oplocks(sconn); #elif HAVE_KERNEL_OPLOCKS_LINUX - koplocks = linux_init_kernel_oplocks(talloc_autofree_context()); -#elif HAVE_ONEFS - koplocks = onefs_init_kernel_oplocks(talloc_autofree_context()); + koplocks = linux_init_kernel_oplocks(sconn); #endif } - - return True; }