diff options
| -rw-r--r-- | source3/Makefile.in | 2 | ||||
| -rw-r--r-- | source3/include/smb.h | 5 | ||||
| -rw-r--r-- | source3/param/loadparm.c | 9 | ||||
| -rw-r--r-- | source3/smbd/oplock.c | 13 | ||||
| -rw-r--r-- | source3/smbd/oplock_irix.c | 4 | ||||
| -rw-r--r-- | source3/smbd/oplock_linux.c | 205 | 
6 files changed, 212 insertions, 26 deletions
| diff --git a/source3/Makefile.in b/source3/Makefile.in index a70d094f8a..ba6424e3d2 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -157,7 +157,7 @@ PASSDB_OBJ = passdb/passdb.o passdb/smbpassfile.o passdb/smbpass.o passdb/secret  PROFILE_OBJ = profile/profile.o -OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o +OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o  SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \              smbd/dfree.o smbd/dir.o smbd/password.o smbd/conn.o smbd/fileio.o \ diff --git a/source3/include/smb.h b/source3/include/smb.h index d2c79e3b53..68df3f250c 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1607,9 +1607,8 @@ extern int chain_size;  #define KERNEL_OPLOCK_CAPABILITY 0x1 -#if defined(HAVE_KERNEL_OPLOCKS_IRIX)  /* - * Oplock break command code sent via the kernel interface. + * Oplock break command code sent via the kernel interface (if it exists).   *   * Form of this is :   * @@ -1618,12 +1617,10 @@ extern int chain_size;   *  | cmd| dev    |  inode |   *  +----+--------+--------+   */ -  #define KERNEL_OPLOCK_BREAK_DEV_OFFSET 2  #define KERNEL_OPLOCK_BREAK_INODE_OFFSET (KERNEL_OPLOCK_BREAK_DEV_OFFSET + sizeof(SMB_DEV_T))  #define KERNEL_OPLOCK_BREAK_MSG_LEN (KERNEL_OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T)) -#endif /* HAVE_KERNEL_OPLOCKS_IRIX */  /* if a kernel does support oplocks then a structure of the following     typee is used to describe how to interact with the kernel */ diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index ef62fc82ca..28dd455e51 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -1144,10 +1144,7 @@ static void init_globals(void)  	Globals.bDNSproxy = True; -	/* -	 * smbd will check at runtime to see if this value -	 * will really be used or not. -	 */ +	/* this just means to use them if they exist */  	Globals.bKernelOplocks = True;  	Globals.bAllowTrustedDomains = True; @@ -2550,7 +2547,7 @@ static BOOL do_parameter(char *pszParmName, char *pszParmValue)  	if (!bInGlobalSection && bGlobalOnly)  		return (True); -	DEBUGADD(3, ("doing parameter %s = %s\n", pszParmName, pszParmValue)); +	DEBUGADD(4, ("doing parameter %s = %s\n", pszParmName, pszParmValue));  	return (lp_do_parameter(bInGlobalSection ? -2 : iServiceIndex,  				pszParmName, pszParmValue)); @@ -3124,7 +3121,7 @@ BOOL lp_load(char *pszFname, BOOL global_only, BOOL save_defaults,  	bRetval = pm_process(n2, do_section, do_parameter);  	/* finish up the last section */ -	DEBUG(3, ("pm_process() returned %s\n", BOOLSTR(bRetval))); +	DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));  	if (bRetval)  		if (iServiceIndex >= 0)  			bRetval = service_ok(iServiceIndex); diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index 33d82f3dde..44a8e9b071 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -1021,22 +1021,9 @@ should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));      reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN]; -#if HAVE_KERNEL_OPLOCKS_IRIX -    if((reply_msg_len != OPLOCK_BREAK_MSG_LEN) && (reply_msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN)) -#else -    if(reply_msg_len != OPLOCK_BREAK_MSG_LEN) -#endif -    { -      /* Ignore it. */ -      DEBUG( 0, ( "request_oplock_break: invalid message length (%d) received.", reply_msg_len ) ); -      DEBUGADD( 0, ( "  Ignoring.\n" ) ); -      continue; -    } -      /*       * Test to see if this is the reply we are awaiting.       */ -      if((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & CMD_REPLY) &&         ((SVAL(reply_msg_start,OPBRK_MESSAGE_CMD_OFFSET) & ~CMD_REPLY) == OPLOCK_BREAK_CMD) &&         (reply_from_port == share_entry->op_port) &&  diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c index 0820c4048d..6eb8ff9191 100644 --- a/source3/smbd/oplock_irix.c +++ b/source3/smbd/oplock_irix.c @@ -3,8 +3,8 @@  /*      Unix SMB/Netbios implementation. -   Version 1.9. -   oplock processing +   Version 2.x +   IRIX kernel oplock processing     Copyright (C) Andrew Tridgell 1992-1998     This program is free software; you can redistribute it and/or modify diff --git a/source3/smbd/oplock_linux.c b/source3/smbd/oplock_linux.c new file mode 100644 index 0000000000..d8496ca9ca --- /dev/null +++ b/source3/smbd/oplock_linux.c @@ -0,0 +1,205 @@ +#define OLD_NTDOMAIN 1 +#if HAVE_KERNEL_OPLOCKS_LINUX + +/*  +   Unix SMB/Netbios implementation. +   Version 3.0 +   kernel oplock processing for Linux +   Copyright (C) Andrew Tridgell 2000 +    +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. +    +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. +    +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern int DEBUGLEVEL; + +static unsigned signals_received; +static unsigned signals_processed; +static int fd_pending; /* the fd of the current pending SIGIO */ + +/**************************************************************************** +handle a SIGIO, incrementing the signals_received and blocking SIGIO +****************************************************************************/ +static void sigio_handler(int signal, siginfo_t *info, void *unused) +{ +	fd_pending = info->si_fd; +	signals_received++; +	BlockSignals(True, SIGIO); +} + +/**************************************************************************** + * Deal with the Linux kernel <--> smbd + * oplock break protocol. +****************************************************************************/ +static BOOL linux_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len) +{ +	SMB_DEV_T dev; +	SMB_INO_T inode; +	SMB_STRUCT_STAT sbuf; +	BOOL ret; + +	if (signals_received == signals_processed) return False; + +	if (sys_fstat(fd_pending,&sbuf) == -1) { +		DEBUG(0,("Invalid file descriptor %d in kernel oplock break!\n", fd_pending)); +		ret = False; +		goto out; +	} + +	dev = sbuf.st_dev; +	inode = sbuf.st_ino; +      +	DEBUG(5,("receive_local_message: kernel oplock break request received for \ +dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode )); +      +	/* +	 * Create a kernel oplock break message. +	 */ +      +	/* Setup the message header */ +	SIVAL(buffer,OPBRK_CMD_LEN_OFFSET,KERNEL_OPLOCK_BREAK_MSG_LEN); +	SSVAL(buffer,OPBRK_CMD_PORT_OFFSET,0); +      +	buffer += OPBRK_CMD_HEADER_LEN; +      +	SSVAL(buffer,OPBRK_MESSAGE_CMD_OFFSET,KERNEL_OPLOCK_BREAK_CMD); +      +	memcpy(buffer + KERNEL_OPLOCK_BREAK_DEV_OFFSET, (char *)&dev, sizeof(dev)); +	memcpy(buffer + KERNEL_OPLOCK_BREAK_INODE_OFFSET, (char *)&inode, sizeof(inode));	 + + out: +	/* now we can receive more signals */ +	fd_pending = -1; +	signals_processed++; +	BlockSignals(False, SIGIO); +      +	return True; +} + + +/**************************************************************************** + Attempt to set an kernel oplock on a file. +****************************************************************************/ +static BOOL linux_set_kernel_oplock(files_struct *fsp, int oplock_type) +{ +	if (fcntl(fsp->fd, F_SETLEASE, 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)); +		return False; +	} +	 +	DEBUG(10,("set_file_oplock: got kernel oplock on file %s, dev = %x, inode = %.0f\n", +		  fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode)); + +	return True; +} + + +/**************************************************************************** + Release a kernel oplock on a file. +****************************************************************************/ +static void linux_release_kernel_oplock(files_struct *fsp) +{ +	if (DEBUGLVL(10)) { +		/* +		 * Check and print out the current kernel +		 * oplock state of this file. +		 */ +		int state = fcntl(fsp->fd, F_GETLEASE, 0); +		dbgtext("release_kernel_oplock: file %s, dev = %x, inode = %.0f has kernel \ +oplock state of %x.\n", fsp->fsp_name, (unsigned int)fsp->dev, +                        (double)fsp->inode, state ); +	} + +	/* +	 * Remove the kernel oplock on this file. +	 */ +	if (fcntl(fsp->fd, F_SETLEASE, 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", +				fsp->fsp_name, (unsigned int)fsp->dev,  +				(double)fsp->inode, strerror(errno) ); +		} +	} +} + + +/**************************************************************************** +parse a kernel oplock message +****************************************************************************/ +static BOOL linux_kernel_oplock_parse(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev) +{ +	/* Ensure that the msg length is correct. */ +	if (msg_len != KERNEL_OPLOCK_BREAK_MSG_LEN) { +		DEBUG(0,("process_local_message: incorrect length for KERNEL_OPLOCK_BREAK_CMD (was %d, \ +should be %d).\n", msg_len, KERNEL_OPLOCK_BREAK_MSG_LEN)); +		return False; +	} + +        memcpy((char *)inode, msg_start+KERNEL_OPLOCK_BREAK_INODE_OFFSET, sizeof(*inode)); +        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)); + +	return True; +} + + +/**************************************************************************** +see if a oplock message is waiting +****************************************************************************/ +static BOOL linux_oplock_msg_waiting(fd_set *fds) +{ +	return signals_processed != signals_received; +} + + +/**************************************************************************** +setup kernel oplocks +****************************************************************************/ +struct kernel_oplocks *linux_init_kernel_oplocks(void)  +{ +	static struct kernel_oplocks koplocks; +        struct sigaction act; + +        act.sa_handler = NULL; +        act.sa_sigaction = sigio_handler; +        act.sa_flags = SA_SIGINFO; +        if (sigaction(SIGIO, &act, NULL) != 0) { +		DEBUG(0,("Failed to setup SIGIO handler\n")); +		return NULL; +        } + +	koplocks.receive_message = linux_oplock_receive_message; +	koplocks.set_oplock = linux_set_kernel_oplock; +	koplocks.release_oplock = linux_release_kernel_oplock; +	koplocks.parse_message = linux_kernel_oplock_parse; +	koplocks.msg_waiting = linux_oplock_msg_waiting; +	koplocks.notification_fd = -1; + +	return &koplocks; +} + + + +#else + void oplock_linux_dummy(void) {} +#endif /* HAVE_KERNEL_OPLOCKS_LINUX */ + +#undef OLD_NTDOMAIN | 
