]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
xfs: implement batched inode lookups for AG walking
authorDave Chinner <dchinner@redhat.com>
Tue, 28 Sep 2010 02:28:19 +0000 (12:28 +1000)
committerAlex Elder <aelder@sgi.com>
Mon, 18 Oct 2010 20:07:53 +0000 (15:07 -0500)
With the reclaim code separated from the generic walking code, it is
simple to implement batched lookups for the generic walk code.
Separate out the inode validation from the execute operations and
modify the tree lookups to get a batch of inodes at a time.

Reclaim operations will be optimised separately.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alex Elder <aelder@sgi.com>
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/linux-2.6/xfs_sync.h

index 37fc2c0a4d255c38ddbc528479518b26f1f610d4..0ed3d0ae3c2870ca0dd73ed8edcf7f314e966cad 100644 (file)
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
+/*
+ * The inode lookup is done in batches to keep the amount of lock traffic and
+ * radix tree lookups to a minimum. The batch size is a trade off between
+ * lookup reduction and stack usage. This is in the reclaim path, so we can't
+ * be too greedy.
+ */
+#define XFS_LOOKUP_BATCH       32
+
 STATIC int
 xfs_inode_ag_walk_grab(
        struct xfs_inode        *ip)
@@ -66,7 +74,6 @@ xfs_inode_ag_walk_grab(
        return 0;
 }
 
-
 STATIC int
 xfs_inode_ag_walk(
        struct xfs_mount        *mp,
@@ -79,54 +86,69 @@ xfs_inode_ag_walk(
        int                     last_error = 0;
        int                     skipped;
        int                     done;
+       int                     nr_found;
 
 restart:
        done = 0;
        skipped = 0;
        first_index = 0;
+       nr_found = 0;
        do {
+               struct xfs_inode *batch[XFS_LOOKUP_BATCH];
                int             error = 0;
-               int             nr_found;
-               xfs_inode_t     *ip;
+               int             i;
 
                read_lock(&pag->pag_ici_lock);
                nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
-                               (void **)&ip, first_index, 1);
+                                       (void **)batch, first_index,
+                                       XFS_LOOKUP_BATCH);
                if (!nr_found) {
                        read_unlock(&pag->pag_ici_lock);
                        break;
                }
 
                /*
-                * Update the index for the next lookup. Catch overflows
-                * into the next AG range which can occur if we have inodes
-                * in the last block of the AG and we are currently
-                * pointing to the last inode.
+                * Grab the inodes before we drop the lock. if we found
+                * nothing, nr == 0 and the loop will be skipped.
                 */
-               first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
-               if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
-                       done = 1;
+               for (i = 0; i < nr_found; i++) {
+                       struct xfs_inode *ip = batch[i];
 
-               if (xfs_inode_ag_walk_grab(ip)) {
-                       read_unlock(&pag->pag_ici_lock);
-                       continue;
+                       if (done || xfs_inode_ag_walk_grab(ip))
+                               batch[i] = NULL;
+
+                       /*
+                        * Update the index for the next lookup. Catch overflows
+                        * into the next AG range which can occur if we have inodes
+                        * in the last block of the AG and we are currently
+                        * pointing to the last inode.
+                        */
+                       first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1);
+                       if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino))
+                               done = 1;
                }
+
+               /* unlock now we've grabbed the inodes. */
                read_unlock(&pag->pag_ici_lock);
 
-               error = execute(ip, pag, flags);
-               IRELE(ip);
-               if (error == EAGAIN) {
-                       skipped++;
-                       continue;
+               for (i = 0; i < nr_found; i++) {
+                       if (!batch[i])
+                               continue;
+                       error = execute(batch[i], pag, flags);
+                       IRELE(batch[i]);
+                       if (error == EAGAIN) {
+                               skipped++;
+                               continue;
+                       }
+                       if (error && last_error != EFSCORRUPTED)
+                               last_error = error;
                }
-               if (error)
-                       last_error = error;
 
                /* bail out if the filesystem is corrupted.  */
                if (error == EFSCORRUPTED)
                        break;
 
-       } while (!done);
+       } while (nr_found && !done);
 
        if (skipped) {
                delay(1);
index e8a352896d203dd7763c118f6379f67c1a624b7b..32ba6628290ce4f14162d28c20eba63a23db1ffb 100644 (file)
@@ -47,7 +47,7 @@ void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip);
 void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,
                                struct xfs_inode *ip);
 
-int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag);
+int xfs_sync_inode_grab(struct xfs_inode *ip);
 int xfs_inode_ag_iterator(struct xfs_mount *mp,
        int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
        int flags);