diff options
-rw-r--r-- | source3/smbd/oplock.c | 10 | ||||
-rw-r--r-- | source3/smbd/oplock_linux.c | 45 | ||||
-rw-r--r-- | source3/smbd/process.c | 21 |
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); |