diff options
author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:49:50 -0500 |
---|---|---|
committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:26 -0500 |
commit | ff0c7d15f9787b7e8c601533c015295cc68329f8 (patch) | |
tree | e3db53950b8ed78e542ab35a3cd3a6eaee26eccd | |
parent | fa0d7e3de6d6fc5004ad9dea0dd6b286af8f03e9 (diff) |
fs: avoid inode RCU freeing for pseudo fs
Pseudo filesystems that don't put inode on RCU list or reachable by
rcu-walk dentries do not need to RCU free their inodes.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
-rw-r--r-- | fs/inode.c | 6 | ||||
-rw-r--r-- | fs/pipe.c | 6 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | include/linux/net.h | 1 | ||||
-rw-r--r-- | net/socket.c | 17 |
5 files changed, 22 insertions, 9 deletions
diff --git a/fs/inode.c b/fs/inode.c index 6751dfe8cc06..da85e56378f3 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -257,6 +257,12 @@ static struct inode *alloc_inode(struct super_block *sb) | |||
257 | return inode; | 257 | return inode; |
258 | } | 258 | } |
259 | 259 | ||
260 | void free_inode_nonrcu(struct inode *inode) | ||
261 | { | ||
262 | kmem_cache_free(inode_cachep, inode); | ||
263 | } | ||
264 | EXPORT_SYMBOL(free_inode_nonrcu); | ||
265 | |||
260 | void __destroy_inode(struct inode *inode) | 266 | void __destroy_inode(struct inode *inode) |
261 | { | 267 | { |
262 | BUG_ON(inode_has_buffers(inode)); | 268 | BUG_ON(inode_has_buffers(inode)); |
@@ -1253,6 +1253,10 @@ out: | |||
1253 | return ret; | 1253 | return ret; |
1254 | } | 1254 | } |
1255 | 1255 | ||
1256 | static const struct super_operations pipefs_ops = { | ||
1257 | .destroy_inode = free_inode_nonrcu, | ||
1258 | }; | ||
1259 | |||
1256 | /* | 1260 | /* |
1257 | * pipefs should _never_ be mounted by userland - too much of security hassle, | 1261 | * pipefs should _never_ be mounted by userland - too much of security hassle, |
1258 | * no real gain from having the whole whorehouse mounted. So we don't need | 1262 | * no real gain from having the whole whorehouse mounted. So we don't need |
@@ -1262,7 +1266,7 @@ out: | |||
1262 | static struct dentry *pipefs_mount(struct file_system_type *fs_type, | 1266 | static struct dentry *pipefs_mount(struct file_system_type *fs_type, |
1263 | int flags, const char *dev_name, void *data) | 1267 | int flags, const char *dev_name, void *data) |
1264 | { | 1268 | { |
1265 | return mount_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC); | 1269 | return mount_pseudo(fs_type, "pipe:", &pipefs_ops, PIPEFS_MAGIC); |
1266 | } | 1270 | } |
1267 | 1271 | ||
1268 | static struct file_system_type pipe_fs_type = { | 1272 | static struct file_system_type pipe_fs_type = { |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 1ff4d0a33b25..ea202fff44f8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -2233,6 +2233,7 @@ extern void iget_failed(struct inode *); | |||
2233 | extern void end_writeback(struct inode *); | 2233 | extern void end_writeback(struct inode *); |
2234 | extern void __destroy_inode(struct inode *); | 2234 | extern void __destroy_inode(struct inode *); |
2235 | extern struct inode *new_inode(struct super_block *); | 2235 | extern struct inode *new_inode(struct super_block *); |
2236 | extern void free_inode_nonrcu(struct inode *inode); | ||
2236 | extern int should_remove_suid(struct dentry *); | 2237 | extern int should_remove_suid(struct dentry *); |
2237 | extern int file_remove_suid(struct file *); | 2238 | extern int file_remove_suid(struct file *); |
2238 | 2239 | ||
diff --git a/include/linux/net.h b/include/linux/net.h index 06bde4908473..16faa130088c 100644 --- a/include/linux/net.h +++ b/include/linux/net.h | |||
@@ -120,6 +120,7 @@ enum sock_shutdown_cmd { | |||
120 | struct socket_wq { | 120 | struct socket_wq { |
121 | wait_queue_head_t wait; | 121 | wait_queue_head_t wait; |
122 | struct fasync_struct *fasync_list; | 122 | struct fasync_struct *fasync_list; |
123 | struct rcu_head rcu; | ||
123 | } ____cacheline_aligned_in_smp; | 124 | } ____cacheline_aligned_in_smp; |
124 | 125 | ||
125 | /** | 126 | /** |
diff --git a/net/socket.c b/net/socket.c index 97fff3a4e72f..817dc92e9ef8 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -262,20 +262,21 @@ static struct inode *sock_alloc_inode(struct super_block *sb) | |||
262 | } | 262 | } |
263 | 263 | ||
264 | 264 | ||
265 | static void sock_free_rcu(struct rcu_head *head) | 265 | |
266 | static void wq_free_rcu(struct rcu_head *head) | ||
266 | { | 267 | { |
267 | struct inode *inode = container_of(head, struct inode, i_rcu); | 268 | struct socket_wq *wq = container_of(head, struct socket_wq, rcu); |
268 | struct socket_alloc *ei = container_of(inode, struct socket_alloc, | ||
269 | vfs_inode); | ||
270 | 269 | ||
271 | kfree(ei->socket.wq); | 270 | kfree(wq); |
272 | INIT_LIST_HEAD(&inode->i_dentry); | ||
273 | kmem_cache_free(sock_inode_cachep, ei); | ||
274 | } | 271 | } |
275 | 272 | ||
276 | static void sock_destroy_inode(struct inode *inode) | 273 | static void sock_destroy_inode(struct inode *inode) |
277 | { | 274 | { |
278 | call_rcu(&inode->i_rcu, sock_free_rcu); | 275 | struct socket_alloc *ei; |
276 | |||
277 | ei = container_of(inode, struct socket_alloc, vfs_inode); | ||
278 | call_rcu(&ei->socket.wq->rcu, wq_free_rcu); | ||
279 | kmem_cache_free(sock_inode_cachep, ei); | ||
279 | } | 280 | } |
280 | 281 | ||
281 | static void init_once(void *foo) | 282 | static void init_once(void *foo) |