Skip to content

Commit

Permalink
locks/nfsd: allocate file lock outside of spinlock
Browse files Browse the repository at this point in the history
As suggested by Christoph Hellwig, this moves allocation
of new file locks out of generic_setlease into the
callers, nfs4_open_delegation and fcntl_setlease in order
to allow GFP_KERNEL allocations when lock_flocks has
become a spinlock.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: J. Bruce Fields <bfields@redhat.com>
  • Loading branch information
Arnd Bergmann committed Oct 27, 2010
1 parent a282a1f commit c5b1f0d
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 35 deletions.
36 changes: 12 additions & 24 deletions fs/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,11 @@ EXPORT_SYMBOL_GPL(unlock_flocks);
static struct kmem_cache *filelock_cache __read_mostly;

/* Allocate an empty lock structure. */
static struct file_lock *locks_alloc_lock(void)
struct file_lock *locks_alloc_lock(void)
{
return kmem_cache_alloc(filelock_cache, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(locks_alloc_lock);

void locks_release_private(struct file_lock *fl)
{
Expand Down Expand Up @@ -1365,7 +1366,6 @@ int fcntl_getlease(struct file *filp)
int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
struct file_lock *new_fl = NULL;
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
Expand All @@ -1385,11 +1385,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
lease = *flp;

if (arg != F_UNLCK) {
error = -ENOMEM;
new_fl = locks_alloc_lock();
if (new_fl == NULL)
goto out;

error = -EAGAIN;
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
goto out;
Expand Down Expand Up @@ -1434,23 +1429,18 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
goto out;
}

error = 0;
if (arg == F_UNLCK)
goto out;

error = -EINVAL;
if (!leases_enable)
goto out;

locks_copy_lock(new_fl, lease);
locks_insert_lock(before, new_fl);

*flp = new_fl;
locks_insert_lock(before, lease);
return 0;

out:
if (new_fl != NULL)
locks_free_lock(new_fl);
locks_free_lock(lease);
return error;
}
EXPORT_SYMBOL(generic_setlease);
Expand Down Expand Up @@ -1514,26 +1504,24 @@ EXPORT_SYMBOL_GPL(vfs_setlease);
*/
int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
{
struct file_lock fl, *flp = &fl;
struct file_lock *fl;
struct inode *inode = filp->f_path.dentry->d_inode;
int error;

locks_init_lock(&fl);
error = lease_init(filp, arg, &fl);
if (error)
return error;
fl = lease_alloc(filp, arg);
if (IS_ERR(fl))
return PTR_ERR(fl);

lock_flocks();

error = __vfs_setlease(filp, arg, &flp);
error = __vfs_setlease(filp, arg, &fl);
if (error || arg == F_UNLCK)
goto out_unlock;

error = fasync_helper(fd, filp, 1, &flp->fl_fasync);
error = fasync_helper(fd, filp, 1, &fl->fl_fasync);
if (error < 0) {
/* remove lease just inserted by setlease */
flp->fl_type = F_UNLCK | F_INPROGRESS;
flp->fl_break_time = jiffies - 10;
fl->fl_type = F_UNLCK | F_INPROGRESS;
fl->fl_break_time = jiffies - 10;
time_out_leases(inode);
goto out_unlock;
}
Expand Down
26 changes: 15 additions & 11 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -2614,7 +2614,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
struct nfs4_delegation *dp;
struct nfs4_stateowner *sop = stp->st_stateowner;
int cb_up = atomic_read(&sop->so_client->cl_cb_set);
struct file_lock fl, *flp = &fl;
struct file_lock *fl;
int status, flag = 0;

flag = NFS4_OPEN_DELEGATE_NONE;
Expand Down Expand Up @@ -2648,20 +2648,24 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
flag = NFS4_OPEN_DELEGATE_NONE;
goto out;
}
locks_init_lock(&fl);
fl.fl_lmops = &nfsd_lease_mng_ops;
fl.fl_flags = FL_LEASE;
fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
fl.fl_end = OFFSET_MAX;
fl.fl_owner = (fl_owner_t)dp;
fl.fl_file = find_readable_file(stp->st_file);
BUG_ON(!fl.fl_file);
fl.fl_pid = current->tgid;
status = -ENOMEM;
fl = locks_alloc_lock();
if (!fl)
goto out;
locks_init_lock(fl);
fl->fl_lmops = &nfsd_lease_mng_ops;
fl->fl_flags = FL_LEASE;
fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
fl->fl_end = OFFSET_MAX;
fl->fl_owner = (fl_owner_t)dp;
fl->fl_file = find_readable_file(stp->st_file);
BUG_ON(!fl->fl_file);
fl->fl_pid = current->tgid;

/* vfs_setlease checks to see if delegation should be handed out.
* the lock_manager callbacks fl_mylease and fl_change are used
*/
if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) {
if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
unhash_delegation(dp);
flag = NFS4_OPEN_DELEGATE_NONE;
Expand Down
1 change: 1 addition & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,7 @@ extern int fcntl_getlease(struct file *filp);

/* fs/locks.c */
extern void locks_init_lock(struct file_lock *);
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 *, const struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t);
Expand Down

0 comments on commit c5b1f0d

Please sign in to comment.