From patchwork Thu Apr 24 14:09:49 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 667 Return-Path: X-Original-To: siddhesh@wilcox.dreamhost.com Delivered-To: siddhesh@wilcox.dreamhost.com Received: from homiemail-mx22.g.dreamhost.com (mx2.sub5.homie.mail.dreamhost.com [208.113.200.128]) by wilcox.dreamhost.com (Postfix) with ESMTP id 35373361149 for ; Thu, 24 Apr 2014 07:10:20 -0700 (PDT) Received: by homiemail-mx22.g.dreamhost.com (Postfix, from userid 14307373) id 886FE4C00A12; Thu, 24 Apr 2014 07:10:19 -0700 (PDT) X-Original-To: glibc@patchwork.siddhesh.in Delivered-To: x14307373@homiemail-mx22.g.dreamhost.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by homiemail-mx22.g.dreamhost.com (Postfix) with ESMTPS id 04E2D4C41A93 for ; Thu, 24 Apr 2014 07:10:18 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id; q=dns; s= default; b=kxZGcQjbQ5h11WkQgxj4CsVCZZTspujMaZ1bJ5odx/OEIiJhK8E4L bPt6Jq/IAH9subOLDQJxchm/xcwmUDXSZNS6tiJipE4C85lrm7010HHQRvquE6h8 zzV3a+toiEMbSBa5AOIKrTuzqdVRGwonv26xC/+PkHs5Gw7Ok+GhVA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id; s=default; bh=TYxbhrAaJVOLV3EG1loy6HIgrP0=; b=HqAgTpPJyK2c9SUDak12d7E7vSlb RtUEyDSq9gRdzD5VniatRKOp2GLwXaCr9rJYPjlzmDbPyDWU9Ud6MjAPOhRyx2cG NlyNY1PMm1OSWA998dbUuJFPoXh1I/oFtI2Ga5g0F0erhxWMzr72f7qz46tutSQx zkjKGwdyNHN62oE= Received: (qmail 6563 invoked by alias); 24 Apr 2014 14:10:16 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 6553 invoked by uid 89); 24 Apr 2014 14:10:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 X-HELO: mail-qc0-f178.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id; bh=eiC7QN0yUA8ba+M41XUuO6X0X9Mz+R6RbIvQVDeWfvc=; b=U+YDM9ZLij+4HvMms3TPFF5ieRqAUzRRASH+UgeEO+d4uZdTTnjZAyQwbCPbi7n5X+ bNyrD9l5AA19dtK+mfV3qFttjV4OyG60jE4+Fg+srjjd23gBe4qk1bDQPBZEN0E7BkKL RJOMtGxoRCbfVdW/ryy+nOUlwmKMrH2oSASW4ZF0cOx+xSNTJ4cJuj0OoOKt2xpgdPSV SZwfXwXw1lFYIUXAbs+7DXwECMlO/JksWmRKdO8p93A2vQjxmjs1Ow+PrsZtWI++STgd RqASxkACoTe/IfSyHxRJ/d1iK/sRkyD1RvhYJXZxGAfkmfn9oBmeGAktS5g1GEeeIi99 mOOQ== X-Gm-Message-State: ALoCoQnyCzp6oUEasGuh3jAzIkbCNhkKFUVkQmP/kpryzKKJjxPBm3u1wuI5b6etriic6bRqZxZ7 X-Received: by 10.224.22.195 with SMTP id o3mr2893764qab.51.1398348610940; Thu, 24 Apr 2014 07:10:10 -0700 (PDT) From: Jeff Layton To: libc-alpha@sourceware.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Theodore Ts'o , Rich Felker , "Michael Kerrisk (man-pages)" , samba-technical@lists.samba.org, Ganesha NFS List , Carlos O'Donell , "Stefan (metze) Metzmacher" , Christoph Hellwig , Boaz Harrosh , "Alfred M. Szmidt" Subject: [glibc PATCHi v4] fcntl-linux.h: add new definitions and manual updates for open file description locks Date: Thu, 24 Apr 2014 10:09:49 -0400 Message-Id: <1398348589-16096-1-git-send-email-jlayton@redhat.com> X-DH-Original-To: glibc@patchwork.siddhesh.in Open file description locks have been merged into the Linux kernel for v3.15. Add the appropriate command-value definitions and an update to the manual that describes their usage. ChangeLog: 2014-04-24 Jeff Layton [BZ#16839] * manual/llio.texi: add section about open file description locks * sysdeps/unix/sysv/linux/bits/fcntl-linux.h: (F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKW): New macros. --- manual/examples/ofdlocks.c | 77 +++++++++ manual/llio.texi | 241 ++++++++++++++++++++++++++++- sysdeps/unix/sysv/linux/bits/fcntl-linux.h | 17 ++ 3 files changed, 332 insertions(+), 3 deletions(-) create mode 100644 manual/examples/ofdlocks.c diff --git a/manual/examples/ofdlocks.c b/manual/examples/ofdlocks.c new file mode 100644 index 000000000000..85e193cdabe6 --- /dev/null +++ b/manual/examples/ofdlocks.c @@ -0,0 +1,77 @@ +/* Open File Description Locks Usage Example + Copyright (C) 1991-2014 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#define FILENAME "/tmp/foo" +#define NUM_THREADS 3 +#define ITERATIONS 5 + +void * +thread_start (void *arg) +{ + int i, fd, len; + long tid = (long) arg; + char buf[256]; + struct flock lck = { + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 1, + }; + + fd = open ("/tmp/foo", O_RDWR | O_CREAT, 0666); + + for (i = 0; i < ITERATIONS; i++) + { + lck.l_type = F_WRLCK; + fcntl (fd, F_OFD_SETLKW, &lck); + + len = sprintf (buf, "%d: tid=%ld fd=%d\n", i, tid, fd); + + lseek (fd, 0, SEEK_END); + write (fd, buf, len); + fsync (fd); + + lck.l_type = F_UNLCK; + fcntl (fd, F_OFD_SETLK, &lck); + + /* sleep to ensure lock is yielded to another thread */ + usleep (1); + } + pthread_exit (NULL); +} + +int +main (int argc, char **argv) +{ + long i; + pthread_t threads[NUM_THREADS]; + + truncate (FILENAME, 0); + + for (i = 0; i < NUM_THREADS; i++) + pthread_create (&threads[i], NULL, thread_start, (void *) i); + + pthread_exit (NULL); + return 0; +} diff --git a/manual/llio.texi b/manual/llio.texi index 6f8adfc607d7..864060dc7140 100644 --- a/manual/llio.texi +++ b/manual/llio.texi @@ -57,6 +57,10 @@ directly.) flags associated with open files. * File Locks:: Fcntl commands for implementing file locking. +* Open File Description Locks:: Fcntl commands for implementing + open file description locking. +* Open File Description Locks Example:: An example of open file description lock + usage * Interrupt Input:: Getting an asynchronous signal when input arrives. * IOCTLs:: Generic I/O Control operations. @@ -2890,7 +2894,7 @@ Get flags associated with the open file. @xref{File Status Flags}. Set flags associated with the open file. @xref{File Status Flags}. @item F_GETLK -Get a file lock. @xref{File Locks}. +Test a file lock. @xref{File Locks}. @item F_SETLK Set or clear a file lock. @xref{File Locks}. @@ -2898,6 +2902,18 @@ Set or clear a file lock. @xref{File Locks}. @item F_SETLKW Like @code{F_SETLK}, but wait for completion. @xref{File Locks}. +@item F_OFD_GETLK +Test an open file description lock. @xref{Open File Description Locks}. +Specific to Linux. + +@item F_OFD_SETLK +Set or clear an open file description lock. @xref{Open File Description Locks}. +Specific to Linux. + +@item F_OFD_SETLKW +Like @code{F_OFD_SETLK}, but block until lock is acquired. +@xref{Open File Description Locks}. Specific to Linux. + @item F_GETOWN Get process or process group ID to receive @code{SIGIO} signals. @xref{Interrupt Input}. @@ -3576,6 +3592,10 @@ set_nonblock_flag (int desc, int value) @cindex file locks @cindex record locking +This section describes record locks that are associated with the process. +There is also a different type of record lock that is associated with the +open file description instead of the process. @xref{Open File Description Locks}. + The remaining @code{fcntl} commands are used to support @dfn{record locking}, which permits multiple cooperating programs to prevent each other from simultaneously accessing parts of a file in error-prone @@ -3641,7 +3661,10 @@ the file. @item pid_t l_pid This field is the process ID (@pxref{Process Creation Concepts}) of the process holding the lock. It is filled in by calling @code{fcntl} with -the @code{F_GETLK} command, but is ignored when making a lock. +the @code{F_GETLK} command, but is ignored when making a lock. If the +conflicting lock is an open file description lock +(@pxref{Open File Description Locks}), then this field will be set to +@math{-1}. @end table @end deftp @@ -3813,10 +3836,222 @@ that part of the file for writing. @c ??? This section could use an example program. -Remember that file locks are only a @emph{voluntary} protocol for +Remember that file locks are only an @emph{advisory} protocol for controlling access to a file. There is still potential for access to the file by programs that don't use the lock protocol. +@node Open File Description Locks +@section Open File Description Locks + +In contrast to process-associated record locks (@pxref{File Locks}), +open file description record locks are associated with an open file +description rather than a process. + +Using @code{fcntl} to apply an open file description lock on a region that +already has an existing open file description lock that was created via the +same file descriptor will never cause a lock conflict. + +Open file description locks are also inherited by child processes across +@code{fork}, or @code{clone} with @code{CLONE_FILES} set +(@pxref{Creating a Process}), along with the file descriptor. + +It is important to distinguish between the open file @emph{description} (an +instance of an open file, usually created by a call to @code{open}) and +an open file @emph{descriptor}, which is a numeric value that refers to the +open file description. The locks described here are associated with the +open file @emph{description} and not the open file @emph{descriptor}. + +Using @code{dup} (@pxref{Duplicating Descriptors}) to copy a file +descriptor does not give you a new open file description, but rather copies a +reference to an existing open file description and assigns it to a new +file descriptor. Thus, open file description locks set on a file +descriptor cloned by @code{dup} will never conflict with open file +description locks set on the original descriptor since they refer to the +same open file description. Depending on the range and type of lock +involved, the original lock may be modified by a @code{F_OFD_SETLK} or +@code{F_OFD_SETLKW} command in this situation however. + +Open file description locks always conflict with process-associated locks, +even if acquired by the same process or on the same open file +descriptor. + +Open file description locks use the same @code{struct flock} as +process-associated locks as an argument (@pxref{File Locks}) and the +macros for the @code{command} values are also declared in the header file +@file{fcntl.h}. To use them, the macro @code{_GNU_SOURCE} must be +defined prior to including any header file. + +In contrast to process-associated locks, any @code{struct flock} used as +an argument to open file description lock commands must have the @code{l_pid} +value set to @math{0}. Also, when returning information about an +open file description lock in a @code{F_GETLK} or @code{F_OFD_GETLK} request, +the @code{l_pid} field in @code{struct flock} will be set to @math{-1} +to indicate that the lock is not associated with a process. + +When the same @code{struct flock} is reused as an argument to a +@code{F_OFD_SETLK} or @code{F_OFD_SETLKW} request after being used for an +@code{F_OFD_GETLK} request, it is necessary to inspect and reset the +@code{l_pid} field to @math{0}. + +@pindex fcntl.h. + +@deftypevr Macro int F_OFD_GETLK +This macro is used as the @var{command} argument to @code{fcntl}, to +specify that it should get information about a lock. This command +requires a third argument of type @w{@code{struct flock *}} to be passed +to @code{fcntl}, so that the form of the call is: + +@smallexample +fcntl (@var{filedes}, F_OFD_GETLK, @var{lockp}) +@end smallexample + +If there is a lock already in place that would block the lock described +by the @var{lockp} argument, information about that lock is written to +@code{*@var{lockp}}. Existing locks are not reported if they are +compatible with making a new lock as specified. Thus, you should +specify a lock type of @code{F_WRLCK} if you want to find out about both +read and write locks, or @code{F_RDLCK} if you want to find out about +write locks only. + +There might be more than one lock affecting the region specified by the +@var{lockp} argument, but @code{fcntl} only returns information about +one of them. Which lock is returned in this situation is undefined. + +The @code{l_whence} member of the @var{lockp} structure are set to +@code{SEEK_SET} and the @code{l_start} and @code{l_len} fields are set +to identify the locked region. + +If no conflicting lock exists, the only change to the @var{lockp} structure +is to update the @code{l_type} field to the value @code{F_UNLCK}. + +The normal return value from @code{fcntl} with this command is either @math{0} +on success or @math{-1}, which indicates an error. The following @code{errno} +error conditions are defined for this command: + +@table @code +@item EBADF +The @var{filedes} argument is invalid. + +@item EINVAL +Either the @var{lockp} argument doesn't specify valid lock information, +the operating system kernel doesn't support open file description locks, or the file +associated with @var{filedes} doesn't support locks. +@end table +@end deftypevr + +@comment fcntl.h +@comment POSIX.1 +@deftypevr Macro int F_OFD_SETLK +This macro is used as the @var{command} argument to @code{fcntl}, to +specify that it should set or clear a lock. This command requires a +third argument of type @w{@code{struct flock *}} to be passed to +@code{fcntl}, so that the form of the call is: + +@smallexample +fcntl (@var{filedes}, F_OFD_SETLK, @var{lockp}) +@end smallexample + +If the open file already has a lock on any part of the +region, the old lock on that part is replaced with the new lock. You +can remove a lock by specifying a lock type of @code{F_UNLCK}. + +If the lock cannot be set, @code{fcntl} returns immediately with a value +of @math{-1}. This command does not wait for other tasks +to release locks. If @code{fcntl} succeeds, it returns @math{0}. + +The following @code{errno} error conditions are defined for this +command: + +@table @code +@item EAGAIN +The lock cannot be set because it is blocked by an existing lock on the +file. + +@item EBADF +Either: the @var{filedes} argument is invalid; you requested a read lock +but the @var{filedes} is not open for read access; or, you requested a +write lock but the @var{filedes} is not open for write access. + +@item EINVAL +Either the @var{lockp} argument doesn't specify valid lock information, +the operating system kernel doesn't support open file description locks, or the +file associated with @var{filedes} doesn't support locks. + +@item ENOLCK +The system has run out of file lock resources; there are already too +many file locks in place. + +Well-designed file systems never report this error, because they have no +limitation on the number of locks. However, you must still take account +of the possibility of this error, as it could result from network access +to a file system on another machine. +@end table +@end deftypevr + +@comment fcntl.h +@comment POSIX.1 +@deftypevr Macro int F_OFD_SETLKW +This macro is used as the @var{command} argument to @code{fcntl}, to +specify that it should set or clear a lock. It is just like the +@code{F_OFD_SETLK} command, but causes the process to wait until the request +can be completed. + +This command requires a third argument of type @code{struct flock *}, as +for the @code{F_OFD_SETLK} command. + +The @code{fcntl} return values and errors are the same as for the +@code{F_OFD_SETLK} command, but these additional @code{errno} error conditions +are defined for this command: + +@table @code +@item EINTR +The function was interrupted by a signal while it was waiting. +@xref{Interrupted Primitives}. + +@end table +@end deftypevr + +Open file description locks are useful in the same sorts of situations as +process-associated locks. They can also be used to synchronize file +access between threads within the same process by having each thread perform +its own @code{open} of the file, to obtain its own open file description. + +Because open file description locks are automatically freed only upon +closing the last file descriptor that refers to the open file +description, this locking mechanism avoids the possibility that locks +are inadvertently released due to a library routine opening and closing +a file without the application being aware. + +As with process-associated locks, open file description locks are advisory. + +@node Open File Description Locks Example +@section Open File Description Locks Example + +Here is an example of using open file description locks in a threaded +program. If this program used process-associated locks, then it would be +subject to data corruption because process-associated locks are shared +by the threads inside a process, and thus cannot be used by one thread +to lock out another thread in the same process. + +Proper error handling has been omitted in the following program for +brevity. + +@smallexample +@include ofdlocks.c.texi +@end smallexample + +This example creates three threads each of which loops five times, +appending to the file. Access to the file is serialized via open file +description locks. If we compile and run the above program, we'll end up +with /tmp/foo that has 15 lines in it. + +If we, however, were to replace the @code{F_OFD_SETLK} and +@code{F_OFD_SETLKW} commands with their process-associated lock +equivalents, the locking essentially becomes a noop since it is all done +within the context of the same process. That leads to data corruption +(typically manifested as missing lines) as some threads race in and +overwrite the data written by others. + @node Interrupt Input @section Interrupt-Driven Input diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h index 915eb3ede560..455389cd2c2a 100644 --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h @@ -117,6 +117,23 @@ # define F_SETLKW64 14 /* Set record locking info (blocking). */ #endif +/* open file description locks. + + Usually record locks held by a process are released on *any* close and are + not inherited across a fork. + + These cmd values will set locks that conflict with process-associated record + locks, but are "owned" by the opened file description, not the process. + This means that they are inherited across fork or clone with CLONE_FILES + like BSD (flock) locks, and they are only released automatically when the + last reference to the the file description against which they were acquired + is put. */ +#if __USE_GNU +# define F_OFD_GETLK 36 +# define F_OFD_SETLK 37 +# define F_OFD_SETLKW 38 +#endif + #ifdef __USE_LARGEFILE64 # define O_LARGEFILE __O_LARGEFILE #endif