diff options
author | Jeremy Allison <jra@samba.org> | 2003-01-30 01:41:46 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2003-01-30 01:41:46 +0000 |
commit | b61f89826f2b7ee8ca7bd388b66c3f5b78ed3e60 (patch) | |
tree | cab03bdf0d9d7b204aec66583513bd96d10e5e4c | |
parent | 812a531f4553c8eb2df572acd4fa42a6f91b3051 (diff) | |
download | samba-b61f89826f2b7ee8ca7bd388b66c3f5b78ed3e60.tar.gz samba-b61f89826f2b7ee8ca7bd388b66c3f5b78ed3e60.tar.bz2 samba-b61f89826f2b7ee8ca7bd388b66c3f5b78ed3e60.zip |
Fix for interesting resource constraint condition. When all opens are
level 2 and a request for open with no oplock is received then the
smbd should send *synchronous* break messages, not asynchronous,
otherwise it spins very rapidly, releasing the lock, sending the
'break to none' messages and then re-acquiring the lock before
any other process has a chance to get the lock and remove it's own
oplock (at least on linux).
Jeremy
(This used to be commit 33e3e863eb7f35b852384e689f3272784261fc39)
-rw-r--r-- | source3/include/smb.h | 4 | ||||
-rw-r--r-- | source3/smbd/open.c | 2 | ||||
-rw-r--r-- | source3/smbd/oplock.c | 33 |
3 files changed, 22 insertions, 17 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h index 3ca8d32289..8138555539 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1512,15 +1512,17 @@ extern int chain_size; * +----+--------+-------+--------+---------+ */ -#define OPLOCK_BREAK_CMD 0x1 #define OPLOCK_BREAK_PID_OFFSET 2 #define OPLOCK_BREAK_DEV_OFFSET (OPLOCK_BREAK_PID_OFFSET + sizeof(pid_t)) #define OPLOCK_BREAK_INODE_OFFSET (OPLOCK_BREAK_DEV_OFFSET + sizeof(SMB_DEV_T)) #define OPLOCK_BREAK_FILEID_OFFSET (OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T)) #define OPLOCK_BREAK_MSG_LEN (OPLOCK_BREAK_FILEID_OFFSET + sizeof(unsigned long)) +/* Message types */ +#define OPLOCK_BREAK_CMD 0x1 #define KERNEL_OPLOCK_BREAK_CMD 0x2 #define LEVEL_II_OPLOCK_BREAK_CMD 0x3 +#define ASYNC_LEVEL_II_OPLOCK_BREAK_CMD 0x4 /* * Capabilities abstracted for different systems. diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 5c3359fc6b..29048bca02 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -585,7 +585,7 @@ dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsi /* Oplock break - unlock to request it. */ unlock_share_entry(conn, dev, inode); - opb_ret = request_oplock_break(share_entry); + opb_ret = request_oplock_break(share_entry, False); /* Now relock. */ lock_share_entry(conn, dev, inode); diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 14b243b36e..f5c19bcf62 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -368,6 +368,7 @@ BOOL process_local_message(char *buffer, int buf_size) case OPLOCK_BREAK_CMD: case LEVEL_II_OPLOCK_BREAK_CMD: + case ASYNC_LEVEL_II_OPLOCK_BREAK_CMD: /* Ensure that the msg length is correct. */ if(msg_len != OPLOCK_BREAK_MSG_LEN) { @@ -438,14 +439,14 @@ oplocks. Returning success.\n")); } /* - * Do the appropriate reply - none in the kernel or level II case. + * Do the appropriate reply - none in the kernel or async level II case. */ - if(SVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET) == OPLOCK_BREAK_CMD) { + if(break_cmd_type == OPLOCK_BREAK_CMD || break_cmd_type == LEVEL_II_OPLOCK_BREAK_CMD) { struct sockaddr_in toaddr; /* Send the message back after OR'ing in the 'REPLY' bit. */ - SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD | CMD_REPLY); + SSVAL(msg_start,OPBRK_MESSAGE_CMD_OFFSET,break_cmd_type | CMD_REPLY); memset((char *)&toaddr,'\0',sizeof(toaddr)); toaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); @@ -902,7 +903,7 @@ 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. ****************************************************************************/ -BOOL request_oplock_break(share_mode_entry *share_entry) +BOOL request_oplock_break(share_mode_entry *share_entry, BOOL async) { char op_break_msg[OPLOCK_BREAK_MSG_LEN]; struct sockaddr_in addr_out; @@ -912,6 +913,7 @@ BOOL request_oplock_break(share_mode_entry *share_entry) SMB_DEV_T dev = share_entry->dev; SMB_INO_T inode = share_entry->inode; unsigned long file_id = share_entry->share_file_id; + uint16 break_cmd_type; if(pid == share_entry->pid) { /* We are breaking our own oplock, make sure it's us. */ @@ -942,11 +944,12 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n", /* 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)) { - SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,LEVEL_II_OPLOCK_BREAK_CMD); + break_cmd_type = async ? ASYNC_LEVEL_II_OPLOCK_BREAK_CMD : LEVEL_II_OPLOCK_BREAK_CMD; } else { - SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,OPLOCK_BREAK_CMD); + break_cmd_type = OPLOCK_BREAK_CMD; } + SSVAL(op_break_msg,OPBRK_MESSAGE_CMD_OFFSET,break_cmd_type); 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)); @@ -959,7 +962,7 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n", addr_out.sin_family = AF_INET; if( DEBUGLVL( 3 ) ) { - dbgtext( "request_oplock_break: sending a oplock break message to " ); + dbgtext( "request_oplock_break: sending a %s oplock break message to ", async ? "asynchronous" : "synchronous" ); 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 ); @@ -972,19 +975,19 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n", 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 ); + (unsigned int)dev, (double)inode, file_id ); dbgtext( "Error was %s\n", strerror(errno) ); } return False; } /* - * If we just sent a message to a level II oplock share entry then + * 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)) { - DEBUG(3,("request_oplock_break: sent break message to level II entry.\n")); + 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; } @@ -1039,10 +1042,10 @@ dev = %x, inode = %.0f, file_id = %lu and no fsp found !\n", reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN]; /* - * Test to see if this is the reply we are awaiting. + * Test to see if this is the reply we are awaiting (ie. the one we sent with the CMD_REPLY flag OR'ed in). */ if((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & CMD_REPLY) && - ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == OPLOCK_BREAK_CMD) && + ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == break_cmd_type) && (reply_from_port == share_entry->op_port) && (memcmp(&reply_msg_start[OPLOCK_BREAK_PID_OFFSET], &op_break_msg[OPLOCK_BREAK_PID_OFFSET], OPLOCK_BREAK_MSG_LEN - OPLOCK_BREAK_PID_OFFSET) == 0)) { @@ -1185,8 +1188,8 @@ void release_level_2_oplocks_on_change(files_struct *fsp) * message. */ - DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock.\n")); - request_oplock_break(share_entry); + DEBUG(10,("release_level_2_oplocks_on_change: breaking remote oplock (async).\n")); + request_oplock_break(share_entry, True); } } |