Skip to content

Commit

Permalink
Merge tag 'locks-v3.20-1' of git://git.samba.org/jlayton/linux
Browse files Browse the repository at this point in the history
Pull file locking related changes #1 from Jeff Layton:
 "This patchset contains a fairly major overhaul of how file locks are
  tracked within the inode.  Rather than a single list, we now create a
  per-inode "lock context" that contains individual lists for the file
  locks, and a new dedicated spinlock for them.

  There are changes in other trees that are based on top of this set so
  it may be easiest to pull this in early"

* tag 'locks-v3.20-1' of git://git.samba.org/jlayton/linux:
  locks: update comments that refer to inode->i_flock
  locks: consolidate NULL i_flctx checks in locks_remove_file
  locks: keep a count of locks on the flctx lists
  locks: clean up the lm_change prototype
  locks: add a dedicated spinlock to protect i_flctx lists
  locks: remove i_flock field from struct inode
  locks: convert lease handling to file_lock_context
  locks: convert posix locks to file_lock_context
  locks: move flock locks to file_lock_context
  ceph: move spinlocking into ceph_encode_locks_to_buffer and ceph_count_locks
  locks: add a new struct file_locking_context pointer to struct inode
  locks: have locks_release_file use flock_lock_file to release generic flock locks
  locks: add new struct list_head to struct file_lock
  • Loading branch information
Linus Torvalds committed Feb 10, 2015
2 parents 8729123 + 8116bf4 commit 4b4f858
Show file tree
Hide file tree
Showing 13 changed files with 510 additions and 405 deletions.
64 changes: 32 additions & 32 deletions fs/ceph/locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,23 +239,21 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
return err;
}

/**
* Must be called with lock_flocks() already held. Fills in the passed
* counter variables, so you can prepare pagelist metadata before calling
* ceph_encode_locks.
/*
* Fills in the passed counter variables, so you can prepare pagelist metadata
* before calling ceph_encode_locks.
*/
void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
{
struct file_lock *lock;
struct file_lock_context *ctx;

*fcntl_count = 0;
*flock_count = 0;

for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
if (lock->fl_flags & FL_POSIX)
++(*fcntl_count);
else if (lock->fl_flags & FL_FLOCK)
++(*flock_count);
ctx = inode->i_flctx;
if (ctx) {
*fcntl_count = ctx->flc_posix_cnt;
*flock_count = ctx->flc_flock_cnt;
}
dout("counted %d flock locks and %d fcntl locks",
*flock_count, *fcntl_count);
Expand All @@ -271,6 +269,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
int num_fcntl_locks, int num_flock_locks)
{
struct file_lock *lock;
struct file_lock_context *ctx = inode->i_flctx;
int err = 0;
int seen_fcntl = 0;
int seen_flock = 0;
Expand All @@ -279,33 +278,34 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
dout("encoding %d flock and %d fcntl locks", num_flock_locks,
num_fcntl_locks);

for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
if (lock->fl_flags & FL_POSIX) {
++seen_fcntl;
if (seen_fcntl > num_fcntl_locks) {
err = -ENOSPC;
goto fail;
}
err = lock_to_ceph_filelock(lock, &flocks[l]);
if (err)
goto fail;
++l;
if (!ctx)
return 0;

spin_lock(&ctx->flc_lock);
list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
++seen_fcntl;
if (seen_fcntl > num_fcntl_locks) {
err = -ENOSPC;
goto fail;
}
err = lock_to_ceph_filelock(lock, &flocks[l]);
if (err)
goto fail;
++l;
}
for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
if (lock->fl_flags & FL_FLOCK) {
++seen_flock;
if (seen_flock > num_flock_locks) {
err = -ENOSPC;
goto fail;
}
err = lock_to_ceph_filelock(lock, &flocks[l]);
if (err)
goto fail;
++l;
list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
++seen_flock;
if (seen_flock > num_flock_locks) {
err = -ENOSPC;
goto fail;
}
err = lock_to_ceph_filelock(lock, &flocks[l]);
if (err)
goto fail;
++l;
}
fail:
spin_unlock(&ctx->flc_lock);
return err;
}

Expand Down
4 changes: 0 additions & 4 deletions fs/ceph/mds_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -2700,20 +2700,16 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
struct ceph_filelock *flocks;

encode_again:
spin_lock(&inode->i_lock);
ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
spin_unlock(&inode->i_lock);
flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
sizeof(struct ceph_filelock), GFP_NOFS);
if (!flocks) {
err = -ENOMEM;
goto out_free;
}
spin_lock(&inode->i_lock);
err = ceph_encode_locks_to_buffer(inode, flocks,
num_fcntl_locks,
num_flock_locks);
spin_unlock(&inode->i_lock);
if (err) {
kfree(flocks);
if (err == -ENOSPC)
Expand Down
34 changes: 11 additions & 23 deletions fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1113,11 +1113,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
return rc;
}

