diff options
author | Dave Chinner <david@fromorbit.com> | 2010-01-11 11:47:44 +0000 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-01-15 15:33:52 -0600 |
commit | 1c1c6ebcf5284aee4910f3b906ac90c20e510c82 (patch) | |
tree | bbcf74752bf7bc058a5c5bdd6bd03090c845b041 /fs/xfs/xfs_mount.h | |
parent | 44b56e0a1aed522a10051645e85d300e10926fd3 (diff) | |
download | linux-3.10-1c1c6ebcf5284aee4910f3b906ac90c20e510c82.tar.gz linux-3.10-1c1c6ebcf5284aee4910f3b906ac90c20e510c82.tar.bz2 linux-3.10-1c1c6ebcf5284aee4910f3b906ac90c20e510c82.zip |
xfs: Replace per-ag array with a radix tree
The use of an array for the per-ag structures requires reallocation
of the array when growing the filesystem. This requires locking
access to the array to avoid use after free situations, and the
locking is difficult to get right. To avoid needing to reallocate an
array, change the per-ag structures to an allocated object per ag
and index them using a tree structure.
The AGs are always densely indexed (hence the use of an array), but
the number supported is 2^32 and lookups tend to be random and hence
indexing needs to scale. A simple choice is a radix tree - it works
well with this sort of index. This change also removes another
large contiguous allocation from the mount/growfs path in XFS.
The growing process now needs to change to only initialise the new
AGs required for the extra space, and as such only needs to
exclusively lock the tree for inserts. The rest of the code only
needs to lock the tree while doing lookups, and hence this will
remove all the deadlocks that currently occur on the m_perag_lock as
it is now an innermost lock. The lock is also changed to a spinlock
from a read/write lock as the hold time is now extremely short.
To complete the picture, the per-ag structures will need to be
reference counted to ensure that we don't free/modify them while
they are still in use. This will be done in subsequent patch.
Signed-off-by: Dave Chinner <david@fromorbit.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_mount.h')
-rw-r--r-- | fs/xfs/xfs_mount.h | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index f8a68a2319b..cfa7a5d22e7 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -207,8 +207,8 @@ typedef struct xfs_mount { uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ uint m_in_maxlevels; /* max inobt btree levels. */ - struct xfs_perag *m_perag; /* per-ag accounting info */ - struct rw_semaphore m_peraglock; /* lock for m_perag (pointer) */ + struct radix_tree_root m_perag_tree; /* per-ag accounting info */ + spinlock_t m_perag_lock; /* lock for m_perag_tree */ struct mutex m_growlock; /* growfs mutex */ int m_fixedfsid[2]; /* unchanged for life of FS */ uint m_dmevmask; /* DMI events for this FS */ @@ -389,7 +389,12 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) static inline struct xfs_perag * xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno) { - return &mp->m_perag[agno]; + struct xfs_perag *pag; + + spin_lock(&mp->m_perag_lock); + pag = radix_tree_lookup(&mp->m_perag_tree, agno); + spin_unlock(&mp->m_perag_lock); + return pag; } static inline void @@ -450,7 +455,8 @@ extern struct xfs_dmops xfs_dmcore_xfs; #endif /* __KERNEL__ */ extern void xfs_mod_sb(struct xfs_trans *, __int64_t); -extern xfs_agnumber_t xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t); +extern int xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t, + xfs_agnumber_t *); extern void xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *); extern void xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t); |