X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fsmbd%2Foplock.c;h=fc6b0efddac74e1c6f42b505d05b6106f2481e31;hb=47f65d5829167f061756621e50b480a8c16e4fbc;hp=3f515b576c6742a4a51d424b1bfe8b5c4152f03b;hpb=17ae2267e346920445ea67253f0a9d82fb3e0e35;p=mat%2Fsamba.git diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 3f515b576c..fc6b0efdda 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -26,15 +26,6 @@ #include "messages.h" #include "../librpc/gen_ndr/open_files.h" -/**************************************************************************** - Get the number of current exclusive oplocks. -****************************************************************************/ - -int32 get_number_of_exclusive_open_oplocks(void) -{ - return exclusive_oplocks_open; -} - /* * helper function used by the kernel oplock backends to post the break message */ @@ -56,34 +47,37 @@ void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp) /**************************************************************************** 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. + disabled (just sets flags). ****************************************************************************/ -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) { - if (koplocks && + if (use_kernel && !(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) && - koplocks && - !koplocks->ops->set_oplock(koplocks, fsp, oplock_type)) { - return False; + use_kernel && + !koplocks->ops->set_oplock(koplocks, fsp, oplock_type)) + { + return map_nt_error_from_unix(errno); } fsp->oplock_type = oplock_type; fsp->sent_oplock_break = NO_BREAK_SENT; if (oplock_type == LEVEL_II_OPLOCK) { - level_II_oplocks_open++; + sconn->oplocks.level_II_open++; } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - exclusive_oplocks_open++; + sconn->oplocks.exclusive_open++; } DEBUG(5,("set_file_oplock: granted oplock on file %s, %s/%lu, " @@ -92,7 +86,7 @@ bool set_file_oplock(files_struct *fsp, int oplock_type) fsp->fh->gen_id, (int)fsp->open_time.tv_sec, (int)fsp->open_time.tv_usec )); - return True; + return NT_STATUS_OK; } /**************************************************************************** @@ -101,27 +95,24 @@ bool set_file_oplock(files_struct *fsp, int oplock_type) 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) && koplocks) { koplocks->ops->release_oplock(koplocks, fsp, NO_OPLOCK); } if (fsp->oplock_type == LEVEL_II_OPLOCK) { - level_II_oplocks_open--; + sconn->oplocks.level_II_open--; } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { - exclusive_oplocks_open--; + sconn->oplocks.exclusive_open--; } - SMB_ASSERT(exclusive_oplocks_open>=0); - SMB_ASSERT(level_II_oplocks_open>=0); + SMB_ASSERT(sconn->oplocks.exclusive_open>=0); + SMB_ASSERT(sconn->oplocks.level_II_open>=0); - 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->oplock_type = NO_OPLOCK; fsp->sent_oplock_break = NO_BREAK_SENT; flush_write_cache(fsp, OPLOCK_RELEASE_FLUSH); @@ -136,6 +127,9 @@ void release_file_oplock(files_struct *fsp) 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")); return; @@ -145,9 +139,11 @@ static void downgrade_file_oplock(files_struct *fsp) koplocks->ops->release_oplock(koplocks, fsp, LEVEL_II_OPLOCK); } fsp->oplock_type = LEVEL_II_OPLOCK; - exclusive_oplocks_open--; - level_II_oplocks_open++; + sconn->oplocks.exclusive_open--; + sconn->oplocks.level_II_open++; fsp->sent_oplock_break = NO_BREAK_SENT; + + TALLOC_FREE(fsp->oplock_timeout); } /**************************************************************************** @@ -161,19 +157,60 @@ bool remove_oplock(files_struct *fsp) bool ret; struct share_mode_lock *lck; + DEBUG(10, ("remove_oplock called for %s\n", + fsp_str_dbg(fsp))); + /* 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_str_dbg(fsp))); return False; } + + if (fsp->oplock_type == LEVEL_II_OPLOCK) { + + /* + * If we're the only LEVEL_II holder, we have to remove the + * have_read_oplocks from the brlock entry + */ + + struct share_mode_data *data = lck->data; + uint32_t i, num_level2; + + num_level2 = 0; + for (i=0; inum_share_modes; i++) { + if (data->share_modes[i].op_type == LEVEL_II_OPLOCK) { + num_level2 += 1; + } + if (num_level2 > 1) { + /* + * No need to count them all... + */ + break; + } + } + + if (num_level2 == 1) { + /* + * That's only us. We are dropping that level2 oplock, + * so remove the brlock flag. + */ + struct byte_range_lock *brl; + + brl = brl_get_locks(talloc_tos(), fsp); + if (brl) { + brl_set_have_read_oplocks(brl, false); + TALLOC_FREE(brl); + } + } + } + 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); @@ -188,9 +225,12 @@ bool downgrade_oplock(files_struct *fsp) { bool ret; struct share_mode_lock *lck; + struct byte_range_lock *brl; + + DEBUG(10, ("downgrade_oplock called for %s\n", + fsp_str_dbg(fsp))); - 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_str_dbg(fsp))); @@ -199,39 +239,32 @@ bool downgrade_oplock(files_struct *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))); } downgrade_file_oplock(fsp); + + brl = brl_get_locks(talloc_tos(), fsp); + if (brl != NULL) { + brl_set_have_read_oplocks(brl, true); + TALLOC_FREE(brl); + } + TALLOC_FREE(lck); 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); @@ -243,7 +276,6 @@ static char *new_break_message_smb1(TALLOC_CTX *mem_ctx, SSVAL(result,smb_vwv2,fsp->fnum); SCVAL(result,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE); SCVAL(result,smb_vwv3+1,cmd); - return result; } /**************************************************************************** @@ -269,12 +301,11 @@ static files_struct *initial_break_processing( { files_struct *fsp = NULL; - if( DEBUGLVL( 3 ) ) { - dbgtext( "initial_break_processing: called for %s/%u\n", - file_id_string_tos(&id), (int)file_id); - dbgtext( "Current oplocks_open (exclusive = %d, levelII = %d)\n", - exclusive_oplocks_open, level_II_oplocks_open ); - } + DEBUG(3, ("initial_break_processing: called for %s/%u\n" + "Current oplocks_open (exclusive = %d, levelII = %d)\n", + file_id_string_tos(&id), (int)file_id, + sconn->oplocks.exclusive_open, + sconn->oplocks.level_II_open)); /* * We need to search the file open table for the @@ -286,11 +317,9 @@ static files_struct *initial_break_processing( if(fsp == NULL) { /* 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( "allowing break to succeed.\n" ); - } + DEBUG(3, ("initial_break_processing: cannot find open file " + "with file_id %s gen_id = %lu, allowing break to " + "succeed.\n", file_id_string_tos(&id), file_id)); return NULL; } @@ -305,32 +334,30 @@ static files_struct *initial_break_processing( */ if(fsp->oplock_type == NO_OPLOCK) { - if( DEBUGLVL( 3 ) ) { - 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" ); - } + DEBUG(3, ("initial_break_processing: file %s (file_id = %s " + "gen_id = %lu) has no oplock. Allowing break to " + "succeed regardless.\n", fsp_str_dbg(fsp), + file_id_string_tos(&id), fsp->fh->gen_id)); 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); } /******************************************************************* @@ -339,6 +366,9 @@ static void oplock_timeout_handler(struct event_context *ctx, 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. @@ -365,12 +395,9 @@ static void add_oplock_timeout_handler(files_struct *fsp) 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, @@ -380,11 +407,9 @@ static void send_break_message_smb1(files_struct *fsp, int level) 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; @@ -396,19 +421,11 @@ void break_level2_to_none_async(files_struct *fsp) 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, + "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. */ @@ -430,7 +447,7 @@ void break_level2_to_none_async(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, @@ -439,13 +456,9 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx struct share_mode_entry msg; files_struct *fsp; struct smbd_server_connection *sconn = - talloc_get_type(private_data, + talloc_get_type_abort(private_data, struct smbd_server_connection); - if (sconn == NULL) { - return; - } - if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); return; @@ -490,13 +503,12 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, struct share_mode_entry msg; files_struct *fsp; bool break_to_level2 = False; + bool use_kernel; struct smbd_server_connection *sconn = - talloc_get_type(private_data, + talloc_get_type_abort(private_data, struct smbd_server_connection); - - if (sconn == NULL) { - return; - } + 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")); @@ -520,24 +532,15 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, 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; } @@ -546,23 +549,20 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, 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; } - if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && - !(msg.op_type & FORCE_OPLOCK_BREAK_TO_NONE) && - !(koplocks && !(koplocks->flags & KOPLOCKS_LEVEL2_SUPPORTED)) && + use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) && koplocks; + + if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && + !(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(); } @@ -576,11 +576,6 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, 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); } @@ -598,13 +593,9 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, unsigned long file_id; files_struct *fsp; struct smbd_server_connection *sconn = - talloc_get_type(private_data, + talloc_get_type_abort(private_data, struct smbd_server_connection); - if (sconn == NULL) { - return; - } - if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); return; @@ -649,150 +640,96 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, 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; inum_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); - } +struct break_to_none_state { + struct smbd_server_connection *sconn; + struct file_id id; +}; +static void do_break_to_none(struct tevent_context *ctx, + struct tevent_immediate *im, + void *private_data); - 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; - } - return; -} +/**************************************************************************** + 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 + none. +****************************************************************************/ -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) +static void contend_level2_oplocks_begin_default(files_struct *fsp, + enum level2_contention_type type) { - struct share_mode_entry msg; - struct smbd_server_connection *sconn = - talloc_get_type(private_data, - struct smbd_server_connection); + struct smbd_server_connection *sconn = fsp->conn->sconn; + struct tevent_immediate *im; + struct break_to_none_state *state; + struct byte_range_lock *brl; - if (sconn == NULL) { - return; - } + /* + * If this file is level II oplocked then we need + * to grab the shared memory lock and inform all + * other files with a level II lock that they need + * to flush their read caches. We keep the lock over + * the shared memory area whilst doing this. + */ - if (data->data == NULL) { - DEBUG(0, ("Got NULL buffer\n")); + if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { + /* + * There can't be any level2 oplocks, we're alone. + */ return; } - if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) { - DEBUG(0, ("Got invalid msg len %u\n", - (unsigned int)data->length)); + brl = brl_get_locks_readonly(fsp); + if ((brl != NULL) && !brl_have_read_oplocks(brl)) { + DEBUG(10, ("No read oplocks around\n")); 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(private_data, - struct smbd_server_connection); - - if (sconn == NULL) { - return; - } + /* + * 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 event. + */ - if (data->data == NULL) { - DEBUG(0, ("Got NULL buffer\n")); + 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; - if (data->length != MSG_SMB_SHARE_MODE_ENTRY_SIZE) { - DEBUG(0, ("Got invalid msg len %d\n", (int)data->length)); + im = tevent_create_immediate(state); + if (im == NULL) { + DEBUG(1, ("tevent_create_immediate failed\n")); + TALLOC_FREE(state); 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); + tevent_schedule_immediate(im, sconn->ev_ctx, do_break_to_none, state); } -/**************************************************************************** - 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 - none. -****************************************************************************/ - -static void contend_level2_oplocks_begin_default(files_struct *fsp, - enum level2_contention_type type) +static void do_break_to_none(struct tevent_context *ctx, + struct tevent_immediate *im, + void *private_data) { + 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; - /* - * If this file is level II oplocked then we need - * to grab the shared memory lock and inform all - * other files with a level II lock that they need - * to flush their read caches. We keep the lock over - * the shared memory area whilst doing this. - */ - - if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) - return; - - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, - NULL); + lck = get_existing_share_mode_lock(talloc_tos(), state->id); if (lck == NULL) { - DEBUG(0,("release_level_2_oplocks_on_change: failed to lock " - "share mode entry for file %s.\n", fsp_str_dbg(fsp))); - return; + 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)) { @@ -841,24 +778,23 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, * Bugid #5980. */ - if (procid_is_me(&share_entry->pid)) { + if (serverid_equal(&self, &share_entry->pid)) { struct files_struct *cur_fsp = - initial_break_processing(fsp->conn->sconn, + 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: " "Did not find fsp, ignoring\n")); } } else { - messaging_send_buf(fsp->conn->sconn->msg_ctx, + messaging_send_buf(state->sconn->msg_ctx, share_entry->pid, MSG_SMB_ASYNC_LEVEL2_BREAK, - (uint8 *)msg, - MSG_SMB_SHARE_MODE_ENTRY_SIZE); + (uint8 *)msg, sizeof(msg)); } } @@ -866,11 +802,17 @@ 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 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; @@ -882,6 +824,9 @@ void smbd_contend_level2_oplocks_begin(files_struct *fsp, 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); @@ -914,7 +859,7 @@ void share_mode_entry_to_message(char *msg, const struct share_mode_entry *e) De-linearize an internal oplock break message to a share mode entry struct. ****************************************************************************/ -void message_to_share_mode_entry(struct share_mode_entry *e, char *msg) +void message_to_share_mode_entry(struct share_mode_entry *e, const char *msg) { e->pid.pid = (pid_t)IVAL(msg,OP_BREAK_MSG_PID_OFFSET); e->op_mid = BVAL(msg,OP_BREAK_MSG_MID_OFFSET); @@ -944,23 +889,22 @@ bool init_oplocks(struct smbd_server_connection *sconn) 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; +} - if (lp_kernel_oplocks()) { +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 - koplocks = irix_init_kernel_oplocks(NULL); + koplocks = irix_init_kernel_oplocks(sconn); #elif HAVE_KERNEL_OPLOCKS_LINUX - koplocks = linux_init_kernel_oplocks(NULL); -#elif HAVE_ONEFS -#error Isilon, please check if the NULL context is okay here. Thanks! - koplocks = onefs_init_kernel_oplocks(NULL); + koplocks = linux_init_kernel_oplocks(sconn); #endif + sconn->oplocks.kernel_ops = koplocks; } - - return True; }