Commit 4b4f8580 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'locks-v3.20-1' of git://git.samba.org/jlayton/linux

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
parents 87291235 8116bf4c
Loading
Loading
Loading
Loading
+32 −32
Original line number Original line Diff line number Diff line
@@ -239,23 +239,21 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
	return err;
	return err;
}
}


/**
/*
 * Must be called with lock_flocks() already held. Fills in the passed
 * Fills in the passed counter variables, so you can prepare pagelist metadata
 * counter variables, so you can prepare pagelist metadata before calling
 * before calling ceph_encode_locks.
 * ceph_encode_locks.
 */
 */
void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
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;
	*fcntl_count = 0;
	*flock_count = 0;
	*flock_count = 0;


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


	for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
	if (!ctx)
		if (lock->fl_flags & FL_POSIX) {
		return 0;

	spin_lock(&ctx->flc_lock);
	list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
		++seen_fcntl;
		++seen_fcntl;
		if (seen_fcntl > num_fcntl_locks) {
		if (seen_fcntl > num_fcntl_locks) {
			err = -ENOSPC;
			err = -ENOSPC;
@@ -291,9 +293,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
			goto fail;
			goto fail;
		++l;
		++l;
	}
	}
	}
	list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
	for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
		if (lock->fl_flags & FL_FLOCK) {
		++seen_flock;
		++seen_flock;
		if (seen_flock > num_flock_locks) {
		if (seen_flock > num_flock_locks) {
			err = -ENOSPC;
			err = -ENOSPC;
@@ -304,8 +304,8 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
			goto fail;
			goto fail;
		++l;
		++l;
	}
	}
	}
fail:
fail:
	spin_unlock(&ctx->flc_lock);
	return err;
	return err;
}
}


+0 −4
Original line number Original line Diff line number Diff line
@@ -2700,20 +2700,16 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
		struct ceph_filelock *flocks;
		struct ceph_filelock *flocks;


encode_again:
encode_again:
		spin_lock(&inode->i_lock);
		ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
		ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
		spin_unlock(&inode->i_lock);
		flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
		flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
				 sizeof(struct ceph_filelock), GFP_NOFS);
				 sizeof(struct ceph_filelock), GFP_NOFS);
		if (!flocks) {
		if (!flocks) {
			err = -ENOMEM;
			err = -ENOMEM;
			goto out_free;
			goto out_free;
		}
		}
		spin_lock(&inode->i_lock);
		err = ceph_encode_locks_to_buffer(inode, flocks,
		err = ceph_encode_locks_to_buffer(inode, flocks,
						  num_fcntl_locks,
						  num_fcntl_locks,
						  num_flock_locks);
						  num_flock_locks);
		spin_unlock(&inode->i_lock);
		if (err) {
		if (err) {
			kfree(flocks);
			kfree(flocks);
			if (err == -ENOSPC)
			if (err == -ENOSPC)
+11 −23
Original line number Original line Diff line number Diff line
@@ -1113,11 +1113,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
	return rc;
	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 lock_to_push {
	struct list_head llist;
	struct list_head llist;
	__u64 offset;
	__u64 offset;
@@ -1132,8 +1127,9 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
{
{
	struct inode *inode = cfile->dentry->d_inode;
	struct inode *inode = cfile->dentry->d_inode;
	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
	struct file_lock *flock, **before;
	struct file_lock *flock;
	unsigned int count = 0, i = 0;
	struct file_lock_context *flctx = inode->i_flctx;
	unsigned int i;
	int rc = 0, xid, type;
	int rc = 0, xid, type;
	struct list_head locks_to_send, *el;
	struct list_head locks_to_send, *el;
	struct lock_to_push *lck, *tmp;
	struct lock_to_push *lck, *tmp;
@@ -1141,21 +1137,17 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)


	xid = get_xid();
	xid = get_xid();


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


	INIT_LIST_HEAD(&locks_to_send);
	INIT_LIST_HEAD(&locks_to_send);


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


	el = locks_to_send.next;
	el = locks_to_send.next;
	spin_lock(&inode->i_lock);
	spin_lock(&flctx->flc_lock);
	cifs_for_each_lock(inode, before) {
	list_for_each_entry(flock, &flctx->flc_posix, fl_list) {
		flock = *before;
		if ((flock->fl_flags & FL_POSIX) == 0)
			continue;
		if (el == &locks_to_send) {
		if (el == &locks_to_send) {
			/*
			/*
			 * The list ended. We don't have enough allocated
			 * The list ended. We don't have enough allocated
@@ -1189,9 +1178,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
		lck->length = length;
		lck->length = length;
		lck->type = type;
		lck->type = type;
		lck->offset = flock->fl_start;
		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) {
	list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
		int stored_rc;
		int stored_rc;
+2 −1
Original line number Original line Diff line number Diff line
@@ -194,7 +194,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
#ifdef CONFIG_FSNOTIFY
#ifdef CONFIG_FSNOTIFY
	inode->i_fsnotify_mask = 0;
	inode->i_fsnotify_mask = 0;
#endif
#endif

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


	return 0;
	return 0;
@@ -237,6 +237,7 @@ void __destroy_inode(struct inode *inode)
	BUG_ON(inode_has_buffers(inode));
	BUG_ON(inode_has_buffers(inode));
	security_inode_free(inode);
	security_inode_free(inode);
	fsnotify_inode_delete(inode);
	fsnotify_inode_delete(inode);
	locks_free_lock_context(inode->i_flctx);
	if (!inode->i_nlink) {
	if (!inode->i_nlink) {
		WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
		WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
		atomic_long_dec(&inode->i_sb->s_remove_count);
		atomic_long_dec(&inode->i_sb->s_remove_count);
+16 −10
Original line number Original line Diff line number Diff line
@@ -164,12 +164,15 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
{
{
	struct inode	 *inode = nlmsvc_file_inode(file);
	struct inode	 *inode = nlmsvc_file_inode(file);
	struct file_lock *fl;
	struct file_lock *fl;
	struct file_lock_context *flctx = inode->i_flctx;
	struct nlm_host	 *lockhost;
	struct nlm_host	 *lockhost;


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


@@ -180,7 +183,7 @@ again:
		if (match(lockhost, host)) {
		if (match(lockhost, host)) {
			struct file_lock lock = *fl;
			struct file_lock lock = *fl;


			spin_unlock(&inode->i_lock);
			spin_unlock(&flctx->flc_lock);
			lock.fl_type  = F_UNLCK;
			lock.fl_type  = F_UNLCK;
			lock.fl_start = 0;
			lock.fl_start = 0;
			lock.fl_end   = OFFSET_MAX;
			lock.fl_end   = OFFSET_MAX;
@@ -192,7 +195,7 @@ again:
			goto again;
			goto again;
		}
		}
	}
	}
	spin_unlock(&inode->i_lock);
	spin_unlock(&flctx->flc_lock);


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


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


	spin_lock(&inode->i_lock);
	if (flctx && !list_empty_careful(&flctx->flc_posix)) {
	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) {
			if (fl->fl_lmops == &nlmsvc_lock_operations) {
			spin_unlock(&inode->i_lock);
				spin_unlock(&flctx->flc_lock);
				return 1;
				return 1;
			}
			}
		}
		}
	spin_unlock(&inode->i_lock);
		spin_unlock(&flctx->flc_lock);
	}
	file->f_locks = 0;
	file->f_locks = 0;
	return 0;
	return 0;
}
}
Loading