BOOL global_client_failed_oplock_break = False;
BOOL global_oplock_break = False;
+extern struct timeval smb_last_time;
+extern uint32 global_client_caps;
+extern struct current_user current_user;
extern int smb_read_error;
static struct kernel_oplocks *koplocks;
(int)remotepid, from_port, (unsigned int)dev, (double)inode, file_id));
break;
+ case RETRY_DEFERRED_OPEN_CMD:
+
+ /* Request to retry and open that would return SHARING_VIOLATION. */
+ if (msg_len != DEFERRED_OPEN_MSG_LEN) {
+ DEBUG(0,("process_local_message: incorrect length for RETRY_DEFERRED_OPEN_CMD (was %d, should be %d).\n",
+ (int)msg_len, (int)DEFERRED_OPEN_MSG_LEN));
+ return False;
+ }
+ {
+ uint16 mid;
+
+ memcpy((char *)&remotepid, msg_start+DEFERRED_OPEN_PID_OFFSET,sizeof(remotepid));
+ memcpy((char *)&inode, msg_start+DEFERRED_OPEN_INODE_OFFSET,sizeof(inode));
+ memcpy((char *)&dev, msg_start+DEFERRED_OPEN_DEV_OFFSET,sizeof(dev));
+ memcpy((char *)&mid, msg_start+DEFERRED_OPEN_MID_OFFSET,sizeof(mid));
+
+ DEBUG(5,("process_local_message: RETRY_DEFERRED_OPEN from \
+pid %d, port %d, dev = %x, inode = %.0f, mid = %u\n",
+ (int)remotepid, from_port, (unsigned int)dev, (double)inode, (unsigned int)mid));
+
+ schedule_sharing_violation_open_smb_message(mid);
+ }
+ return True;
+
/*
* Keep this as a debug case - eventually we can remove it.
*/
static void wait_before_sending_break(BOOL local_request)
{
- extern struct timeval smb_last_time;
-
if(local_request) {
struct timeval cur_tv;
long wait_left = (long)lp_oplock_break_wait_time();
/****************************************************************************
Process a level II oplock break directly.
+ We must call this function with the share mode entry locked.
****************************************************************************/
-BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token)
+static BOOL oplock_break_level2(files_struct *fsp, BOOL local_request)
{
- extern uint32 global_client_caps;
char outbuf[128];
- BOOL got_lock = False;
SMB_DEV_T dev = fsp->dev;
SMB_INO_T inode = fsp->inode;
*/
if (global_client_caps & CAP_LEVEL_II_OPLOCKS) {
+ BOOL sign_state;
+
/*
* If we are sending an oplock break due to an SMB sent
* by our own client we ensure that we wait at leat
wait_before_sending_break(local_request);
/* Prepare the SMBlockingX message. */
-
prepare_break_message( outbuf, fsp, False);
+
+ /* Save the server smb signing state. */
+ sign_state = srv_oplock_set_signing(False);
+
if (!send_smb(smbd_server_fd(), outbuf))
exit_server("oplock_break_level2: send_smb failed.");
+
+ /* Restore the sign state to what it was. */
+ srv_oplock_set_signing(sign_state);
}
/*
* Now we must update the shared memory structure to tell
* everyone else we no longer have a level II oplock on
- * this open file. If local_request is true then token is
- * the existing lock on the shared memory area.
+ * this open file. We must call this function with the share mode
+ * entry locked so we can change the entry directly.
*/
- if(!local_request && lock_share_entry_fsp(fsp) == False) {
- DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name ));
- } else {
- got_lock = True;
- }
-
if(remove_share_oplock(fsp)==False) {
DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name ));
}
release_file_oplock(fsp);
- if (!local_request && got_lock)
- unlock_share_entry_fsp(fsp);
-
if(level_II_oplocks_open < 0) {
DEBUG(0,("oplock_break_level2: level_II_oplocks_open < 0 (%d). PANIC ERROR\n",
level_II_oplocks_open));
/****************************************************************************
Process an oplock break directly.
+ This is always called with the share mode lock *NOT* held.
****************************************************************************/
static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id, BOOL local_request)
{
- extern uint32 global_client_caps;
- extern struct current_user current_user;
char *inbuf = NULL;
char *outbuf = NULL;
files_struct *fsp = NULL;
time_t start_time;
BOOL shutdown_server = False;
BOOL oplock_timeout = False;
+ BOOL sign_state;
connection_struct *saved_user_conn;
connection_struct *saved_fsp_conn;
int saved_vuid;
* Deal with a level II oplock going break to none separately.
*/
- if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type))
- return oplock_break_level2(fsp, local_request, -1);
+ if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) {
+ BOOL ret;
+ /* We must always call oplock_break_level2() with
+ the share mode entry locked. */
+ if (lock_share_entry_fsp(fsp) == False) {
+ DEBUG(0,("oplock_break: unable to lock share entry for file %s\n", fsp->fsp_name ));
+ return False;
+ }
+ ret = oplock_break_level2(fsp, local_request);
+ unlock_share_entry_fsp(fsp);
+ return ret;
+ }
/* Mark the oplock break as sent - we don't want to send twice! */
if (fsp->sent_oplock_break) {
* messages crossing on the wire.
*/
- if((inbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) {
+ if((inbuf = (char *)SMB_MALLOC(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) {
DEBUG(0,("oplock_break: malloc fail for input buffer.\n"));
return False;
}
- if((outbuf = (char *)malloc(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) {
+ if((outbuf = (char *)SMB_MALLOC(BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN))==NULL) {
DEBUG(0,("oplock_break: malloc fail for output buffer.\n"));
SAFE_FREE(inbuf);
return False;
/* Remember if we just sent a break to level II on this file. */
fsp->sent_oplock_break = using_levelII? LEVEL_II_BREAK_SENT:EXCLUSIVE_BREAK_SENT;
- if (!send_smb(smbd_server_fd(), outbuf))
+ /* Save the server smb signing state. */
+ sign_state = srv_oplock_set_signing(False);
+
+ if (!send_smb(smbd_server_fd(), outbuf)) {
+ srv_oplock_set_signing(sign_state);
exit_server("oplock_break: send_smb failed.");
+ }
+
+ /* Restore the sign state to what it was. */
+ srv_oplock_set_signing(sign_state);
/* We need this in case a readraw crosses on the wire. */
global_oplock_break = True;
} else if (smb_read_error == READ_ERROR) {
DEBUG( 0, ("oplock_break: receive_smb error (%s)\n", strerror(errno)) );
shutdown_server = True;
+ } else if (smb_read_error == READ_BAD_SIG) {
+ DEBUG( 0, ("oplock_break: bad signature from client\n" ));
+ shutdown_server = True;
} else if (smb_read_error == READ_TIMEOUT) {
DEBUG( 0, ( "oplock_break: receive_smb timed out after %d seconds.\n", OPLOCK_BREAK_TIMEOUT ) );
oplock_timeout = True;
abort();
}
+ /* We know we have no saved errors here. */
+ set_saved_error_triple(0, 0, NT_STATUS_OK);
+
if( DEBUGLVL( 3 ) ) {
dbgtext( "oplock_break: returning success for " );
dbgtext( "dev = %x, inode = %.0f, file_id = %lu\n", (unsigned int)dev, (double)inode, file_id );
}
/****************************************************************************
-Send an oplock break message to another smbd process. If the oplock is held
-by the local smbd then call the oplock break function directly.
+ Send an oplock break message to another smbd process. If the oplock is held
+ by the local smbd then call the oplock break function directly.
+ This function is called with no share locks held.
****************************************************************************/
-BOOL request_oplock_break(share_mode_entry *share_entry, BOOL async)
+BOOL request_oplock_break(share_mode_entry *share_entry)
{
char op_break_msg[OPLOCK_BREAK_MSG_LEN];
struct sockaddr_in addr_out;
/* We need to send a OPLOCK_BREAK_CMD message to the port in the share mode entry. */
if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) {
- break_cmd_type = async ? ASYNC_LEVEL_II_OPLOCK_BREAK_CMD : LEVEL_II_OPLOCK_BREAK_CMD;
+ break_cmd_type = LEVEL_II_OPLOCK_BREAK_CMD;
} else {
break_cmd_type = OPLOCK_BREAK_CMD;
}
addr_out.sin_family = AF_INET;
if( DEBUGLVL( 3 ) ) {
- dbgtext( "request_oplock_break: sending a %s oplock break message to ", async ? "asynchronous" : "synchronous" );
+ dbgtext( "request_oplock_break: sending a synchronous oplock break message to " );
dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
(unsigned int)dev, (double)inode, file_id );
return False;
}
- /*
- * If we just sent a message to a level II oplock share entry in async mode then
- * we are done and may return.
- */
-
- if (LEVEL_II_OPLOCK_TYPE(share_entry->op_type) && async) {
- DEBUG(3,("request_oplock_break: sent async break message to level II entry.\n"));
- return True;
- }
-
/*
* Now we must await the oplock broken message coming back
* from the target smbd process. Timeout if it fails to
return False;
}
+/****************************************************************************
+ Send an asynchronous oplock break message to another smbd process.
+****************************************************************************/
+
+static BOOL request_remote_level2_async_oplock_break(share_mode_entry *share_entry)
+{
+ char op_break_msg[OPLOCK_BREAK_MSG_LEN];
+ struct sockaddr_in addr_out;
+ pid_t pid = sys_getpid();
+ SMB_DEV_T dev = share_entry->dev;
+ SMB_INO_T inode = share_entry->inode;
+ unsigned long file_id = share_entry->share_file_id;
+
+ /* We need to send a ASYNC_LEVEL_II_OPLOCK_BREAK_CMD message to the port in the share mode entry. */
+
+ SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,ASYNC_LEVEL_II_OPLOCK_BREAK_CMD);
+ memcpy(op_break_msg+OPLOCK_BREAK_PID_OFFSET,(char *)&pid,sizeof(pid));
+ memcpy(op_break_msg+OPLOCK_BREAK_DEV_OFFSET,(char *)&dev,sizeof(dev));
+ memcpy(op_break_msg+OPLOCK_BREAK_INODE_OFFSET,(char *)&inode,sizeof(inode));
+ memcpy(op_break_msg+OPLOCK_BREAK_FILEID_OFFSET,(char *)&file_id,sizeof(file_id));
+
+ /* Set the address and port. */
+ memset((char *)&addr_out,'\0',sizeof(addr_out));
+ addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr_out.sin_port = htons( share_entry->op_port );
+ addr_out.sin_family = AF_INET;
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "request_remote_level2_async_oplock_break: sending an asynchronous oplock break message to ");
+ dbgtext( "pid %d on port %d ", (int)share_entry->pid, share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ }
+
+ if(sys_sendto(oplock_sock,op_break_msg,OPLOCK_BREAK_MSG_LEN,0,
+ (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "request_remote_level2_async_oplock_break: failed when sending a oplock " );
+ dbgtext( "break message to pid %d ", (int)share_entry->pid );
+ dbgtext( "on port %d ", share_entry->op_port );
+ dbgtext( "for dev = %x, inode = %.0f, file_id = %lu\n",
+ (unsigned int)dev, (double)inode, file_id );
+ dbgtext( "Error was %s\n", strerror(errno) );
+ }
+ return False;
+ }
+
+ DEBUG(3,("request_remote_level2_async_oplock_break: sent async break message to level II entry.\n"));
+ return True;
+}
+
/****************************************************************************
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.
{
share_mode_entry *share_list = NULL;
pid_t pid = sys_getpid();
- int token = -1;
int num_share_modes = 0;
int i;
DEBUG(10,("release_level_2_oplocks_on_change: breaking our own oplock.\n"));
- oplock_break_level2(new_fsp, True, token);
+ oplock_break_level2(new_fsp, True);
} else {
*/
DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock (async).\n"));
- request_oplock_break(share_entry, True);
+ request_remote_level2_async_oplock_break(share_entry);
}
}
}
/****************************************************************************
-setup oplocks for this process
+ Send a 'retry your open' message to a process with a deferred open entry.
+****************************************************************************/
+
+BOOL send_deferred_open_retry_message(deferred_open_entry *entry)
+{
+ char de_msg[DEFERRED_OPEN_MSG_LEN];
+ struct sockaddr_in addr_out;
+ pid_t pid = sys_getpid();
+
+ memset(de_msg, '\0', DEFERRED_OPEN_MSG_LEN);
+ SSVAL(de_msg,DEFERRED_OPEN_CMD_OFFSET,RETRY_DEFERRED_OPEN_CMD);
+ memcpy(de_msg+DEFERRED_OPEN_PID_OFFSET,(char *)&pid,sizeof(pid));
+ memcpy(de_msg+DEFERRED_OPEN_DEV_OFFSET,(char *)&entry->dev,sizeof(entry->dev));
+ memcpy(de_msg+DEFERRED_OPEN_INODE_OFFSET,(char *)&entry->inode,sizeof(entry->inode));
+ memcpy(de_msg+DEFERRED_OPEN_MID_OFFSET,(char *)&entry->mid,sizeof(entry->mid));
+
+ /* Set the address and port. */
+ memset((char *)&addr_out,'\0',sizeof(addr_out));
+ addr_out.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr_out.sin_port = htons( entry->port );
+ addr_out.sin_family = AF_INET;
+
+ if( DEBUGLVL( 3 ) ) {
+ dbgtext( "send_deferred_open_retry_message: sending a message to ");
+ dbgtext( "pid %d on port %d ", (int)entry->pid, entry->port );
+ dbgtext( "for dev = %x, inode = %.0f, mid = %u\n",
+ (unsigned int)entry->dev, (double)entry->inode, (unsigned int)entry->mid );
+ }
+
+ if(sys_sendto(oplock_sock,de_msg,DEFERRED_OPEN_MSG_LEN,0,
+ (struct sockaddr *)&addr_out,sizeof(addr_out)) < 0) {
+ if( DEBUGLVL( 0 ) ) {
+ dbgtext( "send_deferred_open_retry_message: failed sending a message to ");
+ dbgtext( "pid %d on port %d ", (int)entry->pid, entry->port );
+ dbgtext( "for dev = %x, inode = %.0f, mid = %u\n",
+ (unsigned int)entry->dev, (double)entry->inode, (unsigned int)entry->mid );
+ dbgtext( "Error was %s\n", strerror(errno) );
+ }
+ return False;
+ }
+ return True;
+}
+
+/****************************************************************************
+ Setup oplocks for this process.
****************************************************************************/
BOOL init_oplocks(void)