summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2000-06-11 05:57:58 +0000
committerAndrew Tridgell <tridge@samba.org>2000-06-11 05:57:58 +0000
commit8843a6379d7c1cf59f0f3673cbc567b09994b7d2 (patch)
tree63f645769adeecd6cfd999a8f2d873f1c5a626b6
parent4ec7597d1154c60f0f55feab93f2dc9c776d56f8 (diff)
downloadsamba-8843a6379d7c1cf59f0f3673cbc567b09994b7d2.tar.gz
samba-8843a6379d7c1cf59f0f3673cbc567b09994b7d2.tar.bz2
samba-8843a6379d7c1cf59f0f3673cbc567b09994b7d2.zip
Linux kernel oplocks now seem to work, but need a _lot_ of testing
I had to modify sys_select() to not loop on EINTR. I added a wrapper called sys_select_intr() which gives the old behaviour. (This used to be commit b28cc4163bc2faaa80c5782fc02c8f03c410cdeb)
-rw-r--r--source3/client/client.c4
-rw-r--r--source3/include/includes.h12
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/lib/system.c26
-rw-r--r--source3/lib/util.c2
-rw-r--r--source3/lib/util_sock.c4
-rw-r--r--source3/libsmb/nmblib.c2
-rw-r--r--source3/nmbd/nmbd_packets.c2
-rw-r--r--source3/param/loadparm.c1
-rw-r--r--source3/rpcclient/rpcclient.c2
-rw-r--r--source3/smbd/oplock.c9
-rw-r--r--source3/smbd/oplock_irix.c4
-rw-r--r--source3/smbd/oplock_linux.c63
-rw-r--r--source3/smbd/process.c107
-rw-r--r--source3/smbd/server.c2
-rw-r--r--source3/utils/smbfilter.c4
16 files changed, 166 insertions, 79 deletions
diff --git a/source3/client/client.c b/source3/client/client.c
index 6449b1335c..cbc4eb6f7c 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -1751,8 +1751,8 @@ static void wait_keyboard(void)
timeout.tv_sec = 20;
timeout.tv_usec = 0;
- sys_select(MAX(cli->fd,fileno(stdin))+1,&fds,&timeout);
-
+ sys_select_intr(MAX(cli->fd,fileno(stdin))+1,&fds,&timeout);
+
if (FD_ISSET(fileno(stdin),&fds))
return;
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 432fd09f0b..a30a8448ad 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -868,6 +868,18 @@ int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
#include <dlfcn.h>
#endif
+#if HAVE_KERNEL_OPLOCKS_LINUX
+#ifndef F_SETLEASE
+#define F_SETLEASE 1024
+#endif
+#ifndef F_GETLEASE
+#define F_GETLEASE 1025
+#endif
+#ifndef CAP_LEASE
+#define CAP_LEASE 28
+#endif
+#endif
+
extern int DEBUGLEVEL;
#endif /* _INCLUDES_H */
diff --git a/source3/include/proto.h b/source3/include/proto.h
index b6aeb19232..f874f0e1a1 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -214,6 +214,7 @@ void standard_sub_vsnum(char *str, user_struct *vuser, int snum);
int sys_select(int maxfd, fd_set *fds,struct timeval *tval);
int sys_select(int maxfd, fd_set *fds,struct timeval *tval);
+int sys_select_intr(int maxfd, fd_set *fds,struct timeval *tval);
int sys_usleep(long usecs);
int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf);
int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf);
diff --git a/source3/lib/system.c b/source3/lib/system.c
index 2a99ae779e..46b01b747a 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -112,9 +112,7 @@ int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
timeout = (tval != NULL) ? (tval->tv_sec * 1000) + (tval->tv_usec/1000) :
-1;
errno = 0;
- do {
- pollrtn = poll( &pfd[0], maxpoll, timeout);
- } while (pollrtn<0 && errno == EINTR);
+ pollrtn = poll( &pfd[0], maxpoll, timeout);
FD_ZERO(fds);
@@ -128,11 +126,9 @@ int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
struct timeval t2;
int selrtn;
- do {
- if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
- errno = 0;
- selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
- } while (selrtn<0 && errno == EINTR);
+ if (tval) memcpy((void *)&t2,(void *)tval,sizeof(t2));
+ errno = 0;
+ selrtn = select(maxfd,SELECT_CAST fds,NULL,NULL,tval?&t2:NULL);
return(selrtn);
}
@@ -140,6 +136,20 @@ int sys_select(int maxfd, fd_set *fds,struct timeval *tval)
#endif /* NO_SELECT */
/*******************************************************************
+similar to sys_select() but catch EINTR and continue
+this is what sys_select() used to do in Samba
+********************************************************************/
+int sys_select_intr(int maxfd, fd_set *fds,struct timeval *tval)
+{
+ int ret;
+ do {
+ ret = sys_select(maxfd, fds, tval);
+ } while (ret == -1 && errno == EINTR);
+ return ret;
+}
+
+
+/*******************************************************************
A wrapper for usleep in case we don't have one.
********************************************************************/
diff --git a/source3/lib/util.c b/source3/lib/util.c
index e5aa20a972..f2d89eebb7 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -728,7 +728,7 @@ void msleep(int t)
FD_ZERO(&fds);
errno = 0;
- sys_select(0,&fds,&tval);
+ sys_select_intr(0,&fds,&tval);
GetTimeOfDay(&t2);
tdiff = TvalDiff(&t1,&t2);
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
index bb62442beb..e6aef16d16 100644
--- a/source3/lib/util_sock.c
+++ b/source3/lib/util_sock.c
@@ -241,7 +241,7 @@ static ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t ma
FD_ZERO(&fds);
FD_SET(fd,&fds);
- selrtn = sys_select(fd+1,&fds,&timeout);
+ selrtn = sys_select_intr(fd+1,&fds,&timeout);
/* Check if error */
if(selrtn == -1) {
@@ -345,7 +345,7 @@ ssize_t read_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned
FD_ZERO(&fds);
FD_SET(fd,&fds);
- selrtn = sys_select(fd+1,&fds,&timeout);
+ selrtn = sys_select_intr(fd+1,&fds,&timeout);
if(selrtn <= 0)
return selrtn;
diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c
index d4955fa6a6..e290ee5d4f 100644
--- a/source3/libsmb/nmblib.c
+++ b/source3/libsmb/nmblib.c
@@ -967,7 +967,7 @@ struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
timeout.tv_sec = t/1000;
timeout.tv_usec = 1000*(t%1000);
- if ((ret = sys_select(fd+1,&fds,&timeout)) == -1) {
+ if ((ret = sys_select_intr(fd+1,&fds,&timeout)) == -1) {
/* errno should be EBADF or EINVAL. */
DEBUG(0,("select returned -1, errno = %s (%d)\n", strerror(errno), errno));
return NULL;
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index ee2ba2e240..05b75e984e 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -1793,7 +1793,7 @@ BOOL listen_for_packets(BOOL run_election)
BlockSignals(False, SIGUSR2);
#endif /* SIGUSR2 */
- selrtn = sys_select(FD_SETSIZE,&fds,&timeout);
+ selrtn = sys_select_intr(FD_SETSIZE,&fds,&timeout);
/* We can only take signals when we are in the select - block them again here. */
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 28dd455e51..20eec790dd 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -1014,7 +1014,6 @@ static void init_globals(void)
string_set(&Globals.szPasswdProgram, PASSWD_PROGRAM);
string_set(&Globals.szPrintcapname, PRINTCAP_NAME);
string_set(&Globals.szLockDir, LOCKDIR);
- string_set(&Globals.szRootdir, "/");
#ifdef WITH_UTMP
string_set(&Globals.szUtmpDir, "");
#endif /* WITH_UTMP */
diff --git a/source3/rpcclient/rpcclient.c b/source3/rpcclient/rpcclient.c
index b0fa85b8a4..eccb2fd06a 100644
--- a/source3/rpcclient/rpcclient.c
+++ b/source3/rpcclient/rpcclient.c
@@ -224,7 +224,7 @@ static void wait_keyboard(struct cli_state *cli)
timeout.tv_sec = 20;
timeout.tv_usec = 0;
- sys_select(MAX(cli->fd,fileno(stdin))+1,&fds,&timeout);
+ sys_select_intr(MAX(cli->fd,fileno(stdin))+1,&fds,&timeout);
if (FD_ISSET(fileno(stdin),&fds))
return;
diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c
index 44a8e9b071..5e63b4d4ff 100644
--- a/source3/smbd/oplock.c
+++ b/source3/smbd/oplock.c
@@ -84,6 +84,13 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou
selrtn = sys_select(maxfd+1,fds,&to);
+ if (selrtn == -1 && errno == EINTR) {
+ /* could be a kernel oplock interrupt */
+ if (koplocks && koplocks->msg_waiting(fds)) {
+ return koplocks->receive_message(fds, buffer, buffer_len);
+ }
+ }
+
/* Check if error */
if(selrtn == -1) {
/* something is wrong. Maybe the socket is dead? */
@@ -1120,6 +1127,8 @@ address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno)));
if (lp_kernel_oplocks()) {
#if HAVE_KERNEL_OPLOCKS_IRIX
koplocks = irix_init_kernel_oplocks();
+#elif HAVE_KERNEL_OPLOCKS_LINUX
+ koplocks = linux_init_kernel_oplocks();
#endif
}
diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c
index 6eb8ff9191..8d55a3d4a0 100644
--- a/source3/smbd/oplock_irix.c
+++ b/source3/smbd/oplock_irix.c
@@ -1,5 +1,4 @@
#define OLD_NTDOMAIN 1
-#if HAVE_KERNEL_OPLOCKS_IRIX
/*
Unix SMB/Netbios implementation.
@@ -24,6 +23,7 @@
#include "includes.h"
+#if HAVE_KERNEL_OPLOCKS_IRIX
extern int DEBUGLEVEL;
@@ -227,7 +227,7 @@ should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
DEBUG(5,("process_local_message: kernel oplock break request for \
-file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode));
+file dev = %x, inode = %.0f\n", (unsigned int)*dev, (double)*inode));
return True;
}
diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c
index d8496ca9ca..73a14b3e88 100644
--- a/source3/smbd/oplock_linux.c
+++ b/source3/smbd/oplock_linux.c
@@ -1,5 +1,4 @@
#define OLD_NTDOMAIN 1
-#if HAVE_KERNEL_OPLOCKS_LINUX
/*
Unix SMB/Netbios implementation.
@@ -24,12 +23,27 @@
#include "includes.h"
+#if HAVE_KERNEL_OPLOCKS_LINUX
+
extern int DEBUGLEVEL;
static unsigned signals_received;
static unsigned signals_processed;
static int fd_pending; /* the fd of the current pending SIGIO */
+/* these can be removed when they are in libc */
+typedef struct __user_cap_header_struct {
+ uint32 version;
+ int pid;
+} *cap_user_header_t;
+
+typedef struct __user_cap_data_struct {
+ uint32 effective;
+ uint32 permitted;
+ uint32 inheritable;
+} *cap_user_data_t;
+
+
/****************************************************************************
handle a SIGIO, incrementing the signals_received and blocking SIGIO
****************************************************************************/
@@ -41,6 +55,41 @@ static void sigio_handler(int signal, siginfo_t *info, void *unused)
}
/****************************************************************************
+try to gain the CAP_LEASE capability
+****************************************************************************/
+static void set_lease_capability(void)
+{
+ cap_user_header_t header;
+ cap_user_data_t data;
+ if (capget(header, data) == -1) {
+ DEBUG(3,("Unable to get kernel capabilities\n"));
+ return;
+ }
+ data->effective |= (1<<CAP_LEASE);
+ if (capset(header, data) == -1) {
+ DEBUG(3,("Unable to set CAP_LEASE capability\n"));
+ }
+}
+
+
+/****************************************************************************
+call SETLEASE. If we get EACCES then we try setting up the right capability and
+try again
+****************************************************************************/
+static int linux_setlease(int fd, int leasetype)
+{
+ int ret;
+ ret = fcntl(fd, F_SETLEASE, leasetype);
+ if (ret == -1 && errno == EACCES) {
+ set_lease_capability();
+ ret = fcntl(fd, F_SETLEASE, leasetype);
+ }
+
+ return ret;
+}
+
+
+/****************************************************************************
* Deal with the Linux kernel <--> smbd
* oplock break protocol.
****************************************************************************/
@@ -95,10 +144,11 @@ dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode ));
****************************************************************************/
static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type)
{
- if (fcntl(fsp->fd, F_SETLEASE, F_WRLCK) == -1) {
+ if (linux_setlease(fsp->fd, F_WRLCK) == -1) {
DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \
-inode = %.0f.\n",
- fsp->fsp_name, fsp->fd, (unsigned int)fsp->dev, (double)fsp->inode));
+inode = %.0f. (%s)\n",
+ fsp->fsp_name, fsp->fd,
+ (unsigned int)fsp->dev, (double)fsp->inode, strerror(errno)));
return False;
}
@@ -128,7 +178,7 @@ oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev,
/*
* Remove the kernel oplock on this file.
*/
- if (fcntl(fsp->fd, F_SETLEASE, F_UNLCK) == -1) {
+ if (linux_setlease(fsp->fd, F_UNLCK) == -1) {
if (DEBUGLVL(0)) {
dbgtext("release_kernel_oplock: Error when removing kernel oplock on file " );
dbgtext("%s, dev = %x, inode = %.0f. Error was %s\n",
@@ -155,7 +205,7 @@ should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN));
memcpy((char *)dev, msg_start+KERNEL_OPLOCK_BREAK_DEV_OFFSET, sizeof(*dev));
DEBUG(5,("process_local_message: kernel oplock break request for \
-file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode));
+file dev = %x, inode = %.0f\n", (unsigned int)*dev, (double)*inode));
return True;
}
@@ -203,3 +253,4 @@ struct kernel_oplocks *linux_init_kernel_oplocks(void)
#endif /* HAVE_KERNEL_OPLOCKS_LINUX */
#undef OLD_NTDOMAIN
+
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 82e61a138e..30d03747d8 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -134,69 +134,74 @@ The timeout is in milli seconds
static BOOL receive_message_or_smb(char *buffer, int buffer_len,
int timeout, BOOL *got_smb)
{
- fd_set fds;
- int selrtn;
- struct timeval to;
- int maxfd;
+ fd_set fds;
+ int selrtn;
+ struct timeval to;
+ int maxfd;
- smb_read_error = 0;
+ smb_read_error = 0;
- *got_smb = False;
+ *got_smb = False;
- /*
- * Check to see if we already have a message on the smb queue.
- * If so - copy and return it.
- */
+ /*
+ * Check to see if we already have a message on the smb queue.
+ * If so - copy and return it.
+ */
- if(ubi_slCount(&smb_oplock_queue) != 0)
- {
- pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue);
- memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
+ if(ubi_slCount(&smb_oplock_queue) != 0) {
+ pending_message_list *msg = (pending_message_list *)ubi_slRemHead(&smb_oplock_queue);
+ memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len));
- /* Free the message we just copied. */
- free((char *)msg->msg_buf);
- free((char *)msg);
- *got_smb = True;
+ /* Free the message we just copied. */
+ free((char *)msg->msg_buf);
+ free((char *)msg);
+ *got_smb = True;
+
+ DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
+ return True;
+ }
- DEBUG(5,("receive_message_or_smb: returning queued smb message.\n"));
- return True;
- }
+ /*
+ * Setup the select read fd set.
+ */
- /*
- * Setup the select read fd set.
- */
+ FD_ZERO(&fds);
+ FD_SET(smbd_server_fd(),&fds);
+ maxfd = setup_oplock_select_set(&fds);
- FD_ZERO(&fds);
- FD_SET(smbd_server_fd(),&fds);
- maxfd = setup_oplock_select_set(&fds);
+ to.tv_sec = timeout / 1000;
+ to.tv_usec = (timeout % 1000) * 1000;
- to.tv_sec = timeout / 1000;
- to.tv_usec = (timeout % 1000) * 1000;
+ selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL);
- selrtn = sys_select(MAX(maxfd,smbd_server_fd())+1,&fds,timeout>0?&to:NULL);
+ /* if we get EINTR then maybe we have received an oplock
+ signal - treat this as select returning 1. This is ugly, but
+ is the best we can do until the oplock code knows more about
+ signals */
+ if (selrtn == -1 && errno == EINTR) {
+ FD_ZERO(&fds);
+ selrtn = 1;
+ }
- /* Check if error */
- if(selrtn == -1) {
- /* something is wrong. Maybe the socket is dead? */
- smb_read_error = READ_ERROR;
- return False;
- }
+ /* Check if error */
+ if(selrtn == -1 && errno != EINTR) {
+ /* something is wrong. Maybe the socket is dead? */
+ smb_read_error = READ_ERROR;
+ return False;
+ }
- /* Did we timeout ? */
- if (selrtn == 0) {
- smb_read_error = READ_TIMEOUT;
- return False;
- }
-
- if (FD_ISSET(smbd_server_fd(),&fds))
- {
- *got_smb = True;
- return receive_smb(smbd_server_fd(), buffer, 0);
- }
- else
- {
- return receive_local_message(&fds, buffer, buffer_len, 0);
- }
+ /* Did we timeout ? */
+ if (selrtn == 0) {
+ smb_read_error = READ_TIMEOUT;
+ return False;
+ }
+
+ if (FD_ISSET(smbd_server_fd(),&fds)) {
+ *got_smb = True;
+ return receive_smb(smbd_server_fd(), buffer, 0);
+ } else {
+ return receive_local_message(&fds, buffer, buffer_len, 0);
+ }
}
/****************************************************************************
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index ecf1deb05a..a5da156250 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -203,7 +203,7 @@ max can be %d\n",
memcpy((char *)&lfds, (char *)&listen_set,
sizeof(listen_set));
- num = sys_select(FD_SETSIZE,&lfds,NULL);
+ num = sys_select_intr(FD_SETSIZE,&lfds,NULL);
if (num == -1 && errno == EINTR)
continue;
diff --git a/source3/utils/smbfilter.c b/source3/utils/smbfilter.c
index 81b10e4519..5d11c74d14 100644
--- a/source3/utils/smbfilter.c
+++ b/source3/utils/smbfilter.c
@@ -120,7 +120,7 @@ static void filter_child(int c, struct in_addr dest_ip)
if (s != -1) FD_SET(s, &fds);
if (c != -1) FD_SET(c, &fds);
- num = sys_select(MAX(s+1, c+1),&fds,NULL);
+ num = sys_select_intr(MAX(s+1, c+1),&fds,NULL);
if (num <= 0) continue;
if (c != -1 && FD_ISSET(c, &fds)) {
@@ -184,7 +184,7 @@ static void start_filter(char *desthost)
FD_ZERO(&fds);
FD_SET(s, &fds);
- num = sys_select(s+1,&fds,NULL);
+ num = sys_select_intr(s+1,&fds,NULL);
if (num > 0) {
c = accept(s, &addr, &in_addrlen);
if (c != -1) {