diff options
Diffstat (limited to 'usr/src/uts/common/syscall/fcntl.c')
| -rw-r--r-- | usr/src/uts/common/syscall/fcntl.c | 137 | 
1 files changed, 126 insertions, 11 deletions
| diff --git a/usr/src/uts/common/syscall/fcntl.c b/usr/src/uts/common/syscall/fcntl.c index 7421957235..d631fe62f6 100644 --- a/usr/src/uts/common/syscall/fcntl.c +++ b/usr/src/uts/common/syscall/fcntl.c @@ -22,6 +22,7 @@  /*   * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.   * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. + * Copyright 2015, Joyent, Inc.   */  /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/ @@ -53,7 +54,8 @@  #include <sys/cmn_err.h> -static int flock_check(vnode_t *, flock64_t *, offset_t, offset_t); +/* This is global so that it can be used by brand emulation. */ +int flock_check(vnode_t *, flock64_t *, offset_t, offset_t);  static int flock_get_start(vnode_t *, flock64_t *, offset_t, u_offset_t *);  static void fd_too_big(proc_t *); @@ -271,11 +273,12 @@ fcntl(int fdes, int cmd, intptr_t arg)  	 * The file system and vnode layers understand and implement  	 * locking with flock64 structures. So here once we pass through  	 * the test for compatibility as defined by LFS API, (for F_SETLK, -	 * F_SETLKW, F_GETLK, F_GETLKW, F_FREESP) we transform -	 * the flock structure to a flock64 structure and send it to the -	 * lower layers. Similarly in case of GETLK the returned flock64 -	 * structure is transformed to a flock structure if everything fits -	 * in nicely, otherwise we return EOVERFLOW. +	 * F_SETLKW, F_GETLK, F_GETLKW, F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKW, +	 * F_FREESP) we transform the flock structure to a flock64 structure +	 * and send it to the lower layers. Similarly in case of GETLK and +	 * OFD_GETLK the returned flock64 structure is transformed to a flock +	 * structure if everything fits in nicely, otherwise we return +	 * EOVERFLOW.  	 */  	case F_GETLK: @@ -283,6 +286,11 @@ fcntl(int fdes, int cmd, intptr_t arg)  	case F_SETLK:  	case F_SETLKW:  	case F_SETLK_NBMAND: +	case F_OFD_GETLK: +	case F_OFD_SETLK: +	case F_OFD_SETLKW: +	case F_FLOCK: +	case F_FLOCKW:  		/*  		 * Copy in input fields only. @@ -345,20 +353,65 @@ fcntl(int fdes, int cmd, intptr_t arg)  		if ((error = flock_check(vp, &bf, offset, maxoffset)) != 0)  			break; +		if (cmd == F_FLOCK || cmd == F_FLOCKW) { +			/* FLOCK* locking is always over the entire file. */ +			if (bf.l_whence != 0 || bf.l_start != 0 || +			    bf.l_len != 0) { +				error = EINVAL; +				break; +			} +			if (bf.l_type < F_RDLCK || bf.l_type > F_UNLCK) { +				error = EINVAL; +				break; +			} +		} + +		if (cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW) { +			/* +			 * TBD OFD-style locking is currently limited to +			 * covering the entire file. +			 */ +			if (bf.l_whence != 0 || bf.l_start != 0 || +			    bf.l_len != 0) { +				error = EINVAL; +				break; +			} +		} +  		/*  		 * Not all of the filesystems understand F_O_GETLK, and  		 * there's no need for them to know.  Map it to F_GETLK. +		 * +		 * The *_frlock functions in the various file systems basically +		 * do some validation and then funnel everything through the +		 * fs_frlock function. For OFD-style locks fs_frlock will do +		 * nothing so that once control returns here we can call the +		 * ofdlock function with the correct fp. For OFD-style locks +		 * the unsupported remote file systems, such as NFS, detect and +		 * reject the OFD-style cmd argument.  		 */  		if ((error = VOP_FRLOCK(vp, (cmd == F_O_GETLK) ? F_GETLK : cmd,  		    &bf, flag, offset, NULL, fp->f_cred, NULL)) != 0)  			break; +		if (cmd == F_FLOCK || cmd == F_FLOCKW || cmd == F_OFD_GETLK || +		    cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW) { +			/* +			 * This is an OFD-style lock so we need to handle it +			 * here. Because OFD-style locks are associated with +			 * the file_t we didn't have enough info down the +			 * VOP_FRLOCK path immediately above. +			 */ +			if ((error = ofdlock(fp, cmd, &bf, flag, offset)) != 0) +				break; +		} +  		/*  		 * If command is GETLK and no lock is found, only  		 * the type field is changed.  		 */ -		if ((cmd == F_O_GETLK || cmd == F_GETLK) && -		    bf.l_type == F_UNLCK) { +		if ((cmd == F_O_GETLK || cmd == F_GETLK || +		    cmd == F_OFD_GETLK) && bf.l_type == F_UNLCK) {  			/* l_type always first entry, always a short */  			if (copyout(&bf.l_type, &((struct flock *)arg)->l_type,  			    sizeof (bf.l_type))) @@ -387,7 +440,7 @@ fcntl(int fdes, int cmd, intptr_t arg)  			obf.l_pid = (int16_t)bf.l_pid;  			if (copyout(&obf, (void *)arg, sizeof (obf)))  				error = EFAULT; -		} else if (cmd == F_GETLK) { +		} else if (cmd == F_GETLK || cmd == F_OFD_GETLK) {  			/*  			 * Copy out SVR4 flock.  			 */ @@ -591,6 +644,11 @@ fcntl(int fdes, int cmd, intptr_t arg)  	case F_SETLK64:  	case F_SETLKW64:  	case F_SETLK64_NBMAND: +	case F_OFD_GETLK64: +	case F_OFD_SETLK64: +	case F_OFD_SETLKW64: +	case F_FLOCK64: +	case F_FLOCKW64:  		/*  		 * Large Files: Here we set cmd as *LK and send it to  		 * lower layers. *LK64 is only for the user land. @@ -611,6 +669,16 @@ fcntl(int fdes, int cmd, intptr_t arg)  			cmd = F_SETLKW;  		else if (cmd == F_SETLK64_NBMAND)  			cmd = F_SETLK_NBMAND; +		else if (cmd == F_OFD_GETLK64) +			cmd = F_OFD_GETLK; +		else if (cmd == F_OFD_SETLK64) +			cmd = F_OFD_SETLK; +		else if (cmd == F_OFD_SETLKW64) +			cmd = F_OFD_SETLKW; +		else if (cmd == F_FLOCK64) +			cmd = F_FLOCK; +		else if (cmd == F_FLOCKW64) +			cmd = F_FLOCKW;  		/*  		 * Note that the size of flock64 is different in the ILP32 @@ -636,18 +704,65 @@ fcntl(int fdes, int cmd, intptr_t arg)  		if ((error = flock_check(vp, &bf, offset, MAXOFFSET_T)) != 0)  			break; +		if (cmd == F_FLOCK || cmd == F_FLOCKW) { +			/* FLOCK* locking is always over the entire file. */ +			if (bf.l_whence != 0 || bf.l_start != 0 || +			    bf.l_len != 0) { +				error = EINVAL; +				break; +			} +			if (bf.l_type < F_RDLCK || bf.l_type > F_UNLCK) { +				error = EINVAL; +				break; +			} +		} + +		if (cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW) { +			/* +			 * TBD OFD-style locking is currently limited to +			 * covering the entire file. +			 */ +			if (bf.l_whence != 0 || bf.l_start != 0 || +			    bf.l_len != 0) { +				error = EINVAL; +				break; +			} +		} + +		/* +		 * The *_frlock functions in the various file systems basically +		 * do some validation and then funnel everything through the +		 * fs_frlock function. For OFD-style locks fs_frlock will do +		 * nothing so that once control returns here we can call the +		 * ofdlock function with the correct fp. For OFD-style locks +		 * the unsupported remote file systems, such as NFS, detect and +		 * reject the OFD-style cmd argument. +		 */  		if ((error = VOP_FRLOCK(vp, cmd, &bf, flag, offset,  		    NULL, fp->f_cred, NULL)) != 0)  			break; -		if ((cmd == F_GETLK) && bf.l_type == F_UNLCK) { +		if (cmd == F_FLOCK || cmd == F_FLOCKW || cmd == F_OFD_GETLK || +		    cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW) { +			/* +			 * This is an OFD-style lock so we need to handle it +			 * here. Because OFD-style locks are associated with +			 * the file_t we didn't have enough info down the +			 * VOP_FRLOCK path immediately above. +			 */ +			if ((error = ofdlock(fp, cmd, &bf, flag, offset)) != 0) +				break; +		} + +		if ((cmd == F_GETLK || cmd == F_OFD_GETLK) && +		    bf.l_type == F_UNLCK) {  			if (copyout(&bf.l_type, &((struct flock *)arg)->l_type,  			    sizeof (bf.l_type)))  				error = EFAULT;  			break;  		} -		if (cmd == F_GETLK) { +		if (cmd == F_GETLK || cmd == F_OFD_GETLK) {  			int i;  			/* | 
