mirror of
https://github.com/samba-team/samba.git
synced 2025-05-28 21:05:48 +03:00
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 commit is contained in:
parent
1871d4a3f6
commit
b28cc4163b
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
********************************************************************/
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<<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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user