mirror of
				https://github.com/samba-team/samba.git
				synced 2025-10-29 04:23:51 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			305 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			305 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|    Unix SMB/CIFS implementation.
 | |
|    IRIX kernel 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 3 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, see <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| 
 | |
| #define DBGC_CLASS DBGC_LOCKING
 | |
| #include "includes.h"
 | |
| 
 | |
| #if HAVE_KERNEL_OPLOCKS_IRIX
 | |
| 
 | |
| 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];
 | |
| 	TALLOC_CTX *ctx = talloc_stackframe();
 | |
| 	char *tmpname = NULL;
 | |
| 
 | |
| 	set_effective_capability(KERNEL_OPLOCK_CAPABILITY);
 | |
| 
 | |
| 	tmpname = talloc_asprintf(ctx,
 | |
| 				"%s/koplock.%d",
 | |
| 				lp_lockdir(),
 | |
| 				(int)sys_getpid());
 | |
| 	if (!tmpname) {
 | |
| 		TALLOC_FREE(ctx);
 | |
| 		return False;
 | |
| 	}
 | |
| 
 | |
| 	if(pipe(pfd) != 0) {
 | |
| 		DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error "
 | |
| 			 "was %s\n",
 | |
| 			 strerror(errno) ));
 | |
| 		TALLOC_FREE(ctx);
 | |
| 		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]);
 | |
| 		TALLOC_FREE(ctx);
 | |
| 		return False;
 | |
| 	}
 | |
| 
 | |
| 	unlink(tmpname);
 | |
| 
 | |
| 	TALLOC_FREE(ctx);
 | |
| 
 | |
| 	if(sys_fcntl_long(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(sys_fcntl_long(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 files_struct *irix_oplock_receive_message(fd_set *fds)
 | |
| {
 | |
| 	extern int smb_read_error;
 | |
| 	oplock_stat_t os;
 | |
| 	char dummy;
 | |
| 	struct file_id fileid;
 | |
| 	files_struct *fsp;
 | |
| 
 | |
| 	/* Ensure we only get one call per select fd set. */
 | |
| 	FD_CLR(oplock_pipe_read, fds);
 | |
| 
 | |
| 	/*
 | |
| 	 * Read one byte of zero to clear the
 | |
| 	 * kernel break notify message.
 | |
| 	 */
 | |
| 
 | |
| 	if(read(oplock_pipe_read, &dummy, 1) != 1) {
 | |
| 		DEBUG(0,("irix_oplock_receive_message: read of kernel "
 | |
| 			 "notification failed. Error was %s.\n",
 | |
| 			 strerror(errno) ));
 | |
| 		smb_read_error = READ_ERROR;
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Do a query to get the
 | |
| 	 * device and inode of the file that has the break
 | |
| 	 * request outstanding.
 | |
| 	 */
 | |
| 
 | |
| 	if(sys_fcntl_ptr(oplock_pipe_read, F_OPLKSTAT, &os) < 0) {
 | |
| 		DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
 | |
| 			 "notification failed. Error was %s.\n",
 | |
| 			 strerror(errno) ));
 | |
| 		if(errno == EAGAIN) {
 | |
| 			/*
 | |
| 			 * Duplicate kernel break message - ignore.
 | |
| 			 */
 | |
| 			return NULL;
 | |
| 		}
 | |
| 		smb_read_error = READ_ERROR;
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * We only have device and inode info here - we have to guess that this
 | |
| 	 * is the first fsp open with this dev,ino pair.
 | |
| 	 *
 | |
| 	 * NOTE: this doesn't work if any VFS modules overloads
 | |
| 	 *       the file_id_create() hook!
 | |
| 	 */
 | |
| 
 | |
| 	fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
 | |
| 				    (SMB_INO_T)os.os_ino);
 | |
| 	if ((fsp = file_find_di_first(fileid)) == NULL) {
 | |
| 		DEBUG(0,("irix_oplock_receive_message: unable to find open "
 | |
| 			 "file with dev = %x, inode = %.0f\n",
 | |
| 			 (unsigned int)os.os_dev, (double)os.os_ino ));
 | |
| 		return NULL;
 | |
| 	}
 | |
|      
 | |
| 	DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
 | |
| 		 "received for file_id %s gen_id = %ul",
 | |
| 		 file_id_string_tos(&fsp->file_id),
 | |
| 		 fsp->fh->gen_id ));
 | |
| 
 | |
| 	return fsp;
 | |
| }
 | |
| 
 | |
| /****************************************************************************
 | |
|  Attempt to set an kernel oplock on a file.
 | |
| ****************************************************************************/
 | |
| 
 | |
| static BOOL irix_set_kernel_oplock(files_struct *fsp, int oplock_type)
 | |
| {
 | |
| 	if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, oplock_pipe_write) == -1) {
 | |
| 		if(errno != EAGAIN) {
 | |
| 			DEBUG(0,("irix_set_kernel_oplock: Unable to get "
 | |
| 				 "kernel oplock on file %s, file_id %s "
 | |
| 				 "gen_id = %ul. Error was %s\n", 
 | |
| 				 fsp->fsp_name, file_id_string_tos(&fsp->file_id), 
 | |
| 				 fsp->fh->gen_id,
 | |
| 				 strerror(errno) ));
 | |
| 		} else {
 | |
| 			DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
 | |
| 				 "file %s, fd = %d, file_id = 5s, "
 | |
| 				 "gen_id = %ul. Another process had the file "
 | |
| 				 "open.\n",
 | |
| 				 fsp->fsp_name, fsp->fh->fd,
 | |
| 				 file_id_string_tos(&fsp->file_id),
 | |
| 				 fsp->fh->gen_id ));
 | |
