Commit f7789dc0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'locks-3.15' of git://git.samba.org/jlayton/linux

Pull file locking updates from Jeff Layton:
 "Highlights:

   - maintainership change for fs/locks.c.  Willy's not interested in
     maintaining it these days, and is OK with Bruce and I taking it.
   - fix for open vs setlease race that Al ID'ed
   - cleanup and consolidation of file locking code
   - eliminate unneeded BUG() call
   - merge of file-private lock implementation"

* 'locks-3.15' of git://git.samba.org/jlayton/linux:
  locks: make locks_mandatory_area check for file-private locks
  locks: fix locks_mandatory_locked to respect file-private locks
  locks: require that flock->l_pid be set to 0 for file-private locks
  locks: add new fcntl cmd values for handling file private locks
  locks: skip deadlock detection on FL_FILE_PVT locks
  locks: pass the cmd value to fcntl_getlk/getlk64
  locks: report l_pid as -1 for FL_FILE_PVT locks
  locks: make /proc/locks show IS_FILE_PVT locks as type "FLPVT"
  locks: rename locks_remove_flock to locks_remove_file
  locks: consolidate checks for compatible filp->f_mode values in setlk handlers
  locks: fix posix lock range overflow handling
  locks: eliminate BUG() call when there's an unexpected lock on file close
  locks: add __acquires and __releases annotations to locks_start and locks_stop
  locks: remove "inline" qualifier from fl_link manipulation functions
  locks: clean up comment typo
  locks: close potential race between setlease and open
  MAINTAINERS: update entry for fs/locks.c
