[XFS] Add lockdep support for XFS
authorLachlan McIlroy <lachlan@sgi.com>
Tue, 8 May 2007 03:50:19 +0000 (13:50 +1000)
committerTim Shimmin <tes@sgi.com>
Tue, 8 May 2007 03:50:19 +0000 (13:50 +1000)
SGI-PV: 963965
SGI-Modid: xfs-linux-melb:xfs-kern:28485a

Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
fs/xfs/linux-2.6/mrlock.h
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_vfsops.c
fs/xfs/xfs_vnodeops.c

index af168a1..c110bb0 100644 (file)
@@ -43,6 +43,18 @@ static inline void mrupdate(mrlock_t *mrp)
        mrp->mr_writer = 1;
 }
 
+static inline void mraccess_nested(mrlock_t *mrp, int subclass)
+{
+       down_read_nested(&mrp->mr_lock, subclass);
+}
+
+static inline void mrupdate_nested(mrlock_t *mrp, int subclass)
+{
+       down_write_nested(&mrp->mr_lock, subclass);
+       mrp->mr_writer = 1;
+}
+
+
 static inline int mrtryaccess(mrlock_t *mrp)
 {
        return down_read_trylock(&mrp->mr_lock);
index c1c89da..114433a 100644 (file)
@@ -879,17 +879,17 @@ xfs_ilock(xfs_inode_t     *ip,
               (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
        ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
               (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-       ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0);
+       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
 
        if (lock_flags & XFS_IOLOCK_EXCL) {
-               mrupdate(&ip->i_iolock);
+               mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
        } else if (lock_flags & XFS_IOLOCK_SHARED) {
-               mraccess(&ip->i_iolock);
+               mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
        }
        if (lock_flags & XFS_ILOCK_EXCL) {
-               mrupdate(&ip->i_lock);
+               mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
        } else if (lock_flags & XFS_ILOCK_SHARED) {
-               mraccess(&ip->i_lock);
+               mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
        }
        xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)__return_address);
 }
@@ -923,7 +923,7 @@ xfs_ilock_nowait(xfs_inode_t        *ip,
               (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
        ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
               (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-       ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0);
+       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
 
        iolocked = 0;
        if (lock_flags & XFS_IOLOCK_EXCL) {
@@ -983,7 +983,8 @@ xfs_iunlock(xfs_inode_t     *ip,
               (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
        ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
               (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
-       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY)) == 0);
+       ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY |
+                       XFS_LOCK_DEP_MASK)) == 0);
        ASSERT(lock_flags != 0);
 
        if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) {
index cfe7b58..f75afec 100644 (file)
@@ -382,26 +382,58 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags)
 
 /*
  * Flags for inode locking.
+ * Bit ranges: 1<<1  - 1<<16-1 -- iolock/ilock modes (bitfield)
+ *             1<<16 - 1<<32-1 -- lockdep annotation (integers)
  */
-#define        XFS_IOLOCK_EXCL         0x001
-#define        XFS_IOLOCK_SHARED       0x002
-#define        XFS_ILOCK_EXCL          0x004
-#define        XFS_ILOCK_SHARED        0x008
-#define        XFS_IUNLOCK_NONOTIFY    0x010
-/*     XFS_IOLOCK_NESTED       0x020 */
-#define XFS_EXTENT_TOKEN_RD    0x040
-#define XFS_SIZE_TOKEN_RD      0x080
+#define        XFS_IOLOCK_EXCL         (1<<0)
+#define        XFS_IOLOCK_SHARED       (1<<1)
+#define        XFS_ILOCK_EXCL          (1<<2)
+#define        XFS_ILOCK_SHARED        (1<<3)
+#define        XFS_IUNLOCK_NONOTIFY    (1<<4)
+/*     #define XFS_IOLOCK_NESTED       (1<<5)  */
+#define XFS_EXTENT_TOKEN_RD    (1<<6)
+#define XFS_SIZE_TOKEN_RD      (1<<7)
 #define XFS_EXTSIZE_RD         (XFS_EXTENT_TOKEN_RD|XFS_SIZE_TOKEN_RD)
-#define XFS_WILLLEND           0x100   /* Always acquire tokens for lending */
+#define XFS_WILLLEND           (1<<8)  /* Always acquire tokens for lending */
 #define XFS_EXTENT_TOKEN_WR    (XFS_EXTENT_TOKEN_RD | XFS_WILLLEND)
 #define XFS_SIZE_TOKEN_WR       (XFS_SIZE_TOKEN_RD | XFS_WILLLEND)
 #define XFS_EXTSIZE_WR         (XFS_EXTSIZE_RD | XFS_WILLLEND)
-/*     XFS_SIZE_TOKEN_WANT     0x200 */
+/* TODO:XFS_SIZE_TOKEN_WANT    (1<<9) */
 
