fs/fcntl.c:kill_fasync_rcu() fa_lock must be IRQ-safe
authorAndrew Morton <[email protected]>
Tue, 29 Jun 2010 22:05:42 +0000 (15:05 -0700)
committerLinus Torvalds <[email protected]>
Tue, 29 Jun 2010 22:29:32 +0000 (15:29 -0700)
Fix a lockdep-splat-causing regression introduced by commit 989a2979205d
("fasync: RCU and fine grained locking").

kill_fasync() can be called from both process and hard-irq context, so
fa_lock must be taken with IRQs disabled.

Addresses https://bugzilla.kernel.org/show_bug.cgi?id=16230

Reported-by: Sergey Senozhatsky <[email protected]>
Reported-by: Dominik Brodowski <[email protected]>
Tested-by: Dominik Brodowski <[email protected]>
Cc: Maciej Rutecki <[email protected]>
Acked-by: Eric Dumazet <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Lai Jiangshan <[email protected]>
Cc: "David S. Miller" <[email protected]>
Acked-by: Peter Zijlstra <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
fs/fcntl.c

index 51e11bf5708f2430cca213485d597ff070f228af..9d175d623aabc5e7c99a83e75e6c970a340465c6 100644 (file)
@@ -733,12 +733,14 @@ static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
 {
        while (fa) {
                struct fown_struct *fown;
+               unsigned long flags;
+
                if (fa->magic != FASYNC_MAGIC) {
                        printk(KERN_ERR "kill_fasync: bad magic number in "
                               "fasync_struct!\n");
                        return;
                }
-               spin_lock(&fa->fa_lock);
+               spin_lock_irqsave(&fa->fa_lock, flags);
                if (fa->fa_file) {
                        fown = &fa->fa_file->f_owner;
                        /* Don't send SIGURG to processes which have not set a
@@ -747,7 +749,7 @@ static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
                        if (!(sig == SIGURG && fown->signum == 0))
                                send_sigio(fown, fa->fa_fd, band);
                }
-               spin_unlock(&fa->fa_lock);
+               spin_unlock_irqrestore(&fa->fa_lock, flags);
                fa = rcu_dereference(fa->fa_next);
        }
 }