Skip to contentSkip to conversation

Per Allocation Group inode radix trees

PATCH In review David Chinner 2 participants 2 messages Aug 8, 2007 – Aug 9, 2007 XFS filesystem

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Per Allocation Group inode radix trees

One of the big problems with the hash of radix trees is that they require 64 bit inode number indexing and hence would prevent the use of 64 bit inodes on a 32 bit platform.

Also, the hashing only provides limited parallelism as inodes in different allocation groups that can be operated on in parallel in all other might shared the same radix tree. The hash sizing is also uses relatively basic heuristics for sizing that were provided just to get "sufficient" trees rather than a more optimal number.

By moving to a radix tree per AG, we can use the agino number as the index rather than the inode number, thereby rducing the radix tree key to 32 bits enabling this to be used for 64 bit inodes on 32 bit machines. In doing so, we also grately reduce the sparseness of the radix trees because the agino is a more compact representation of the inode location than the inode number.

It also provides inherent parallelism in the same manner as the rest of XFS without the need for heuristics. i.e. we parallelise operations by keeping structures and operations within AGs. This removes the need for the ihashsize mount parameter altogether as the inode caches should never need size hints anymore.

---
 fs/xfs/linux-2.6/xfs_export.c |    4 -
 fs/xfs/xfs_ag.h               |    4 +
 fs/xfs/xfs_buf_item.c         |    1 
 fs/xfs/xfs_clnt.h             |    1 
 fs/xfs/xfs_dir2_block.c       |    1 
 fs/xfs/xfs_dir2_data.c        |    1 
 fs/xfs/xfs_dir2_node.c        |    1 
 fs/xfs/xfs_dir2_sf.c          |    1 
 fs/xfs/xfs_error.c            |    1 
 fs/xfs/xfs_extfree_item.c     |    1 
 fs/xfs/xfs_iget.c             |  158 +++++++++++++++---------------------------
 fs/xfs/xfs_inode.c            |   18 ++--
 fs/xfs/xfs_inode.h            |   22 -----
 fs/xfs/xfs_mount.c            |   20 ++---
 fs/xfs/xfs_mount.h            |   22 ++++-
 fs/xfs/xfs_rename.c           |    1 
 fs/xfs/xfs_trans_ail.c        |    1 
 fs/xfs/xfs_trans_extfree.c    |    1 
 fs/xfs/xfs_vfsops.c           |   16 ----
 fs/xfs/xfs_vnodeops.c         |    9 +-
 fs/xfs/xfsidbg.c              |  103 ---------------------------
 21 files changed, 121 insertions(+), 266 deletions(-)
fs/xfs/xfs_ag.h +4 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_ag.h
===================================================================
@@ -197,6 +197,10 @@ typedef struct xfs_perag
 #endif
 	xfs_perag_busy_t *pagb_list;	/* unstable blocks */
 	atomic_t        pagf_fstrms;    /* # of filestreams active in this AG */
+
+	int		pag_ici_init;	/* incore inode cache initialised */
+	rwlock_t	pag_ici_lock;	/* incore inode lock */
+	struct radix_tree_root pag_ici_root;	/* incore inode cache root */
 } xfs_perag_t;
 
 #define	XFS_AG_MAXLEVELS(mp)		((mp)->m_ag_maxlevels)
fs/xfs/xfs_iget.c +58 -100

315 lines not on this page · raw message