| 		}
 | |
| 		return False;
 | |
| 	}
 | |
| 	
 | |
| 	DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
 | |
| 		  "gen_id = %ul\n",
 | |
| 		  fsp->fsp_name, file_id_string_tos(&fsp->file_id),
 | |
| 		  fsp->fh->gen_id));
 | |
| 
 | |
| 	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 = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
 | |
| 		dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
 | |
| 			"gen_id = %ul, has kernel oplock state "
 | |
| 			"of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id),
 | |
|                         fsp->fh->gen_id, state );
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Remove the kernel oplock on this file.
 | |
| 	 */
 | |
| 	if(sys_fcntl_long(fsp->fh->fd, F_OPLKACK, OP_REVOKE) < 0) {
 | |
| 		if( DEBUGLVL( 0 )) {
 | |
| 			dbgtext("irix_release_kernel_oplock: Error when "
 | |
| 				"removing kernel oplock on file " );
 | |
| 			dbgtext("%s, file_id = %s gen_id = %ul. "
 | |
| 				"Error was %s\n",
 | |
| 				fsp->fsp_name, file_id_string_tos(&fsp->file_id),
 | |
| 				fsp->fh->gen_id,
 | |
| 				strerror(errno) );
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /****************************************************************************
 | |
|  See if there is a message waiting in this fd set.
 | |
|  Note that fds MAY BE NULL ! If so we must do our own select.
 | |
| ****************************************************************************/
 | |
| 
 | |
| static BOOL irix_oplock_msg_waiting(fd_set *fds)
 | |
| {
 | |
| 	int selrtn;
 | |
| 	fd_set myfds;
 | |
| 	struct timeval to;
 | |
| 
 | |
| 	if (oplock_pipe_read == -1)
 | |
| 		return False;
 | |
| 
 | |
| 	if (fds) {
 | |
| 		return FD_ISSET(oplock_pipe_read, fds);
 | |
| 	}
 | |
| 
 | |
| 	/* Do a zero-time select. We just need to find out if there
 | |
| 	 * are any outstanding messages. We use sys_select_intr as
 | |
| 	 * we need to ignore any signals. */
 | |
| 
 | |
| 	FD_ZERO(&myfds);
 | |
| 	FD_SET(oplock_pipe_read, &myfds);
 | |
| 
 | |
| 	to = timeval_set(0, 0);
 | |
| 	selrtn = sys_select_intr(oplock_pipe_read+1,&myfds,NULL,NULL,&to);
 | |
| 	return (selrtn == 1) ? True : False;
 | |
| }
 | |
| 
 | |
| /****************************************************************************
 | |
|  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.msg_waiting = irix_oplock_msg_waiting;
 | |
| 	koplocks.notification_fd = oplock_pipe_read;
 | |
| 
 | |
| 	return &koplocks;
 | |
| }
 | |
| #else
 | |
|  void oplock_irix_dummy(void);
 | |
|  void oplock_irix_dummy(void) {}
 | |
| #endif /* HAVE_KERNEL_OPLOCKS_IRIX */
 |