mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 19:29:37 +00:00
[XFS] Make use of the init-once slab optimisation.
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. SGI-PV: 981498 SGI-Modid: xfs-linux-melb:xfs-kern:31925a Signed-off-by: David Chinner <david@fromorbit.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org>
This commit is contained in:
parent
e946217e4f
commit
07c8f67587
5 changed files with 119 additions and 59 deletions
|
@ -887,6 +887,41 @@ 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(
|
||||
kmem_zone_t *zone,
|
||||
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);
|
||||
/*
|
||||
* Because we want to use a counting completion, complete
|
||||
* the flush completion once to allow a single access to
|
||||
* the flush completion without blocking.
|
||||
*/
|
||||
init_completion(&ip->i_flush);
|
||||
complete(&ip->i_flush);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to flush the inode, this will actually fail
|
||||
* if the inode is pinned, but we dirty the inode again
|
||||
|
@ -2018,7 +2053,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;
|
||||
|
||||
|
|
|
@ -210,21 +210,6 @@ xfs_iget_core(
|
|||
|
||||
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);
|
||||
|
||||
/*
|
||||
* Because we want to use a counting completion, complete
|
||||
* the flush completion once to allow a single access to
|
||||
* the flush completion without blocking.
|
||||
*/
|
||||
init_completion(&ip->i_flush);
|
||||
complete(&ip->i_flush);
|
||||
|
||||
if (lock_flags)
|
||||
xfs_ilock(ip, lock_flags);
|
||||
|
||||
|
|
|
@ -787,6 +787,70 @@ xfs_dic2xflags(
|
|||
(XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* Initialize inode's trace buffers.
|
||||
*/
|
||||
#ifdef XFS_INODE_TRACE
|
||||
ip->i_trace = ktrace_alloc(INODE_TRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_BMAP_TRACE
|
||||
ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_BMBT_TRACE
|
||||
ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_RW_TRACE
|
||||
ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_ILOCK_TRACE
|
||||
ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_DIR2_TRACE
|
||||
ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a mount structure and an inode number, return a pointer
|
||||
* to a newly allocated in-core inode corresponding to the given
|
||||
|
@ -809,13 +873,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.
|
||||
|
@ -830,35 +890,12 @@ xfs_iread(
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize inode's trace buffers.
|
||||
* Do this before xfs_iformat in case it adds entries.
|
||||
*/
|
||||
#ifdef XFS_INODE_TRACE
|
||||
ip->i_trace = ktrace_alloc(INODE_TRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_BMAP_TRACE
|
||||
ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_BMBT_TRACE
|
||||
ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_RW_TRACE
|
||||
ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_ILOCK_TRACE
|
||||
ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
#ifdef XFS_DIR2_TRACE
|
||||
ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we got something that isn't an inode it means someone
|
||||
* (nfs or dmi) has a stale handle.
|
||||
*/
|
||||
if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC) {
|
||||
kmem_zone_free(xfs_inode_zone, ip);
|
||||
xfs_idestroy(ip);
|
||||
xfs_trans_brelse(tp, bp);
|
||||
#ifdef DEBUG
|
||||
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "
|
||||
|
@ -881,7 +918,7 @@ xfs_iread(
|
|||
xfs_dinode_from_disk(&ip->i_d, &dip->di_core);
|
||||
error = xfs_iformat(ip, dip);
|
||||
if (error) {
|
||||
kmem_zone_free(xfs_inode_zone, ip);
|
||||
xfs_idestroy(ip);
|
||||
xfs_trans_brelse(tp, bp);
|
||||
#ifdef DEBUG
|
||||
xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: "
|
||||
|
@ -911,8 +948,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,
|
||||
|
@ -2631,8 +2666,6 @@ xfs_idestroy(
|
|||
}
|
||||
if (ip->i_afp)
|
||||
xfs_idestroy_fork(ip, XFS_ATTR_FORK);
|
||||
mrfree(&ip->i_lock);
|
||||
mrfree(&ip->i_iolock);
|
||||
|
||||
#ifdef XFS_INODE_TRACE
|
||||
ktrace_free(ip->i_trace);
|
||||
|
@ -2671,7 +2704,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -513,6 +513,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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
Loading…
Reference in a new issue