Commit 16ff49a0 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'locks-v4.2-1' of git://git.samba.org/jlayton/linux

Pull file locking updates from Jeff Layton:
 "I had thought that I was going to get away without a pull request this
  cycle.  There was a NFSv4 file locking problem that cropped up that I
  tried to fix in the NFSv4 code alone, but that fix has turned out to
  be problematic.  These patches fix this in the correct way.

  Note that this touches some NFSv4 code as well.  Ordinarily I'd wait
  for Trond to ACK this, but he's on holiday right now and the bug is
  rather nasty.  So I suggest we merge this and if he raises issues with
  it we can sort it out when he gets back"
Acked-by: default avatarBruce Fields <bfields@fieldses.org>
Acked-by: default avatarDan Williams <dan.j.williams@intel.com>
 [ +1 to this series fixing a 100% reproducible slab corruption +
   general protection fault in my nfs-root test environment. - Dan ]
Acked-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>

* tag 'locks-v4.2-1' of git://git.samba.org/jlayton/linux:
  locks: inline posix_lock_file_wait and flock_lock_file_wait
  nfs4: have do_vfs_lock take an inode pointer
  locks: new helpers - flock_lock_inode_wait and posix_lock_inode_wait
  locks: have flock_lock_file take an inode pointer instead of a filp
  Revert "nfs: take extra reference to fl->fl_file when running a LOCKU operation"
