Fix a lockdep warning in fasync_helper()
authorJonathan Corbet <corbet@lwn.net>
Fri, 27 Mar 2009 18:24:31 +0000 (12:24 -0600)
committerJonathan Corbet <corbet@lwn.net>
Mon, 30 Mar 2009 14:00:24 +0000 (08:00 -0600)
Lockdep gripes if file->f_lock is taken in a no-IRQ situation, since that
is not always the case.  We don't really want to disable IRQs for every
acquisition of f_lock; instead, just move it outside of fasync_lock.

Reported-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Reported-by: Larry Finger <Larry.Finger@lwfinger.net>
Reported-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
fs/fcntl.c
include/linux/fs.h

index d865ca6..cc8e4de 100644 (file)
@@ -531,6 +531,12 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
                if (!new)
                        return -ENOMEM;
        }
+
+       /*
+        * We need to take f_lock first since it's not an IRQ-safe
+        * lock.
+        */
+       spin_lock(&filp->f_lock);
        write_lock_irq(&fasync_lock);
        for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
                if (fa->fa_file == filp) {
@@ -555,14 +561,12 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
                result = 1;
        }
 out:
-       /* Fix up FASYNC bit while still holding fasync_lock */
-       spin_lock(&filp->f_lock);
        if (on)
                filp->f_flags |= FASYNC;
        else
                filp->f_flags &= ~FASYNC;
-       spin_unlock(&filp->f_lock);
        write_unlock_irq(&fasync_lock);
+       spin_unlock(&filp->f_lock);
        return result;
 }
 
index 7428c6d..2f13c1d 100644 (file)
@@ -848,7 +848,7 @@ struct file {
 #define f_dentry       f_path.dentry
 #define f_vfsmnt       f_path.mnt
        const struct file_operations    *f_op;
-       spinlock_t              f_lock;  /* f_ep_links, f_flags */
+       spinlock_t              f_lock;  /* f_ep_links, f_flags, no IRQ */
        atomic_long_t           f_count;
        unsigned int            f_flags;
        fmode_t                 f_mode;