summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/oplock.c10
-rw-r--r--source3/smbd/oplock_linux.c45
-rw-r--r--source3/smbd/process.c21
3 files changed, 55 insertions, 21 deletions
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index f20885a7e1..14b243b36e 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -83,6 +83,16 @@ BOOL receive_local_message( char *buffer, int buffer_len, int timeout)
FD_ZERO(&fds);
smb_read_error = 0;
+ /*
+ * We need to check for kernel oplocks before going into the select
+ * here, as the EINTR generated by the linux kernel oplock may have
+ * already been eaten. JRA.
+ */
+
+ if (koplocks && koplocks->msg_waiting(&fds)) {
+ return koplocks->receive_message(&fds, buffer, buffer_len);
+ }
+
while (timeout > 0 && selrtn == -1) {
struct timeval to;
int maxfd = oplock_sock;
diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c
index 372ad857c4..459d987272 100644
--- a/source3/smbd/oplock_linux.c
+++ b/source3/smbd/oplock_linux.c
@@ -23,8 +23,8 @@
#if HAVE_KERNEL_OPLOCKS_LINUX
static VOLATILE sig_atomic_t signals_received;
-static VOLATILE sig_atomic_t signals_processed;
-static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal */
+#define FD_PENDING_SIZE 100
+static VOLATILE sig_atomic_t fd_pending_array[FD_PENDING_SIZE];
#ifndef F_SETLEASE
#define F_SETLEASE 1024
@@ -52,9 +52,10 @@ static VOLATILE sig_atomic_t fd_pending; /* the fd of the current pending signal
static void signal_handler(int sig, siginfo_t *info, void *unused)
{
- BlockSignals(True, sig);
- fd_pending = (sig_atomic_t)info->si_fd;
- signals_received++;
+ if (signals_received < FD_PENDING_SIZE - 1) {
+ fd_pending_array[signals_received] = (sig_atomic_t)info->si_fd;
+ signals_received++;
+ } /* Else signal is lost. */
sys_select_signal();
}
@@ -124,20 +125,28 @@ static int linux_setlease(int fd, int leasetype)
static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len)
{
- BOOL ret = True;
+ int fd;
struct files_struct *fsp;
- if (signals_received == signals_processed)
- return False;
+ BlockSignals(True, RT_SIGNAL_LEASE);
+ fd = fd_pending_array[0];
+ fsp = file_find_fd(fd);
+ fd_pending_array[0] = (sig_atomic_t)-1;
+ if (signals_received > 1)
+ memmove(&fd_pending_array[0], &fd_pending_array[1],
+ sizeof(sig_atomic_t)*(signals_received-1));
+ signals_received--;
+ /* now we can receive more signals */
+ BlockSignals(False, RT_SIGNAL_LEASE);
- if ((fsp = file_find_fd(fd_pending)) == NULL) {
- DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd_pending));
- ret = False;
- goto out;
+ if (fsp == NULL) {
+ DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", (int)fd));
+ return False;
}
DEBUG(3,("linux_oplock_receive_message: kernel oplock break request received for \
-dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
+dev = %x, inode = %.0f fd = %d, fileid = %lu \n", (unsigned int)fsp->dev, (double)fsp->inode,
+ fd, fsp->file_id));
/*
* Create a kernel oplock break message.
@@ -155,13 +164,7 @@ dev = %x, inode = %.0f\n", (unsigned int)fsp->dev, (double)fsp->inode ));
memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&fsp->inode, sizeof(fsp->inode));
memcpy(buffer + KERNEL_OPLOCK_BREAK_FILEID_OFFSET, (char *)&fsp->file_id, sizeof(fsp->file_id));
- out:
- /* now we can receive more signals */
- fd_pending = (sig_atomic_t)-1;
- signals_processed++;
- BlockSignals(False, RT_SIGNAL_LEASE);
-
- return ret;
+ return True;
}
/****************************************************************************
@@ -244,7 +247,7 @@ static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *i
static BOOL linux_oplock_msg_waiting(fd_set *fds)
{
- return signals_processed != signals_received;
+ return signals_received != 0;
}
/****************************************************************************
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 010b188701..0cfb4a6264 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -195,6 +195,27 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
*/
FD_ZERO(&fds);
+
+ /*
+ * Ensure we process oplock break messages by preference.
+ * We have to do this before the select, after the select
+ * and if the select returns EINTR. This is due to the fact
+ * that the selects called from async_processing can eat an EINTR
+ * caused by a signal (we can't take the break message there).
+ * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
+ */
+
+ if (oplock_message_waiting(&fds)) {
+ DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
+ async_processing(buffer, buffer_len);
+ /*
+ * After async processing we must go and do the select again, as
+ * the state of the flag in fds for the server file descriptor is
+ * indeterminate - we may have done I/O on it in the oplock processing. JRA.
+ */
+ goto again;
+ }
+
FD_SET(smbd_server_fd(),&fds);
maxfd = setup_oplock_select_set(&fds);