xfs
[Top] [All Lists]

[PATCH 5/7] XFS: Make use of the init-once slab optimisation.

To: xfs@xxxxxxxxxxx
Subject: [PATCH 5/7] XFS: Make use of the init-once slab optimisation.
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Thu, 14 Aug 2008 17:14:41 +1000
Cc: Dave Chinner <david@xxxxxxxxxxxxx>
In-reply-to: <1218698083-11226-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1218698083-11226-1-git-send-email-david@xxxxxxxxxxxxx>
Sender: xfs-bounce@xxxxxxxxxxx
To avoid having to initialise some fields of the XFS inode
on every allocation, we can use the slab init-once feature
to initialise them. All we have to guarantee is that when
we free the inode, all it's entries are in the initial state.
Add asserts where possible to ensure debug kernels check this
initial state before freeing and after allocation.

Signed-off-by: Dave Chinner <david@xxxxxxxxxxxxx>
---
 fs/xfs/linux-2.6/xfs_super.c |   30 +++++++++++++++++++-
 fs/xfs/xfs_iget.c            |    7 ----
 fs/xfs/xfs_inode.c           |   63 ++++++++++++++++++++++++++++++++++--------
 fs/xfs/xfs_inode.h           |    1 +
 fs/xfs/xfs_itable.c          |   14 ++++----
 5 files changed, 88 insertions(+), 27 deletions(-)

diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 188057b..6529d2b 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -888,6 +888,34 @@ xfs_fs_inode_init_once(
        inode_init_once((struct inode *)vnode);
 }
 
+
+/*
+ * Slab object creation initialisation for the XFS inode.
+ * This covers only the idempotent fields in the XFS inode;
+ * all other fields need to be initialised on allocation
+ * from the slab. This avoids the need to repeatedly intialise
+ * fields in the xfs inode that left in the initialise state
+ * when freeing the inode.
+ */
+void
+xfs_inode_init_once(
+       void                    *inode)
+{
+       struct xfs_inode        *ip = inode;
+
+       memset(ip, 0, sizeof(struct xfs_inode));
+       atomic_set(&ip->i_iocount, 0);
+       atomic_set(&ip->i_pincount, 0);
+       spin_lock_init(&ip->i_flags_lock);
+       INIT_LIST_HEAD(&ip->i_reclaim);
+       init_waitqueue_head(&ip->i_ipin_wait);
+       initnsema(&ip->i_flock, 1, "xfsfino");
+
+       mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
+                    "xfsino", ip->i_ino);
+       mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
+}
+
 /*
  * The inode has been marked dirty at the VFS. because we are using unhashed
  * inodes now, we have to move the inode to the sb->s_dirty_list ourselves as
@@ -1924,7 +1952,7 @@ xfs_init_zones(void)
        xfs_inode_zone =
                kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode",
                                        KM_ZONE_HWALIGN | KM_ZONE_RECLAIM |
-                                       KM_ZONE_SPREAD, NULL);
+                                       KM_ZONE_SPREAD, xfs_inode_init_once);
        if (!xfs_inode_zone)
                goto out_destroy_efi_zone;
 
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 640ce29..1f539f9 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -165,13 +165,6 @@ xfs_iget_cache_miss(
 
        xfs_itrace_exit_tag(ip, "xfs_iget.alloc");
 
-       mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER,
-                    "xfsino", ip->i_ino);
-       mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino);
-       init_waitqueue_head(&ip->i_ipin_wait);
-       atomic_set(&ip->i_pincount, 0);
-       initnsema(&ip->i_flock, 1, "xfsfino");
-
        if (lock_flags)
                xfs_ilock(ip, lock_flags);
 
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index ced22e4..e2ac32c 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -788,6 +788,48 @@ xfs_dic2xflags(
 }
 
 /*
+ * Allocate and initialise an xfs_inode.
+ */
+struct xfs_inode *
+xfs_inode_alloc(
+       struct xfs_mount        *mp,
+       xfs_ino_t               ino)
+{
+       struct xfs_inode        *ip;
+
+       /*
+        * if this didn't occur in transactions, we could use
+        * KM_MAYFAIL and return NULL here on ENOMEM. Set the
+        * code up to do this anyway.
+        */
+       ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP);
+       if (!ip)
+               return NULL;
+
+       ASSERT(atomic_read(&ip->i_iocount) == 0);
+       ASSERT(atomic_read(&ip->i_pincount) == 0);
+       ASSERT(!spin_is_locked(&ip->i_flags_lock));
+       ASSERT(list_empty(&ip->i_reclaim));
+
+       ip->i_ino = ino;
+       ip->i_mount = mp;
+       ip->i_blkno = 0;
+       ip->i_len = 0;
+       ip->i_boffset =0;
+       ip->i_afp = NULL;
+       memset(&ip->i_df, 0, sizeof(xfs_ifork_t));
+       ip->i_flags = 0;
+       ip->i_update_core = 0;
+       ip->i_update_size = 0;
+       ip->i_delayed_blks = 0;
+       memset(&ip->i_d, 0, sizeof(xfs_icdinode_t));
+       ip->i_size = 0;
+       ip->i_new_size = 0;
+
+       return ip;
+}
+
+/*
  * Given a mount structure and an inode number, return a pointer
  * to a newly allocated in-core inode corresponding to the given
  * inode number.
@@ -809,13 +851,9 @@ xfs_iread(
        xfs_inode_t     *ip;
        int             error;
 
-       ASSERT(xfs_inode_zone != NULL);
-
-       ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP);
-       ip->i_ino = ino;
-       ip->i_mount = mp;
-       atomic_set(&ip->i_iocount, 0);
-       spin_lock_init(&ip->i_flags_lock);
+       ip = xfs_inode_alloc(mp, ino);
+       if (!ip)
+               return ENOMEM;
 
        /*
         * Get pointer's to the on-disk inode and the buffer containing it.
@@ -911,8 +949,6 @@ xfs_iread(
                        XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
        }
 
-       INIT_LIST_HEAD(&ip->i_reclaim);
-
        /*
         * The inode format changed when we moved the link count and
         * made it 32 bits long.  If this is an old format inode,
@@ -2624,9 +2660,6 @@ xfs_idestroy(
        }
        if (ip->i_afp)
                xfs_idestroy_fork(ip, XFS_ATTR_FORK);
-       mrfree(&ip->i_lock);
-       mrfree(&ip->i_iolock);
-       freesema(&ip->i_flock);
 
 #ifdef XFS_INODE_TRACE
        ktrace_free(ip->i_trace);
@@ -2665,7 +2698,13 @@ xfs_idestroy(
                                spin_unlock(&mp->m_ail_lock);
                }
                xfs_inode_item_destroy(ip);
+               ip->i_itemp = NULL;
        }
+       /* asserts to verify all state is correct here */
+       ASSERT(atomic_read(&ip->i_iocount) == 0);
+       ASSERT(atomic_read(&ip->i_pincount) == 0);
+       ASSERT(!spin_is_locked(&ip->i_flags_lock));
+       ASSERT(list_empty(&ip->i_reclaim));
        kmem_zone_free(xfs_inode_zone, ip);
 }
 
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index d97d6ec..d75c820 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -508,6 +508,7 @@ int         xfs_itruncate_finish(struct xfs_trans **, 
xfs_inode_t *,
                                     xfs_fsize_t, int, int);
 int            xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
 
