aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:49 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:26 -0500
commitfa0d7e3de6d6fc5004ad9dea0dd6b286af8f03e9 (patch)
tree203e0f73883e4c26b5597e36042386a1237dab35 /drivers/staging
parent77812a1ef139d84270d27faacc0630c887411013 (diff)
fs: icache RCU free inodes
RCU free the struct inode. This will allow: - Subsequent store-free path walking patch. The inode must be consulted for permissions when walking, so an RCU inode reference is a must. - sb_inode_list_lock to be moved inside i_lock because sb list walkers who want to take i_lock no longer need to take sb_inode_list_lock to walk the list in the first place. This will simplify and optimize locking. - Could remove some nested trylock loops in dcache code - Could potentially simplify things a bit in VM land. Do not need to take the page lock to follow page->mapping. The downsides of this is the performance cost of using RCU. In a simple creat/unlink microbenchmark, performance drops by about 10% due to inability to reuse cache-hot slab objects. As iterations increase and RCU freeing starts kicking over, this increases to about 20%. In cases where inode lifetimes are longer (ie. many inodes may be allocated during the average life span of a single inode), a lot of this cache reuse is not applicable, so the regression caused by this patch is smaller. The cache-hot regression could largely be avoided by using SLAB_DESTROY_BY_RCU, however this adds some complexity to list walking and store-free path walking, so I prefer to implement this at a later date, if it is shown to be a win in real situations. I haven't found a regression in any non-micro benchmark so I doubt it will be a problem. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/pohmelfs/inode.c9
-rw-r--r--drivers/staging/smbfs/inode.c9
2 files changed, 16 insertions, 2 deletions
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
index 61685ccceda8..cc8d2840f9b6 100644
--- a/drivers/staging/pohmelfs/inode.c
+++ b/drivers/staging/pohmelfs/inode.c
@@ -826,6 +826,13 @@ const struct address_space_operations pohmelfs_aops = {
826 .set_page_dirty = __set_page_dirty_nobuffers, 826 .set_page_dirty = __set_page_dirty_nobuffers,
827}; 827};
828 828
829static void pohmelfs_i_callback(struct rcu_head *head)
830{
831 struct inode *inode = container_of(head, struct inode, i_rcu);
832 INIT_LIST_HEAD(&inode->i_dentry);
833 kmem_cache_free(pohmelfs_inode_cache, POHMELFS_I(inode));
834}
835
829/* 836/*
830 * ->detroy_inode() callback. Deletes inode from the caches 837 * ->detroy_inode() callback. Deletes inode from the caches
831 * and frees private data. 838 * and frees private data.
@@ -842,8 +849,8 @@ static void pohmelfs_destroy_inode(struct inode *inode)
842 849
843 dprintk("%s: pi: %p, inode: %p, ino: %llu.\n", 850 dprintk("%s: pi: %p, inode: %p, ino: %llu.\n",
844 __func__, pi, &pi->vfs_inode, pi->ino); 851 __func__, pi, &pi->vfs_inode, pi->ino);
845 kmem_cache_free(pohmelfs_inode_cache, pi);
846 atomic_long_dec(&psb->total_inodes); 852 atomic_long_dec(&psb->total_inodes);
853 call_rcu(&inode->i_rcu, pohmelfs_i_callback);
847} 854}
848 855
849/* 856/*
diff --git a/drivers/staging/smbfs/inode.c b/drivers/staging/smbfs/inode.c
index 540a984bb516..244319dc9702 100644
--- a/drivers/staging/smbfs/inode.c
+++ b/drivers/staging/smbfs/inode.c
@@ -62,11 +62,18 @@ static struct inode *smb_alloc_inode(struct super_block *sb)
62 return &ei->vfs_inode; 62 return &ei->vfs_inode;
63} 63}
64 64
65static void smb_destroy_inode(struct inode *inode) 65static void smb_i_callback(struct rcu_head *head)
66{ 66{
67 struct inode *inode = container_of(head, struct inode, i_rcu);
68 INIT_LIST_HEAD(&inode->i_dentry);
67 kmem_cache_free(smb_inode_cachep, SMB_I(inode)); 69 kmem_cache_free(smb_inode_cachep, SMB_I(inode));
68} 70}
69 71
72static void smb_destroy_inode(struct inode *inode)
73{
74 call_rcu(&inode->i_rcu, smb_i_callback);
75}
76
70static void init_once(void *foo) 77static void init_once(void *foo)
71{ 78{
72 struct smb_inode_info *ei = (struct smb_inode_info *) foo; 79 struct smb_inode_info *ei = (struct smb_inode_info *) foo;