aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2010-01-29 18:38:32 -0500
committerThomas Gleixner <tglx@linutronix.de>2010-04-27 11:32:49 -0400
commita119db1dc3f3a6da86148960937383ce0c162ad4 (patch)
tree8530d8117f5aaa11c10a7984b1ad8aee3143106e
parent6f22d55b46fbf80b018009ece79f15b8582843e5 (diff)
fs-inode_rcu
RCU free the struct inode. This will allow: - 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. - eventually, completely write-free RCU path walking. The inode must be consulted for permissions when walking, so a write-free reference (ie. RCU is helpful). - can potentially simplify things a bit in VM land. May not need to take the page lock to get back to the page->mapping. - can remove some nested trylock loops in dcache code todo: convert all filesystems Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--fs/block_dev.c9
-rw-r--r--fs/ext2/super.c9
-rw-r--r--fs/ext3/super.c9
-rw-r--r--fs/fat/inode.c9
-rw-r--r--fs/hugetlbfs/inode.c9
-rw-r--r--fs/inode.c9
-rw-r--r--fs/nfs/inode.c9
-rw-r--r--fs/proc/inode.c9
-rw-r--r--include/linux/fs.h5
-rw-r--r--ipc/mqueue.c9
-rw-r--r--mm/shmem.c9
-rw-r--r--net/socket.c9
-rw-r--r--net/sunrpc/rpc_pipe.c10
13 files changed, 101 insertions, 13 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index bf503be689c3..37a7a1f12329 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -435,13 +435,20 @@ static struct inode *bdev_alloc_inode(struct super_block *sb)
435 return &ei->vfs_inode; 435 return &ei->vfs_inode;
436} 436}
437 437
438static void bdev_destroy_inode(struct inode *inode) 438static void bdev_i_callback(struct rcu_head *head)
439{ 439{
440 struct inode *inode = container_of(head, struct inode, i_rcu);
440 struct bdev_inode *bdi = BDEV_I(inode); 441 struct bdev_inode *bdi = BDEV_I(inode);
441 442
443 INIT_LIST_HEAD(&inode->i_dentry);
442 kmem_cache_free(bdev_cachep, bdi); 444 kmem_cache_free(bdev_cachep, bdi);
443} 445}
444 446
447static void bdev_destroy_inode(struct inode *inode)
448{
449 call_rcu(&inode->i_rcu, bdev_i_callback);
450}
451
445static void init_once(void *foo) 452static void init_once(void *foo)
446{ 453{
447 struct bdev_inode *ei = (struct bdev_inode *) foo; 454 struct bdev_inode *ei = (struct bdev_inode *) foo;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index f9cb54a585ce..d5f19f954fb7 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -157,11 +157,18 @@ static struct inode *ext2_alloc_inode(struct super_block *sb)
157 return &ei->vfs_inode; 157 return &ei->vfs_inode;
158} 158}
159 159
160static void ext2_destroy_inode(struct inode *inode) 160static void ext2_i_callback(struct rcu_head *head)
161{ 161{
162 struct inode *inode = container_of(head, struct inode, i_rcu);
163 INIT_LIST_HEAD(&inode->i_dentry);
162 kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); 164 kmem_cache_free(ext2_inode_cachep, EXT2_I(inode));
163} 165}
164 166
167static void ext2_destroy_inode(struct inode *inode)
168{
169 call_rcu(&inode->i_rcu, ext2_i_callback);
170}
171
165static void init_once(void *foo) 172static void init_once(void *foo)
166{ 173{
167 struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; 174 struct ext2_inode_info *ei = (struct ext2_inode_info *) foo;
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index afa2b569da10..29dae329d4f6 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -483,6 +483,13 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
483 return &ei->vfs_inode; 483 return &ei->vfs_inode;
484} 484}
485 485
486static void ext3_i_callback(struct rcu_head *head)
487{
488 struct inode *inode = container_of(head, struct inode, i_rcu);
489 INIT_LIST_HEAD(&inode->i_dentry);
490 kmem_cache_free(ext3_inode_cachep, EXT3_I(inode));
491}
492
486static void ext3_destroy_inode(struct inode *inode) 493static void ext3_destroy_inode(struct inode *inode)
487{ 494{
488 if (!list_empty(&(EXT3_I(inode)->i_orphan))) { 495 if (!list_empty(&(EXT3_I(inode)->i_orphan))) {
@@ -493,7 +500,7 @@ static void ext3_destroy_inode(struct inode *inode)
493 false); 500 false);
494 dump_stack(); 501 dump_stack();
495 } 502 }
496 kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); 503 call_rcu(&inode->i_rcu, ext3_i_callback);
497} 504}
498 505
499static void init_once(void *foo) 506static void init_once(void *foo)
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 5c5e1cd62414..5220e057664d 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -497,11 +497,18 @@ static struct inode *fat_alloc_inode(struct super_block *sb)
497 return &ei->vfs_inode; 497 return &ei->vfs_inode;
498} 498}
499 499
500static void fat_destroy_inode(struct inode *inode) 500static void fat_i_callback(struct rcu_head *head)
501{ 501{
502 struct inode *inode = container_of(head, struct inode, i_rcu);
503 INIT_LIST_HEAD(&inode->i_dentry);
502 kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); 504 kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));
503} 505}
504 506
507static void fat_destroy_inode(struct inode *inode)
508{
509 call_rcu(&inode->i_rcu, fat_i_callback);
510}
511
505static void init_once(void *foo) 512static void init_once(void *foo)
506{ 513{
507 struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; 514 struct msdos_inode_info *ei = (struct msdos_inode_info *)foo;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 5b50a7a2225e..d1a78fc2a78e 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -665,11 +665,18 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb)
665 return &p->vfs_inode; 665 return &p->vfs_inode;
666} 666}
667 667
668static void hugetlbfs_i_callback(struct rcu_head *head)
669{
670 struct inode *inode = container_of(head, struct inode, i_rcu);
671 INIT_LIST_HEAD(&inode->i_dentry);
672 kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode));
673}
674
668static void hugetlbfs_destroy_inode(struct inode *inode) 675static void hugetlbfs_destroy_inode(struct inode *inode)
669{ 676{
670 hugetlbfs_inc_free_inodes(HUGETLBFS_SB(inode->i_sb)); 677 hugetlbfs_inc_free_inodes(HUGETLBFS_SB(inode->i_sb));
671 mpol_free_shared_policy(&HUGETLBFS_I(inode)->policy); 678 mpol_free_shared_policy(&HUGETLBFS_I(inode)->policy);
672 kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode)); 679 call_rcu(&inode->i_rcu, hugetlbfs_i_callback);
673} 680}
674 681
675static const struct address_space_operations hugetlbfs_aops = { 682static const struct address_space_operations hugetlbfs_aops = {
diff --git a/fs/inode.c b/fs/inode.c
index 5039ddf4f0e0..fd57c8371686 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -245,13 +245,20 @@ void __destroy_inode(struct inode *inode)
245} 245}
246EXPORT_SYMBOL(__destroy_inode); 246EXPORT_SYMBOL(__destroy_inode);
247 247
248static void i_callback(struct rcu_head *head)
249{
250 struct inode *inode = container_of(head, struct inode, i_rcu);
251 INIT_LIST_HEAD(&inode->i_dentry);
252 kmem_cache_free(inode_cachep, inode);
253}
254
248void destroy_inode(struct inode *inode) 255void destroy_inode(struct inode *inode)
249{ 256{
250 __destroy_inode(inode); 257 __destroy_inode(inode);
251 if (inode->i_sb->s_op->destroy_inode) 258 if (inode->i_sb->s_op->destroy_inode)
252 inode->i_sb->s_op->destroy_inode(inode); 259 inode->i_sb->s_op->destroy_inode(inode);
253 else 260 else
254 kmem_cache_free(inode_cachep, (inode)); 261 call_rcu(&inode->i_rcu, i_callback);
255} 262}
256 263
257/* 264/*
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 8e7fcc253e43..86eefbafb7b4 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1395,11 +1395,18 @@ struct inode *nfs_alloc_inode(struct super_block *sb)
1395 return &nfsi->vfs_inode; 1395 return &nfsi->vfs_inode;
1396} 1396}
1397 1397
1398void nfs_destroy_inode(struct inode *inode) 1398static void nfs_i_callback(struct rcu_head *head)
1399{ 1399{
1400 struct inode *inode = container_of(head, struct inode, i_rcu);
1401 INIT_LIST_HEAD(&inode->i_dentry);
1400 kmem_cache_free(nfs_inode_cachep, NFS_I(inode)); 1402 kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
1401} 1403}
1402 1404
1405void nfs_destroy_inode(struct inode *inode)
1406{
1407 call_rcu(&inode->i_rcu, nfs_i_callback);
1408}
1409
1403static inline void nfs4_init_once(struct nfs_inode *nfsi) 1410static inline void nfs4_init_once(struct nfs_inode *nfsi)
1404{ 1411{
1405#ifdef CONFIG_NFS_V4 1412#ifdef CONFIG_NFS_V4
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 445a02bcaab3..ee0a77b56810 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -65,11 +65,18 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
65 return inode; 65 return inode;
66} 66}
67 67
68static void proc_destroy_inode(struct inode *inode) 68static void proc_i_callback(struct rcu_head *head)
69{ 69{
70 struct inode *inode = container_of(head, struct inode, i_rcu);
71 INIT_LIST_HEAD(&inode->i_dentry);
70 kmem_cache_free(proc_inode_cachep, PROC_I(inode)); 72 kmem_cache_free(proc_inode_cachep, PROC_I(inode));
71} 73}
72 74
75static void proc_destroy_inode(struct inode *inode)
76{
77 call_rcu(&inode->i_rcu, proc_i_callback);
78}
79
73static void init_once(void *foo) 80static void init_once(void *foo)
74{ 81{
75 struct proc_inode *ei = (struct proc_inode *) foo; 82 struct proc_inode *ei = (struct proc_inode *) foo;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b86542c8d68c..9c595e725ee1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -726,7 +726,10 @@ struct inode {
726 struct hlist_node i_hash; 726 struct hlist_node i_hash;
727 struct list_head i_list; /* backing dev IO list */ 727 struct list_head i_list; /* backing dev IO list */
728 struct list_head i_sb_list; 728 struct list_head i_sb_list;
729 struct list_head i_dentry; 729 union {
730 struct list_head i_dentry;
731 struct rcu_head i_rcu;
732 };
730 unsigned long i_ino; 733 unsigned long i_ino;
731 unsigned int i_count; 734 unsigned int i_count;
732 unsigned int i_nlink; 735 unsigned int i_nlink;
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index d72c0fa15e0c..f3a43f7747ca 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -237,11 +237,18 @@ static struct inode *mqueue_alloc_inode(struct super_block *sb)
237 return &ei->vfs_inode; 237 return &ei->vfs_inode;
238} 238}
239 239
240static void mqueue_destroy_inode(struct inode *inode) 240static void mqueue_i_callback(struct rcu_head *head)
241{ 241{
242 struct inode *inode = container_of(head, struct inode, i_rcu);
243 INIT_LIST_HEAD(&inode->i_dentry);
242 kmem_cache_free(mqueue_inode_cachep, MQUEUE_I(inode)); 244 kmem_cache_free(mqueue_inode_cachep, MQUEUE_I(inode));
243} 245}
244 246
247static void mqueue_destroy_inode(struct inode *inode)
248{
249 call_rcu(&inode->i_rcu, mqueue_i_callback);
250}
251
245static void mqueue_delete_inode(struct inode *inode) 252static void mqueue_delete_inode(struct inode *inode)
246{ 253{
247 struct mqueue_inode_info *info; 254 struct mqueue_inode_info *info;
diff --git a/mm/shmem.c b/mm/shmem.c
index c4e04a5da5af..d7905296c2d3 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2397,13 +2397,20 @@ static struct inode *shmem_alloc_inode(struct super_block *sb)
2397 return &p->vfs_inode; 2397 return &p->vfs_inode;
2398} 2398}
2399 2399
2400static void shmem_i_callback(struct rcu_head *head)
2401{
2402 struct inode *inode = container_of(head, struct inode, i_rcu);
2403 INIT_LIST_HEAD(&inode->i_dentry);
2404 kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
2405}
2406
2400static void shmem_destroy_inode(struct inode *inode) 2407static void shmem_destroy_inode(struct inode *inode)
2401{ 2408{
2402 if ((inode->i_mode & S_IFMT) == S_IFREG) { 2409 if ((inode->i_mode & S_IFMT) == S_IFREG) {
2403 /* only struct inode is valid if it's an inline symlink */ 2410 /* only struct inode is valid if it's an inline symlink */
2404 mpol_free_shared_policy(&SHMEM_I(inode)->policy); 2411 mpol_free_shared_policy(&SHMEM_I(inode)->policy);
2405 } 2412 }
2406 kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); 2413 call_rcu(&inode->i_rcu, shmem_i_callback);
2407} 2414}
2408 2415
2409static void init_once(void *foo) 2416static void init_once(void *foo)
diff --git a/net/socket.c b/net/socket.c
index 367296ccafbe..371eaf092a31 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -263,12 +263,19 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
263 return &ei->vfs_inode; 263 return &ei->vfs_inode;
264} 264}
265 265
266static void sock_destroy_inode(struct inode *inode) 266static void sock_i_callback(struct rcu_head *head)
267{ 267{
268 struct inode *inode = container_of(head, struct inode, i_rcu);
269 INIT_LIST_HEAD(&inode->i_dentry);
268 kmem_cache_free(sock_inode_cachep, 270 kmem_cache_free(sock_inode_cachep,
269 container_of(inode, struct socket_alloc, vfs_inode)); 271 container_of(inode, struct socket_alloc, vfs_inode));
270} 272}
271 273
274static void sock_destroy_inode(struct inode *inode)
275{
276 call_rcu(&inode->i_rcu, sock_i_callback);
277}
278
272static void init_once(void *foo) 279static void init_once(void *foo)
273{ 280{
274 struct socket_alloc *ei = (struct socket_alloc *)foo; 281 struct socket_alloc *ei = (struct socket_alloc *)foo;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 27a23785a50d..6792d5634fa0 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -162,11 +162,19 @@ rpc_alloc_inode(struct super_block *sb)
162} 162}
163 163
164static void 164static void
165rpc_destroy_inode(struct inode *inode) 165rpc_i_callback(struct rcu_head *head)
166{ 166{
167 struct inode *inode = container_of(head, struct inode, i_rcu);
168 INIT_LIST_HEAD(&inode->i_dentry);
167 kmem_cache_free(rpc_inode_cachep, RPC_I(inode)); 169 kmem_cache_free(rpc_inode_cachep, RPC_I(inode));
168} 170}
169 171
172static void
173rpc_destroy_inode(struct inode *inode)
174{
175 call_rcu(&inode->i_rcu, rpc_i_callback);
176}
177
170static int 178static int
171rpc_pipe_open(struct inode *inode, struct file *filp) 179rpc_pipe_open(struct inode *inode, struct file *filp)
172{ 180{