summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2003-01-30 01:41:46 +0000
committerJeremy Allison <jra@samba.org>2003-01-30 01:41:46 +0000
commitb61f89826f2b7ee8ca7bd388b66c3f5b78ed3e60 (patch)
treecab03bdf0d9d7b204aec66583513bd96d10e5e4c
parent812a531f4553c8eb2df572acd4fa42a6f91b3051 (diff)
downloadsamba-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.h4
-rw-r--r--source3/smbd/open.c2
-rw-r--r--source3/smbd/oplock.c33
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);
}
}