/* copied from fs/locks.c with a name change */
#define cifs_for_each_lock(inode, lockp) \
for (lockp = &inode->i_flock; *lockp != NULL; \
lockp = &(*lockp)->fl_next)

struct lock_to_push {
struct list_head llist;
__u64 offset;
Expand All @@ -1132,30 +1127,27 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
{
struct inode *inode = cfile->dentry->d_inode;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct file_lock *flock, **before;
unsigned int count = 0, i = 0;
struct file_lock *flock;
struct file_lock_context *flctx = inode->i_flctx;
unsigned int i;
int rc = 0, xid, type;
struct list_head locks_to_send, *el;
struct lock_to_push *lck, *tmp;
__u64 length;

xid = get_xid();

spin_lock(&inode->i_lock);
cifs_for_each_lock(inode, before) {
if ((*before)->fl_flags & FL_POSIX)
count++;
}
spin_unlock(&inode->i_lock);
if (!flctx)
goto out;

INIT_LIST_HEAD(&locks_to_send);

/*
* Allocating count locks is enough because no FL_POSIX locks can be
* added to the list while we are holding cinode->lock_sem that
* Allocating flc_posix_cnt locks is enough because no FL_POSIX locks
* can be added to the list while we are holding cinode->lock_sem that
* protects locking operations of this inode.
*/
for (; i < count; i++) {
for (i = 0; i < flctx->flc_posix_cnt; i++) {
lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL);
if (!lck) {
rc = -ENOMEM;
Expand All @@ -1165,11 +1157,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
}

el = locks_to_send.next;
spin_lock(&inode->i_lock);
cifs_for_each_lock(inode, before) {
flock = *before;
if ((flock->fl_flags & FL_POSIX) == 0)
continue;
spin_lock(&flctx->flc_lock);
list_for_each_entry(flock, &flctx->flc_posix, fl_list) {
if (el == &locks_to_send) {
/*
* The list ended. We don't have enough allocated
Expand All @@ -1189,9 +1178,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
lck->length = length;
lck->type = type;
lck->offset = flock->fl_start;
el = el->next;
}
spin_unlock(&inode->i_lock);
spin_unlock(&flctx->flc_lock);

list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
int stored_rc;
Expand Down
3 changes: 2 additions & 1 deletion fs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
#ifdef CONFIG_FSNOTIFY
inode->i_fsnotify_mask = 0;
#endif

inode->i_flctx = NULL;
this_cpu_inc(nr_inodes);

return 0;
Expand Down Expand Up @@ -237,6 +237,7 @@ void __destroy_inode(struct inode *inode)
BUG_ON(inode_has_buffers(inode));
security_inode_free(inode);
fsnotify_inode_delete(inode);
locks_free_lock_context(inode->i_flctx);
if (!inode->i_nlink) {
WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
atomic_long_dec(&inode->i_sb->s_remove_count);
Expand Down
26 changes: 16 additions & 10 deletions fs/lockd/svcsubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,15 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
{
struct inode *inode = nlmsvc_file_inode(file);
struct file_lock *fl;
struct file_lock_context *flctx = inode->i_flctx;
struct nlm_host *lockhost;

if (!flctx || list_empty_careful(&flctx->flc_posix))
return 0;
again:
file->f_locks = 0;
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl; fl = fl->fl_next) {
spin_lock(&flctx->flc_lock);
list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
if (fl->fl_lmops != &nlmsvc_lock_operations)
continue;

Expand All @@ -180,7 +183,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
if (match(lockhost, host)) {
struct file_lock lock = *fl;

spin_unlock(&inode->i_lock);
spin_unlock(&flctx->flc_lock);
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
Expand All @@ -192,7 +195,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
goto again;
}
}
spin_unlock(&inode->i_lock);
spin_unlock(&flctx->flc_lock);

return 0;
}
Expand Down Expand Up @@ -223,18 +226,21 @@ nlm_file_inuse(struct nlm_file *file)
{
struct inode *inode = nlmsvc_file_inode(file);
struct file_lock *fl;
struct file_lock_context *flctx = inode->i_flctx;

if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
return 1;

spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl; fl = fl->fl_next) {
if (fl->fl_lmops == &nlmsvc_lock_operations) {
spin_unlock(&inode->i_lock);
return 1;
if (flctx && !list_empty_careful(&flctx->flc_posix)) {
spin_lock(&flctx->flc_lock);
list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
if (fl->fl_lmops == &nlmsvc_lock_operations) {
spin_unlock(&flctx->flc_lock);
return 1;
}
}
spin_unlock(&flctx->flc_lock);
}
spin_unlock(&inode->i_lock);
file->f_locks = 0;
return 0;
}
Expand Down
Loading

0 comments on commit 4b4f858

Please sign in to comment.