From 8843a6379d7c1cf59f0f3673cbc567b09994b7d2 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 11 Jun 2000 05:57:58 +0000 Subject: 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) --- source3/client/client.c | 4 +- source3/include/includes.h | 12 +++++ source3/include/proto.h | 1 + source3/lib/system.c | 26 ++++++---- source3/lib/util.c | 2 +- source3/lib/util_sock.c | 4 +- source3/libsmb/nmblib.c | 2 +- source3/nmbd/nmbd_packets.c | 2 +- source3/param/loadparm.c | 1 - source3/rpcclient/rpcclient.c | 2 +- source3/smbd/oplock.c | 9 ++++ source3/smbd/oplock_irix.c | 4 +- source3/smbd/oplock_linux.c | 63 ++++++++++++++++++++++--- source3/smbd/process.c | 107 ++++++++++++++++++++++-------------------- source3/smbd/server.c | 2 +- source3/utils/smbfilter.c | 4 +- 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 #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,17 +126,29 @@ 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); } #endif /* USE_POLL */ #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 ****************************************************************************/ @@ -40,6 +54,41 @@ static void sigio_handler(int signal, siginfo_t *info, void *unused) BlockSignals(True, SIGIO); } +/**************************************************************************** +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< 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) { -- cgit