|
|
|
|
@@ -2,117 +2,11 @@
|
|
|
|
|
/*
|
|
|
|
|
* linux/fs/locks.c
|
|
|
|
|
*
|
|
|
|
|
* Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls.
|
|
|
|
|
* Doug Evans (dje@spiff.uucp), August 07, 1992
|
|
|
|
|
* We implement four types of file locks: BSD locks, posix locks, open
|
|
|
|
|
* file description locks, and leases. For details about BSD locks,
|
|
|
|
|
* see the flock(2) man page; for details about the other three, see
|
|
|
|
|
* fcntl(2).
|
|
|
|
|
*
|
|
|
|
|
* Deadlock detection added.
|
|
|
|
|
* FIXME: one thing isn't handled yet:
|
|
|
|
|
* - mandatory locks (requires lots of changes elsewhere)
|
|
|
|
|
* Kelly Carmichael (kelly@[142.24.8.65]), September 17, 1994.
|
|
|
|
|
*
|
|
|
|
|
* Miscellaneous edits, and a total rewrite of posix_lock_file() code.
|
|
|
|
|
* Kai Petzke (wpp@marie.physik.tu-berlin.de), 1994
|
|
|
|
|
*
|
|
|
|
|
* Converted file_lock_table to a linked list from an array, which eliminates
|
|
|
|
|
* the limits on how many active file locks are open.
|
|
|
|
|
* Chad Page (pageone@netcom.com), November 27, 1994
|
|
|
|
|
*
|
|
|
|
|
* Removed dependency on file descriptors. dup()'ed file descriptors now
|
|
|
|
|
* get the same locks as the original file descriptors, and a close() on
|
|
|
|
|
* any file descriptor removes ALL the locks on the file for the current
|
|
|
|
|
* process. Since locks still depend on the process id, locks are inherited
|
|
|
|
|
* after an exec() but not after a fork(). This agrees with POSIX, and both
|
|
|
|
|
* BSD and SVR4 practice.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), February 14, 1995
|
|
|
|
|
*
|
|
|
|
|
* Scrapped free list which is redundant now that we allocate locks
|
|
|
|
|
* dynamically with kmalloc()/kfree().
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), February 21, 1995
|
|
|
|
|
*
|
|
|
|
|
* Implemented two lock personalities - FL_FLOCK and FL_POSIX.
|
|
|
|
|
*
|
|
|
|
|
* FL_POSIX locks are created with calls to fcntl() and lockf() through the
|
|
|
|
|
* fcntl() system call. They have the semantics described above.
|
|
|
|
|
*
|
|
|
|
|
* FL_FLOCK locks are created with calls to flock(), through the flock()
|
|
|
|
|
* system call, which is new. Old C libraries implement flock() via fcntl()
|
|
|
|
|
* and will continue to use the old, broken implementation.
|
|
|
|
|
*
|
|
|
|
|
* FL_FLOCK locks follow the 4.4 BSD flock() semantics. They are associated
|
|
|
|
|
* with a file pointer (filp). As a result they can be shared by a parent
|
|
|
|
|
* process and its children after a fork(). They are removed when the last
|
|
|
|
|
* file descriptor referring to the file pointer is closed (unless explicitly
|
|
|
|
|
* unlocked).
|
|
|
|
|
*
|
|
|
|
|
* FL_FLOCK locks never deadlock, an existing lock is always removed before
|
|
|
|
|
* upgrading from shared to exclusive (or vice versa). When this happens
|
|
|
|
|
* any processes blocked by the current lock are woken up and allowed to
|
|
|
|
|
* run before the new lock is applied.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), June 09, 1995
|
|
|
|
|
*
|
|
|
|
|
* Removed some race conditions in flock_lock_file(), marked other possible
|
|
|
|
|
* races. Just grep for FIXME to see them.
|
|
|
|
|
* Dmitry Gorodchanin (pgmdsg@ibi.com), February 09, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Addressed Dmitry's concerns. Deadlock checking no longer recursive.
|
|
|
|
|
* Lock allocation changed to GFP_ATOMIC as we can't afford to sleep
|
|
|
|
|
* once we've checked for blocking and deadlocking.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), April 03, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Initial implementation of mandatory locks. SunOS turned out to be
|
|
|
|
|
* a rotten model, so I implemented the "obvious" semantics.
|
|
|
|
|
* See 'Documentation/filesystems/mandatory-locking.rst' for details.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), April 06, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Don't allow mandatory locks on mmap()'ed files. Added simple functions to
|
|
|
|
|
* check if a file has mandatory locks, used by mmap(), open() and creat() to
|
|
|
|
|
* see if system call should be rejected. Ref. HP-UX/SunOS/Solaris Reference
|
|
|
|
|
* Manual, Section 2.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), April 09, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Tidied up block list handling. Added '/proc/locks' interface.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), April 24, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Fixed deadlock condition for pathological code that mixes calls to
|
|
|
|
|
* flock() and fcntl().
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Allow only one type of locking scheme (FL_POSIX or FL_FLOCK) to be in use
|
|
|
|
|
* for a given file at a time. Changed the CONFIG_LOCK_MANDATORY scheme to
|
|
|
|
|
* guarantee sensible behaviour in the case where file system modules might
|
|
|
|
|
* be compiled with different options than the kernel itself.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Added a couple of missing wake_up() calls. Thanks to Thomas Meckel
|
|
|
|
|
* (Thomas.Meckel@mni.fh-giessen.de) for spotting this.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Changed FL_POSIX locks to use the block list in the same way as FL_FLOCK
|
|
|
|
|
* locks. Changed process synchronisation to avoid dereferencing locks that
|
|
|
|
|
* have already been freed.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), Sep 21, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Made the block list a circular list to minimise searching in the list.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), Sep 25, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Made mandatory locking a mount option. Default is not to allow mandatory
|
|
|
|
|
* locking.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), Oct 04, 1996.
|
|
|
|
|
*
|
|
|
|
|
* Some adaptations for NFS support.
|
|
|
|
|
* Olaf Kirch (okir@monad.swb.de), Dec 1996,
|
|
|
|
|
*
|
|
|
|
|
* Fixed /proc/locks interface so that we can't overrun the buffer we are handed.
|
|
|
|
|
* Andy Walker (andy@lysaker.kvaerner.no), May 12, 1997.
|
|
|
|
|
*
|
|
|
|
|
* Use slab allocator instead of kmalloc/kfree.
|
|
|
|
|
* Use generic list implementation from <linux/list.h>.
|
|
|
|
|
* Sped up posix_locks_deadlock by only considering blocked locks.
|
|
|
|
|
* Matthew Wilcox <willy@debian.org>, March, 2000.
|
|
|
|
|
*
|
|
|
|
|
* Leases and LOCK_MAND
|
|
|
|
|
* Matthew Wilcox <willy@debian.org>, June, 2000.
|
|
|
|
|
* Stephen Rothwell <sfr@canb.auug.org.au>, June, 2000.
|
|
|
|
|
*
|
|
|
|
|
* Locking conflicts and dependencies:
|
|
|
|
|
* If multiple threads attempt to lock the same byte (or flock the same file)
|
|
|
|
|
@@ -461,8 +355,6 @@ static void locks_move_blocks(struct file_lock *new, struct file_lock *fl)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int flock_translate_cmd(int cmd) {
|
|
|
|
|
if (cmd & LOCK_MAND)
|
|
|
|
|
return cmd & (LOCK_MAND | LOCK_RW);
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case LOCK_SH:
|
|
|
|
|
return F_RDLCK;
|
|
|
|
|
@@ -942,8 +834,6 @@ static bool flock_locks_conflict(struct file_lock *caller_fl,
|
|
|
|
|
*/
|
|
|
|
|
if (caller_fl->fl_file == sys_fl->fl_file)
|
|
|
|
|
return false;
|
|
|
|
|
if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return locks_conflict(caller_fl, sys_fl);
|
|
|
|
|
}
|
|
|
|
|
@@ -2116,11 +2006,9 @@ EXPORT_SYMBOL(locks_lock_inode_wait);
|
|
|
|
|
* - %LOCK_SH -- a shared lock.
|
|
|
|
|
* - %LOCK_EX -- an exclusive lock.
|
|
|
|
|
* - %LOCK_UN -- remove an existing lock.
|
|
|
|
|
* - %LOCK_MAND -- a 'mandatory' flock.
|
|
|
|
|
* This exists to emulate Windows Share Modes.
|
|
|
|
|
* - %LOCK_MAND -- a 'mandatory' flock. (DEPRECATED)
|
|
|
|
|
*
|
|
|
|
|
* %LOCK_MAND can be combined with %LOCK_READ or %LOCK_WRITE to allow other
|
|
|
|
|
* processes read and write access respectively.
|
|
|
|
|
* %LOCK_MAND support has been removed from the kernel.
|
|
|
|
|
*/
|
|
|
|
|
SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
|
|
|
|
|
{
|
|
|
|
|
@@ -2137,10 +2025,23 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
|
|
|
|
|
cmd &= ~LOCK_NB;
|
|
|
|
|
unlock = (cmd == LOCK_UN);
|
|
|
|
|
|
|
|
|
|
if (!unlock && !(cmd & LOCK_MAND) &&
|
|
|
|
|
!(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
|
|
|
|
|
if (!unlock && !(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
|
|
|
|
|
goto out_putf;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* LOCK_MAND locks were broken for a long time in that they never
|
|
|
|
|
* conflicted with one another and didn't prevent any sort of open,
|
|
|
|
|
* read or write activity.
|
|
|
|
|
*
|
|
|
|
|
* Just ignore these requests now, to preserve legacy behavior, but
|
|
|
|
|
* throw a warning to let people know that they don't actually work.
|
|
|
|
|
*/
|
|
|
|
|
if (cmd & LOCK_MAND) {
|
|
|
|
|
pr_warn_once("Attempt to set a LOCK_MAND lock via flock(2). This support has been removed and the request ignored.\n");
|
|
|
|
|
error = 0;
|
|
|
|
|
goto out_putf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lock = flock_make_lock(f.file, cmd, NULL);
|
|
|
|
|
if (IS_ERR(lock)) {
|
|
|
|
|
error = PTR_ERR(lock);
|
|
|
|
|
@@ -2718,6 +2619,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
|
|
|
|
|
struct inode *inode = NULL;
|
|
|
|
|
unsigned int fl_pid;
|
|
|
|
|
struct pid_namespace *proc_pidns = proc_pid_ns(file_inode(f->file)->i_sb);
|
|
|
|
|
int type;
|
|
|
|
|
|
|
|
|
|
fl_pid = locks_translate_pid(fl, proc_pidns);
|
|
|
|
|
/*
|
|
|
|
|
@@ -2745,11 +2647,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
|
|
|
|
|
seq_printf(f, " %s ",
|
|
|
|
|
(inode == NULL) ? "*NOINODE*" : "ADVISORY ");
|
|
|
|
|
} else if (IS_FLOCK(fl)) {
|
|
|
|
|
if (fl->fl_type & LOCK_MAND) {
|
|
|
|
|
seq_puts(f, "FLOCK MSNFS ");
|
|
|
|
|
} else {
|
|
|
|
|
seq_puts(f, "FLOCK ADVISORY ");
|
|
|
|
|
}
|
|
|
|
|
seq_puts(f, "FLOCK ADVISORY ");
|
|
|
|
|
} else if (IS_LEASE(fl)) {
|
|
|
|
|
if (fl->fl_flags & FL_DELEG)
|
|
|
|
|
seq_puts(f, "DELEG ");
|
|
|
|
|
@@ -2765,17 +2663,10 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
|
|
|
|
|
} else {
|
|
|
|
|
seq_puts(f, "UNKNOWN UNKNOWN ");
|
|
|
|
|
}
|
|
|
|
|
if (fl->fl_type & LOCK_MAND) {
|
|
|
|
|
seq_printf(f, "%s ",
|
|
|
|
|
(fl->fl_type & LOCK_READ)
|
|
|
|
|
? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ "
|
|
|
|
|
: (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
|
|
|
|
|
} else {
|
|
|
|
|
int type = IS_LEASE(fl) ? target_leasetype(fl) : fl->fl_type;
|
|
|
|
|
type = IS_LEASE(fl) ? target_leasetype(fl) : fl->fl_type;
|
|
|
|
|
|
|
|
|
|
seq_printf(f, "%s ", (type == F_WRLCK) ? "WRITE" :
|
|
|
|
|
(type == F_RDLCK) ? "READ" : "UNLCK");
|
|
|
|
|
}
|
|
|
|
|
seq_printf(f, "%s ", (type == F_WRLCK) ? "WRITE" :
|
|
|
|
|
(type == F_RDLCK) ? "READ" : "UNLCK");
|
|
|
|
|
if (inode) {
|
|
|
|
|
/* userspace relies on this representation of dev_t */
|
|
|
|
|
seq_printf(f, "%d %02x:%02x:%lu ", fl_pid,
|
|
|
|
|
|