Remove xfs_icluster
PATCH 6/9 Remove xfs_icluster
Remove the xfs_icluster structure and replace with a radix tree lookup.
We don't need to keep a list of inodes in each cluster around anymore as we can look them up quickly when we need to. The only time we need to do this now is during inode writeback.
Factor the inode cluster writeback code out of xfs_iflush and convert it to use radix_tree_gang_lookup() instead of walking a list of inodes built when we first read in the inodes.
This remove 3 pointers from each xfs_inode structure and the xfs_icluster structure per inode cluster. Hence we reduce the cache footprint of the xfs_inodes by between 5-10% depending on cluster sparseness.
To be truly efficient we need a radix_tree_gang_lookup_range() call to stop searching once we are past the end of the cluster instead of trying to find a full cluster's worth of inodes.
Before (ia64):
$ cat /sys/slab/xfs_inode/object_size 536
After:
$ cat /sys/slab/xfs_inode/object_size 512
--- fs/xfs/linux-2.6/xfs_ksyms.c | 1 fs/xfs/xfs_iget.c | 49 ------- fs/xfs/xfs_inode.c | 266 ++++++++++++++++++++++++------------------- fs/xfs/xfs_inode.h | 16 -- fs/xfs/xfs_vfsops.c | 5 fs/xfs/xfsidbg.c | 4 6 files changed, 154 insertions(+), 187 deletions(-)
fs/xfs/xfs_iget.c +3 -46
@@ -78,7 +78,6 @@ xfs_iget_core(xfs_inode_t *ip;xfs_inode_t *iq;int error; -xfs_icluster_t *icl, *new_icl =NULL ;unsigned long first_index, mask;xfs_perag_t *pag;xfs_agino_t agino;
@@ -229,11 +228,9 @@ finish_inode: }/* -* This is a bit messy - we preallocate everything we _might_ -* need before we pick up the ici lock. That way we don't have to -* juggle locks and go all the way back to the start. +* Preload the radix tree so we can insert safely under the +* write spinlock. */ - new_icl =kmem_zone_alloc (xfs_icluster_zone,KM_SLEEP );if (radix_tree_preload (GFP_KERNEL )) {delay (1 ); goto again;
@@ -241,17 +238,6 @@ finish_inode: mask = ~(((XFS_INODE_CLUSTER_SIZE (mp) >> mp->m_sb.sb_inodelog)) -1 ); first_index = agino & mask;write_lock (&pag->pag_ici_lock); - -/* -* Find the cluster if it exists -*/ - icl =NULL ; -if (radix_tree_gang_lookup (&pag->pag_ici_root, (void **)&iq, - first_index,1 )) { -if ((XFS_INO_TO_AGINO (mp, iq->i_ino) & mask) == first_index) - icl = iq->i_cluster; - } -/* * insert the new inode */
@@ -266,30 +252,13 @@ finish_inode: }/* -* These values _must_ be set before releasing ihlock! +* These values _must_ be set before releasing the radix tree lock! */ ip->i_udquot = ip->i_gdquot =NULL ;xfs_iflags_set (ip,XFS_INEW ); -ASSERT (ip->i_cluster ==NULL ); - -if (!icl) { -spin_lock_init (&new_icl->icl_lock); -INIT_HLIST_HEAD (&new_icl->icl_inodes); - icl = new_icl; - new_icl =NULL ; - }else { -ASSERT (!hlist_empty (&icl->icl_inodes)); - } -spin_lock (&icl->icl_lock); -hlist_add_head (&ip->i_cnode, &icl->icl_inodes); - ip->i_cluster = icl; -spin_unlock (&icl->icl_lock); -write_unlock (&pag->pag_ici_lock);radix_tree_preload_end (); -if (new_icl) -kmem_zone_free (xfs_icluster_zone, new_icl);/* * Link ip to its mount and thread it on the mount's inode list.
@@ -528,18 +497,6 @@ xfs_iextract(xfs_put_perag (mp, pag);/* -* Remove from cluster list -*/ - mp = ip->i_mount; -spin_lock (&ip->i_cluster->icl_lock); -hlist_del (&ip->i_cnode); -spin_unlock (&ip->i_cluster->icl_lock); - -/* was last inode in cluster? */ -if (hlist_empty (&ip->i_cluster->icl_inodes)) -kmem_zone_free (xfs_icluster_zone, ip->i_cluster); - -/* * Remove from mount's inode list. */ XFS_MOUNT_ILOCK (mp);
fs/xfs/xfs_inode.c +151 -115
308 lines not on this page · raw message
fs/xfs/xfs_inode.h +0 -16
@@ -133,19 +133,6 @@ typedef struct dm_attrs_s { } dm_attrs_t;/* -* This is the xfs inode cluster structure. This structure is used by -* xfs_iflush to find inodes that share a cluster and can be flushed to disk at -* the same time. -*/ -typedef struct xfs_icluster { -struct hlist_head icl_inodes;/* list of inodes on cluster */ -xfs_daddr_t icl_blkno;/* starting block number of -* the cluster */ -struct xfs_buf *icl_buf;/* the inode buffer */ -spinlock_t icl_lock;/* inode list lock */ -}xfs_icluster_t ; - -/* * This is the xfs in-core inode structure. * Most of the on-disk inode is embedded in the i_d field. *
@@ -252,8 +239,6 @@ typedef struct xfs_inode {unsigned int i_delayed_blks;/* count of delay alloc blks */ xfs_icdinode_t i_d;/* most of ondisk inode */ -xfs_icluster_t *i_cluster;/* cluster list header */ -struct hlist_node i_cnode;/* cluster link node */ xfs_fsize_t i_size;/* in-memory size */ xfs_fsize_t i_new_size;/* size when write completes */
@@ -578,7 +563,6 @@ void xfs_inobp_check(struct xfs_mount *#define xfs_inobp_check (mp, bp)#endif /* DEBUG */ -extern struct kmem_zone *xfs_icluster_zone;extern struct kmem_zone *xfs_ifork_zone;extern struct kmem_zone *xfs_inode_zone;extern struct kmem_zone *xfs_ili_zone;
fs/xfs/xfs_vfsops.c +0 -5
@@ -113,9 +113,6 @@ xfs_init(void) xfs_ili_zone =kmem_zone_init_flags (sizeof (xfs_inode_log_item_t),"xfs_ili" ,KM_ZONE_SPREAD ,NULL ); - xfs_icluster_zone = -kmem_zone_init_flags (sizeof (xfs_icluster_t),"xfs_icluster" , -KM_ZONE_SPREAD ,NULL );/* * Allocate global trace buffers.
@@ -153,7 +150,6 @@ xfs_cleanup(void)extern kmem_zone_t *xfs_inode_zone;extern kmem_zone_t *xfs_efd_zone;extern kmem_zone_t *xfs_efi_zone; -extern kmem_zone_t *xfs_icluster_zone;xfs_cleanup_procfs ();xfs_sysctl_unregister ();
@@ -189,7 +185,6 @@ xfs_cleanup(void)kmem_zone_destroy (xfs_efi_zone);kmem_zone_destroy (xfs_ifork_zone);kmem_zone_destroy (xfs_ili_zone); -kmem_zone_destroy (xfs_icluster_zone); }/*
fs/xfs/linux-2.6/xfs_ksyms.c +0 -1
@@ -211,7 +211,6 @@ EXPORT_SYMBOL(xfs_bulkstat);EXPORT_SYMBOL (xfs_bunmapi);EXPORT_SYMBOL (xfs_bwrite);EXPORT_SYMBOL (xfs_change_file_space); -EXPORT_SYMBOL (xfs_icluster_zone);EXPORT_SYMBOL (xfs_dev_is_read_only);EXPORT_SYMBOL (xfs_dir_ialloc);EXPORT_SYMBOL (xfs_error_report);
fs/xfs/xfsidbg.c +0 -4
@@ -6465,10 +6465,6 @@ xfsidbg_xnode(xfs_inode_t *ip)qprintf (" dir trace 0x%p\n" , ip->i_dir_trace);#endif kdb_printf ("\n" ); -kdb_printf ("icluster 0x%p cnext 0x%p cprev 0x%p\n" , - ip->i_cluster, - ip->i_cnode.next, - ip->i_cnode.pprev);xfs_xnode_fork ("data" , &ip->i_df);xfs_xnode_fork ("attr" , ip->i_afp);kdb_printf ("\n" );
Quoted 10 lines · David Chinner
Remove the
xfs_iclusterstructure and replace with a radix tree lookup.We don't need to keep a list of inodes in each cluster around anymore as we can look them up quickly when we need to. The only time we need to do this now is during inode writeback.
Factor the inode cluster writeback code out of
xfs_iflushand convert it to useradix_tree_gang_lookup()instead of walking a list of inodes built when we first read in the inodes.
Quoted 7 lines
This remove 3 pointers from each
xfs_inodestructure and thexfs_iclusterstructure per inode cluster. Hence we reduce the cache footprint of thexfs_inodesby between 5-10% depending on cluster sparseness.To be truly efficient we need a
radix_tree_gang_lookup_range()call to stop searching once we are past the end of the cluster instead of trying to find a full cluster's worth of inodes.
Nice, I like this a lot. I was wondering about something like this already when you put in the radix-tree based inode cache.
Quoted 13 lines
fs/xfs/xfs_inode.c +13
-0+STATIC int +xfs_iflush_cluster ( +xfs_inode_t *ip, +xfs_buf_t *bp) +{ +xfs_mount_t *mp = ip->i_mount; +xfs_perag_t *pag =xfs_get_perag (mp, ip->i_ino); +unsigned long first_index, mask; +int ilist_size; +xfs_inode_t *ilist; +xfs_inode_t *iq; +xfs_inode_log_item_t *iip; +int nr_found;
fs/xfs/xfs_inode.c xfs_iflush_fork( · line 3038
Quoted 10 lines
fs/xfs/xfs_inode.c +10
-0+int clcount =0 ; +int bufwasdelwri; + +ASSERT (pag->pagi_inodeok); +ASSERT (pag->pag_ici_init); + + ilist_size =XFS_INODE_CLUSTER_SIZE (mp) *sizeof (xfs_inode_t *); + ilist =kmem_alloc (ilist_size,KM_MAYFAIL ); +if (!ilist) +return 0 ;
Now if you just used the linux native allocator this could be a kcalloc :)
fs/xfs/xfs_inode.c xfs_iflush_fork( · line 3067
Quoted 6 lines
fs/xfs/xfs_inode.c +6
-0+if ((iq->i_update_core ==0 ) && + ((iip ==NULL ) || + !(iip->ili_format.ilf_fields &XFS_ILOG_ALL )) && +xfs_ipincount (iq) ==0 ) { +continue ; + }
if (!iq->i_update_core && (!iip || !(iip->ili_format.ilf_fields & XFS_ILOG_ALL)) && !xfs_ipincount(iq)) continue;
fs/xfs/xfs_inode.c xfs_iflush_fork( · line 3092
Quoted 7 lines
fs/xfs/xfs_inode.c +7
-0+/* +* arriving here means that this inode can be flushed. First +* re-check that it's dirty before flushing. +*/ + iip = iq->i_itemp; +if ((iq->i_update_core !=0 ) || ((iip !=NULL ) && + (iip->ili_format.ilf_fields &XFS_ILOG_ALL ))) {
if (!iq->i_update_core ||
(!iip && (iip->ili_format.ilf_fields & XFS_ILOG_ALL)) {Quoted 19 lines
fs/xfs/xfs_inode.c +19
-0+/* +* Clean up the buffer. If it was B_DELWRI, just release it -- +* brelse can handle it with no problems. If not, shut down the +* filesystem before releasing the buffer. +*/ + bufwasdelwri =XFS_BUF_ISDELAYWRITE (bp); +if (bufwasdelwri) +xfs_buf_relse (bp); + +xfs_force_shutdown (mp,SHUTDOWN_CORRUPT_INCORE ); + +if (!bufwasdelwri) { +/* +* Just like incore_relse: if we have b_iodone functions, +* mark the buffer as an error and call them. Otherwise +* mark it as stale and brelse. +*/ +if (XFS_BUF_IODONE_FUNC (bp)) { +XFS_BUF_CLR_BDSTRAT_FUNC (bp);
fs/xfs/xfs_inode.c xfs_iflush_fork( · line 3151
Quoted 10 lines
fs/xfs/xfs_inode.c +10
-0+XFS_BUF_UNDONE (bp); +XFS_BUF_STALE (bp); +XFS_BUF_SHUT (bp); +XFS_BUF_ERROR (bp,EIO ); +xfs_biodone (bp); + }else { +XFS_BUF_STALE (bp); +xfs_buf_relse (bp); + } + }
What's the point of all this if the filesystem is shut down anyway?