fs/xfs/xfs_inode.h +3 -19
Index: 2.6.x-xfs-new/fs/xfs/xfs_inode.h
===================================================================
@@ -168,24 +168,10 @@ typedef struct xfs_iocore {
 extern void xfs_iocore_inode_init(struct xfs_inode *);
 extern void xfs_iocore_inode_reinit(struct xfs_inode *);
 
-
 /*
- * This is the type used in the xfs inode hash table.
- * An array of these is allocated for each mounted
- * file system to hash the inodes for that file system.
- */
-typedef struct xfs_ihash {
-	struct radix_tree_root	ih_root;
-	rwlock_t		ih_lock;
-	uint			ih_version;
-} xfs_ihash_t;
-
-#define XFS_IHASH(mp,ino) ((mp)->m_ihash + (((uint)((ino) >> 6)) % (mp)->m_ihsize))
-
-/*
- * This is the xfs inode cluster hash.  This hash is used by xfs_iflush to
- * find inodes that share a cluster and can be flushed to disk at the same
- * time.
+ * 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 xfs_inode	*icl_ip;
@@ -219,7 +205,6 @@ typedef struct xfs_icluster {
  */
 
 typedef struct {
-	struct xfs_ihash	*ip_hash;	/* pointer to hash header */
 	struct xfs_inode	*ip_mnext;	/* next inode in mount list */
 	struct xfs_inode	*ip_mprev;	/* ptr to prev inode */
 	struct xfs_mount	*ip_mount;	/* fs mount struct ptr */
@@ -227,7 +212,6 @@ typedef struct {
 
 typedef struct xfs_inode {
 	/* Inode linking and identification information. */
-	struct xfs_ihash	*i_hash;	/* pointer to hash header */
 	struct xfs_inode	*i_mnext;	/* next inode in mount list */
 	struct xfs_inode	*i_mprev;	/* ptr to prev inode */
 	struct xfs_mount	*i_mount;	/* fs mount struct ptr */
fs/xfs/xfs_mount.c +10 -10
Index: 2.6.x-xfs-new/fs/xfs/xfs_mount.c
===================================================================
@@ -160,9 +160,6 @@ xfs_mount_free(
 	xfs_mount_t	*mp,
 	int		remove_bhv)
 {
-	if (mp->m_ihash)
-		xfs_ihash_free(mp);
-
 	if (mp->m_perag) {
 		int	agno;
 
@@ -394,12 +391,22 @@ xfs_initialize_perag(
 			pag->pagi_inodeok = 1;
 			if (index < max_metadata)
 				pag->pagf_metadata = 1;
+			if (!pag->pag_ici_init) {
+				rwlock_init(&pag->pag_ici_lock);
+				INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
+				pag->pag_ici_init = 1;
+			}
 		}
 	} else {
 		/* Setup default behavior for smaller filesystems */
 		for (index = 0; index < agcount; index++) {
 			pag = &mp->m_perag[index];
 			pag->pagi_inodeok = 1;
+			if (!pag->pag_ici_init) {
+				rwlock_init(&pag->pag_ici_lock);
+				INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
+				pag->pag_ici_init = 1;
+			}
 		}
 	}
 	return index;
@@ -1031,12 +1038,6 @@ xfs_mountfs(
 	xfs_trans_init(mp);
 
 	/*
-	 * Allocate and initialize the inode hash table for this
-	 * file system.
-	 */
-	xfs_ihash_init(mp);
-
-	/*
 	 * Allocate and initialize the per-ag data.
 	 */
 	init_rwsem(&mp->m_peraglock);
@@ -1187,7 +1188,6 @@ xfs_mountfs(
  error3:
 	xfs_log_unmount_dealloc(mp);
  error2:
-	xfs_ihash_free(mp);
 	for (agno = 0; agno < sbp->sb_agcount; agno++)
 		if (mp->m_perag[agno].pagb_list)
 			kmem_free(mp->m_perag[agno].pagb_list,
fs/xfs/xfs_mount.h +16 -6
Index: 2.6.x-xfs-new/fs/xfs/xfs_mount.h
===================================================================
@@ -57,10 +57,7 @@ struct log;
 struct bhv_vfs;
 struct bhv_vnode;
 struct xfs_mount_args;
-struct xfs_ihash;
-struct xfs_chash;
 struct xfs_inode;
-struct xfs_perag;
 struct xfs_iocore;
 struct xfs_bmbt_irec;
 struct xfs_bmap_free;
@@ -335,8 +332,6 @@ typedef struct xfs_mount {
 	xfs_agnumber_t		m_agirotor;	/* last ag dir inode alloced */
 	lock_t			m_agirotor_lock;/* .. and lock protecting it */
 	xfs_agnumber_t		m_maxagi;	/* highest inode alloc group */
-	size_t			m_ihsize;	/* size of next field */
-	struct xfs_ihash	*m_ihash;	/* fs private inode hash table*/
 	struct xfs_inode	*m_inodes;	/* active inode list */
 	struct list_head	m_del_inodes;	/* inodes to reclaim */
 	mutex_t			m_ilock;	/* inode list mutex */
@@ -458,7 +453,7 @@ typedef struct xfs_mount {
 #define XFS_MOUNT_IDELETE	(1ULL << 18)	/* delete empty inode clusters*/
 #define XFS_MOUNT_SWALLOC	(1ULL << 19)	/* turn on stripe width
 						 * allocation */
-#define XFS_MOUNT_IHASHSIZE	(1ULL << 20)	/* inode hash table size */
+			     /*	(1ULL << 20)	-- currently unused */
 #define XFS_MOUNT_DIRSYNC	(1ULL << 21)	/* synchronous directory ops */
 #define XFS_MOUNT_COMPAT_IOSIZE	(1ULL << 22)	/* don't report large preferred
 						 * I/O size in stat() */
@@ -572,6 +567,21 @@ xfs_daddr_to_agbno(struct xfs_mount *mp,
 }
 
 /*
+ * perag get/put wrappers for eventual ref counting
+ */
+static inline xfs_perag_t *
+xfs_get_perag(struct xfs_mount *mp, xfs_ino_t ino)
+{
+	return &mp->m_perag[XFS_INO_TO_AGNO(mp, ino)];
+}
+
+static inline void
+xfs_put_perag(struct xfs_mount *mp, xfs_perag_t *pag)
+{
+	/* nothing to see here, move along */
+}
+
+/*
  * Per-cpu superblock locking functions
  */
 #ifdef HAVE_PERCPU_SB
fs/xfs/linux-2.6/xfs_export.c +3 -1
Index: 2.6.x-xfs-new/fs/xfs/linux-2.6/xfs_export.c
===================================================================
@@ -17,10 +17,12 @@
  */
 #include "xfs.h"
 #include "xfs_types.h"
-#include "xfs_dmapi.h"
+#include "xfs_inum.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_export.h"
 
fs/xfs/xfs_buf_item.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_buf_item.c
===================================================================
@@ -23,6 +23,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_buf_item.h"
fs/xfs/xfs_dir2_block.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_dir2_block.c
===================================================================
@@ -22,6 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
fs/xfs/xfs_dir2_data.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_dir2_data.c
===================================================================
@@ -22,6 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
fs/xfs/xfs_dir2_node.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_dir2_node.c
===================================================================
@@ -22,6 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
fs/xfs/xfs_dir2_sf.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_dir2_sf.c
===================================================================
@@ -22,6 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
fs/xfs/xfs_error.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_error.c
===================================================================
@@ -22,6 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
fs/xfs/xfs_extfree_item.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_extfree_item.c
===================================================================
@@ -23,6 +23,7 @@
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
fs/xfs/xfs_inode.c +9 -9
Index: 2.6.x-xfs-new/fs/xfs/xfs_inode.c
===================================================================
@@ -2182,10 +2182,10 @@ xfs_ifree_cluster(
 	int			i, j, found, pre_flushed;
 	xfs_daddr_t		blkno;
 	xfs_buf_t		*bp;
-	xfs_ihash_t		*ih;
 	xfs_inode_t		*ip, **ip_found;
 	xfs_inode_log_item_t	*iip;
 	xfs_log_item_t		*lip;
+	xfs_perag_t		*pag = xfs_get_perag(mp, inum);
 	SPLDECL(s);
 
 	if (mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) {
@@ -2220,20 +2220,20 @@ xfs_ifree_cluster(
 		 */
 		found = 0;
 		for (i = 0; i < ninodes; i++) {
-			ih = XFS_IHASH(mp, inum + i);
-			read_lock(&ih->ih_lock);
-			ip = (xfs_inode_t *)radix_tree_lookup(&ih->ih_root, inum + i);
+			read_lock(&pag->pag_ici_lock);
+			ip = radix_tree_lookup(&pag->pag_ici_root,
+					XFS_INO_TO_AGINO(mp, (inum + i)));
 
 			/* Inode not in memory or we found it already,
 			 * nothing to do
 			 */
 			if (!ip || xfs_iflags_test(ip, XFS_ISTALE)) {
-				read_unlock(&ih->ih_lock);
+				read_unlock(&pag->pag_ici_lock);
 				continue;
 			}
 
 			if (xfs_inode_clean(ip)) {
-				read_unlock(&ih->ih_lock);
+				read_unlock(&pag->pag_ici_lock);
 				continue;
 			}
 
@@ -2256,7 +2256,7 @@ xfs_ifree_cluster(
 						ip_found[found++] = ip;
 					}
 				}
-				read_unlock(&ih->ih_lock);
+				read_unlock(&pag->pag_ici_lock);
 				continue;
 			}
 
@@ -2274,8 +2274,7 @@ xfs_ifree_cluster(
 					xfs_iunlock(ip, XFS_ILOCK_EXCL);
 				}
 			}
-
-			read_unlock(&ih->ih_lock);
+			read_unlock(&pag->pag_ici_lock);
 		}
 
 		bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, 
@@ -2330,6 +2329,7 @@ xfs_ifree_cluster(
 	}
 
 	kmem_free(ip_found, ninodes * sizeof(xfs_inode_t *));
+	xfs_put_perag(mp, pag);
 }
 
 /*
fs/xfs/xfs_rename.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_rename.c
===================================================================
@@ -22,6 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
fs/xfs/xfs_trans_ail.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_trans_ail.c
===================================================================
@@ -22,6 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
fs/xfs/xfs_trans_extfree.c +1 -0
Index: 2.6.x-xfs-new/fs/xfs/xfs_trans_extfree.c
===================================================================
@@ -22,6 +22,7 @@
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
+#include "xfs_ag.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
fs/xfs/xfs_vfsops.c +0 -16
Index: 2.6.x-xfs-new/fs/xfs/xfs_vfsops.c
===================================================================
@@ -246,7 +246,6 @@ xfs_start_flags(
 			ap->logbufsize);
 		return XFS_ERROR(EINVAL);
 	}
-	mp->m_ihsize = ap->ihashsize;
 	mp->m_logbsize = ap->logbufsize;
 	mp->m_fsname_len = strlen(ap->fsname) + 1;
 	mp->m_fsname = kmem_alloc(mp->m_fsname_len, KM_SLEEP);
@@ -293,8 +292,6 @@ xfs_start_flags(
 		mp->m_readio_log = mp->m_writeio_log = ap->iosizelog;
 	}
 
-	if (ap->flags & XFSMNT_IHASHSIZE)
-		mp->m_flags |= XFS_MOUNT_IHASHSIZE;
 	if (ap->flags & XFSMNT_IDELETE)
 		mp->m_flags |= XFS_MOUNT_IDELETE;
 	if (ap->flags & XFSMNT_DIRSYNC)
@@ -1693,7 +1690,6 @@ xfs_vget(
 #define MNTOPT_BSDGROUPS    "bsdgroups"    /* group-ID from parent directory */
 #define MNTOPT_SYSVGROUPS   "sysvgroups"   /* group-ID from current process */
 #define MNTOPT_ALLOCSIZE    "allocsize"    /* preferred allocation size */
-#define MNTOPT_IHASHSIZE    "ihashsize"    /* size of inode hash table */
 #define MNTOPT_NORECOVERY   "norecovery"   /* don't run XFS recovery */
 #define MNTOPT_BARRIER	"barrier"	/* use writer barriers for log write and
 					 * unwritten extent conversion */
@@ -1819,15 +1815,6 @@ xfs_parseargs(
 			iosize = suffix_strtoul(value, &eov, 10);
 			args->flags |= XFSMNT_IOSIZE;
 			args->iosizelog = ffs(iosize) - 1;
-		} else if (!strcmp(this_char, MNTOPT_IHASHSIZE)) {
-			if (!value || !*value) {
-				cmn_err(CE_WARN,
-					"XFS: %s option requires an argument",
-					this_char);
-				return EINVAL;
-			}
-			args->flags |= XFSMNT_IHASHSIZE;
-			args->ihashsize = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_GRPID) ||
 			   !strcmp(this_char, MNTOPT_BSDGROUPS)) {
 			vfsp->vfs_flag |= VFS_GRPID;
@@ -1986,9 +1973,6 @@ xfs_showargs(
 			seq_puts(m, xfs_infop->str);
 	}
 
-	if (mp->m_flags & XFS_MOUNT_IHASHSIZE)
-		seq_printf(m, "," MNTOPT_IHASHSIZE "=%d", (int)mp->m_ihsize);
-
 	if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
 		seq_printf(m, "," MNTOPT_ALLOCSIZE "=%dk",
 				(int)(1 << mp->m_writeio_log) >> 10);
fs/xfs/xfs_vnodeops.c +5 -4
Index: 2.6.x-xfs-new/fs/xfs/xfs_vnodeops.c
===================================================================
@@ -3859,7 +3859,7 @@ xfs_finish_reclaim(
 	int		locked,
 	int		sync_mode)
 {
-	xfs_ihash_t	*ih = ip->i_hash;
+	xfs_perag_t	*pag = xfs_get_perag(ip->i_mount, ip->i_ino);
 	bhv_vnode_t	*vp = XFS_ITOV_NULL(ip);
 	int		error;
 
@@ -3871,12 +3871,12 @@ xfs_finish_reclaim(
 	 * Once we have the XFS_IRECLAIM flag set it will not touch
 	 * us.
 	 */
-	write_lock(&ih->ih_lock);
+	write_lock(&pag->pag_ici_lock);
 	spin_lock(&ip->i_flags_lock);
 	if (__xfs_iflags_test(ip, XFS_IRECLAIM) ||
 	    (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) && vp == NULL)) {
 		spin_unlock(&ip->i_flags_lock);
-		write_unlock(&ih->ih_lock);
+		write_unlock(&pag->pag_ici_lock);
 		if (locked) {
 			xfs_ifunlock(ip);
 			xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -3885,7 +3885,8 @@ xfs_finish_reclaim(
 	}
 	__xfs_iflags_set(ip, XFS_IRECLAIM);
 	spin_unlock(&ip->i_flags_lock);
-	write_unlock(&ih->ih_lock);
+	write_unlock(&pag->pag_ici_lock);
+	xfs_put_perag(ip->i_mount, pag);
 
 	/*
 	 * If the inode is still dirty, then flush it out.  If the inode
fs/xfs/xfsidbg.c +3 -100

156 lines not on this page · raw message

fs/xfs/xfs_clnt.h +0 -1
Index: 2.6.x-xfs-new/fs/xfs/xfs_clnt.h
===================================================================
@@ -89,7 +89,6 @@ struct xfs_mount_args {
 #define XFSMNT_IDELETE		0x08000000	/* inode cluster delete */
 #define XFSMNT_SWALLOC		0x10000000	/* turn on stripe width
 						 * allocation */
-#define XFSMNT_IHASHSIZE	0x20000000	/* inode hash table size */
 #define XFSMNT_DIRSYNC		0x40000000	/* sync creat,link,unlink,rename
 						 * symlink,mkdir,rmdir,mknod */
 #define XFSMNT_FLAGS2		0x80000000	/* more flags set in flags2 */
#1 lore raw
Quoted 10 lines

...
operations by keeping structures and operations within AGs. This removes the need for the ihashsize mount parameter altogether as the inode caches should never need size hints anymore.
...
--- 2.6.x-xfs-new.orig/fs/xfs/xfs_vfsops.c 2007-08-01 15:43:30.383433897
+1000
+++ 2.6.x-xfs-new/fs/xfs/xfs_vfsops.c 2007-08-01 15:43:34.150945479 +1000
...
-#define MNTOPT_IHASHSIZE "ihashsize" /* size of inode hash table */

You probably want to keep this string & parsing for awhile (forever?), but move it to the end of the list with the other deprecated options - just so as to not fail mounts on kernel upgrades... and surprise/annoy sysadmins the world over.

cheers.

--
Nathan