Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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 Diff line number Diff line
@@ -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);
@@ -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;
@@ -279,8 +278,11 @@ 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) {
	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;
@@ -291,9 +293,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
			goto fail;
		++l;
	}
	}
	for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
		if (lock->fl_flags & FL_FLOCK) {
	list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
		++seen_flock;
		if (seen_flock > num_flock_locks) {
			err = -ENOSPC;
@@ -304,8 +304,8 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
			goto fail;
		++l;
	}
	}
fail:
	spin_unlock(&ctx->flc_lock);
	return err;
}

+0 −4
Original line number 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;

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)
+11 −23
Original line number Diff line number Diff line
@@ -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;
@@ -1132,8 +1127,9 @@ 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;
@@ -1141,21 +1137,17 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)

	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;
@@ -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
@@ -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;
+2 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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);
+16 −10
Original line number 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 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;

@@ -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;
@@ -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;
}
@@ -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 (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(&inode->i_lock);
				spin_unlock(&flctx->flc_lock);
				return 1;
			}
		}
	spin_unlock(&inode->i_lock);
		spin_unlock(&flctx->flc_lock);
	}
	file->f_locks = 0;
	return 0;
}
Loading