-#define XFS_LOCK_MASK  \
-       (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL | \
-        XFS_ILOCK_SHARED | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD | \
-        XFS_WILLLEND)
+#define XFS_LOCK_MASK          (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED \
+                               | XFS_ILOCK_EXCL | XFS_ILOCK_SHARED \
+                               | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD \
+                               | XFS_WILLLEND)
+
+/*
+ * Flags for lockdep annotations.
+ *
+ * XFS_I[O]LOCK_PARENT - for operations that require locking two inodes
+ * (ie directory operations that require locking a directory inode and
+ * an entry inode).  The first inode gets locked with this flag so it
+ * gets a lockdep subclass of 1 and the second lock will have a lockdep
+ * subclass of 0.
+ *
+ * XFS_I[O]LOCK_INUMORDER - for locking several inodes at the some time
+ * with xfs_lock_inodes().  This flag is used as the starting subclass
+ * and each subsequent lock acquired will increment the subclass by one.
+ * So the first lock acquired will have a lockdep subclass of 2, the
+ * second lock will have a lockdep subclass of 3, and so on.
+ */
+#define XFS_IOLOCK_SHIFT       16
+#define        XFS_IOLOCK_PARENT       (1 << XFS_IOLOCK_SHIFT)
+#define        XFS_IOLOCK_INUMORDER    (2 << XFS_IOLOCK_SHIFT)
+
+#define XFS_ILOCK_SHIFT                24
+#define        XFS_ILOCK_PARENT        (1 << XFS_ILOCK_SHIFT)
+#define        XFS_ILOCK_INUMORDER     (2 << XFS_ILOCK_SHIFT)
+
+#define XFS_IOLOCK_DEP_MASK    0x00ff0000
+#define XFS_ILOCK_DEP_MASK     0xff000000
+#define XFS_LOCK_DEP_MASK      (XFS_IOLOCK_DEP_MASK | XFS_ILOCK_DEP_MASK)
+
+#define XFS_IOLOCK_DEP(flags)  (((flags) & XFS_IOLOCK_DEP_MASK) >> XFS_IOLOCK_SHIFT)
+#define XFS_ILOCK_DEP(flags)   (((flags) & XFS_ILOCK_DEP_MASK) >> XFS_ILOCK_SHIFT)
 
 /*
  * Flags for xfs_iflush()
index 2e830e7..65c5612 100644 (file)
@@ -696,7 +696,7 @@ xfs_unmount_flush(
        bhv_vnode_t     *rvp = XFS_ITOV(rip);
        int             error;
 
-       xfs_ilock(rip, XFS_ILOCK_EXCL);
+       xfs_ilock(rip, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
        xfs_iflock(rip);
 
        /*
index e2c9bbc..de17aed 100644 (file)
@@ -1947,7 +1947,7 @@ xfs_create(
                goto error_return;
        }
 
-       xfs_ilock(dp, XFS_ILOCK_EXCL);
+       xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 
        XFS_BMAP_INIT(&free_list, &first_block);
 
@@ -2141,7 +2141,7 @@ xfs_lock_dir_and_entry(
        attempts = 0;
 
 again:
-       xfs_ilock(dp, XFS_ILOCK_EXCL);
+       xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 
        e_inum = ip->i_ino;
 
@@ -2209,6 +2209,21 @@ int xfs_lots_retries;
 int xfs_lock_delays;
 #endif
 
+/*
+ * Bump the subclass so xfs_lock_inodes() acquires each lock with
+ * a different value
+ */
+static inline int
+xfs_lock_inumorder(int lock_mode, int subclass)
+{
+       if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
+               lock_mode |= (subclass + XFS_IOLOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
+       if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
+               lock_mode |= (subclass + XFS_ILOCK_INUMORDER) << XFS_ILOCK_SHIFT;
+
+       return lock_mode;
+}
+
 /*
  * The following routine will lock n inodes in exclusive mode.
  * We assume the caller calls us with the inodes in i_ino order.
@@ -2276,7 +2291,7 @@ again:
                         * that is in the AIL.
                         */
                        ASSERT(i != 0);
-                       if (!xfs_ilock_nowait(ips[i], lock_mode)) {
+                       if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) {
                                attempts++;
 
                                /*
@@ -2311,7 +2326,7 @@ again:
                                goto again;
                        }
                } else {
-                       xfs_ilock(ips[i], lock_mode);
+                       xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i));
                }
        }
 
@@ -2845,7 +2860,7 @@ xfs_mkdir(
                goto error_return;
        }
 
-       xfs_ilock(dp, XFS_ILOCK_EXCL);
+       xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 
        /*
         * Check for directory link count overflow.
@@ -3399,7 +3414,7 @@ xfs_symlink(
                goto error_return;
        }
 
-       xfs_ilock(dp, XFS_ILOCK_EXCL);
+       xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
 
        /*
         * Check whether the directory allows new symlinks or not.