diff options
author | Nick Piggin <npiggin@suse.de> | 2010-01-29 18:38:32 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2010-04-27 11:32:49 -0400 |
commit | a119db1dc3f3a6da86148960937383ce0c162ad4 (patch) | |
tree | 8530d8117f5aaa11c10a7984b1ad8aee3143106e | |
parent | 6f22d55b46fbf80b018009ece79f15b8582843e5 (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.c | 9 | ||||
-rw-r--r-- | fs/ext2/super.c | 9 | ||||
-rw-r--r-- | fs/ext3/super.c | 9 | ||||
-rw-r--r-- | fs/fat/inode.c | 9 | ||||
-rw-r--r-- | fs/hugetlbfs/inode.c | 9 | ||||
-rw-r--r-- | fs/inode.c | 9 | ||||
-rw-r--r-- | fs/nfs/inode.c | 9 | ||||
-rw-r--r-- | fs/proc/inode.c | 9 | ||||
-rw-r--r-- | include/linux/fs.h | 5 | ||||
-rw-r--r-- | ipc/mqueue.c | 9 | ||||
-rw-r--r-- | mm/shmem.c | 9 | ||||
-rw-r--r-- | net/socket.c | 9 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 10 |
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 | ||
438 | static void bdev_destroy_inode(struct inode *inode) | 438 | static 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 | ||
447 | static void bdev_destroy_inode(struct inode *inode) | ||
448 | { | ||
449 | call_rcu(&inode->i_rcu, bdev_i_callback); | ||
450 | } | ||
451 | |||
445 | static void init_once(void *foo) | 452 | static 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 | ||
160 | static void ext2_destroy_inode(struct inode *inode) | 160 | static 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 | ||
167 | static void ext2_destroy_inode(struct inode *inode) | ||
168 | { | ||
169 | call_rcu(&inode->i_rcu, ext2_i_callback); | ||
170 | } | ||
171 | |||
165 | static void init_once(void *foo) | 172 | static 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 | ||
486 | static 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 | |||
486 | static void ext3_destroy_inode(struct inode *inode) | 493 | static 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 | ||
499 | static void init_once(void *foo) | 506 | static 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 | ||
500 | static void fat_destroy_inode(struct inode *inode) | 500 | static 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 | ||
507 | static void fat_destroy_inode(struct inode *inode) | ||
508 | { | ||
509 | call_rcu(&inode->i_rcu, fat_i_callback); | ||
510 | } | ||
511 | |||
505 | static void init_once(void *foo) | 512 | static 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 | ||
668 | static 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 | |||
668 | static void hugetlbfs_destroy_inode(struct inode *inode) | 675 | static 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 | ||
675 | static const struct address_space_operations hugetlbfs_aops = { | 682 | static 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 | } |
246 | EXPORT_SYMBOL(__destroy_inode); | 246 | EXPORT_SYMBOL(__destroy_inode); |
247 | 247 | ||
248 | static 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 | |||
248 | void destroy_inode(struct inode *inode) | 255 | void 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 | ||
1398 | void nfs_destroy_inode(struct inode *inode) | 1398 | static 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 | ||
1405 | void nfs_destroy_inode(struct inode *inode) | ||
1406 | { | ||
1407 | call_rcu(&inode->i_rcu, nfs_i_callback); | ||
1408 | } | ||
1409 | |||
1403 | static inline void nfs4_init_once(struct nfs_inode *nfsi) | 1410 | static 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 | ||
68 | static void proc_destroy_inode(struct inode *inode) | 68 | static 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 | ||
75 | static void proc_destroy_inode(struct inode *inode) | ||
76 | { | ||
77 | call_rcu(&inode->i_rcu, proc_i_callback); | ||
78 | } | ||
79 | |||
73 | static void init_once(void *foo) | 80 | static 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 | ||
240 | static void mqueue_destroy_inode(struct inode *inode) | 240 | static 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 | ||
247 | static void mqueue_destroy_inode(struct inode *inode) | ||
248 | { | ||
249 | call_rcu(&inode->i_rcu, mqueue_i_callback); | ||
250 | } | ||
251 | |||
245 | static void mqueue_delete_inode(struct inode *inode) | 252 | static 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 | ||
2400 | static 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 | |||
2400 | static void shmem_destroy_inode(struct inode *inode) | 2407 | static 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 | ||
2409 | static void init_once(void *foo) | 2416 | static 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 | ||
266 | static void sock_destroy_inode(struct inode *inode) | 266 | static 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 | ||
274 | static void sock_destroy_inode(struct inode *inode) | ||
275 | { | ||
276 | call_rcu(&inode->i_rcu, sock_i_callback); | ||
277 | } | ||
278 | |||
272 | static void init_once(void *foo) | 279 | static 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 | ||
164 | static void | 164 | static void |
165 | rpc_destroy_inode(struct inode *inode) | 165 | rpc_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 | ||
172 | static void | ||
173 | rpc_destroy_inode(struct inode *inode) | ||
174 | { | ||
175 | call_rcu(&inode->i_rcu, rpc_i_callback); | ||
176 | } | ||
177 | |||
170 | static int | 178 | static int |
171 | rpc_pipe_open(struct inode *inode, struct file *filp) | 179 | rpc_pipe_open(struct inode *inode, struct file *filp) |
172 | { | 180 | { |