Skip to content

Commit

Permalink
Merge tag 'locks-v4.2-1' of git://git.samba.org/jlayton/linux
Browse files Browse the repository at this point in the history
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: Bruce Fields <bfields@fieldses.org>
Acked-by: Dan 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: Anna 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"
  • Loading branch information
Linus Torvalds committed Jul 15, 2015
2 parents df14a68 + ee296d7 commit 16ff49a
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 40 deletions.
38 changes: 18 additions & 20 deletions fs/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* 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 *fl;
struct file_lock_context *ctx;
struct inode *inode = file_inode(filp);
int error = 0;
bool found = false;
LIST_HEAD(dispose);
Expand All @@ -890,7 +889,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
goto find_conflict;

list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
if (filp != fl->fl_file)
if (request->fl_file != fl->fl_file)
continue;
if (request->fl_type == fl->fl_type)
goto out;
Expand Down Expand Up @@ -1164,20 +1163,19 @@ int posix_lock_file(struct file *filp, struct file_lock *fl,
EXPORT_SYMBOL(posix_lock_file);

/**
* posix_lock_file_wait - Apply a POSIX-style lock to a file
* @filp: The file to apply the lock to
* posix_lock_inode_wait - Apply a POSIX-style lock to a file
* @inode: inode of file to which lock request should be applied
* @fl: The lock to be applied
*
* Add a POSIX style lock to a file.
* We merge adjacent & overlapping locks whenever possible.
* POSIX locks are sorted by owner task, then by starting address
* Variant of posix_lock_file_wait that does not take a filp, and so can be
* used after the filp has already been torn down.
*/
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;
might_sleep ();
for (;;) {
error = posix_lock_file(filp, fl, NULL);
error = __posix_lock_file(inode, fl, NULL);
if (error != FILE_LOCK_DEFERRED)
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
Expand All @@ -1189,7 +1187,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
}
return error;
}
EXPORT_SYMBOL(posix_lock_file_wait);
EXPORT_SYMBOL(posix_lock_inode_wait);

/**
* locks_mandatory_locked - Check for an active lock
Expand Down Expand Up @@ -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
* @filp: The file to apply the lock to
* flock_lock_inode_wait - Apply a FLOCK-style lock to a file
* @inode: inode of the file to apply to
* @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;
might_sleep();
for (;;) {
error = flock_lock_file(filp, fl);
error = flock_lock_inode(inode, fl);
if (error != FILE_LOCK_DEFERRED)
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
Expand All @@ -1874,8 +1872,7 @@ int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
}
return error;
}

EXPORT_SYMBOL(flock_lock_file_wait);
EXPORT_SYMBOL(flock_lock_inode_wait);

/**
* sys_flock: - flock() system call.
Expand Down Expand Up @@ -2401,15 +2398,16 @@ locks_remove_flock(struct file *filp)
.fl_type = F_UNLCK,
.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))
return;

if (filp->f_op->flock)
filp->f_op->flock(filp, F_SETLKW, &fl);
else
flock_lock_file(filp, &fl);
flock_lock_inode(inode, &fl);

if (fl.fl_ops && fl.fl_ops->fl_release_private)
fl.fl_ops->fl_release_private(&fl);
Expand Down
18 changes: 8 additions & 10 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -5439,15 +5439,15 @@ static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *
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;
switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
case FL_POSIX:
res = posix_lock_file_wait(file, fl);
res = posix_lock_inode_wait(inode, fl);
break;
case FL_FLOCK:
res = flock_lock_file_wait(file, fl);
res = flock_lock_inode_wait(inode, fl);
break;
default:
BUG();
Expand Down Expand Up @@ -5484,7 +5484,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
atomic_inc(&lsp->ls_count);
/* Ensure we don't close file until we're done freeing locks! */
p->ctx = get_nfs_open_context(ctx);
get_file(fl->fl_file);
memcpy(&p->fl, fl, sizeof(p->fl));
p->server = NFS_SERVER(inode);
return p;
Expand All @@ -5496,7 +5495,6 @@ static void nfs4_locku_release_calldata(void *data)
nfs_free_seqid(calldata->arg.seqid);
nfs4_put_lock_state(calldata->lsp);
put_nfs_open_context(calldata->ctx);
fput(calldata->fl.fl_file);
kfree(calldata);
}

Expand All @@ -5509,7 +5507,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
switch (task->tk_status) {
case 0:
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,
&calldata->res.stateid))
break;
Expand Down Expand Up @@ -5617,7 +5615,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
mutex_lock(&sp->so_delegreturn_mutex);
/* Exclude nfs4_reclaim_open_stateid() - note nesting! */
down_read(&nfsi->rwsem);
if (do_vfs_lock(request->fl_file, request) == -ENOENT) {
if (do_vfs_lock(inode, request) == -ENOENT) {
up_read(&nfsi->rwsem);
mutex_unlock(&sp->so_delegreturn_mutex);
goto out;
Expand Down Expand Up @@ -5758,7 +5756,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
data->timestamp);
if (data->arg.new_lock) {
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);
break;
}
Expand Down Expand Up @@ -6000,15 +5998,15 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
if (status != 0)
goto out;
request->fl_flags |= FL_ACCESS;
status = do_vfs_lock(request->fl_file, request);
status = do_vfs_lock(state->inode, request);
if (status < 0)
goto out;
down_read(&nfsi->rwsem);
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
/* Yes: cache locks! */
/* ...but avoid races with delegation recall... */
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);
goto out;
}
Expand Down
30 changes: 20 additions & 10 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1046,12 +1046,12 @@ extern void locks_remove_file(struct file *);
extern void locks_release_private(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_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 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_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 void lease_get_mtime(struct inode *, struct timespec *time);
extern int generic_setlease(struct file *, long, struct file_lock **, void **priv);
Expand Down Expand Up @@ -1137,7 +1137,8 @@ static inline int posix_lock_file(struct file *filp, struct file_lock *fl,
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;
}
Expand All @@ -1163,8 +1164,8 @@ static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
return 0;
}

static inline int flock_lock_file_wait(struct file *filp,
struct file_lock *request)
static inline int flock_lock_inode_wait(struct inode *inode,
struct file_lock *request)
{
return -ENOLCK;
}
Expand Down Expand Up @@ -1202,6 +1203,20 @@ static inline void show_fd_locks(struct seq_file *f,
struct file *filp, struct files_struct *files) {}
#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 {
spinlock_t fa_lock;
Expand Down Expand Up @@ -2011,11 +2026,6 @@ extern void ihold(struct inode * inode);
extern void iput(struct inode *);
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 */
extern struct kobject *fs_kobj;

Expand Down

0 comments on commit 16ff49a

Please sign in to comment.