parents 7df93452 29723ade
...@@ -3521,7 +3521,8 @@ F: include/scsi/libfcoe.h ...@@ -3521,7 +3521,8 @@ F: include/scsi/libfcoe.h
F: include/uapi/scsi/fc/ F: include/uapi/scsi/fc/
FILE LOCKING (flock() and fcntl()/lockf()) FILE LOCKING (flock() and fcntl()/lockf())
M: Matthew Wilcox <matthew@wil.cx> M: Jeff Layton <jlayton@redhat.com>
M: J. Bruce Fields <bfields@fieldses.org>
L: linux-fsdevel@vger.kernel.org L: linux-fsdevel@vger.kernel.org
S: Maintained S: Maintained
F: include/linux/fcntl.h F: include/linux/fcntl.h
......
...@@ -203,6 +203,9 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, ...@@ -203,6 +203,9 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
int ret; int ret;
switch (cmd) { switch (cmd) {
case F_GETLKP:
case F_SETLKP:
case F_SETLKPW:
case F_GETLK64: case F_GETLK64:
case F_SETLK64: case F_SETLK64:
case F_SETLKW64: case F_SETLKW64:
......
...@@ -399,12 +399,28 @@ static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *u ...@@ -399,12 +399,28 @@ static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *u
} }
#endif #endif
static unsigned int
convert_fcntl_cmd(unsigned int cmd)
{
switch (cmd) {
case F_GETLK64:
return F_GETLK;
case F_SETLK64:
return F_SETLK;
case F_SETLKW64:
return F_SETLKW;
}
return cmd;
}
COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
compat_ulong_t, arg) compat_ulong_t, arg)
{ {
mm_segment_t old_fs; mm_segment_t old_fs;
struct flock f; struct flock f;
long ret; long ret;
unsigned int conv_cmd;
switch (cmd) { switch (cmd) {
case F_GETLK: case F_GETLK:
...@@ -441,16 +457,18 @@ COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, ...@@ -441,16 +457,18 @@ COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
case F_GETLK64: case F_GETLK64:
case F_SETLK64: case F_SETLK64:
case F_SETLKW64: case F_SETLKW64:
case F_GETLKP:
case F_SETLKP:
case F_SETLKPW:
ret = get_compat_flock64(&f, compat_ptr(arg)); ret = get_compat_flock64(&f, compat_ptr(arg));
if (ret != 0) if (ret != 0)
break; break;
old_fs = get_fs(); old_fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK : conv_cmd = convert_fcntl_cmd(cmd);
((cmd == F_SETLK64) ? F_SETLK : F_SETLKW), ret = sys_fcntl(fd, conv_cmd, (unsigned long)&f);
(unsigned long)&f);
set_fs(old_fs); set_fs(old_fs);
if (cmd == F_GETLK64 && ret == 0) { if ((conv_cmd == F_GETLK || conv_cmd == F_GETLKP) && ret == 0) {
/* need to return lock information - see above for commentary */ /* need to return lock information - see above for commentary */
if (f.l_start > COMPAT_LOFF_T_MAX) if (f.l_start > COMPAT_LOFF_T_MAX)
ret = -EOVERFLOW; ret = -EOVERFLOW;
...@@ -471,8 +489,15 @@ COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, ...@@ -471,8 +489,15 @@ COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, COMPAT_SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd,
compat_ulong_t, arg) compat_ulong_t, arg)
{ {
if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64)) switch (cmd) {
case F_GETLK64:
case F_SETLK64:
case F_SETLKW64:
case F_GETLKP:
case F_SETLKP:
case F_SETLKPW:
return -EINVAL; return -EINVAL;
}
return compat_sys_fcntl64(fd, cmd, arg); return compat_sys_fcntl64(fd, cmd, arg);
} }
......
...@@ -272,9 +272,19 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, ...@@ -272,9 +272,19 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
case F_SETFL: case F_SETFL:
err = setfl(fd, filp, arg); err = setfl(fd, filp, arg);
break; break;
#if BITS_PER_LONG != 32
/* 32-bit arches must use fcntl64() */
case F_GETLKP:
#endif
case F_GETLK: case F_GETLK:
err = fcntl_getlk(filp, (struct flock __user *) arg); err = fcntl_getlk(filp, cmd, (struct flock __user *) arg);
break; break;
#if BITS_PER_LONG != 32
/* 32-bit arches must use fcntl64() */
case F_SETLKP:
case F_SETLKPW:
#endif
/* Fallthrough */
case F_SETLK: case F_SETLK:
case F_SETLKW: case F_SETLKW:
err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg); err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg);
...@@ -388,17 +398,20 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, ...@@ -388,17 +398,20 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
goto out1; goto out1;
switch (cmd) { switch (cmd) {
case F_GETLK64: case F_GETLK64:
err = fcntl_getlk64(f.file, (struct flock64 __user *) arg); case F_GETLKP:
break; err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg);
case F_SETLK64: break;
case F_SETLKW64: case F_SETLK64:
err = fcntl_setlk64(fd, f.file, cmd, case F_SETLKW64:
(struct flock64 __user *) arg); case F_SETLKP:
break; case F_SETLKPW:
default: err = fcntl_setlk64(fd, f.file, cmd,
err = do_fcntl(fd, cmd, arg, f.file); (struct flock64 __user *) arg);
break; break;
default:
err = do_fcntl(fd, cmd, arg, f.file);
break;
} }
out1: out1:
fdput(f); fdput(f);
......
...@@ -235,7 +235,7 @@ static void __fput(struct file *file) ...@@ -235,7 +235,7 @@ static void __fput(struct file *file)
* in the file cleanup chain. * in the file cleanup chain.
*/ */
eventpoll_release(file); eventpoll_release(file);
locks_remove_flock(file); locks_remove_file(file);
if (unlikely(file->f_flags & FASYNC)) { if (unlikely(file->f_flags & FASYNC)) {
if (file->f_op->fasync) if (file->f_op->fasync)
......
This diff is collapsed.
...@@ -2569,7 +2569,7 @@ static int handle_truncate(struct file *filp) ...@@ -2569,7 +2569,7 @@ static int handle_truncate(struct file *filp)
/* /*
* Refuse to truncate files with mandatory locks held on them. * Refuse to truncate files with mandatory locks held on them.
*/ */
error = locks_verify_locked(inode); error = locks_verify_locked(filp);
if (!error) if (!error)
error = security_path_truncate(path); error = security_path_truncate(path);
if (!error) { if (!error) {
......
...@@ -893,6 +893,7 @@ static inline int file_check_writeable(struct file *filp) ...@@ -893,6 +893,7 @@ static inline int file_check_writeable(struct file *filp)
#define FL_SLEEP 128 /* A blocking lock */ #define FL_SLEEP 128 /* A blocking lock */
#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ #define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */
#define FL_UNLOCK_PENDING 512 /* Lease is being broken */ #define FL_UNLOCK_PENDING 512 /* Lease is being broken */
#define FL_FILE_PVT 1024 /* lock is private to the file */
/* /*
* Special return value from posix_lock_file() and vfs_lock_file() for * Special return value from posix_lock_file() and vfs_lock_file() for
...@@ -997,12 +998,12 @@ struct file_lock { ...@@ -997,12 +998,12 @@ struct file_lock {
extern void send_sigio(struct fown_struct *fown, int fd, int band); extern void send_sigio(struct fown_struct *fown, int fd, int band);
#ifdef CONFIG_FILE_LOCKING #ifdef CONFIG_FILE_LOCKING
extern int fcntl_getlk(struct file *, struct flock __user *); extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *);
extern int fcntl_setlk(unsigned int, struct file *, unsigned int, extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
struct flock __user *); struct flock __user *);
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
extern int fcntl_getlk64(struct file *, struct flock64 __user *); extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 __user *);
extern int fcntl_setlk64(unsigned int, struct file *, unsigned int, extern int fcntl_setlk64(unsigned int, struct file *, unsigned int,
struct flock64 __user *); struct flock64 __user *);
#endif #endif
...@@ -1017,7 +1018,7 @@ extern struct file_lock * locks_alloc_lock(void); ...@@ -1017,7 +1018,7 @@ extern struct file_lock * locks_alloc_lock(void);
extern void locks_copy_lock(struct file_lock *, struct file_lock *); extern void locks_copy_lock(struct file_lock *, struct file_lock *);
extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); extern void __locks_copy_lock(struct file_lock *, const struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_flock(struct file *); extern void locks_remove_file(struct file *);
extern void locks_release_private(struct file_lock *); extern void locks_release_private(struct file_lock *);
extern void posix_test_lock(struct file *, struct file_lock *); extern void posix_test_lock(struct file *, struct file_lock *);
extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
...@@ -1035,7 +1036,8 @@ extern int lease_modify(struct file_lock **, int); ...@@ -1035,7 +1036,8 @@ extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count); extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count); extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
#else /* !CONFIG_FILE_LOCKING */ #else /* !CONFIG_FILE_LOCKING */
static inline int fcntl_getlk(struct file *file, struct flock __user *user) static inline int fcntl_getlk(struct file *file, unsigned int cmd,
struct flock __user *user)
{ {
return -EINVAL; return -EINVAL;
} }
...@@ -1047,7 +1049,8 @@ static inline int fcntl_setlk(unsigned int fd, struct file *file, ...@@ -1047,7 +1049,8 @@ static inline int fcntl_setlk(unsigned int fd, struct file *file,
} }
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
static inline int fcntl_getlk64(struct file *file, struct flock64 __user *user) static inline int fcntl_getlk64(struct file *file, unsigned int cmd,
struct flock64 __user *user)
{ {
return -EINVAL; return -EINVAL;
} }
...@@ -1088,7 +1091,7 @@ static inline void locks_remove_posix(struct file *filp, fl_owner_t owner) ...@@ -1088,7 +1091,7 @@ static inline void locks_remove_posix(struct file *filp, fl_owner_t owner)
return; return;
} }
static inline void locks_remove_flock(struct file *filp) static inline void locks_remove_file(struct file *filp)
{ {
return; return;
} }
...@@ -1916,6 +1919,11 @@ extern int current_umask(void); ...@@ -1916,6 +1919,11 @@ extern int current_umask(void);
extern void ihold(struct inode * inode); extern void ihold(struct inode * inode);
extern void iput(struct inode *); extern void iput(struct inode *);
static inline struct inode *file_inode(struct file *f)
{
return f->f_inode;
}
/* /sys/fs */ /* /sys/fs */
extern struct kobject *fs_kobj; extern struct kobject *fs_kobj;
...@@ -1925,7 +1933,7 @@ extern struct kobject *fs_kobj; ...@@ -1925,7 +1933,7 @@ extern struct kobject *fs_kobj;
#define FLOCK_VERIFY_WRITE 2 #define FLOCK_VERIFY_WRITE 2
#ifdef CONFIG_FILE_LOCKING #ifdef CONFIG_FILE_LOCKING
extern int locks_mandatory_locked(struct inode *); extern int locks_mandatory_locked(struct file *);
extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t); extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
/* /*
...@@ -1948,10 +1956,10 @@ static inline int mandatory_lock(struct inode *ino) ...@@ -1948,10 +1956,10 @@ static inline int mandatory_lock(struct inode *ino)
return IS_MANDLOCK(ino) && __mandatory_lock(ino); return IS_MANDLOCK(ino) && __mandatory_lock(ino);
} }
static inline int locks_verify_locked(struct inode *inode) static inline int locks_verify_locked(struct file *file)
{ {
if (mandatory_lock(inode)) if (mandatory_lock(file_inode(file)))
return locks_mandatory_locked(inode); return locks_mandatory_locked(file);
return 0; return 0;
} }
...@@ -1971,6 +1979,12 @@ static inline int locks_verify_truncate(struct inode *inode, ...@@ -1971,6 +1979,12 @@ static inline int locks_verify_truncate(struct inode *inode,
static inline int break_lease(struct inode *inode, unsigned int mode) static inline int break_lease(struct inode *inode, unsigned int mode)
{ {
/*
* Since this check is lockless, we must ensure that any refcounts
* taken are done before checking inode->i_flock. Otherwise, we could
* end up racing with tasks trying to set a new lease on this file.
*/
smp_mb();
if (inode->i_flock) if (inode->i_flock)
return __break_lease(inode, mode, FL_LEASE); return __break_lease(inode, mode, FL_LEASE);
return 0; return 0;
...@@ -2006,7 +2020,7 @@ static inline int break_deleg_wait(struct inode **delegated_inode) ...@@ -2006,7 +2020,7 @@ static inline int break_deleg_wait(struct inode **delegated_inode)
} }
#else /* !CONFIG_FILE_LOCKING */ #else /* !CONFIG_FILE_LOCKING */
static inline int locks_mandatory_locked(struct inode *inode) static inline int locks_mandatory_locked(struct file *file)
{ {
return 0; return 0;
} }
...@@ -2028,7 +2042,7 @@ static inline int mandatory_lock(struct inode *inode) ...@@ -2028,7 +2042,7 @@ static inline int mandatory_lock(struct inode *inode)
return 0; return 0;
} }
static inline int locks_verify_locked(struct inode *inode) static inline int locks_verify_locked(struct file *file)
{ {
return 0; return 0;
} }
...@@ -2302,11 +2316,6 @@ static inline bool execute_ok(struct inode *inode) ...@@ -2302,11 +2316,6 @@ static inline bool execute_ok(struct inode *inode)
return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode);
} }
static inline struct inode *file_inode(struct file *f)
{
return f->f_inode;
}
static inline void file_start_write(struct file *file) static inline void file_start_write(struct file *file)
{ {
if (!S_ISREG(file_inode(file)->i_mode)) if (!S_ISREG(file_inode(file)->i_mode))
......
...@@ -132,6 +132,22 @@ ...@@ -132,6 +132,22 @@
#define F_GETOWNER_UIDS 17 #define F_GETOWNER_UIDS 17
#endif #endif
/*
* fd "private" POSIX locks.
*
* Usually POSIX 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 normal POSIX locks, but
* are "owned" by the opened file, not the process. This means that they are
* inherited across fork() like BSD (flock) locks, and they are only released
* automatically when the last reference to the the open file against which
* they were acquired is put.
*/
#define F_GETLKP 36
#define F_SETLKP 37
#define F_SETLKPW 38
#define F_OWNER_TID 0 #define F_OWNER_TID 0
#define F_OWNER_PID 1 #define F_OWNER_PID 1
#define F_OWNER_PGRP 2 #define F_OWNER_PGRP 2
...@@ -186,8 +202,6 @@ struct flock { ...@@ -186,8 +202,6 @@ struct flock {
}; };
#endif #endif
#ifndef CONFIG_64BIT
#ifndef HAVE_ARCH_STRUCT_FLOCK64 #ifndef HAVE_ARCH_STRUCT_FLOCK64
#ifndef __ARCH_FLOCK64_PAD #ifndef __ARCH_FLOCK64_PAD
#define __ARCH_FLOCK64_PAD #define __ARCH_FLOCK64_PAD
...@@ -202,6 +216,5 @@ struct flock64 { ...@@ -202,6 +216,5 @@ struct flock64 {
__ARCH_FLOCK64_PAD __ARCH_FLOCK64_PAD
}; };
#endif #endif
#endif /* !CONFIG_64BIT */
#endif /* _ASM_GENERIC_FCNTL_H */ #endif /* _ASM_GENERIC_FCNTL_H */
...@@ -1299,7 +1299,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, ...@@ -1299,7 +1299,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
/* /*
* Make sure there are no mandatory locks on the file. * Make sure there are no mandatory locks on the file.
*/ */
if (locks_verify_locked(inode)) if (locks_verify_locked(file))
return -EAGAIN; return -EAGAIN;
vm_flags |= VM_SHARED | VM_MAYSHARE; vm_flags |= VM_SHARED | VM_MAYSHARE;
......
...@@ -995,7 +995,7 @@ static int validate_mmap_request(struct file *file, ...@@ -995,7 +995,7 @@ static int validate_mmap_request(struct file *file,
(file->f_mode & FMODE_WRITE)) (file->f_mode & FMODE_WRITE))
return -EACCES; return -EACCES;
if (locks_verify_locked(file_inode(file))) if (locks_verify_locked(file))
return -EAGAIN; return -EAGAIN;
if (!(capabilities & BDI_CAP_MAP_DIRECT)) if (!(capabilities & BDI_CAP_MAP_DIRECT))
......
...@@ -3317,6 +3317,9 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd, ...@@ -3317,6 +3317,9 @@ static int selinux_file_fcntl(struct file *file, unsigned int cmd,
case F_GETLK: case F_GETLK:
case F_SETLK: case F_SETLK:
case F_SETLKW: case F_SETLKW:
case F_GETLKP:
case F_SETLKP:
case F_SETLKPW:
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
case F_GETLK64: case F_GETLK64:
case F_SETLK64: case F_SETLK64:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment