Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes
[pandora-kernel.git] / fs / fcntl.c
index 452d02f..f74d270 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/dnotify.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/pipe_fs_i.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
 #include <linux/signal.h>
@@ -412,6 +413,10 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
        case F_NOTIFY:
                err = fcntl_dirnotify(fd, filp, arg);
                break;
+       case F_SETPIPE_SZ:
+       case F_GETPIPE_SZ:
+               err = pipe_fcntl(filp, cmd, arg);
+               break;
        default:
                break;
        }
@@ -614,9 +619,15 @@ int send_sigurg(struct fown_struct *fown)
        return ret;
 }
 
-static DEFINE_RWLOCK(fasync_lock);
+static DEFINE_SPINLOCK(fasync_lock);
 static struct kmem_cache *fasync_cache __read_mostly;
 
+static void fasync_free_rcu(struct rcu_head *head)
+{
+       kmem_cache_free(fasync_cache,
+                       container_of(head, struct fasync_struct, fa_rcu));
+}
+
 /*
  * Remove a fasync entry. If successfully removed, return
  * positive and clear the FASYNC flag. If no entry exists,
@@ -625,8 +636,6 @@ static struct kmem_cache *fasync_cache __read_mostly;
  * NOTE! It is very important that the FASYNC flag always
  * match the state "is the filp on a fasync list".
  *
- * We always take the 'filp->f_lock', in since fasync_lock
- * needs to be irq-safe.
  */
 static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
 {
@@ -634,17 +643,22 @@ static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
        int result = 0;
 
        spin_lock(&filp->f_lock);
-       write_lock_irq(&fasync_lock);
+       spin_lock(&fasync_lock);
        for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
                if (fa->fa_file != filp)
                        continue;
+
+               spin_lock_irq(&fa->fa_lock);
+               fa->fa_file = NULL;
+               spin_unlock_irq(&fa->fa_lock);
+
                *fp = fa->fa_next;
-               kmem_cache_free(fasync_cache, fa);
+               call_rcu(&fa->fa_rcu, fasync_free_rcu);
                filp->f_flags &= ~FASYNC;
                result = 1;
                break;
        }
-       write_unlock_irq(&fasync_lock);
+       spin_unlock(&fasync_lock);
        spin_unlock(&filp->f_lock);
        return result;
 }
@@ -666,25 +680,30 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa
                return -ENOMEM;
 
        spin_lock(&filp->f_lock);
-       write_lock_irq(&fasync_lock);
+       spin_lock(&fasync_lock);
        for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
                if (fa->fa_file != filp)
                        continue;
+
+               spin_lock_irq(&fa->fa_lock);
                fa->fa_fd = fd;
+               spin_unlock_irq(&fa->fa_lock);
+
                kmem_cache_free(fasync_cache, new);
                goto out;
        }
 
+       spin_lock_init(&new->fa_lock);
        new->magic = FASYNC_MAGIC;
        new->fa_file = filp;
        new->fa_fd = fd;
        new->fa_next = *fapp;
-       *fapp = new;
+       rcu_assign_pointer(*fapp, new);
        result = 1;
        filp->f_flags |= FASYNC;
 
 out:
-       write_unlock_irq(&fasync_lock);
+       spin_unlock(&fasync_lock);
        spin_unlock(&filp->f_lock);
        return result;
 }
@@ -704,37 +723,41 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
 
 EXPORT_SYMBOL(fasync_helper);
 
-void __kill_fasync(struct fasync_struct *fa, int sig, int band)
+/*
+ * rcu_read_lock() is held
+ */
+static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
 {
        while (fa) {
-               struct fown_struct * fown;
+               struct fown_struct *fown;
                if (fa->magic != FASYNC_MAGIC) {
                        printk(KERN_ERR "kill_fasync: bad magic number in "
                               "fasync_struct!\n");
                        return;
                }
-               fown = &fa->fa_file->f_owner;
-               /* Don't send SIGURG to processes which have not set a
-                  queued signum: SIGURG has its own default signalling
-                  mechanism. */
-               if (!(sig == SIGURG && fown->signum == 0))
-                       send_sigio(fown, fa->fa_fd, band);
-               fa = fa->fa_next;
+               spin_lock(&fa->fa_lock);
+               if (fa->fa_file) {
+                       fown = &fa->fa_file->f_owner;
+                       /* Don't send SIGURG to processes which have not set a
+                          queued signum: SIGURG has its own default signalling
+                          mechanism. */
+                       if (!(sig == SIGURG && fown->signum == 0))
+                               send_sigio(fown, fa->fa_fd, band);
+               }
+               spin_unlock(&fa->fa_lock);
+               fa = rcu_dereference(fa->fa_next);
        }
 }
 
-EXPORT_SYMBOL(__kill_fasync);
-
 void kill_fasync(struct fasync_struct **fp, int sig, int band)
 {
        /* First a quick test without locking: usually
         * the list is empty.
         */
        if (*fp) {
-               read_lock(&fasync_lock);
-               /* reread *fp after obtaining the lock */
-               __kill_fasync(*fp, sig, band);
-               read_unlock(&fasync_lock);
+               rcu_read_lock();
+               kill_fasync_rcu(rcu_dereference(*fp), sig, band);
+               rcu_read_unlock();
        }
 }
 EXPORT_SYMBOL(kill_fasync);