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; /* |