• Peter Staubach's avatar
    [PATCH] stale POSIX lock handling · c293621b
    Peter Staubach authored
    I believe that there is a problem with the handling of POSIX locks, which
    the attached patch should address.
    
    The problem appears to be a race between fcntl(2) and close(2).  A
    multithreaded application could close a file descriptor at the same time as
    it is trying to acquire a lock using the same file descriptor.  I would
    suggest that that multithreaded application is not providing the proper
    synchronization for itself, but the OS should still behave correctly.
    
    SUS3 (Single UNIX Specification Version 3, read: POSIX) indicates that when
    a file descriptor is closed, that all POSIX locks on the file, owned by the
    process which closed the file descriptor, should be released.
    
    The trick here is when those locks are released.  The current code releases
    all locks which exist when close is processing, but any locks in progress
    are handled when the last reference to the open file is released.
    
    There are three cases to consider.
    
    One is the simple case, a multithreaded (mt) process has a file open and
    races to close it and acquire a lock on it.  In this case, the close will
    release one reference to the open file and when the fcntl is done, it will
    release the other reference.  For this situation, no locks should exist on
    the file when both the close and fcntl operations are done.  The current
    system will handle this case because the last reference to the open file is
    being released.
    
    The second case is when the mt process has dup(2)'d the file descriptor.
    The close will release one reference to the file and the fcntl, when done,
    will release another, but there will still be at least one more reference
    to the open file.  One could argue that the existence of a lock on the file
    after the close has completed is okay, because it was acquired after the
    close operation and there is still a way for the application to release the
    lock on the file, using an existing file descriptor.
    
    The third case is when the mt process has forked, after opening the file
    and either before or after becoming an mt process.  In this case, each
    process would hold a reference to the open file.  For each process, this
    degenerates to first case above.  However, the lock continues to exist
    until both processes have released their references to the open file.  This
    lock could block other lock requests.
    
    The changes to release the lock when the last reference to the open file
    aren't quite right because they would allow the lock to exist as long as
    there was a reference to the open file.  This is too long.
    
    The new proposed solution is to add support in the fcntl code path to
    detect a race with close and then to release the lock which was just
    acquired when such as race is detected.  This causes locks to be released
    in a timely fashion and for the system to conform to the POSIX semantic
    specification.
    
    This was tested by instrumenting a kernel to detect the handling locks and
    then running a program which generates case #3 above.  A dangling lock
    could be reliably generated.  When the changes to detect the close/fcntl
    race were added, a dangling lock could no longer be generated.
    
    Cc: Matthew Wilcox <willy@debian.org>
    Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
    Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
    c293621b
locks.c 54.9 KB