diff options
| author | Andrew Tridgell <tridge@samba.org> | 2000-06-10 13:38:07 +0000 | 
|---|---|---|
| committer | Andrew Tridgell <tridge@samba.org> | 2000-06-10 13:38:07 +0000 | 
| commit | 52cb05678a9b08b5aa7dbe13ae6b54ff9ee4ecac (patch) | |
| tree | 3d8dfdc81837b743cbfd383b6f9203df5e4c5285 | |
| parent | a9a512192d05d6559d0315be96e0bfcf8800f69e (diff) | |
| download | samba-52cb05678a9b08b5aa7dbe13ae6b54ff9ee4ecac.tar.gz samba-52cb05678a9b08b5aa7dbe13ae6b54ff9ee4ecac.tar.bz2 samba-52cb05678a9b08b5aa7dbe13ae6b54ff9ee4ecac.zip | |
continued the split of the kernel level oplocks code into a more
modular form. In this pass I added oplock_irix.c and added a "struct
kernel_oplocks" that describes a kernel oplock implementation.
(This used to be commit b5ceab810292602ea9a81696c20a781c16b706c2)
| -rw-r--r-- | source3/include/proto.h | 13 | ||||
| -rw-r--r-- | source3/include/smb.h | 14 | ||||
| -rw-r--r-- | source3/lib/system.c | 2 | ||||
| -rw-r--r-- | source3/param/loadparm.c | 32 | ||||
| -rw-r--r-- | source3/smbd/oplock.c | 499 | ||||
| -rw-r--r-- | source3/smbd/oplock_irix.c | 282 | ||||
| -rw-r--r-- | source3/smbd/server.c | 23 | 
7 files changed, 436 insertions, 429 deletions
| diff --git a/source3/include/proto.h b/source3/include/proto.h index 9563b432fd..4d57740877 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1339,6 +1339,7 @@ BOOL lp_stat_cache(void);  BOOL lp_allow_trusted_domains(void);  BOOL lp_restrict_anonymous(void);  BOOL lp_host_msdfs(void); +BOOL lp_kernel_oplocks(void);  int lp_os_level(void);  int lp_max_ttl(void);  int lp_max_wins_ttl(void); @@ -1491,8 +1492,6 @@ int lp_default_server_announce(void);  int lp_major_announce_version(void);  int lp_minor_announce_version(void);  void lp_set_name_resolve_order(char *new_order); -void lp_set_kernel_oplocks(BOOL val); -BOOL lp_kernel_oplocks(void);  int lp_security_mask(int snum);  int lp_force_security_mode(int snum);  int lp_dir_security_mask(int snum); @@ -3277,8 +3276,6 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op);  #if OLD_NTDOMAIN  int32 get_number_of_exclusive_open_oplocks(void); -BOOL setup_kernel_oplock_pipe(void); -BOOL open_oplock_ipc(void);  BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeout);  BOOL set_file_oplock(files_struct *fsp, int oplock_type);  void release_file_oplock(files_struct *fsp); @@ -3289,7 +3286,13 @@ BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token);  BOOL request_oplock_break(share_mode_entry *share_entry,                             SMB_DEV_T dev, SMB_INO_T inode);  BOOL attempt_close_oplocked_file(files_struct *fsp); -void check_kernel_oplocks(void); +BOOL init_oplocks(void); +#endif + +/*The following definitions come from  smbd/oplock_irix.c  */ + +#if OLD_NTDOMAIN +struct kernel_oplocks *irix_init_kernel_oplocks(void) ;  #endif  /*The following definitions come from  smbd/password.c  */ diff --git a/source3/include/smb.h b/source3/include/smb.h index 91f0e04b48..d2c79e3b53 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1598,6 +1598,7 @@ extern int chain_size;  #define OPLOCK_BREAK_INODE_OFFSET (OPLOCK_BREAK_DEV_OFFSET + sizeof(SMB_DEV_T))  #define OPLOCK_BREAK_MSG_LEN (OPLOCK_BREAK_INODE_OFFSET + sizeof(SMB_INO_T)) +#define KERNEL_OPLOCK_BREAK_CMD 0x2  #define LEVEL_II_OPLOCK_BREAK_CMD 0x3  /* @@ -1618,13 +1619,24 @@ extern int chain_size;   *  +----+--------+--------+   */ -#define KERNEL_OPLOCK_BREAK_CMD 0x2  #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 */ +struct kernel_oplocks { +	BOOL (*receive_message)(fd_set *fds, char *buffer, int buffer_len); +	BOOL (*set_oplock)(files_struct *fsp, int oplock_type); +	void (*release_oplock)(files_struct *fsp); +	BOOL (*parse_message)(char *msg_start, int msg_len, SMB_INO_T *inode, SMB_DEV_T *dev); +	BOOL (*msg_waiting)(fd_set *fds); +	int notification_fd; +}; + +  #define CMD_REPLY 0x8000  #include "smb_macros.h" diff --git a/source3/lib/system.c b/source3/lib/system.c index 3a9cca6a72..2a99ae779e 100644 --- a/source3/lib/system.c +++ b/source3/lib/system.c @@ -391,6 +391,8 @@ int sys_chroot(const char *dname)  		DEBUG(1,("WARNING: no chroot!\n"));  		done=1;  	} +	errno = ENOSYS; +	return -1;  #else  	return(chroot(dname));  #endif diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 8f23d20796..ef62fc82ca 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -1429,6 +1429,7 @@ FN_GLOBAL_BOOL(lp_stat_cache, &Globals.bStatCache)  FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains)  FN_GLOBAL_BOOL(lp_restrict_anonymous, &Globals.bRestrictAnonymous)  FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs) +FN_GLOBAL_BOOL(lp_kernel_oplocks, &Globals.bKernelOplocks)  FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level)  FN_GLOBAL_INTEGER(lp_max_ttl, &Globals.max_ttl)  FN_GLOBAL_INTEGER(lp_max_wins_ttl, &Globals.max_wins_ttl) @@ -3439,37 +3440,6 @@ void lp_set_name_resolve_order(char *new_order)  }  /*********************************************************** - Set the flag that says if kernel oplocks are available  - (called by smbd). -************************************************************/ - -static BOOL kernel_oplocks_available = False; - -void lp_set_kernel_oplocks(BOOL val) -{ -	/* -	 * Only set this to True if kerenl -	 * oplocks are really available and were -	 * turned on in the smb.conf file. -	 */ - -	if (Globals.bKernelOplocks && val) -		kernel_oplocks_available = True; -	else -		kernel_oplocks_available = False; -} - -/*********************************************************** - Return True if kernel oplocks are available and were turned - on in smb.conf. -************************************************************/ - -BOOL lp_kernel_oplocks(void) -{ -	return kernel_oplocks_available; -} - -/***********************************************************   Functions to return the current security masks/modes. If   set to -1 then return the create mask/mode instead.  ************************************************************/ diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index af48b06ab0..33d82f3dde 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -28,11 +28,6 @@ extern int DEBUGLEVEL;  /* Oplock ipc UDP socket. */  static int oplock_sock = -1;  uint16 global_oplock_port = 0; -static int oplock_pipe_read = -1; - -#if defined(HAVE_KERNEL_OPLOCKS_IRIX) -static int oplock_pipe_write = -1; -#endif  /* Current number of oplocks we have outstanding. */  static int32 exclusive_oplocks_open = 0; @@ -42,6 +37,8 @@ BOOL global_oplock_break = False;  extern int smb_read_error; +static struct kernel_oplocks *koplocks; +  static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, BOOL local);  /**************************************************************************** @@ -54,200 +51,9 @@ int32 get_number_of_exclusive_open_oplocks(void)  } -#if HAVE_KERNEL_OPLOCKS_IRIX -/**************************************************************************** -test to see if IRIX kernel oplocks work -****************************************************************************/ -static BOOL irix_oplocks_available(void) -{ -	int fd; -	int pfd[2]; -	pstring tmpname; - -	oplock_set_capability(True, True); - -	slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(), (int)sys_getpid()); - -	if(pipe(pfd) != 0) { -		DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n", -			 strerror(errno) )); -		return False; -	} - -	if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) { -		DEBUG(0,("check_kernel_oplocks: Unable to open temp test file %s. Error was %s\n", -			 tmpname, strerror(errno) )); -		unlink( tmpname ); -		close(pfd[0]); -		close(pfd[1]); -		return False; -	} - -	unlink( tmpname ); - -	if(fcntl(fd, F_OPLKREG, pfd[1]) == -1) { -		DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \ -Disabling kernel oplock support.\n" )); -		close(pfd[0]); -		close(pfd[1]); -		close(fd); -		return False; -	} - -	if(fcntl(fd, F_OPLKACK, OP_REVOKE) < 0 ) { -		DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \ -Disabling kernel oplock support.\n", strerror(errno) )); -		close(pfd[0]); -		close(pfd[1]); -		close(fd); -		return False; -	} - -	close(pfd[0]); -	close(pfd[1]); -	close(fd); - -	return True; -} -#endif - -/**************************************************************************** - Setup the kernel level oplock backchannel for this process. -****************************************************************************/ -BOOL setup_kernel_oplock_pipe(void) -{ -#if defined(HAVE_KERNEL_OPLOCKS_IRIX) -	if(lp_kernel_oplocks()) { -		int pfd[2]; - -		if(pipe(pfd) != 0) { -			DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n", -				 strerror(errno) )); -			return False; -		} - -		oplock_pipe_read = pfd[0]; -		oplock_pipe_write = pfd[1]; -	} -#endif /* HAVE_KERNEL_OPLOCKS_IRIX */ -	return True; -} - -/**************************************************************************** - Open the oplock IPC socket communication. -****************************************************************************/ - -BOOL open_oplock_ipc(void) -{ -  struct sockaddr_in sock_name; -  int len = sizeof(sock_name); - -  DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n")); - -  /* Open a lookback UDP socket on a random port. */ -  oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK),False); -  if (oplock_sock == -1) -  { -    DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \ -address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno))); -    global_oplock_port = 0; -    return(False); -  } - -  /* Find out the transient UDP port we have been allocated. */ -  if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0) -  { -    DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n", -            strerror(errno))); -    close(oplock_sock); -    oplock_sock = -1; -    global_oplock_port = 0; -    return False; -  } -  global_oplock_port = ntohs(sock_name.sin_port); - -  if(!setup_kernel_oplock_pipe()) -    return False; - -  DEBUG(3,("open_oplock ipc: pid = %d, global_oplock_port = %u\n",  -            (int)sys_getpid(), global_oplock_port)); - -  return True; -} - -#if defined(HAVE_KERNEL_OPLOCKS_IRIX) -/**************************************************************************** - * Deal with the IRIX kernel <--> smbd - * oplock break protocol. -****************************************************************************/ -static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len, int timeout) -{ -     oplock_stat_t os; -     SMB_DEV_T dev; -     SMB_INO_T inode; -     char dummy; - -     /* -      * Read one byte of zero to clear the -      * kernel break notify message. -      */ - -     if(read(oplock_pipe_read, &dummy, 1) != 1) { -	     DEBUG(0,("receive_local_message: read of kernel notification failed. \ -Error was %s.\n", strerror(errno) )); -	     smb_read_error = READ_ERROR; -	     return False; -     } - -     /* -      * Do a query to get the -      * device and inode of the file that has the break -      * request outstanding. -      */ - -     if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) { -	     DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \ -Error was %s.\n", strerror(errno) )); -	     if(errno == EAGAIN) { -		     /* -		      * Duplicate kernel break message - ignore. -		      */ -		     memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN); -		     return True; -	     } -	     smb_read_error = READ_ERROR; -	     return False; -     } - -     dev = (SMB_DEV_T)os.os_dev; -     inode = (SMB_INO_T)os.os_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));	 -      -     return True; -} -#endif /* HAVE_KERNEL_OPLOCKS_IRIX */ - -  /****************************************************************************   Read an oplock break message from either the oplock UDP fd or the - kernel oplock pipe fd (if kernel oplocks are supported). + kernel (if kernel oplocks are supported).   If timeout is zero then *fds contains the file descriptors that   are ready to be read and acted upon. If timeout is non-zero then @@ -269,8 +75,9 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou      int selrtn;      int maxfd = oplock_sock; -    if(lp_kernel_oplocks() && (oplock_pipe_read != -1)) -      maxfd = MAX(maxfd, oplock_pipe_read); +    if (koplocks && koplocks->notification_fd != -1) { +	    FD_SET(koplocks->notification_fd, fds); +    }      to.tv_sec = timeout / 1000;      to.tv_usec = (timeout % 1000) * 1000; @@ -291,11 +98,9 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou      }    } -#if HAVE_KERNEL_OPLOCKS_IRIX -  if (FD_ISSET(oplock_pipe_read,fds)) { -	  return irix_receive_message(fds, buffer, buffer_len, timeout); +  if (koplocks && koplocks->msg_waiting(fds)) { +	  return koplocks->receive_message(fds, buffer, buffer_len);    } -#endif    /*     * From here down we deal with the smbd <--> smbd @@ -337,42 +142,12 @@ BOOL receive_local_message(fd_set *fds, char *buffer, int buffer_len, int timeou  }  /**************************************************************************** - Attempt to set an kernel oplock on a file. Always returns True if kernel - oplocks not available. -****************************************************************************/ -static BOOL set_kernel_oplock(files_struct *fsp, int oplock_type) -{ -	if(!lp_kernel_oplocks()) return True; - -#if defined(HAVE_KERNEL_OPLOCKS_IRIX) -	if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) < 0 ) { -		if(errno != EAGAIN) { -			DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \ -inode = %.0f. Error was %s\n",  -				 fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, -				 strerror(errno) )); -		} else { -			DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ -inode = %.0f. Another process had the file open.\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)); -#endif /* HAVE_KERNEL_OPLOCKS_IRIX */ - -	return True; -} - -/****************************************************************************   Attempt to set an oplock on a file. Always succeeds if kernel oplocks are   disabled (just sets flags). Returns True if oplock set.  ****************************************************************************/  BOOL set_file_oplock(files_struct *fsp, int oplock_type)  { -	if (!set_kernel_oplock(fsp, oplock_type)) +	if (koplocks && !koplocks->set_oplock(fsp, oplock_type))  		return False;  	fsp->oplock_type = oplock_type; @@ -390,46 +165,12 @@ BOOL set_file_oplock(files_struct *fsp, int oplock_type)  }  /**************************************************************************** - Release a kernel oplock on a file. -****************************************************************************/ -static void release_kernel_oplock(files_struct *fsp) -{ -	if (!lp_kernel_oplocks()) return; - -#if defined(HAVE_KERNEL_OPLOCKS_IRIX) -	if (DEBUGLVL(10)) { -		/* -		 * Check and print out the current kernel -		 * oplock state of this file. -		 */ -		int state = fcntl(fsp->fd, F_OPLKACK, -1); -		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_OPLKACK, OP_REVOKE) < 0) { -		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) ); -		} -	} -#endif /* HAVE_KERNEL_OPLOCKS_IRIX */ -} - - -/****************************************************************************   Attempt to release an oplock on a file. Decrements oplock count.  ****************************************************************************/  void release_file_oplock(files_struct *fsp)  { -	release_kernel_oplock(fsp); +	if (koplocks) koplocks->release_oplock(fsp);  	if (fsp->oplock_type == LEVEL_II_OPLOCK)  		level_II_oplocks_open--; @@ -448,11 +189,11 @@ void release_file_oplock(files_struct *fsp)  static void downgrade_file_oplock(files_struct *fsp)  { -  release_kernel_oplock(fsp); -  fsp->oplock_type = LEVEL_II_OPLOCK; -  exclusive_oplocks_open--; -  level_II_oplocks_open++; -  fsp->sent_oplock_break = NO_BREAK_SENT; +	if (koplocks) koplocks->release_oplock(fsp); +	fsp->oplock_type = LEVEL_II_OPLOCK; +	exclusive_oplocks_open--; +	level_II_oplocks_open++; +	fsp->sent_oplock_break = NO_BREAK_SENT;  }  /**************************************************************************** @@ -462,48 +203,44 @@ static void downgrade_file_oplock(files_struct *fsp)  BOOL remove_oplock(files_struct *fsp)  { -  SMB_DEV_T dev = fsp->dev; -  SMB_INO_T inode = fsp->inode; -  BOOL ret = True; - -  /* Remove the oplock flag from the sharemode. */ -  if (lock_share_entry_fsp(fsp) == False) { -    DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n", -          fsp->fsp_name )); -    ret = False; -  } - -  if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT) { +	SMB_DEV_T dev = fsp->dev; +	SMB_INO_T inode = fsp->inode; +	BOOL ret = True; + +	/* Remove the oplock flag from the sharemode. */ +	if (lock_share_entry_fsp(fsp) == False) { +		DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n", +			 fsp->fsp_name )); +		ret = False; +	} -    /* -     * Deal with a reply when a break-to-none was sent. -     */ +	if (fsp->sent_oplock_break == EXCLUSIVE_BREAK_SENT) { +		/* +		 * Deal with a reply when a break-to-none was sent. +		 */ -    if(remove_share_oplock(fsp)==False) { -      DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \ +		if(remove_share_oplock(fsp)==False) { +			DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \  dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode)); -      ret = False; -    } - -    release_file_oplock(fsp); - -  } else { - -    /* -     * Deal with a reply when a break-to-level II was sent. -     */ +			ret = False; +		} -    if(downgrade_share_oplock(fsp)==False) { -      DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \ +		release_file_oplock(fsp); +	} else { +		/* +		 * Deal with a reply when a break-to-level II was sent. +		 */ +		if(downgrade_share_oplock(fsp)==False) { +			DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \  dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode)); -      ret = False; -    } - -    downgrade_file_oplock(fsp); -  } +			ret = False; +		} +		 +		downgrade_file_oplock(fsp); +	} -  unlock_share_entry_fsp(fsp); -  return ret; +	unlock_share_entry_fsp(fsp); +	return ret;  }  /**************************************************************************** @@ -514,26 +251,25 @@ dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)  int setup_oplock_select_set( fd_set *fds)  { -  int maxfd = oplock_sock; +	int maxfd = oplock_sock; -  if(oplock_sock == -1) -    return 0; +	if(oplock_sock == -1) +		return 0; -  FD_SET(oplock_sock,fds); +	FD_SET(oplock_sock,fds); -  if(lp_kernel_oplocks() && (oplock_pipe_read != -1)) { -    FD_SET(oplock_pipe_read,fds);  -    maxfd = MAX(maxfd,oplock_pipe_read); -  } +	if (koplocks && koplocks->notification_fd != -1) { +		FD_SET(koplocks->notification_fd, fds); +		maxfd = MAX(maxfd, koplocks->notification_fd); +	} -  return maxfd; +	return maxfd;  }  /****************************************************************************   Process an oplock break message - whether it came from the UDP socket   or from the kernel.  ****************************************************************************/ -  BOOL process_local_message(char *buffer, int buf_size)  {    int32 msg_len; @@ -562,26 +298,15 @@ BOOL process_local_message(char *buffer, int buf_size)    switch(break_cmd_type)    { -#if defined(HAVE_KERNEL_OPLOCKS_IRIX)      case KERNEL_OPLOCK_BREAK_CMD: -      /* 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)); - -        ptval = NULL; - -        DEBUG(5,("process_local_message: kernel oplock break request for \ -file dev = %x, inode = %.0f\n", (unsigned int)dev, (double)inode)); -      } -      break; -#endif /* HAVE_KERNEL_OPLOCKS_IRIX */ +	    if (!koplocks) { +		    DEBUG(0,("unexpected kernel oplock break!\n")); +		    break; +	    }  +	    if (!koplocks->parse_message(msg_start, msg_len, &inode, &dev)) { +		    DEBUG(0,("kernel oplock break parse failure!\n")); +	    } +	    break;      case OPLOCK_BREAK_CMD:      case LEVEL_II_OPLOCK_BREAK_CMD: @@ -708,18 +433,18 @@ pid %d, port %d, for file dev = %x, inode = %.0f\n",  static void prepare_break_message(char *outbuf, files_struct *fsp, BOOL level2)  { -  memset(outbuf,'\0',smb_size); -  set_message(outbuf,8,0,True); - -  SCVAL(outbuf,smb_com,SMBlockingX); -  SSVAL(outbuf,smb_tid,fsp->conn->cnum); -  SSVAL(outbuf,smb_pid,0xFFFF); -  SSVAL(outbuf,smb_uid,0); -  SSVAL(outbuf,smb_mid,0xFFFF); -  SCVAL(outbuf,smb_vwv0,0xFF); -  SSVAL(outbuf,smb_vwv2,fsp->fnum); -  SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE); -  SCVAL(outbuf,smb_vwv3+1,level2 ? OPLOCKLEVEL_II : OPLOCKLEVEL_NONE); +	memset(outbuf,'\0',smb_size); +	set_message(outbuf,8,0,True); + +	SCVAL(outbuf,smb_com,SMBlockingX); +	SSVAL(outbuf,smb_tid,fsp->conn->cnum); +	SSVAL(outbuf,smb_pid,0xFFFF); +	SSVAL(outbuf,smb_uid,0); +	SSVAL(outbuf,smb_mid,0xFFFF); +	SCVAL(outbuf,smb_vwv0,0xFF); +	SSVAL(outbuf,smb_vwv2,fsp->fnum); +	SCVAL(outbuf,smb_vwv3,LOCKING_ANDX_OPLOCK_RELEASE); +	SCVAL(outbuf,smb_vwv3+1,level2 ? OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);  }  /**************************************************************************** @@ -749,7 +474,6 @@ static void wait_before_sending_break(BOOL local_request)  /****************************************************************************   Ensure that we have a valid oplock.  ****************************************************************************/ -  static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval)  {    files_struct *fsp = NULL; @@ -966,7 +690,10 @@ static BOOL oplock_break(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval, B    /* Prepare the SMBlockingX message. */ -  if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) && !lp_kernel_oplocks() && lp_level2_oplocks(SNUM(fsp->conn))) { +  if ((global_client_caps & CAP_LEVEL_II_OPLOCKS) &&  +      !koplocks && /* NOTE: we force levelII off for kernel oplocks - +                      this will change when it is supported */ +      lp_level2_oplocks(SNUM(fsp->conn))) {  	  using_levelII = True;    } else {  	  using_levelII = False; @@ -1244,8 +971,10 @@ should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));      FD_ZERO(&fds);      FD_SET(oplock_sock,&fds); -    if(lp_kernel_oplocks() && (oplock_pipe_read != -1)) -      FD_SET(oplock_pipe_read,&fds); + +    if (koplocks && koplocks->notification_fd != -1) { +	    FD_SET(koplocks->notification_fd, &fds); +    }      if(receive_local_message(&fds, op_break_reply, sizeof(op_break_reply),                 time_left ? time_left * 1000 : 1) == False) @@ -1292,7 +1021,7 @@ should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));      reply_msg_start = &op_break_reply[OPBRK_CMD_HEADER_LEN]; -#if defined(HAVE_KERNEL_OPLOCKS_IRIX) +#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) @@ -1354,7 +1083,6 @@ should be %d\n", (int)pid, share_entry->op_port, global_oplock_port));    Used as a last ditch attempt to free a space in the     file table when we have run out.  ****************************************************************************/ -  BOOL attempt_close_oplocked_file(files_struct *fsp)  { @@ -1371,30 +1099,47 @@ BOOL attempt_close_oplocked_file(files_struct *fsp)    return False;  } +  /**************************************************************************** - Init function to check if kernel level oplocks are available. +setup oplocks for this process  ****************************************************************************/ - -void check_kernel_oplocks(void) +BOOL init_oplocks(void)  { -	static BOOL done; - -	/* -	 * We only do this check once on startup. -	 */ -	if(done) return; -   -	done = True; -	lp_set_kernel_oplocks(False); - -#if defined(HAVE_KERNEL_OPLOCKS_IRIX) -	if (irix_oplocks_available()) { -		lp_set_kernel_oplocks(True); - -		DEBUG(0,("check_kernel_oplocks: Kernel oplocks available and set to %s.\n", -			 lp_kernel_oplocks() ? "True" : "False" )); +	struct sockaddr_in sock_name; +	int len = sizeof(sock_name); + +	DEBUG(3,("open_oplock_ipc: opening loopback UDP socket.\n")); + +	/* Open a lookback UDP socket on a random port. */ +	oplock_sock = open_socket_in(SOCK_DGRAM, 0, 0, htonl(INADDR_LOOPBACK),False); +	if (oplock_sock == -1) { +		DEBUG(0,("open_oplock_ipc: Failed to get local UDP socket for \ +address %lx. Error was %s\n", (long)htonl(INADDR_LOOPBACK), strerror(errno))); +		global_oplock_port = 0; +		return(False); +	} + +	/* Find out the transient UDP port we have been allocated. */ +	if(getsockname(oplock_sock, (struct sockaddr *)&sock_name, &len)<0) { +		DEBUG(0,("open_oplock_ipc: Failed to get local UDP port. Error was %s\n", +			 strerror(errno))); +		close(oplock_sock); +		oplock_sock = -1; +		global_oplock_port = 0; +		return False;  	} -#endif /* HAVE_KERNEL_OPLOCKS_IRIX */ +	global_oplock_port = ntohs(sock_name.sin_port); + +	if (lp_kernel_oplocks()) { +#if HAVE_KERNEL_OPLOCKS_IRIX +		koplocks = irix_init_kernel_oplocks(); +#endif +	} + +	DEBUG(3,("open_oplock ipc: pid = %d, global_oplock_port = %u\n",  +		 (int)sys_getpid(), global_oplock_port)); + +	return True;  }  #undef OLD_NTDOMAIN diff --git a/source3/smbd/oplock_irix.c b/source3/smbd/oplock_irix.c new file mode 100644 index 0000000000..0820c4048d --- /dev/null +++ b/source3/smbd/oplock_irix.c @@ -0,0 +1,282 @@ +#define OLD_NTDOMAIN 1 +#if HAVE_KERNEL_OPLOCKS_IRIX + +/*  +   Unix SMB/Netbios implementation. +   Version 1.9. +   oplock processing +   Copyright (C) Andrew Tridgell 1992-1998 +    +   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 int oplock_pipe_write = -1; +static int oplock_pipe_read = -1; + +/**************************************************************************** +test to see if IRIX kernel oplocks work +****************************************************************************/ +static BOOL irix_oplocks_available(void) +{ +	int fd; +	int pfd[2]; +	pstring tmpname; + +	oplock_set_capability(True, False); + +	slprintf(tmpname,sizeof(tmpname)-1, "%s/koplock.%d", lp_lockdir(), (int)sys_getpid()); + +	if(pipe(pfd) != 0) { +		DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error was %s\n", +			 strerror(errno) )); +		return False; +	} + +	if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) { +		DEBUG(0,("check_kernel_oplocks: Unable to open temp test file %s. Error was %s\n", +			 tmpname, strerror(errno) )); +		unlink( tmpname ); +		close(pfd[0]); +		close(pfd[1]); +		return False; +	} + +	unlink(tmpname); + +	if(fcntl(fd, F_OPLKREG, pfd[1]) == -1) { +		DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not available on this machine. \ +Disabling kernel oplock support.\n" )); +		close(pfd[0]); +		close(pfd[1]); +		close(fd); +		return False; +	} + +	if(fcntl(fd, F_OPLKACK, OP_REVOKE) < 0 ) { +		DEBUG(0,("check_kernel_oplocks: Error when removing kernel oplock. Error was %s. \ +Disabling kernel oplock support.\n", strerror(errno) )); +		close(pfd[0]); +		close(pfd[1]); +		close(fd); +		return False; +	} + +	close(pfd[0]); +	close(pfd[1]); +	close(fd); + +	return True; +} + + + +/**************************************************************************** + * Deal with the IRIX kernel <--> smbd + * oplock break protocol. +****************************************************************************/ +static BOOL irix_oplock_receive_message(fd_set *fds, char *buffer, int buffer_len) +{ +     oplock_stat_t os; +     SMB_DEV_T dev; +     SMB_INO_T inode; +     char dummy; + +     /* +      * Read one byte of zero to clear the +      * kernel break notify message. +      */ + +     if(read(oplock_pipe_read, &dummy, 1) != 1) { +	     DEBUG(0,("receive_local_message: read of kernel notification failed. \ +Error was %s.\n", strerror(errno) )); +	     smb_read_error = READ_ERROR; +	     return False; +     } + +     /* +      * Do a query to get the +      * device and inode of the file that has the break +      * request outstanding. +      */ + +     if(fcntl(oplock_pipe_read, F_OPLKSTAT, &os) < 0) { +	     DEBUG(0,("receive_local_message: fcntl of kernel notification failed. \ +Error was %s.\n", strerror(errno) )); +	     if(errno == EAGAIN) { +		     /* +		      * Duplicate kernel break message - ignore. +		      */ +		     memset(buffer, '\0', KERNEL_OPLOCK_BREAK_MSG_LEN); +		     return True; +	     } +	     smb_read_error = READ_ERROR; +	     return False; +     } + +     dev = (SMB_DEV_T)os.os_dev; +     inode = (SMB_INO_T)os.os_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));	 +      +     return True; +} + + +/**************************************************************************** + Attempt to set an kernel oplock on a file. +****************************************************************************/ +static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type) +{ +	if (fcntl(fsp->fd, F_OPLKREG, oplock_pipe_write) == -1) { +		if(errno != EAGAIN) { +			DEBUG(0,("set_file_oplock: Unable to get kernel oplock on file %s, dev = %x, \ +inode = %.0f. Error was %s\n",  +				 fsp->fsp_name, (unsigned int)fsp->dev, (double)fsp->inode, +				 strerror(errno) )); +		} else { +			DEBUG(5,("set_file_oplock: Refused oplock on file %s, fd = %d, dev = %x, \ +inode = %.0f. Another process had the file open.\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 irix_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_OPLKACK, -1); +		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_OPLKACK, OP_REVOKE) < 0) { +		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 irix_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; +} + + +/**************************************************************************** +set *maxfd to include oplock read pipe +****************************************************************************/ +static BOOL irix_oplock_msg_waiting(fd_set *fds) +{ +	if (oplock_pipe_read == -1) return False; + +	return FD_ISSET(oplock_pipe_read,fds); +} + + +/**************************************************************************** +setup kernel oplocks +****************************************************************************/ +struct kernel_oplocks *irix_init_kernel_oplocks(void)  +{ +	int pfd[2]; +	static struct kernel_oplocks koplocks; + +	if (!irix_oplocks_available()) return NULL; + +	if(pipe(pfd) != 0) { +		DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. Error was %s\n", +			 strerror(errno) )); +		return False; +	} + +	oplock_pipe_read = pfd[0]; +	oplock_pipe_write = pfd[1]; + +	koplocks.receive_message = irix_oplock_receive_message; +	koplocks.set_oplock = irix_set_kernel_oplock; +	koplocks.release_oplock = irix_release_kernel_oplock; +	koplocks.parse_message = irix_kernel_oplock_parse; +	koplocks.msg_waiting = irix_oplock_msg_waiting; +	koplocks.notification_fd = oplock_pipe_read; + +	return &koplocks; +} + + + +#else + void oplock_irix_dummy(void) {} +#endif /* HAVE_KERNEL_OPLOCKS_IRIX */ + +#undef OLD_NTDOMAIN diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 72c0cb105d..ecf1deb05a 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -259,12 +259,6 @@ max can be %d\n",  				   done correctly in the process.  */  				reset_globals_after_fork(); -				/* -				 * Ensure this child has kernel oplock -				 * capabilities, but not it's children. -				 */ -				oplock_set_capability(True, False); -  				return True;   			}  			/* The parent doesn't need this socket */ @@ -723,8 +717,6 @@ static void usage(char *pname)  		mkdir(lp_lockdir(), 0755);  	} -	check_kernel_oplocks(); -  	if (is_daemon) {  		pidfile_create("smbd");  	} @@ -733,20 +725,20 @@ static void usage(char *pname)  		exit(1);  	/* -	 * Note that this call should be done after the fork() call -	 * in open_sockets(), as some versions of the locking shared -	 * memory code register openers in a flat file. +	 * everything after this point is run after the fork()  	 */  -	if (!locking_init(0)) +	if (!locking_init(0)) {  		exit(1); +	}  	if (!print_backend_init()) {  		exit(1);  	} -	if(!initialize_password_db()) +	if(!initialize_password_db()) {  		exit(1); +	}  	/* possibly reload the services file. */  	reload_services(True); @@ -761,9 +753,10 @@ static void usage(char *pname)  			DEBUG(2,("Changed root to %s\n", lp_rootdir()));  	} -	/* Setup the oplock IPC socket. */ -	if( !open_oplock_ipc() ) +	/* Setup oplocks */ +	if (!init_oplocks()) {  		exit(1); +	}  	smbd_process(); | 
