diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2015-02-19 09:05:18 -0800 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2015-11-24 16:26:22 -0800 |
commit | 7a5aac98bc37534537d4896efd4efd30627d221e (patch) | |
tree | 952057632cf0d7aa29610276f7b1df251d564a43 | |
parent | 8c6ffd5964f28b15919c0a4ad3d120f84cedbc3d (diff) | |
download | illumos-gate-7a5aac98bc37534537d4896efd4efd30627d221e.tar.gz |
3252 Need a proper flock() implementation
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
Reviewed by: Jason King <jason.brian.king@gmail.com>
Approved by: Garrett D'Amore <garrett@damore.org>
25 files changed, 1187 insertions, 148 deletions
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c index 4e453da0c1..303b652b91 100644 --- a/usr/src/cmd/truss/codes.c +++ b/usr/src/cmd/truss/codes.c @@ -23,7 +23,7 @@ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2014, Joyent, Inc. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. All rights reserved. * Copyright (c) 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ @@ -108,7 +108,7 @@ #include "proto.h" #define FCNTLMIN F_DUPFD -#define FCNTLMAX F_BADFD +#define FCNTLMAX F_FLOCKW const char *const FCNTLname[] = { "F_DUPFD", "F_GETFD", @@ -156,7 +156,15 @@ const char *const FCNTLname[] = { "F_SHARE_NBMAND", "F_SETLK64_NBMAND", NULL, /* 45 */ - "F_BADFD" + "F_BADFD", + "F_OFD_GETLK", + "F_OFD_SETLK", + "F_OFD_SETLKW", + NULL, /* 50 */ + NULL, /* 51 */ + NULL, /* 52 */ + "F_FLOCK", + "F_FLOCKW" }; #define SYSFSMIN GETFSIND diff --git a/usr/src/cmd/truss/expound.c b/usr/src/cmd/truss/expound.c index 52c8c57537..ce98740cfa 100644 --- a/usr/src/cmd/truss/expound.c +++ b/usr/src/cmd/truss/expound.c @@ -23,6 +23,7 @@ * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2014 by Delphix. All rights reserved. + * Copyright 2015 Joyent, Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -1872,6 +1873,11 @@ show_fcntl(private_t *pri) case F_FREESP: case F_ALLOCSP: case F_SETLK_NBMAND: + case F_OFD_GETLK: + case F_OFD_SETLK: + case F_OFD_SETLKW: + case F_FLOCK: + case F_FLOCKW: if (data_model == PR_MODEL_LP64) show_flock64(pri, offset); else @@ -1883,6 +1889,11 @@ show_fcntl(private_t *pri) case 27: /* F_FREESP64 */ case 28: /* F_ALLOCSP64 */ case 44: /* F_SETLK64_NBMAND */ + case 50: /* F_OFD_GETLK64 */ + case 51: /* F_OFD_SETLK64 */ + case 52: /* F_OFD_SETLKW64 */ + case 55: /* F_FLOCK64 */ + case 56: /* F_FLOCKW64 */ show_flock64(pri, offset); break; #else /* _LP64 */ @@ -1900,6 +1911,11 @@ show_fcntl(private_t *pri) case F_FREESP64: case F_ALLOCSP64: case F_SETLK64_NBMAND: + case F_OFD_GETLK64: + case F_OFD_SETLK64: + case F_OFD_SETLKW64: + case F_FLOCK64: + case F_FLOCKW64: show_flock64(pri, offset); break; #endif /* _LP64 */ diff --git a/usr/src/lib/libbc/libc/sys/common/flock.c b/usr/src/lib/libbc/libc/sys/common/flock.c index 1c34632344..db3525236a 100644 --- a/usr/src/lib/libbc/libc/sys/common/flock.c +++ b/usr/src/lib/libbc/libc/sys/common/flock.c @@ -22,18 +22,18 @@ /* * Copyright 1990 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2015 Joyent, Inc. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/file.h> #include <sys/fcntl.h> -int flock(fd, operation) +int +flock(fd, operation) int fd, operation; { struct flock fl; - int cmd = F_SETLKW; + int cmd = F_FLOCKW; fl.l_whence = 0; fl.l_start = 0; @@ -45,7 +45,7 @@ int fd, operation; fl.l_type |= F_RDLCK; if (operation & LOCK_EX) fl.l_type |= F_WRLCK; - if (operation & LOCK_NB) - cmd = F_SETLK; - return(bc_fcntl(fd, cmd, &fl)); + if (operation & LOCK_NB) + cmd = F_FLOCK; + return (bc_fcntl(fd, cmd, &fl)); } diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile index a968fa45f7..831d8f15e6 100644 --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -385,6 +385,7 @@ PORTGEN= \ fdetach.o \ fdopendir.o \ ffs.o \ + flock.o \ fls.o \ fmtmsg.o \ ftime.o \ diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com index c0f74678f8..68c2660a2e 100644 --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -418,6 +418,7 @@ PORTGEN= \ fdetach.o \ fdopendir.o \ ffs.o \ + flock.o \ fls.o \ fmtmsg.o \ ftime.o \ diff --git a/usr/src/lib/libc/port/gen/flock.c b/usr/src/lib/libc/port/gen/flock.c new file mode 100644 index 0000000000..44dd12673f --- /dev/null +++ b/usr/src/lib/libc/port/gen/flock.c @@ -0,0 +1,60 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2015 Joyent, Inc. + */ + +#include <sys/feature_tests.h> + +#include "lint.h" +#include <sys/types.h> +#include <sys/file.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +int +flock(int fildes, int operation) +{ + struct flock64 l; + int op; + int rv; + + l.l_whence = SEEK_SET; + l.l_start = 0; + l.l_len = 0; + l.l_sysid = 0; + l.l_pid = 0; + + switch (operation & ~LOCK_NB) { + case LOCK_UN: + if (operation & LOCK_NB) { + errno = EINVAL; + return (-1); + } + l.l_type = F_UNLCK; + rv = fcntl(fildes, F_FLOCK, &l); + break; + case LOCK_EX: + case LOCK_SH: + l.l_type = ((operation & ~LOCK_NB) == LOCK_EX) ? + F_WRLCK : F_RDLCK; + op = (operation & LOCK_NB) ? F_FLOCK : F_FLOCKW; + rv = fcntl(fildes, op, &l); + break; + default: + errno = EINVAL; + return (-1); + } + + return (rv); +} diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc index 9fb5935f7c..b86f23280c 100644 --- a/usr/src/lib/libc/port/llib-lc +++ b/usr/src/lib/libc/port/llib-lc @@ -26,6 +26,7 @@ * Copyright (c) 2013 Gary Mills * Copyright 2014 Garrett D'Amore <garrett@damore.org> * Copyright 2015 Circonus, Inc. All rights reserved. + * Copyright 2015 Joyent, Inc. */ /* LINTLIBRARY */ @@ -427,6 +428,9 @@ int fdetach(const char *path); /* ffs.c */ int ffs(int field); +/* flock.c */ +int flock(int filedes, int operation); + /* fmtmsg.c */ int addseverity(int value, const char *string); int fmtmsg(long class, const char *label, int severity, const char *text, diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index d62c86b364..2e51bc8f54 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -93,6 +93,11 @@ $if _x86 && _ELF64 $add amd64 $endif +SYMBOL_VERSION ILLUMOS_0.19 { # flock + protected: + flock; +} ILLUMOS_0.18; + SYMBOL_VERSION ILLUMOS_0.18 { # signalfd protected: signalfd; diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com index dc50cf3b38..ce767f688c 100644 --- a/usr/src/lib/libc/sparc/Makefile.com +++ b/usr/src/lib/libc/sparc/Makefile.com @@ -449,6 +449,7 @@ PORTGEN= \ fdetach.o \ fdopendir.o \ ffs.o \ + flock.o \ fls.o \ fmtmsg.o \ ftime.o \ diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com index 2156bad20b..5f8e513ac7 100644 --- a/usr/src/lib/libc/sparcv9/Makefile.com +++ b/usr/src/lib/libc/sparcv9/Makefile.com @@ -409,6 +409,7 @@ PORTGEN= \ fdetach.o \ fdopendir.o \ ffs.o \ + flock.o \ fls.o \ fmtmsg.o \ ftime.o \ diff --git a/usr/src/man/man2/fcntl.2 b/usr/src/man/man2/fcntl.2 index c7d769f874..0506896118 100644 --- a/usr/src/man/man2/fcntl.2 +++ b/usr/src/man/man2/fcntl.2 @@ -1,4 +1,5 @@ '\" te +.\" Copyright 2015 Joyent, Inc. .\" Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. .\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved. .\" Copyright 1989 AT&T @@ -10,7 +11,7 @@ .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH FCNTL 2 "Apr 19, 2013" +.TH FCNTL 2 "Feb 16, 2015" .SH NAME fcntl \- file control .SH SYNOPSIS @@ -24,7 +25,6 @@ fcntl \- file control .fi .SH DESCRIPTION -.sp .LP The \fBfcntl()\fR function provides for control over open files. The \fIfildes\fR argument is an open file descriptor. @@ -227,20 +227,25 @@ results are unspecified. .sp .LP -The following commands are available for advisory record locking. Record -locking is supported for regular files, and may be supported for other files. +The following commands are available for POSIX advisory or mandatory record +locking. POSIX record locking is supported for regular files, and may be +supported for other files. See the FILE LOCKING section of this manual page for +information about the types of file locks available and their interaction. .sp .ne 2 .na \fB\fBF_GETLK\fR\fR .ad .RS 14n -Get the first lock which blocks the lock description pointed to by the third -argument, \fIarg\fR, taken as a pointer to type \fBstruct flock\fR, defined in -<\fBfcntl.h\fR>. The information retrieved overwrites the information passed to -\fBfcntl()\fR in the structure \fBflock\fR. If no lock is found that would -prevent this lock from being created, then the structure will be left unchanged -except for the lock type which will be set to \fBF_UNLCK\fR. +Get the first lock which blocks the POSIX lock description pointed to by the +third argument, \fIarg\fR, taken as a pointer to type \fBstruct flock\fR, +defined in <\fBfcntl.h\fR>. The information retrieved overwrites the +information passed to \fBfcntl()\fR in the structure \fBflock\fR. If no lock is +found that would prevent this lock from being created, then the structure will +be left unchanged except for the lock type which will be set to \fBF_UNLCK\fR. +If multiple locks exist that would prevent this lock from being created, which +one is returned is unspecified. If the blocking lock is an OFD-style lock, +\fB\(mi1\fR\& will be returned for the lock's pid value. .RE .sp @@ -250,7 +255,7 @@ except for the lock type which will be set to \fBF_UNLCK\fR. .ad .RS 14n Equivalent to \fBF_GETLK\fR, but takes a \fBstruct flock64\fR argument rather -than a \fBstruct flock\fR argument. +than a \fBstruct flock\fR argument. See \fBlf64\fR(5). .RE .sp @@ -259,7 +264,7 @@ than a \fBstruct flock\fR argument. \fB\fBF_SETLK\fR\fR .ad .RS 14n -Set or clear a file segment lock according to the lock description pointed to +Set or clear a POSIX record lock according to the lock description pointed to by the third argument, \fIarg\fR, taken as a pointer to type \fBstruct flock\fR, defined in <\fBfcntl.h\fR>. \fBF_SETLK\fR is used to establish shared (or read) locks (\fBF_RDLCK\fR) or exclusive (or write) locks (\fBF_WRLCK\fR), @@ -276,7 +281,7 @@ return value of \fB\(mi1\fR\&. .ad .RS 14n Equivalent to \fBF_SETLK\fR, but takes a \fBstruct flock64\fR argument rather -than a \fBstruct flock\fR argument. +than a \fBstruct flock\fR argument. See \fBlf64\fR(5). .RE .sp @@ -300,22 +305,193 @@ set to \fBEINTR\fR, and the lock operation will not be done. .ad .RS 14n Equivalent to \fBF_SETLKW\fR, but takes a \fBstruct flock64\fR argument rather -than a \fBstruct flock\fR argument. +than a \fBstruct flock\fR argument. See \fBlf64\fR(5). +.RE + +.sp +.LP +The following commands are available for OFD (open file description) advisory +record locking. OFD record locking is supported for regular files, and may be +supported for other files. See the FILE LOCKING section of this manual page for +information about the types of file locks available and their interaction. +OFD-style record locks are currently limited to spanning the entire file and +these locks are currently not supported over remote file systems (e.g. +\fBnfs\fR(4)) which use the Network Lock Manager. +.sp +.ne 2 +.na +\fB\fBF_OFD_GETLK\fR\fR +.ad +.RS 14n +Get the first lock which blocks the OFD lock description pointed to by the +third argument, \fIarg\fR, taken as a pointer to type \fBstruct flock\fR, +defined in <\fBfcntl.h\fR>. The information retrieved overwrites the +information passed to \fBfcntl()\fR in the structure \fBflock\fR. If no lock is +found that would prevent this lock from being created, then the structure will +be left unchanged except for the lock type which will be set to \fBF_UNLCK\fR. +If multiple locks exist that would prevent this lock from being created, which +one is returned is unspecified. If the blocking lock is an OFD-style lock, +\fB\(mi1\fR\& will be returned for the lock's pid value. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_GETLK64\fR\fR +.ad +.RS 14n +Equivalent to \fBF_OFD_GETLK\fR, but takes a \fBstruct flock64\fR argument +rather than a \fBstruct flock\fR argument. See \fBlf64\fR(5). This command +exists solely to allow the use of OFD locks with the transitional 64-bit file +interfaces. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_SETLK\fR\fR +.ad +.RS 14n +Set or clear a OFD record lock according to the lock description pointed to +by the third argument, \fIarg\fR, taken as a pointer to type \fBstruct +flock\fR, defined in <\fBfcntl.h\fR>. \fBF_OFD_SETLK\fR is used to establish +shared (or read) locks (\fBF_RDLCK\fR) or exclusive (or write) locks +(\fBF_WRLCK\fR), as well as to remove either type of lock (\fBF_UNLCK\fR). +\fBF_RDLCK\fR, \fBF_WRLCK\fR and \fBF_UNLCK\fR are defined in <\fBfcntl.h\fR>. +If a shared or exclusive lock cannot be set, \fBfcntl()\fR will return +immediately with a return value of \fB\(mi1\fR\&. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_SETLK64\fR\fR +.ad +.RS 14n +Equivalent to \fBF_OFD_SETLK\fR, but takes a \fBstruct flock64\fR argument +rather than a \fBstruct flock\fR argument. See \fBlf64\fR(5). This command +exists solely to allow the use of OFD locks with the transitional 64-bit file +interfaces. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_SETLKW\fR\fR +.ad +.RS 14n +This command is the same as \fBF_OFD_SETLK\fR except that if a shared or +exclusive lock is blocked by other locks, the process will wait until the +request can be satisfied. If a signal that is to be caught is received while +\fBfcntl()\fR is waiting for a region, \fBfcntl()\fR will be interrupted. Upon +return from the process' signal handler, \fBfcntl()\fR will return \fB\(mi1\fR +with \fBerrno\fR set to \fBEINTR\fR, and the lock operation will not be done. .RE .sp +.ne 2 +.na +\fB\fBF_OFD_SETLKW64\fR\fR +.ad +.RS 14n +Equivalent to \fBF_OFD_SETLKW\fR, but takes a \fBstruct flock64\fR argument +rather than a \fBstruct flock\fR argument. See \fBlf64\fR(5). This command +exists solely to allow the use of OFD locks with the transitional 64-bit file +interfaces. +.RE + +.sp +.LP +The following values for \fIcmd\fR are used for file share reservations. A +share reservation is placed on an entire file to allow cooperating processes to +control access to the file. See the SHARE RESERVATIONS section of this manual +page below for additional information. +.sp +.ne 2 +.na +\fB\fBF_SHARE\fR\fR +.ad +.RS 13n +Sets a share reservation on a file with the specified access mode and +designates which types of access to deny. +.RE + +.sp +.ne 2 +.na +\fB\fBF_UNSHARE\fR\fR +.ad +.RS 13n +Remove an existing share reservation. +.RE + +.SH FILE LOCKING +.LP +Two types of file locks are supported: POSIX-style and OFD-style. OFD-style +locks are associated with the open file description (not descriptor) instead +of with a process. Either type is advisory by default, but POSIX-style locks +can be mandatory if, and only if, mandatory locking has been enabled on the +file being locked. Each type of lock may be created through two different +interfaces. POSIX-style locks are created via the \fBF_SETLK\fR, +\fBF_SETLK64\fR, \fBF_SETLKW\fR, or \fBF_SETLKW64\fR commands to this system +call or by use of the \fBlockf\fR(3C) routine. There is no difference between +locks created via one mechanism or the other. Likewise, OFD-style locks are +created via the \fBF_OFD_SETLK\fR, \fBF_OFD_SETLK64\fR, \fBF_OFD_SETLKW\fR, or +\fBF_OFD_SETLKW64\fR commands to this system call or by use of the +Linux/BSD-compatible \fBflock\fR(3C) routine. Note that this system call +supports the creation of range-specified OFD-style file locks, while +\fBflock\fR(3C) does not. However, the current implementation of OFD-style +locking is limited to locking the entire file. This limitation might be +removed in the future. +.sp +.LP +The essential distinction between POSIX-style locks and OFD-style locks lie +in how ownership of a lock is scoped. POSIX locks are scoped to a process. All +POSIX locks associated with a file for a given process are removed when any +file descriptor for that file is closed by that process or the process holding +that file descriptor terminates. POSIX-style locks are not inherited by a child +process created using \fBfork\fR(2). An OFD-style lock is scoped to the file +description for a file, not the process or open file descriptor. Thus all file +descriptors referring to the same description (i.e. those created via the +\fBF_DUPFD\fR, \fBF_DUP2FD\fR, \fBF_DUPFD_CLOEXEC\fR, or \fBF_DUP2FD_CLOEXEC\fR +commands to the \fBfcntl\fR(2) system call, or those created via the +\fBdup\fR(2) system call, or those inherited by a child process created via +\fBfork\fR(2)) reference the same lock, but a file descriptor obtained via a +separate \fBopen\fR(2) call on the same file will reference a different lock. +A lock is removed only on the last \fBclose\fR(2) of the description, or when +the lock is explicitly unlocked. +.sp +.LP +Locks of both styles are compatible. A file that has been locked with one +style of lock will be regarded as locked when creation of a lock of either +style is attempted, and information about the lock will be provided via +any of the \fBF_GETLK\fR, \fBF_GETLK64\fR, \fBF_OFD_GETLK\fR, or +\fBF_OFD_GETLK64\fR commands to this system call if that lock would conflict +with an attempt to create the specified lock regardless of whether the +specified lock is of the same style as the conflicting extant lock. +Because ownership of OFD-style locks is scoped to the open description rather +than the calling process, the \fBl_pid\fR field of a lock descriptor for any +such lock will always be set to \fB\(mi1\fR\&. +.sp .LP -When a shared lock is set on a segment of a file, other processes will be able -to set shared locks on that segment or a portion of it. A shared lock prevents -any other process from setting an exclusive lock on any portion of the -protected area. A request for a shared lock will fail if the file descriptor -was not opened with read access. +When a shared lock is set on a segment of a file, other callers (regardless +of whether in the same or different process and of whether referenced via the +same open file) will be able to set shared locks on that segment or a portion +of it. A POSIX-style shared lock prevents any other process from setting an +exclusive lock on any portion of the protected area. A OFD-style shared lock +prevents any caller (even callers in the same process) from setting an +exclusive lock on any portion of the protected area, unless the caller makes +the request against a file descriptor referencing the same open file against +which the shared lock was created, in which case the lock will be downgraded +to a shared lock with respect to the specified region. A request for a shared +lock of either style will fail if the file descriptor was not opened with +read access. .sp .LP -An exclusive lock will prevent any other process from setting a shared lock or -an exclusive lock on any portion of the protected area. A request for an -exclusive lock will fail if the file descriptor was not opened with write -access. +A POSIX-style exclusive lock will prevent any other process from setting a +shared lock or an exclusive lock (of either style) on any portion of the +protected area. A request for an exclusive lock will fail if the file +descriptor was not opened with write access. .sp .LP The \fBflock\fR structure contains at least the following elements: @@ -340,13 +516,17 @@ be measured from the start of the file, current position or end of the file, respectively. The value of \fBl_len\fR is the number of consecutive bytes to be locked. The value of \fBl_len\fR may be negative (where the definition of \fBoff_t\fR permits negative values of \fBl_len\fR). After a successful -\fBF_GETLK\fR or \fBF_GETLK64\fR request, that is, one in which a lock was -found, the value of \fBl_whence\fR will be \fBSEEK_SET\fR. +\fBF_GETLK\fR, \fBF_GETLK64\fR, \fBF_OFD_GETLK\fR, or \fBF_OFD_GETLK64\fR +request, that is, one in which a lock was found, the value of \fBl_whence\fR +will be \fBSEEK_SET\fR. .sp .LP The \fBl_pid\fR and \fBl_sysid\fR fields are used only with \fBF_GETLK\fR or \fBF_GETLK64\fR to return the process \fBID\fR of the process holding a -blocking lock and to indicate which system is running that process. +POSIX-style blocking lock and to indicate which system is running that process, +or \fB\(mi1\fR\& if it is an OFD-style lock. These fields must both be +initialized to 0 prior to issuing a OFD-style locking command +(\fBF_OFD_GETLK\fR or \fBF_OFD_GETLK64\fR). .sp .LP If \fBl_len\fR is positive, the area affected starts at \fBl_start\fR and ends @@ -359,62 +539,48 @@ to the largest possible value of the file offset for that file by setting \fBl_whence\fR is set to \fBSEEK_SET\fR, the whole file will be locked. .sp .LP -If a process has an existing lock in which \fBl_len\fR is 0 and which includes -the last byte of the requested segment, and an unlock (\fBF_UNLCK\fR) request -is made in which \fBl_len\fR is non-zero and the offset of the last byte of the -requested segment is the maximum value for an object of type \fBoff_t\fR, then -the \fBF_UNLCK\fR request will be treated as a request to unlock from the start +If a lock exists for which \fBl_len\fR is 0 and which includes the last byte of +the requested segment, and an unlock (\fBF_UNLCK\fR) request is made in which +\fBl_len\fR is non-zero and the offset of the last byte of the requested +segment is the maximum value for an object of type \fBoff_t\fR, then the +\fBF_UNLCK\fR request will be treated as a request to unlock from the start of the requested segment with an \fBl_len\fR equal to 0. Otherwise, the request will attempt to unlock only the requested segment. .sp .LP -There will be at most one type of lock set for each byte in the file. Before a -successful return from an \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, or -\fBF_SETLKW64\fR request when the calling process has previously existing locks -on bytes in the region specified by the request, the previous lock type for -each byte in the specified region will be replaced by the new lock type. As -specified above under the descriptions of shared locks and exclusive locks, an -\fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, or \fBF_SETLKW64\fR request -will (respectively) fail or block when another process has existing locks on -bytes in the specified region and the type of any of those locks conflicts with -the type specified in the request. +There will be at most one type of lock set for each byte in the +file. Before a successful return from an \fBF_SETLK\fR, \fBF_SETLK64\fR, +\fBF_SETLKW\fR, or \fBF_SETLKW64\fR request when the calling process has +previously existing POSIX-style locks on bytes in the region specified by the +request, the previous POSIX-style lock type for each byte in the specified +region will be replaced by the new lock type. As specified above under the +descriptions of shared locks and exclusive locks, an \fBF_SETLK\fR, +\fBF_SETLK64\fR, \fBF_SETLKW\fR, or \fBF_SETLKW64\fR request will +(respectively) fail or block when locks exist on bytes in the specified region +and the type of any of those locks conflicts with the type specified in the +request. .sp .LP -All locks associated with a file for a given process are removed when a file -descriptor for that file is closed by that process or the process holding that -file descriptor terminates. Locks are not inherited by a child process created -using \fBfork\fR(2). +Similarly, before a successful return from an \fBF_OFD_SETLK\fR, +\fBF_OFD_SETLK64\fR, \fBF_OFD_SETLKW\fR, or \fBF_OFD_SETLKW64\fR request when +previously-created OFD-style locks associated with the open file apply to +bytes in the region specified by the request, the previous OFD-style lock type +for each byte in the specified region will be replaced by the new lock type. +As specified above under the descriptions of shared locks and exclusive locks, +an \fBF_OFD_SETLK\fR, \fBF_OFD_SETLK64\fR, \fBF_OFD_SETLKW\fR, or +\fBF_OFD_SETLKW64\fR request will (respectively) fail or block when locks exist +on bytes in the specified region and the type of any of those locks conflicts +with the type specified in the request. .sp .LP A potential for deadlock occurs if a process controlling a locked region is put to sleep by attempting to lock another process' locked region. If the system detects that sleeping until a locked region is unlocked would cause a deadlock, -\fBfcntl()\fR will fail with an \fBEDEADLK\fR error. -.sp -.LP -The following values for \fIcmd\fR are used for file share reservations. A -share reservation is placed on an entire file to allow cooperating processes to -control access to the file. -.sp -.ne 2 -.na -\fB\fBF_SHARE\fR\fR -.ad -.RS 13n -Sets a share reservation on a file with the specified access mode and -designates which types of access to deny. -.RE +\fBfcntl()\fR will fail with an \fBEDEADLK\fR error. This deadlock detection +and error value apply only to POSIX-style locks. No deadlock detection is +performed when attempting to set an OFD-style lock. -.sp -.ne 2 -.na -\fB\fBF_UNSHARE\fR\fR -.ad -.RS 13n -Remove an existing share reservation. -.RE - -.sp +.SH SHARE RESERVATIONS .LP File share reservations are an advisory form of access control among cooperating processes, on both local and remote machines. They are most often @@ -526,7 +692,6 @@ Do not deny read or write access to any other process. .RE .SH RETURN VALUES -.sp .LP Upon successful completion, the value returned depends on \fIcmd\fR as follows: .sp @@ -608,6 +773,60 @@ The return value will not be negative. .sp .ne 2 .na +\fB\fBF_OFD_GETLK\fR\fR +.ad +.RS 14n +Value other then \fB\(mi1\fR\&. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_GETLK64\fR\fR +.ad +.RS 14n +Value other then \fB\(mi1\fR\&. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_SETLK\fR\fR +.ad +.RS 14n +Value other then \fB\(mi1\fR\&. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_SETLK64\fR\fR +.ad +.RS 14n +Value other then \fB\(mi1\fR\&. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_SETLKW\fR\fR +.ad +.RS 14n +Value other then \fB\(mi1\fR\&. +.RE + +.sp +.ne 2 +.na +\fB\fBF_OFD_SETLKW64\fR\fR +.ad +.RS 14n +Value other then \fB\(mi1\fR\&. +.RE + +.sp +.ne 2 +.na \fB\fBF_SETFD\fR\fR .ad .RS 14n @@ -691,7 +910,6 @@ Value other than \fB\(mi1\fR\&. Otherwise, \fB\(mi1\fR is returned and \fBerrno\fR is set to indicate the error. .SH ERRORS -.sp .LP The \fBfcntl()\fR function will fail if: .sp @@ -700,12 +918,13 @@ The \fBfcntl()\fR function will fail if: \fB\fBEAGAIN\fR\fR .ad .RS 13n -The \fIcmd\fR argument is \fBF_SETLK\fR or \fBF_SETLK64\fR, the type of lock -\fB(l_type)\fR is a shared (\fBF_RDLCK\fR) or exclusive (\fBF_WRLCK\fR) lock, -and the segment of a file to be locked is already exclusive-locked by another -process; or the type is an exclusive lock and some portion of the segment of a -file to be locked is already shared-locked or exclusive-locked by another -process. +The \fIcmd\fR argument is \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_OFD_SETLK\fR, +or \fBF_OFD_SETLK64\fR, the type of lock \fB(l_type)\fR is a shared +(\fBF_RDLCK\fR) or exclusive (\fBF_WRLCK\fR) lock, and the segment of a file +to be locked is already exclusive-locked by another process or open file; or +the type is an exclusive lock and some portion of the segment of a file to be +locked is already shared-locked or exclusive-locked by another process or open +file. .sp The \fIcmd\fR argument is \fBF_FREESP\fR, the file exists, mandatory file/record locking is set, and there are outstanding record locks on the file; @@ -724,8 +943,9 @@ existing \fBf_deny\fR share reservation. .ad .RS 13n The \fIfildes\fR argument is not a valid open file descriptor; or the \fIcmd\fR -argument is \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, or -\fBF_SETLKW64\fR, the type of lock, \fBl_type\fR, is a shared lock +argument is \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, \fBF_SETLKW64\fR, +\fBF_OFD_SETLK\fR, \fBF_OFD_SETLK64\fR, \fBF_OFD_SETLKW\fR, or +\fBF_OFD_SETLKW64\fR, the type of lock, \fBl_type\fR, is a shared lock (\fBF_RDLCK\fR), and \fIfildes\fR is not a valid file descriptor open for reading; or the type of lock \fBl_type\fR is an exclusive lock (\fBF_WRLCK\fR) and \fIfildes\fR is not a valid file descriptor open for writing. @@ -752,11 +972,10 @@ reading. .ad .RS 13n The \fIcmd\fR argument is \fBF_GETLK\fR, \fBF_GETLK64\fR, \fBF_SETLK\fR, -\fBF_SETLK64\fR, \fBF_SETLKW\fR, \fBF_SETLKW64\fR, or \fBF_FREESP\fR and the +\fBF_SETLK64\fR, \fBF_SETLKW\fR, \fBF_SETLKW64\fR, \fBF_OFD_GETLK\fR, +\fBF_OFD_GETLK64\fR, \fBF_OFD_SETLK\fR, \fBF_OFD_SETLK64\fR, \fBF_OFD_SETLKW\fR, +\fBF_OFD_SETLKW64\fB, \fBF_SHARE\fR, \fBF_UNSHARE\fR, or \fBF_FREESP\fR and the \fIarg\fR argument points to an illegal address. -.sp -The \fIcmd\fR argument is \fBF_SHARE\fR or \fBF_UNSHARE\fR and \fIarg\fR points -to an illegal address. .RE .sp @@ -765,8 +984,8 @@ to an illegal address. \fB\fBEINTR\fR\fR .ad .RS 13n -The \fIcmd\fR argument is \fBF_SETLKW\fR or \fBF_SETLKW64\fR and the function -was interrupted by a signal. +The \fIcmd\fR argument is \fBF_SETLKW\fR, \fBF_SETLKW64\fR, \fBF_OFD_SETLKW\fR, +or \fBF_OFD_SETLKW64\fR, and the function was interrupted by a signal. .RE .sp @@ -778,9 +997,11 @@ was interrupted by a signal. The \fIcmd\fR argument is invalid or not supported by the file system; or the \fIcmd\fR argument is \fBF_DUPFD\fR and \fIarg\fR is negative or greater than or equal to \fBOPEN_MAX\fR; or the \fIcmd\fR argument is \fBF_GETLK\fR, -\fBF_GETLK64\fR, \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, or -\fBF_SETLKW64\fR and the data pointed to by \fIarg\fR is not valid; or -\fIfildes\fR refers to a file that does not support locking. +\fBF_GETLK64\fR, \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, +\fBF_SETLKW64\fR, \fBF_OFD_GETLK\fR, \fBF_OFD_GETLK64\fR, \fBF_OFD_SETLK\fR, +\fBF_OFD_SETLK64\fR, \fBF_OFD_SETLKW\fR, or \fBF_OFD_SETLKW64\fR, and the data +pointed to by \fIarg\fR is not valid; or \fIfildes\fR refers to a file that +does not support locking. .sp The \fIcmd\fR argument is \fBF_UNSHARE\fR and a reservation with this \fBf_id\fR for this process does not exist. @@ -815,9 +1036,11 @@ greater than or equal to \fIarg\fR are available. \fB\fBENOLCK\fR\fR .ad .RS 13n -The \fIcmd\fR argument is \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, or -\fBF_SETLKW64\fR and satisfying the lock or unlock request would result in the -number of locked regions in the system exceeding a system-imposed limit. +The \fIcmd\fR argument is \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, +\fBF_SETLKW64\fR, \fBF_OFD_SETLK\fR, \fBF_OFD_SETLK64\fR, \fBF_OFD_SETLKW\fR, +or \fBF_OFD_SETLKW64\fR, and satisfying the lock or unlock request would +result in the number of locked regions in the system exceeding a +system-imposed limit. .RE .sp @@ -839,12 +1062,14 @@ file is on a remote machine, and the link to that machine is no longer active. .RS 13n One of the values to be returned cannot be represented correctly. .sp -The \fIcmd\fR argument is \fBF_GETLK\fR, \fBF_SETLK\fR, or \fBF_SETLKW\fR and +The \fIcmd\fR argument is \fBF_GETLK\fR, \fBF_SETLK\fR, \fBF_SETLKW\fR, +\fBF_OFD_GETLK\fR, \fBF_OFD_SETLK\fR, or \fBF_OFD_SETLKW\fR, and the smallest or, if \fBl_len\fR is non-zero, the largest, offset of any byte in the requested segment cannot be represented correctly in an object of type \fBoff_t\fR. .sp -The \fIcmd\fR argument is \fBF_GETLK64\fR, \fBF_SETLK64\fR, or \fBF_SETLKW64\fR +The \fIcmd\fR argument is \fBF_GETLK64\fR, \fBF_SETLK64\fR, \fBF_SETLKW64\fR, +\fBF_OFD_GETLK64\fR, \fBF_OFD_SETLK64\fR, or \fBF_OFD_SETLKW64\fR, and the smallest or, if \fBl_len\fR is non-zero, the largest, offset of any byte in the requested segment cannot be represented correctly in an object of type \fBoff64_t\fR. @@ -859,8 +1084,9 @@ The \fBfcntl()\fR function may fail if: \fB\fBEAGAIN\fR\fR .ad .RS 11n -The \fIcmd\fR argument is \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, or -\fBF_SETLKW64\fR, and the file is currently being mapped to virtual memory +The \fIcmd\fR argument is \fBF_SETLK\fR, \fBF_SETLK64\fR, \fBF_SETLKW\fR, +\fBF_SETLKW64\fR, \fBF_OFD_SETLK\fR, \fBF_OFD_SETLK64\fR, \fBF_OFD_SETLKW\fR, +or \fBF_OFD_SETLKW64\fR and the file is currently being mapped to virtual memory using \fBmmap\fR(2). .RE @@ -880,7 +1106,6 @@ detected. .RE .SH ATTRIBUTES -.sp .LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -898,17 +1123,16 @@ MT-Level Async-Signal Safe .TE .SH SEE ALSO -.sp .LP \fBlockd\fR(1M), \fBchmod\fR(2), \fBclose\fR(2), \fBcreat\fR(2), \fBdup\fR(2), \fBexec\fR(2), \fBfork\fR(2), \fBmmap\fR(2), \fBopen\fR(2), \fBpipe\fR(2), \fBread\fR(2), \fBsigaction\fR(2), \fBwrite\fR(2), \fBdup2\fR(3C), -\fBfcntl.h\fR(3HEAD), \fBattributes\fR(5), \fBstandards\fR(5) +\fBflock\fR(3C), \fBlockf\fR(3C), \fBfcntl.h\fR(3HEAD), \fBattributes\fR(5), +\fBlf64\fR(5), \fBstandards\fR(5) .sp .LP \fIProgramming Interfaces Guide\fR .SH NOTES -.sp .LP In the past, the variable \fBerrno\fR was set to \fBEACCES\fR rather than \fBEAGAIN\fR when a section of a file is already locked by another process. diff --git a/usr/src/man/man3c/Makefile b/usr/src/man/man3c/Makefile index 9ba004eff7..224b0fafbe 100644 --- a/usr/src/man/man3c/Makefile +++ b/usr/src/man/man3c/Makefile @@ -131,6 +131,7 @@ MANFILES= __fbufsize.3c \ fgetpos.3c \ fgetwc.3c \ floating_to_decimal.3c \ + flock.3c \ flockfile.3c \ fmtmsg.3c \ fnmatch.3c \ diff --git a/usr/src/man/man3c/flock.3c b/usr/src/man/man3c/flock.3c new file mode 100644 index 0000000000..66e9bedde3 --- /dev/null +++ b/usr/src/man/man3c/flock.3c @@ -0,0 +1,203 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright 1989 AT&T +.\" Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved +.\" Portions Copyright (c) 1992, X/Open Company Limited All Rights Reserved +.\" Copyright 2015 Joyent, Inc. +.\" +.TH FLOCK 3C "Feb 16, 2015" +.SH NAME +flock \- OFD(open file description)-style file locking +.SH SYNOPSIS +.LP +.nf +#include <sys/file.h> + +\fBint\fR \fBflock\fR(\fBint\fR \fIfildes\fR, \fBint\fR \fIoperation\fR); +.fi + +.SH DESCRIPTION +.LP +The \fBflock()\fR function allows advisory locks to be applied to and removed +from a file. Calls to \fBflock()\fR from callers that attempt to lock +the locked file section via a different open file handle will either return an +error value or be put to sleep until the resource becomes unlocked. +See \fBfcntl\fR(2) for more information about record locking. Locks created or +removed via this function will apply to the entire file, including any future +growth in the file's length. +.sp +.LP +The \fIfildes\fR argument is an open file descriptor. A lock can be established +without regard for the mode with which the file was opened. +.sp +.LP +The \fIoperation\fR argument is a control value that specifies the action to be +taken. The permissible values for \fIoperation\fR are defined in +<\fBsys/file.h\fR> as follows: +.sp +.in +2 +.nf +#define LOCK_SH 1 /* shared file lock */ +#define LOCK_EX 2 /* exclusive file lock */ +#define LOCK_NB 4 /* do not block when attempting to create lock */ +#define LOCK_UN 8 /* remove existing file lock */ +.fi +.in -2 + +.sp +.LP +To create a lock, either \fBLOCK_SH\fR or \fBLOCK_EX\fR should be specified, +optionally bitwise-ored with \fBLOCK_NB\fR. To remove a lock, \fBLOCK_UN\fR +should be specified. All other values of \fIoperation\fR are reserved for +future extensions and will result in an error if not implemented. +.sp +.LP +This function creates, upgrades, downgrades, or removes either shared or +exclusive OFD-style locks. Locks created by this function are owned by open +files, not file descriptors. That is, file descriptors duplicated through +\fBdup\fR(2), \fBfork\fR(2), or \fBfcntl\fR(2) do not result in multiple +instances of a lock, but rather multiple references to the same lock. If a +process holding a lock on a file forks and the child explicitly unlocks the +file, the parent will lose its lock. See \fBfcntl\fR(2) for more information +about file locking and the interaction between locks created by this function +and those created by other mechanisms. These locks are currently not supported +over remote file systems (e.g. \fBnfs\fR(4)) which use the Network Lock +Manager. +.sp +.LP +Sleeping on a resource is interrupted with any signal. The \fBalarm\fR(2) +function may be used to provide a timeout facility in applications that require +this facility. +.SH RETURN VALUES +.LP +Upon successful completion, \fB0\fR is returned. Otherwise, \fB\(mi1\fR is +returned and \fBerrno\fR is set to indicate the error. +.SH ERRORS +.LP +The \fBflock()\fR function will fail if: +.sp +.ne 2 +.na +\fB\fBEBADF\fR\fR +.ad +.RS 20n +The \fIfildes\fR argument is not a valid open file descriptor; or +\fIoperation\fR contains \fBLOCK_SH\fR and \fIfiledes\fR is not open for +reading; or \fIoperation\fR contains \fBLOCK_EX\fR and \fIfiledes\fR is not +open for writing. +.RE + +.sp +.ne 2 +.na +\fB\fBEWOULDBLOCK\fR\fR +.ad +.RS 20n +The \fIoperation\fR argument contains \fBLOCK_NB\fR and a conflicting lock +exists. +.RE + +.sp +.ne 2 +.na +\fB\fBEINTR\fR\fR +.ad +.RS 20n +A signal was caught during execution of the function. +.RE + +.sp +.ne 2 +.na +\fB\fBEINVAL\fR\fR +.ad +.RS 20n +The \fIoperation\fR argument does not contain one of \fBLOCK_SH\fR, +\fBLOCK_EX\fR, or \fBLOCK_UN\fR; or the \fIoperation\fR argument contains +\fBLOCK_UN\fR and \fBLOCK_NB\fR; or the \fIoperation\fR argument contains +any bits other than those set by \fBLOCK_SH\fR, \fBLOCK_EX\fR, \fBLOCK_NB\fR, +and \fBLOCK_UN\fR. +.RE + +.sp +.LP +The \fBflock()\fR function may fail if: +.sp +.ne 2 +.na +\fB\fBEAGAIN\fR\fR +.ad +.RS 24n +The \fIoperation\fR argument contains \fBLOCK_SH\fR or \fBLOCK_EX\fR and the +file is mapped with \fBmmap\fR(2). +.RE + +.sp +.ne 2 +.na +\fB\fBENOLCK\fR\fR +.ad +.RS 20n +The number of locked file regions in the system would exceed a system-imposed +limit. +.RE + +.sp +.ne 2 +.na +\fB\fBEOPNOTSUPP\fR +.ad +.RS 24n +The locking of files of the type indicated by the \fIfildes\fR argument is not +supported. +.RE + +.SH USAGE +.LP +File-locking should not be used in combination with the \fBfopen\fR(3C), +\fBfread\fR(3C), \fBfwrite\fR(3C) and other \fBstdio\fR functions. Instead, +the more primitive, non-buffered functions (such as \fBopen\fR(2)) should be +used. Unexpected results may occur in processes that do buffering in the user +address space. The process may later read/write data which is/was locked. The +\fBstdio\fR functions are the most common source of unexpected buffering. +.sp +.LP +The \fBalarm\fR(2) function may be used to provide a timeout facility in +applications requiring it. +.sp +.LP +Locks created by this facility conflict with those created by the +\fBlockf\fR(3C) and \fBfcntl\fR(2) facilities. This facility creates and +removed OFD-style locks; see \fBfcntl\fR(2) for information about the +interaction between OFD-style and POSIX-style file locks. +.SH ATTRIBUTES +.LP +See \fBattributes\fR(5) for descriptions of the following attributes: +.sp + +.sp +.TS +box; +c | c +l | l . +ATTRIBUTE TYPE ATTRIBUTE VALUE +_ +Interface Stability Standard +_ +MT-Level MT-Safe +.TE + +.SH SEE ALSO +.LP +\fBIntro\fR(2), \fBalarm\fR(2), \fBchmod\fR(2), \fBclose\fR(2), \fBcreat\fR(2), +\fBfcntl\fR(2), \fBmmap\fR(2), \fBopen\fR(2), \fBread\fR(2), \fBwrite\fR(2), +\fBattributes\fR(5), \fBstandards\fR(5) diff --git a/usr/src/man/man3c/lockf.3c b/usr/src/man/man3c/lockf.3c index 3b698f60a7..53d607a4f1 100644 --- a/usr/src/man/man3c/lockf.3c +++ b/usr/src/man/man3c/lockf.3c @@ -1,4 +1,5 @@ '\" te +.\" Copyright 2015 Joyent, Inc. .\" Copyright 1989 AT&T Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved Portions Copyright (c) 1992, X/Open Company Limited All Rights Reserved .\" Sun Microsystems, Inc. gratefully acknowledges The Open Group for permission to reproduce portions of its copyrighted documentation. Original documentation from The Open Group can be obtained online at .\" http://www.opengroup.org/bookstore/. @@ -7,9 +8,9 @@ .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH LOCKF 3C "May 27, 2014" +.TH LOCKF 3C "Feb 16, 2015" .SH NAME -lockf \- record locking on files +lockf \- POSIX-style record locking on files .SH SYNOPSIS .LP .nf @@ -19,10 +20,9 @@ lockf \- record locking on files .fi .SH DESCRIPTION -.sp .LP The \fBlockf()\fR function allows sections of a file to be locked; advisory or -mandatory write locks depending on the mode bits of the file (see +mandatory write locks depending on the mode bits of the file (see \fBchmod\fR(2)). Calls to \fBlockf()\fR from other threads that attempt to lock the locked file section will either return an error value or be put to sleep until the resource becomes unlocked. All the locks for a process are removed @@ -54,10 +54,10 @@ All other values of \fIfunction\fR are reserved for future extensions and will result in an error if not implemented. .sp .LP -\fBF_TEST\fR is used to detect if a lock by another process is present on the -specified section. \fBF_LOCK\fR and \fBF_TLOCK\fR both lock a section of a file -if the section is available. \fBF_ULOCK\fR removes locks from a section of the -file. +\fBF_TEST\fR is used to detect if a lock by another process or open file handle +is present on the specified section. \fBF_LOCK\fR and \fBF_TLOCK\fR both lock +a section of a file if the section is available. \fBF_ULOCK\fR removes locks +from a section of the file. .sp .LP The \fIsize\fR argument is the number of contiguous bytes to be locked or @@ -119,12 +119,10 @@ Sleeping on a resource is interrupted with any signal. The \fBalarm\fR(2) function may be used to provide a timeout facility in applications that require this facility. .SH RETURN VALUES -.sp .LP Upon successful completion, \fB0\fR is returned. Otherwise, \fB\(mi1\fR is returned and \fBerrno\fR is set to indicate the error. .SH ERRORS -.sp .LP The \fBlockf()\fR function will fail if: .sp @@ -233,7 +231,6 @@ supported. .RE .SH USAGE -.sp .LP Record-locking should not be used in combination with the \fBfopen\fR(3C), \fBfread\fR(3C), \fBfwrite\fR(3C) and other \fBstdio\fR functions. Instead, @@ -250,7 +247,6 @@ applications requiring it. The \fBlockf()\fR function has a transitional interface for 64-bit file offsets. See \fBlf64\fR(5). .SH ATTRIBUTES -.sp .LP See \fBattributes\fR(5) for descriptions of the following attributes: .sp @@ -268,7 +264,6 @@ MT-Level MT-Safe .TE .SH SEE ALSO -.sp .LP \fBIntro\fR(2), \fBalarm\fR(2), \fBchmod\fR(2), \fBclose\fR(2), \fBcreat\fR(2), \fBfcntl\fR(2), \fBmmap\fR(2), \fBopen\fR(2), \fBread\fR(2), \fBwrite\fR(2), diff --git a/usr/src/pkg/manifests/system-library.man3c.inc b/usr/src/pkg/manifests/system-library.man3c.inc index 30999ee484..cfe418f7cf 100644 --- a/usr/src/pkg/manifests/system-library.man3c.inc +++ b/usr/src/pkg/manifests/system-library.man3c.inc @@ -126,6 +126,7 @@ file path=usr/share/man/man3c/fgetc.3c file path=usr/share/man/man3c/fgetpos.3c file path=usr/share/man/man3c/fgetwc.3c file path=usr/share/man/man3c/floating_to_decimal.3c +file path=usr/share/man/man3c/flock.3c file path=usr/share/man/man3c/flockfile.3c file path=usr/share/man/man3c/fmtmsg.3c file path=usr/share/man/man3c/fnmatch.3c diff --git a/usr/src/ucbhead/sys/fcntl.h b/usr/src/ucbhead/sys/fcntl.h index 8567282301..d0ddfd9889 100644 --- a/usr/src/ucbhead/sys/fcntl.h +++ b/usr/src/ucbhead/sys/fcntl.h @@ -22,6 +22,7 @@ /* * Copyright 1998 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2015 Joyent, Inc. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -40,8 +41,6 @@ #ifndef _SYS_FCNTL_H #define _SYS_FCNTL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifndef _SYS_TYPES_H #include <sys/types.h> #endif @@ -79,6 +78,8 @@ extern "C" { #define F_SETFL 4 /* Set file flags */ #define F_SETLK 6 /* Set file lock */ #define F_SETLKW 7 /* Set file lock and wait */ +#define F_FLOCK 53 /* private - flock */ +#define F_FLOCKW 54 /* private - flock wait */ /* * Applications that read /dev/mem must be built like the kernel. A new diff --git a/usr/src/ucblib/libucb/port/sys/flock.c b/usr/src/ucblib/libucb/port/sys/flock.c index ee473bf2f8..d29a07eac0 100644 --- a/usr/src/ucblib/libucb/port/sys/flock.c +++ b/usr/src/ucblib/libucb/port/sys/flock.c @@ -21,6 +21,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2015 Joyent, Inc. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -51,12 +52,11 @@ flock(int fd, int operation) fl.l_len = 0; fl.l_type = 0; - /* In non-blocking lock, use F_SETLK for cmd, F_SETLKW otherwise */ if (operation & LOCK_NB) { - cmd = F_SETLK; + cmd = F_FLOCK; operation &= ~LOCK_NB; /* turn off this bit */ } else - cmd = F_SETLKW; + cmd = F_FLOCKW; switch (operation) { case LOCK_UN: diff --git a/usr/src/uts/common/fs/fs_subr.c b/usr/src/uts/common/fs/fs_subr.c index 744d269716..ec5b145a86 100644 --- a/usr/src/uts/common/fs/fs_subr.c +++ b/usr/src/uts/common/fs/fs_subr.c @@ -25,6 +25,7 @@ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2015 Joyent, Inc. */ /* @@ -246,6 +247,7 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag, int frcmd; int nlmid; int error = 0; + boolean_t skip_lock = B_FALSE; flk_callback_t serialize_callback; int serialize = 0; v_mode_t mode; @@ -265,6 +267,17 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag, } break; + case F_OFD_GETLK: + /* + * TBD we do not support remote OFD locks at this time. + */ + if (flag & (F_REMOTELOCK | F_PXFSLOCK)) { + error = EINVAL; + goto done; + } + skip_lock = B_TRUE; + break; + case F_SETLK_NBMAND: /* * Are NBMAND locks allowed on this file? @@ -326,6 +339,20 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag, } break; + case F_OFD_SETLK: + case F_OFD_SETLKW: + case F_FLOCK: + case F_FLOCKW: + /* + * TBD we do not support remote OFD locks at this time. + */ + if (flag & (F_REMOTELOCK | F_PXFSLOCK)) { + error = EINVAL; + goto done; + } + skip_lock = B_TRUE; + break; + case F_HASREMOTELOCKS: nlmid = GETNLMID(bfp->l_sysid); if (nlmid != 0) { /* booted as a cluster */ @@ -354,7 +381,8 @@ fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag, flk_cbp = &serialize_callback; } - error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp); + if (!skip_lock) + error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp); done: if (serialize) diff --git a/usr/src/uts/common/os/fio.c b/usr/src/uts/common/os/fio.c index 98ca32332f..76eddd4e50 100644 --- a/usr/src/uts/common/os/fio.c +++ b/usr/src/uts/common/os/fio.c @@ -21,7 +21,7 @@ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, Joyent Inc. All rights reserved. + * Copyright 2015, Joyent Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -40,6 +40,7 @@ #include <sys/vnode.h> #include <sys/pathname.h> #include <sys/file.h> +#include <sys/flock.h> #include <sys/proc.h> #include <sys/var.h> #include <sys/cpuvar.h> @@ -952,6 +953,8 @@ closef(file_t *fp) return (error); } ASSERT(fp->f_count == 0); + /* Last reference, remove any OFD style lock for the file_t */ + ofdcleanlock(fp); mutex_exit(&fp->f_tlock); /* diff --git a/usr/src/uts/common/os/flock.c b/usr/src/uts/common/os/flock.c index 9671b7664d..884de65fe8 100644 --- a/usr/src/uts/common/os/flock.c +++ b/usr/src/uts/common/os/flock.c @@ -29,6 +29,7 @@ /* * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2015 Joyent, Inc. */ #include <sys/flock_impl.h> @@ -243,9 +244,293 @@ flk_get_lockmgr_status(void) } /* - * Routine called from fs_frlock in fs/fs_subr.c + * This implements Open File Description (not descriptor) style record locking. + * These locks can also be thought of as pid-less since they are not tied to a + * specific process, thus they're preserved across fork. + * + * Called directly from fcntl. + * + * See reclock() for the implementation of the traditional POSIX style record + * locking scheme (pid-ful). This function is derived from reclock() but + * simplified and modified to work for OFD style locking. + * + * The two primary advantages of OFD style of locking are: + * 1) It is per-file description, so closing a file descriptor that refers to a + * different file description for the same file will not drop the lock (i.e. + * two open's of the same file get different descriptions but a dup or fork + * will refer to the same description). + * 2) Locks are preserved across fork(2). + * + * Because these locks are per-description a lock ptr lives at the f_filocks + * member of the file_t and the lock_descriptor includes a file_t pointer + * to enable unique lock identification and management. + * + * Since these locks are pid-less we cannot do deadlock detection with the + * current process-oriented implementation. This is consistent with OFD locking + * behavior on other operating systems such as Linux. Since we don't do + * deadlock detection we never interact with the process graph that is + * maintained for deadlock detection on the traditional POSIX-style locks. + * + * Future Work: + * + * The current implementation does not support record locks. That is, + * currently the single lock must cover the entire file. This is validated in + * fcntl. To support record locks the f_filock pointer in the file_t needs to + * be changed to a list of pointers to the locks. That list needs to be + * managed independently of the lock list on the vnode itself and it needs to + * be maintained as record locks are created, split, coalesced and deleted. + * + * The current implementation does not support remote file systems (e.g. + * NFS or CIFS). This is handled in fs_frlock(). The design of how OFD locks + * interact with the NLM is not clear since the NLM protocol/implementation + * appears to be oriented around locks associated with a process. A further + * problem is that a design is needed for what nlm_send_siglost() should do and + * where it will send SIGLOST. More recent versions of Linux apparently try to + * emulate OFD locks on NFS by converting them to traditional POSIX style locks + * that work with the NLM. It is not clear that this provides the correct + * semantics in all cases. */ +int +ofdlock(file_t *fp, int fcmd, flock64_t *lckdat, int flag, u_offset_t offset) +{ + int cmd = 0; + vnode_t *vp; + lock_descriptor_t stack_lock_request; + lock_descriptor_t *lock_request; + int error = 0; + graph_t *gp; + int serialize = 0; + + if (fcmd != F_OFD_GETLK) + cmd = SETFLCK; + + if (fcmd == F_OFD_SETLKW || fcmd == F_FLOCKW) + cmd |= SLPFLCK; + + /* see block comment */ + VERIFY(lckdat->l_whence == 0); + VERIFY(lckdat->l_start == 0); + VERIFY(lckdat->l_len == 0); + + vp = fp->f_vnode; + + /* + * For reclock fs_frlock() would normally have set these in a few + * places but for us it's cleaner to centralize it here. Note that + * IGN_PID is -1. We use 0 for our pid-less locks. + */ + lckdat->l_pid = 0; + lckdat->l_sysid = 0; + + /* + * Check access permissions + */ + if ((fcmd == F_OFD_SETLK || fcmd == F_OFD_SETLKW) && + ((lckdat->l_type == F_RDLCK && (flag & FREAD) == 0) || + (lckdat->l_type == F_WRLCK && (flag & FWRITE) == 0))) + return (EBADF); + + /* + * for query and unlock we use the stack_lock_request + */ + if (lckdat->l_type == F_UNLCK || !(cmd & SETFLCK)) { + lock_request = &stack_lock_request; + (void) bzero((caddr_t)lock_request, + sizeof (lock_descriptor_t)); + + /* + * following is added to make the assertions in + * flk_execute_request() pass + */ + lock_request->l_edge.edge_in_next = &lock_request->l_edge; + lock_request->l_edge.edge_in_prev = &lock_request->l_edge; + lock_request->l_edge.edge_adj_next = &lock_request->l_edge; + lock_request->l_edge.edge_adj_prev = &lock_request->l_edge; + lock_request->l_status = FLK_INITIAL_STATE; + } else { + lock_request = flk_get_lock(); + fp->f_filock = (struct filock *)lock_request; + } + lock_request->l_state = 0; + lock_request->l_vnode = vp; + lock_request->l_zoneid = getzoneid(); + lock_request->l_ofd = fp; + + /* + * Convert the request range into the canonical start and end + * values then check the validity of the lock range. + */ + error = flk_convert_lock_data(vp, lckdat, &lock_request->l_start, + &lock_request->l_end, offset); + if (error) + goto done; + + error = flk_check_lock_data(lock_request->l_start, lock_request->l_end, + MAXEND); + if (error) + goto done; + + ASSERT(lock_request->l_end >= lock_request->l_start); + + lock_request->l_type = lckdat->l_type; + if (cmd & SLPFLCK) + lock_request->l_state |= WILLING_TO_SLEEP_LOCK; + + if (!(cmd & SETFLCK)) { + if (lock_request->l_type == F_RDLCK || + lock_request->l_type == F_WRLCK) + lock_request->l_state |= QUERY_LOCK; + } + lock_request->l_flock = (*lckdat); + + /* + * We are ready for processing the request + */ + + if (fcmd != F_OFD_GETLK && lock_request->l_type != F_UNLCK && + nbl_need_check(vp)) { + nbl_start_crit(vp, RW_WRITER); + serialize = 1; + } + /* Get the lock graph for a particular vnode */ + gp = flk_get_lock_graph(vp, FLK_INIT_GRAPH); + + mutex_enter(&gp->gp_mutex); + + lock_request->l_state |= REFERENCED_LOCK; + lock_request->l_graph = gp; + + switch (lock_request->l_type) { + case F_RDLCK: + case F_WRLCK: + if (IS_QUERY_LOCK(lock_request)) { + flk_get_first_blocking_lock(lock_request); + if (lock_request->l_ofd != NULL) + lock_request->l_flock.l_pid = -1; + (*lckdat) = lock_request->l_flock; + } else { + /* process the request now */ + error = flk_process_request(lock_request); + } + break; + + case F_UNLCK: + /* unlock request will not block so execute it immediately */ + error = flk_execute_request(lock_request); + break; + + default: + error = EINVAL; + break; + } + + if (lock_request == &stack_lock_request) { + flk_set_state(lock_request, FLK_DEAD_STATE); + } else { + lock_request->l_state &= ~REFERENCED_LOCK; + if ((error != 0) || IS_DELETED(lock_request)) { + flk_set_state(lock_request, FLK_DEAD_STATE); + flk_free_lock(lock_request); + } + } + + mutex_exit(&gp->gp_mutex); + if (serialize) + nbl_end_crit(vp); + + return (error); + +done: + flk_set_state(lock_request, FLK_DEAD_STATE); + if (lock_request != &stack_lock_request) + flk_free_lock(lock_request); + return (error); +} + +/* + * Remove any lock on the vnode belonging to the given file_t. + * Called from closef on last close, file_t is locked. + * + * This is modeled on the cleanlocks() function but only removes the single + * lock associated with fp. + */ +void +ofdcleanlock(file_t *fp) +{ + lock_descriptor_t *fplock, *lock, *nlock; + vnode_t *vp; + graph_t *gp; + + ASSERT(MUTEX_HELD(&fp->f_tlock)); + + if ((fplock = (lock_descriptor_t *)fp->f_filock) == NULL) + return; + + fp->f_filock = NULL; + vp = fp->f_vnode; + + gp = flk_get_lock_graph(vp, FLK_USE_GRAPH); + + if (gp == NULL) + return; + mutex_enter(&gp->gp_mutex); + + CHECK_SLEEPING_LOCKS(gp); + CHECK_ACTIVE_LOCKS(gp); + + SET_LOCK_TO_FIRST_SLEEP_VP(gp, lock, vp); + + if (lock) { + do { + nlock = lock->l_next; + if (fplock == lock) { + CANCEL_WAKEUP(lock); + break; + } + lock = nlock; + } while (lock->l_vnode == vp); + } + + SET_LOCK_TO_FIRST_ACTIVE_VP(gp, lock, vp); + + if (lock) { + do { + nlock = lock->l_next; + if (fplock == lock) { + flk_delete_active_lock(lock, 0); + flk_wakeup(lock, 1); + flk_free_lock(lock); + break; + } + lock = nlock; + } while (lock->l_vnode == vp); + } + + CHECK_SLEEPING_LOCKS(gp); + CHECK_ACTIVE_LOCKS(gp); + mutex_exit(&gp->gp_mutex); +} + +/* + * Routine called from fs_frlock in fs/fs_subr.c + * + * This implements traditional POSIX style record locking. The two primary + * drawbacks to this style of locking are: + * 1) It is per-process, so any close of a file descriptor that refers to the + * file will drop the lock (e.g. lock /etc/passwd, call a library function + * which opens /etc/passwd to read the file, when the library closes it's + * file descriptor the application loses its lock and does not know). + * 2) Locks are not preserved across fork(2). + * + * Because these locks are only assoiciated with a pid they are per-process. + * This is why any close will drop the lock and is also why once the process + * forks then the lock is no longer related to the new process. These locks can + * be considered as pid-ful. + * + * See ofdlock() for the implementation of a similar but improved locking + * scheme. + */ int reclock(vnode_t *vp, flock64_t *lckdat, @@ -424,6 +709,8 @@ reclock(vnode_t *vp, case F_WRLCK: if (IS_QUERY_LOCK(lock_request)) { flk_get_first_blocking_lock(lock_request); + if (lock_request->l_ofd != NULL) + lock_request->l_flock.l_pid = -1; (*lckdat) = lock_request->l_flock; break; } @@ -712,7 +999,13 @@ flk_get_lock(void) void flk_free_lock(lock_descriptor_t *lock) { + file_t *fp; + ASSERT(IS_DEAD(lock)); + + if ((fp = lock->l_ofd) != NULL) + fp->f_filock = NULL; + if (IS_REFERENCED(lock)) { lock->l_state |= DELETED_LOCK; return; @@ -1214,7 +1507,7 @@ flk_add_edge(lock_descriptor_t *from_lock, lock_descriptor_t *to_lock, from_lock->l_edge.edge_adj_next = edge; /* - * put in in list of to vertex + * put in list of to vertex */ to_lock->l_edge.edge_in_next->edge_in_prev = edge; @@ -2620,9 +2913,11 @@ flk_canceled(lock_descriptor_t *request) } /* - * Remove all the locks for the vnode belonging to the given pid and sysid. + * Remove all non-OFD locks for the vnode belonging to the given pid and sysid. + * That is, since OFD locks are pid-less we'll never match on the incoming + * pid. OFD locks are removed earlier in the close() path via closef() and + * ofdcleanlock(). */ - void cleanlocks(vnode_t *vp, pid_t pid, int sysid) { @@ -2789,6 +3084,14 @@ flk_check_deadlock(lock_descriptor_t *lock) edge_t *ep, *nep; proc_vertex_t *process_stack; + /* + * OFD style locks are not associated with any process so there is + * no proc graph for these. Thus we cannot, and do not, do deadlock + * detection. + */ + if (lock->l_ofd != NULL) + return (0); + STACK_INIT(process_stack); mutex_enter(&flock_lock); @@ -3081,6 +3384,16 @@ flk_update_proc_graph(edge_t *ep, int delete) proc_edge_t *pep, *prevpep; mutex_enter(&flock_lock); + + /* + * OFD style locks are not associated with any process so there is + * no proc graph for these. + */ + if (ep->from_vertex->l_ofd != NULL) { + mutex_exit(&flock_lock); + return; + } + toproc = flk_get_proc_vertex(ep->to_vertex); fromproc = flk_get_proc_vertex(ep->from_vertex); @@ -3910,6 +4223,7 @@ report_blocker(lock_descriptor_t *blocker, lock_descriptor_t *request) flrp->l_type = blocker->l_type; flrp->l_pid = blocker->l_flock.l_pid; flrp->l_sysid = blocker->l_flock.l_sysid; + request->l_ofd = blocker->l_ofd; if (IS_LOCKMGR(request)) { flrp->l_start = blocker->l_start; @@ -4225,6 +4539,10 @@ check_owner_locks(graph_t *gp, pid_t pid, int sysid, vnode_t *vp) { lock_descriptor_t *lock; + /* Ignore OFD style locks since they're not process-wide. */ + if (pid == 0) + return; + SET_LOCK_TO_FIRST_ACTIVE_VP(gp, lock, vp); if (lock) { diff --git a/usr/src/uts/common/sys/fcntl.h b/usr/src/uts/common/sys/fcntl.h index aa74cab8b5..5ddade90e4 100644 --- a/usr/src/uts/common/sys/fcntl.h +++ b/usr/src/uts/common/sys/fcntl.h @@ -37,6 +37,7 @@ */ /* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */ +/* Copyright 2015, Joyent, Inc. */ #ifndef _SYS_FCNTL_H #define _SYS_FCNTL_H @@ -145,6 +146,7 @@ extern "C" { * the large and small file environments; therefore, the #defined values must * as well. * The NBMAND forms are private and should not be used. + * The FLOCK forms are also private and should not be used. */ #if defined(_LP64) || _FILE_OFFSET_BITS == 32 @@ -155,6 +157,13 @@ extern "C" { #define F_FREESP 11 /* Free file space */ #define F_GETLK 14 /* Get file lock */ #define F_SETLK_NBMAND 42 /* private */ +#if !defined(_STRICT_SYMBOLS) +#define F_OFD_GETLK 47 /* Get file lock owned by file */ +#define F_OFD_SETLK 48 /* Set file lock owned by file */ +#define F_OFD_SETLKW 49 /* Set file lock owned by file and wait */ +#define F_FLOCK 53 /* private - set flock owned by file */ +#define F_FLOCKW 54 /* private - set flock owned by file and wait */ +#endif /* _STRICT_SYMBOLS */ #else /* ILP32 large file application compilation environment version */ #define F_SETLK 34 /* Set file lock */ @@ -163,6 +172,13 @@ extern "C" { #define F_FREESP 27 /* Free file space */ #define F_GETLK 33 /* Get file lock */ #define F_SETLK_NBMAND 44 /* private */ +#if !defined(_STRICT_SYMBOLS) +#define F_OFD_GETLK 50 /* Get file lock owned by file */ +#define F_OFD_SETLK 51 /* Set file lock owned by file */ +#define F_OFD_SETLKW 52 /* Set file lock owned by file and wait */ +#define F_FLOCK 55 /* private - set flock owned by file */ +#define F_FLOCKW 56 /* private - set flock owned by file and wait */ +#endif /* _STRICT_SYMBOLS */ #endif /* _LP64 || _FILE_OFFSET_BITS == 32 */ #if defined(_LARGEFILE64_SOURCE) @@ -180,6 +196,13 @@ extern "C" { #define F_FREESP64 27 /* Free file space */ #define F_GETLK64 33 /* Get file lock */ #define F_SETLK64_NBMAND 44 /* private */ +#if !defined(_STRICT_SYMBOLS) +#define F_OFD_GETLK64 50 /* Get file lock owned by file */ +#define F_OFD_SETLK64 51 /* Set file lock owned by file */ +#define F_OFD_SETLKW64 52 /* Set file lock owned by file and wait */ +#define F_FLOCK64 55 /* private - set flock owned by file */ +#define F_FLOCKW64 56 /* private - set flock owned by file and wait */ +#endif /* _STRICT_SYMBOLS */ #else #define F_SETLK64 6 /* Set file lock */ #define F_SETLKW64 7 /* Set file lock and wait */ @@ -187,6 +210,13 @@ extern "C" { #define F_FREESP64 11 /* Free file space */ #define F_GETLK64 14 /* Get file lock */ #define F_SETLK64_NBMAND 42 /* private */ +#if !defined(_STRICT_SYMBOLS) +#define F_OFD_GETLK64 47 /* Get file lock owned by file */ +#define F_OFD_SETLK64 48 /* Set file lock owned by file */ +#define F_OFD_SETLKW64 49 /* Set file lock owned by file and wait */ +#define F_FLOCK64 53 /* private - set flock owned by file */ +#define F_FLOCKW64 54 /* private - set flock owned by file and wait */ +#endif /* _STRICT_SYMBOLS */ #endif /* !_LP64 || _KERNEL */ #endif /* _LARGEFILE64_SOURCE */ diff --git a/usr/src/uts/common/sys/file.h b/usr/src/uts/common/sys/file.h index 1f736d3d01..7e297042af 100644 --- a/usr/src/uts/common/sys/file.h +++ b/usr/src/uts/common/sys/file.h @@ -27,6 +27,7 @@ /* All Rights Reserved */ /* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */ +/* Copyright 2015 Joyent, Inc. */ #ifndef _SYS_FILE_H #define _SYS_FILE_H @@ -54,7 +55,7 @@ extern "C" { */ /* * One file structure is allocated for each open/creat/pipe call. - * Main use is to hold the read/write pointer associated with + * Main use is to hold the read/write pointer (and OFD locks) associated with * each open file. */ typedef struct file { @@ -66,6 +67,7 @@ typedef struct file { struct cred *f_cred; /* credentials of user who opened it */ struct f_audit_data *f_audit_data; /* file audit data */ int f_count; /* reference count */ + struct filock *f_filock; /* ptr to single lock_descriptor_t */ } file_t; /* @@ -173,6 +175,19 @@ typedef struct fpollinfo { #define L_SET 0 /* for lseek */ #endif /* L_SET */ +/* + * For flock(3C). These really don't belong here but for historical reasons + * the interface defines them to be here. + */ +#define LOCK_SH 1 +#define LOCK_EX 2 +#define LOCK_NB 4 +#define LOCK_UN 8 + +#if !defined(_STRICT_SYMBOLS) +extern int flock(int, int); +#endif + #if defined(_KERNEL) /* diff --git a/usr/src/uts/common/sys/flock.h b/usr/src/uts/common/sys/flock.h index e0cc609960..3d4b3626b9 100644 --- a/usr/src/uts/common/sys/flock.h +++ b/usr/src/uts/common/sys/flock.h @@ -29,6 +29,7 @@ */ /* * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2015 Joyent, Inc. */ #ifndef _SYS_FLOCK_H @@ -41,6 +42,9 @@ #include <sys/callb.h> #include <sys/param.h> #include <sys/zone.h> +#if defined(_KERNEL) +#include <sys/file.h> +#endif #ifdef __cplusplus extern "C" { @@ -221,6 +225,10 @@ typedef struct locklist { #define FLK_QUERY_ACTIVE 0x1 #define FLK_QUERY_SLEEPING 0x2 +#if defined(_KERNEL) +int ofdlock(file_t *, int, struct flock64 *, int, u_offset_t); +void ofdcleanlock(file_t *); +#endif int reclock(struct vnode *, struct flock64 *, int, int, u_offset_t, flk_callback_t *); int chklock(struct vnode *, int, u_offset_t, ssize_t, int, diff --git a/usr/src/uts/common/sys/flock_impl.h b/usr/src/uts/common/sys/flock_impl.h index d088192025..b1be1d598a 100644 --- a/usr/src/uts/common/sys/flock_impl.h +++ b/usr/src/uts/common/sys/flock_impl.h @@ -22,13 +22,12 @@ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2015 Joyent, Inc. */ #ifndef _SYS_FLOCK_IMPL_H #define _SYS_FLOCK_IMPL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/fcntl.h> /* flock definition */ #include <sys/file.h> /* FREAD etc */ @@ -83,6 +82,7 @@ struct lock_descriptor { flk_nlm_status_t l_nlm_state; /* state of NLM server */ flk_callback_t *l_callbacks; /* callbacks, or NULL */ zoneid_t l_zoneid; /* zone of request */ + file_t *l_ofd; /* OFD-style reference */ }; typedef struct lock_descriptor lock_descriptor_t; @@ -204,7 +204,8 @@ graph_t *flk_get_lock_graph(vnode_t *, int); #define SAME_OWNER(lock1, lock2) \ (((lock1)->l_flock.l_pid == (lock2)->l_flock.l_pid) && \ - ((lock1)->l_flock.l_sysid == (lock2)->l_flock.l_sysid)) + ((lock1)->l_flock.l_sysid == (lock2)->l_flock.l_sysid) && \ + ((lock1)->l_ofd == (lock2)->l_ofd)) #define COLORED(vertex) ((vertex)->l_color == (vertex)->l_graph->mark) #define COLOR(vertex) ((vertex)->l_color = (vertex)->l_graph->mark) diff --git a/usr/src/uts/common/syscall/fcntl.c b/usr/src/uts/common/syscall/fcntl.c index 7421957235..371bc83c29 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 */ @@ -271,11 +272,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 +285,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 +352,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 +439,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 +643,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 +668,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 +703,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; /* |