+struct xfs_inode * xfs_inode_alloc(struct xfs_mount *, xfs_ino_t);
 void           xfs_idestroy_fork(xfs_inode_t *, int);
 void           xfs_idestroy(xfs_inode_t *);
 void           xfs_idata_realloc(xfs_inode_t *, int, int);
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index cf6754a..4f4c939 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -594,21 +594,21 @@ xfs_bulkstat(
                                                /*
                                                 * Get the inode cluster buffer
                                                 */
-                                               ASSERT(xfs_inode_zone != NULL);
-                                               ip = 
kmem_zone_zalloc(xfs_inode_zone,
-                                                                     KM_SLEEP);
-                                               ip->i_ino = ino;
-                                               ip->i_mount = mp;
-                                               
spin_lock_init(&ip->i_flags_lock);
                                                if (bp)
                                                        xfs_buf_relse(bp);
+                                               ip = xfs_inode_alloc(mp, ino);
+                                               if (!ip) {
+                                                       bp = NULL;
+                                                       rval = ENOMEM;
+                                                       break;
+                                               }
                                                error = xfs_itobp(mp, NULL, ip,
                                                                &dip, &bp, bno,
                                                                
XFS_IMAP_BULKSTAT,
                                                                XFS_BUF_LOCK);
                                                if (!error)
                                                        clustidx = 
ip->i_boffset / mp->m_sb.sb_inodesize;
-                                               kmem_zone_free(xfs_inode_zone, 
ip);
+                                               xfs_idestroy(ip);
                                                if (XFS_TEST_ERROR(error != 0,
                                                                   mp, 
XFS_ERRTAG_BULKSTAT_READ_CHUNK,
                                                                   
XFS_RANDOM_BULKSTAT_READ_CHUNK)) {
-- 
1.5.6


<Prev in Thread] Current Thread [Next in Thread>