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

Commit 7420a8c0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'flock' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/bkl:
  locks: turn lock_flocks into a spinlock
  fasync: re-organize fasync entry insertion to allow it under a spinlock
  locks/nfsd: allocate file lock outside of spinlock
  lockd: fix nlmsvc_notify_blocked locking
  lockd: push lock_flocks down
parents 12ba8d1e 72f98e72
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ config EXPORTFS
config FILE_LOCKING
	bool "Enable POSIX file locking API" if EMBEDDED
	default y
	select BKL # while lockd still uses it.
	help
	  This option enables standard file locking support, required
          for filesystems like NFS and for the flock() system
+50 −16
Original line number Diff line number Diff line
@@ -640,7 +640,7 @@ static void fasync_free_rcu(struct rcu_head *head)
 * match the state "is the filp on a fasync list".
 *
 */
static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
{
	struct fasync_struct *fa, **fp;
	int result = 0;
@@ -666,21 +666,28 @@ static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
	return result;
}

struct fasync_struct *fasync_alloc(void)
{
	return kmem_cache_alloc(fasync_cache, GFP_KERNEL);
}

/*
 * Add a fasync entry. Return negative on error, positive if
 * added, and zero if did nothing but change an existing one.
 *
 * NOTE! It is very important that the FASYNC flag always
 * match the state "is the filp on a fasync list".
 * NOTE! This can be used only for unused fasync entries:
 * entries that actually got inserted on the fasync list
 * need to be released by rcu - see fasync_remove_entry.
 */
static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp)
void fasync_free(struct fasync_struct *new)
{
	struct fasync_struct *new, *fa, **fp;
	int result = 0;
	kmem_cache_free(fasync_cache, new);
}

	new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
	if (!new)
		return -ENOMEM;
/*
 * Insert a new entry into the fasync list.  Return the pointer to the
 * old one if we didn't use the new one.
 */
struct fasync_struct *fasync_insert_entry(int fd, struct file *filp, struct fasync_struct **fapp, struct fasync_struct *new)
{
        struct fasync_struct *fa, **fp;

	spin_lock(&filp->f_lock);
	spin_lock(&fasync_lock);
@@ -691,8 +698,6 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa
		spin_lock_irq(&fa->fa_lock);
		fa->fa_fd = fd;
		spin_unlock_irq(&fa->fa_lock);

		kmem_cache_free(fasync_cache, new);
		goto out;
	}

@@ -702,13 +707,42 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa
	new->fa_fd = fd;
	new->fa_next = *fapp;
	rcu_assign_pointer(*fapp, new);
	result = 1;
	filp->f_flags |= FASYNC;

out:
	spin_unlock(&fasync_lock);
	spin_unlock(&filp->f_lock);
	return result;
	return fa;
}

/*
 * Add a fasync entry. Return negative on error, positive if
 * added, and zero if did nothing but change an existing one.
 *
 * NOTE! It is very important that the FASYNC flag always
 * match the state "is the filp on a fasync list".
 */
static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp)
{
	struct fasync_struct *new;

	new = fasync_alloc();
	if (!new)
		return -ENOMEM;

	/*
	 * fasync_insert_entry() returns the old (update) entry if
	 * it existed.
	 *
	 * So free the (unused) new entry and return 0 to let the
	 * caller know that we didn't add any new fasync entries.
	 */
	if (fasync_insert_entry(fd, filp, fapp, new)) {
		fasync_free(new);
		return 0;
	}

	return 1;
}

/*
+0 −11
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@
#include <linux/in.h>
#include <linux/uio.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
@@ -130,15 +129,6 @@ lockd(void *vrqstp)

	dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");

	/*
	 * FIXME: it would be nice if lockd didn't spend its entire life
	 * running under the BKL. At the very least, it would be good to
	 * have someone clarify what it's intended to protect here. I've
	 * seen some handwavy posts about posix locking needing to be
	 * done under the BKL, but it's far from clear.
	 */
	lock_kernel();

	if (!nlm_timeout)
		nlm_timeout = LOCKD_DFLT_TIMEO;
	nlmsvc_timeout = nlm_timeout * HZ;
@@ -195,7 +185,6 @@ lockd(void *vrqstp)
	if (nlmsvc_ops)
		nlmsvc_invalidate_all();
	nlm_shutdown_hosts();
	unlock_kernel();
	return 0;
}

+4 −2
Original line number Diff line number Diff line
@@ -700,14 +700,16 @@ nlmsvc_notify_blocked(struct file_lock *fl)
	struct nlm_block	*block;

	dprintk("lockd: VFS unblock notification for block %p\n", fl);
	spin_lock(&nlm_blocked_lock);
	list_for_each_entry(block, &nlm_blocked, b_list) {
		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
			nlmsvc_insert_block(block, 0);
			nlmsvc_insert_block_locked(block, 0);
			spin_unlock(&nlm_blocked_lock);
			svc_wake_up(block->b_daemon);
			return;
		}
	}

	spin_unlock(&nlm_blocked_lock);
	printk(KERN_WARNING "lockd: notification for unknown block!\n");
}

+8 −1
Original line number Diff line number Diff line
@@ -170,6 +170,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,

again:
	file->f_locks = 0;
	lock_flocks(); /* protects i_flock list */
	for (fl = inode->i_flock; fl; fl = fl->fl_next) {
		if (fl->fl_lmops != &nlmsvc_lock_operations)
			continue;
@@ -181,6 +182,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
		if (match(lockhost, host)) {
			struct file_lock lock = *fl;

			unlock_flocks();
			lock.fl_type  = F_UNLCK;
			lock.fl_start = 0;
			lock.fl_end   = OFFSET_MAX;
@@ -192,6 +194,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
			goto again;
		}
	}
	unlock_flocks();

	return 0;
}
@@ -226,10 +229,14 @@ nlm_file_inuse(struct nlm_file *file)
	if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
		return 1;

	lock_flocks();
	for (fl = inode->i_flock; fl; fl = fl->fl_next) {
		if (fl->fl_lmops == &nlmsvc_lock_operations)
		if (fl->fl_lmops == &nlmsvc_lock_operations) {
			unlock_flocks();
			return 1;
		}
	}
	unlock_flocks();
	file->f_locks = 0;
	return 0;
}
Loading