parents df14a68d ee296d7c
...@@ -862,12 +862,11 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, ...@@ -862,12 +862,11 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
* whether or not a lock was successfully freed by testing the return * whether or not a lock was successfully freed by testing the return
* value for -ENOENT. * value for -ENOENT.
*/ */
static int flock_lock_file(struct file *filp, struct file_lock *request) static int flock_lock_inode(struct inode *inode, struct file_lock *request)
{ {
struct file_lock *new_fl = NULL; struct file_lock *new_fl = NULL;
struct file_lock *fl; struct file_lock *fl;
struct file_lock_context *ctx; struct file_lock_context *ctx;
struct inode *inode = file_inode(filp);
int error = 0; int error = 0;
bool found = false; bool found = false;
LIST_HEAD(dispose); LIST_HEAD(dispose);
...@@ -890,7 +889,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) ...@@ -890,7 +889,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
goto find_conflict; goto find_conflict;
list_for_each_entry(fl, &ctx->flc_flock, fl_list) { list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
if (filp != fl->fl_file) if (request->fl_file != fl->fl_file)
continue; continue;
if (request->fl_type == fl->fl_type) if (request->fl_type == fl->fl_type)
goto out; goto out;
...@@ -1164,20 +1163,19 @@ int posix_lock_file(struct file *filp, struct file_lock *fl, ...@@ -1164,20 +1163,19 @@ int posix_lock_file(struct file *filp, struct file_lock *fl,
EXPORT_SYMBOL(posix_lock_file); EXPORT_SYMBOL(posix_lock_file);
/** /**
* posix_lock_file_wait - Apply a POSIX-style lock to a file * posix_lock_inode_wait - Apply a POSIX-style lock to a file
* @filp: The file to apply the lock to * @inode: inode of file to which lock request should be applied
* @fl: The lock to be applied * @fl: The lock to be applied
* *
* Add a POSIX style lock to a file. * Variant of posix_lock_file_wait that does not take a filp, and so can be
* We merge adjacent & overlapping locks whenever possible. * used after the filp has already been torn down.
* POSIX locks are sorted by owner task, then by starting address
*/ */
int posix_lock_file_wait(struct file *filp, struct file_lock *fl) int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
{ {
int error; int error;
might_sleep (); might_sleep ();
for (;;) { for (;;) {
error = posix_lock_file(filp, fl, NULL); error = __posix_lock_file(inode, fl, NULL);
if (error != FILE_LOCK_DEFERRED) if (error != FILE_LOCK_DEFERRED)
break; break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
...@@ -1189,7 +1187,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) ...@@ -1189,7 +1187,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
} }
return error; return error;
} }
EXPORT_SYMBOL(posix_lock_file_wait); EXPORT_SYMBOL(posix_lock_inode_wait);
/** /**
* locks_mandatory_locked - Check for an active lock * locks_mandatory_locked - Check for an active lock
...@@ -1851,18 +1849,18 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) ...@@ -1851,18 +1849,18 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
} }
/** /**
* flock_lock_file_wait - Apply a FLOCK-style lock to a file * flock_lock_inode_wait - Apply a FLOCK-style lock to a file
* @filp: The file to apply the lock to * @inode: inode of the file to apply to
* @fl: The lock to be applied * @fl: The lock to be applied
* *
* Add a FLOCK style lock to a file. * Apply a FLOCK style lock request to an inode.
*/ */
int flock_lock_file_wait(struct file *filp, struct file_lock *fl) int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
{ {
int error; int error;
might_sleep(); might_sleep();
for (;;) { for (;;) {
error = flock_lock_file(filp, fl); error = flock_lock_inode(inode, fl);
if (error != FILE_LOCK_DEFERRED) if (error != FILE_LOCK_DEFERRED)
break; break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
...@@ -1874,8 +1872,7 @@ int flock_lock_file_wait(struct file *filp, struct file_lock *fl) ...@@ -1874,8 +1872,7 @@ int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
} }
return error; return error;
} }
EXPORT_SYMBOL(flock_lock_inode_wait);
EXPORT_SYMBOL(flock_lock_file_wait);
/** /**
* sys_flock: - flock() system call. * sys_flock: - flock() system call.
...@@ -2401,7 +2398,8 @@ locks_remove_flock(struct file *filp) ...@@ -2401,7 +2398,8 @@ locks_remove_flock(struct file *filp)
.fl_type = F_UNLCK, .fl_type = F_UNLCK,
.fl_end = OFFSET_MAX, .fl_end = OFFSET_MAX,
}; };
struct file_lock_context *flctx = file_inode(filp)->i_flctx; struct inode *inode = file_inode(filp);
struct file_lock_context *flctx = inode->i_flctx;
if (list_empty(&flctx->flc_flock)) if (list_empty(&flctx->flc_flock))
return; return;
...@@ -2409,7 +2407,7 @@ locks_remove_flock(struct file *filp) ...@@ -2409,7 +2407,7 @@ locks_remove_flock(struct file *filp)
if (filp->f_op->flock) if (filp->f_op->flock)
filp->f_op->flock(filp, F_SETLKW, &fl); filp->f_op->flock(filp, F_SETLKW, &fl);
else else
flock_lock_file(filp, &fl); flock_lock_inode(inode, &fl);
if (fl.fl_ops && fl.fl_ops->fl_release_private) if (fl.fl_ops && fl.fl_ops->fl_release_private)
fl.fl_ops->fl_release_private(&fl); fl.fl_ops->fl_release_private(&fl);
......
...@@ -5439,15 +5439,15 @@ static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock * ...@@ -5439,15 +5439,15 @@ static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *
return err; return err;
} }
static int do_vfs_lock(struct file *file, struct file_lock *fl) static int do_vfs_lock(struct inode *inode, struct file_lock *fl)
{ {
int res = 0; int res = 0;
switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
case FL_POSIX: case FL_POSIX:
res = posix_lock_file_wait(file, fl); res = posix_lock_inode_wait(inode, fl);
break; break;
case FL_FLOCK: case FL_FLOCK:
res = flock_lock_file_wait(file, fl); res = flock_lock_inode_wait(inode, fl);
break; break;
default: default:
BUG(); BUG();
...@@ -5484,7 +5484,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, ...@@ -5484,7 +5484,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
atomic_inc(&lsp->ls_count); atomic_inc(&lsp->ls_count);
/* Ensure we don't close file until we're done freeing locks! */ /* Ensure we don't close file until we're done freeing locks! */
p->ctx = get_nfs_open_context(ctx); p->ctx = get_nfs_open_context(ctx);
get_file(fl->fl_file);
memcpy(&p->fl, fl, sizeof(p->fl)); memcpy(&p->fl, fl, sizeof(p->fl));
p->server = NFS_SERVER(inode); p->server = NFS_SERVER(inode);
return p; return p;
...@@ -5496,7 +5495,6 @@ static void nfs4_locku_release_calldata(void *data) ...@@ -5496,7 +5495,6 @@ static void nfs4_locku_release_calldata(void *data)
nfs_free_seqid(calldata->arg.seqid); nfs_free_seqid(calldata->arg.seqid);
nfs4_put_lock_state(calldata->lsp); nfs4_put_lock_state(calldata->lsp);
put_nfs_open_context(calldata->ctx); put_nfs_open_context(calldata->ctx);
fput(calldata->fl.fl_file);
kfree(calldata); kfree(calldata);
} }
...@@ -5509,7 +5507,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) ...@@ -5509,7 +5507,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
switch (task->tk_status) { switch (task->tk_status) {
case 0: case 0:
renew_lease(calldata->server, calldata->timestamp); renew_lease(calldata->server, calldata->timestamp);
do_vfs_lock(calldata->fl.fl_file, &calldata->fl); do_vfs_lock(calldata->lsp->ls_state->inode, &calldata->fl);
if (nfs4_update_lock_stateid(calldata->lsp, if (nfs4_update_lock_stateid(calldata->lsp,
&calldata->res.stateid)) &calldata->res.stateid))
break; break;
...@@ -5617,7 +5615,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * ...@@ -5617,7 +5615,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
mutex_lock(&sp->so_delegreturn_mutex); mutex_lock(&sp->so_delegreturn_mutex);
/* Exclude nfs4_reclaim_open_stateid() - note nesting! */ /* Exclude nfs4_reclaim_open_stateid() - note nesting! */
down_read(&nfsi->rwsem); down_read(&nfsi->rwsem);
if (do_vfs_lock(request->fl_file, request) == -ENOENT) { if (do_vfs_lock(inode, request) == -ENOENT) {
up_read(&nfsi->rwsem); up_read(&nfsi->rwsem);
mutex_unlock(&sp->so_delegreturn_mutex); mutex_unlock(&sp->so_delegreturn_mutex);
goto out; goto out;
...@@ -5758,7 +5756,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) ...@@ -5758,7 +5756,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
data->timestamp); data->timestamp);
if (data->arg.new_lock) { if (data->arg.new_lock) {
data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS); data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
if (do_vfs_lock(data->fl.fl_file, &data->fl) < 0) { if (do_vfs_lock(lsp->ls_state->inode, &data->fl) < 0) {
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
break; break;
} }
...@@ -6000,7 +5998,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock ...@@ -6000,7 +5998,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
if (status != 0) if (status != 0)
goto out; goto out;
request->fl_flags |= FL_ACCESS; request->fl_flags |= FL_ACCESS;
status = do_vfs_lock(request->fl_file, request); status = do_vfs_lock(state->inode, request);
if (status < 0) if (status < 0)
goto out; goto out;
down_read(&nfsi->rwsem); down_read(&nfsi->rwsem);
...@@ -6008,7 +6006,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock ...@@ -6008,7 +6006,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
/* Yes: cache locks! */ /* Yes: cache locks! */
/* ...but avoid races with delegation recall... */ /* ...but avoid races with delegation recall... */
request->fl_flags = fl_flags & ~FL_SLEEP; request->fl_flags = fl_flags & ~FL_SLEEP;
status = do_vfs_lock(request->fl_file, request); status = do_vfs_lock(state->inode, request);
up_read(&nfsi->rwsem); up_read(&nfsi->rwsem);
goto out; goto out;
} }
......
...@@ -1046,12 +1046,12 @@ extern void locks_remove_file(struct file *); ...@@ -1046,12 +1046,12 @@ 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 *);
extern int posix_lock_file_wait(struct file *, struct file_lock *); extern int posix_lock_inode_wait(struct inode *, struct file_lock *);
extern int posix_unblock_lock(struct file_lock *); extern int posix_unblock_lock(struct file_lock *);
extern int vfs_test_lock(struct file *, struct file_lock *); extern int vfs_test_lock(struct file *, struct file_lock *);
extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl); extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl); extern int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type); extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
extern void lease_get_mtime(struct inode *, struct timespec *time); extern void lease_get_mtime(struct inode *, struct timespec *time);
extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); extern int generic_setlease(struct file *, long, struct file_lock **, void **priv);
...@@ -1137,7 +1137,8 @@ static inline int posix_lock_file(struct file *filp, struct file_lock *fl, ...@@ -1137,7 +1137,8 @@ static inline int posix_lock_file(struct file *filp, struct file_lock *fl,
return -ENOLCK; return -ENOLCK;
} }
static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl) static inline int posix_lock_inode_wait(struct inode *inode,
struct file_lock *fl)
{ {
return -ENOLCK; return -ENOLCK;
} }
...@@ -1163,7 +1164,7 @@ static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl) ...@@ -1163,7 +1164,7 @@ static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
return 0; return 0;
} }
static inline int flock_lock_file_wait(struct file *filp, static inline int flock_lock_inode_wait(struct inode *inode,
struct file_lock *request) struct file_lock *request)
{ {
return -ENOLCK; return -ENOLCK;
...@@ -1202,6 +1203,20 @@ static inline void show_fd_locks(struct seq_file *f, ...@@ -1202,6 +1203,20 @@ static inline void show_fd_locks(struct seq_file *f,
struct file *filp, struct files_struct *files) {} struct file *filp, struct files_struct *files) {}
#endif /* !CONFIG_FILE_LOCKING */ #endif /* !CONFIG_FILE_LOCKING */
static inline struct inode *file_inode(const struct file *f)
{
return f->f_inode;
}
static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
{
return posix_lock_inode_wait(file_inode(filp), fl);
}
static inline int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
{
return flock_lock_inode_wait(file_inode(filp), fl);
}
struct fasync_struct { struct fasync_struct {
spinlock_t fa_lock; spinlock_t fa_lock;
...@@ -2011,11 +2026,6 @@ extern void ihold(struct inode * inode); ...@@ -2011,11 +2026,6 @@ extern void ihold(struct inode * inode);
extern void iput(struct inode *); extern void iput(struct inode *);
extern int generic_update_time(struct inode *, struct timespec *, int); extern int generic_update_time(struct inode *, struct timespec *, int);
static inline struct inode *file_inode(const struct file *f)
{
return f->f_inode;
}
/* /sys/fs */ /* /sys/fs */
extern struct kobject *fs_kobj; extern struct kobject *fs_kobj;
......
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