aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2009-01-06 10:20:54 -0500
committerArjan van de Ven <arjan@linux.intel.com>2009-01-07 11:47:24 -0500
commitefaee192063a54749c56b7383803e16fe553630e (patch)
treeb18e3072904e53701bdd7889bb32babf8cc7bf7c
parentf29d3b23238e1955a8094e038c72546e99308e61 (diff)
async: make the final inode deletion an asynchronous event
this makes "rm -rf" on a (names cached) kernel tree go from 11.6 to 8.6 seconds on an ext3 filesystem Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
-rw-r--r--fs/inode.c20
-rw-r--r--fs/super.c10
-rw-r--r--include/linux/fs.h5
3 files changed, 28 insertions, 7 deletions
diff --git a/fs/inode.c b/fs/inode.c
index 7a6e8c2ff7b1..0013ac1af8e7 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -22,6 +22,7 @@
22#include <linux/bootmem.h> 22#include <linux/bootmem.h>
23#include <linux/inotify.h> 23#include <linux/inotify.h>
24#include <linux/mount.h> 24#include <linux/mount.h>
25#include <linux/async.h>
25 26
26/* 27/*
27 * This is needed for the following functions: 28 * This is needed for the following functions:
@@ -1138,16 +1139,11 @@ EXPORT_SYMBOL(remove_inode_hash);
1138 * I_FREEING is set so that no-one will take a new reference to the inode while 1139 * I_FREEING is set so that no-one will take a new reference to the inode while
1139 * it is being deleted. 1140 * it is being deleted.
1140 */ 1141 */
1141void generic_delete_inode(struct inode *inode) 1142static void generic_delete_inode_async(void *data, async_cookie_t cookie)
1142{ 1143{
1144 struct inode *inode = data;
1143 const struct super_operations *op = inode->i_sb->s_op; 1145 const struct super_operations *op = inode->i_sb->s_op;
1144 1146
1145 list_del_init(&inode->i_list);
1146 list_del_init(&inode->i_sb_list);
1147 inode->i_state |= I_FREEING;
1148 inodes_stat.nr_inodes--;
1149 spin_unlock(&inode_lock);
1150
1151 security_inode_delete(inode); 1147 security_inode_delete(inode);
1152 1148
1153 if (op->delete_inode) { 1149 if (op->delete_inode) {
@@ -1171,6 +1167,16 @@ void generic_delete_inode(struct inode *inode)
1171 destroy_inode(inode); 1167 destroy_inode(inode);
1172} 1168}
1173 1169
1170void generic_delete_inode(struct inode *inode)
1171{
1172 list_del_init(&inode->i_list);
1173 list_del_init(&inode->i_sb_list);
1174 inode->i_state |= I_FREEING;
1175 inodes_stat.nr_inodes--;
1176 spin_unlock(&inode_lock);
1177 async_schedule_special(generic_delete_inode_async, inode, &inode->i_sb->s_async_list);
1178}
1179
1174EXPORT_SYMBOL(generic_delete_inode); 1180EXPORT_SYMBOL(generic_delete_inode);
1175 1181
1176static void generic_forget_inode(struct inode *inode) 1182static void generic_forget_inode(struct inode *inode)
diff --git a/fs/super.c b/fs/super.c
index ddba069d7a99..cb20744ec789 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -38,6 +38,7 @@
38#include <linux/kobject.h> 38#include <linux/kobject.h>
39#include <linux/mutex.h> 39#include <linux/mutex.h>
40#include <linux/file.h> 40#include <linux/file.h>
41#include <linux/async.h>
41#include <asm/uaccess.h> 42#include <asm/uaccess.h>
42#include "internal.h" 43#include "internal.h"
43 44
@@ -71,6 +72,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
71 INIT_HLIST_HEAD(&s->s_anon); 72 INIT_HLIST_HEAD(&s->s_anon);
72 INIT_LIST_HEAD(&s->s_inodes); 73 INIT_LIST_HEAD(&s->s_inodes);
73 INIT_LIST_HEAD(&s->s_dentry_lru); 74 INIT_LIST_HEAD(&s->s_dentry_lru);
75 INIT_LIST_HEAD(&s->s_async_list);
74 init_rwsem(&s->s_umount); 76 init_rwsem(&s->s_umount);
75 mutex_init(&s->s_lock); 77 mutex_init(&s->s_lock);
76 lockdep_set_class(&s->s_umount, &type->s_umount_key); 78 lockdep_set_class(&s->s_umount, &type->s_umount_key);
@@ -289,11 +291,18 @@ void generic_shutdown_super(struct super_block *sb)
289{ 291{
290 const struct super_operations *sop = sb->s_op; 292 const struct super_operations *sop = sb->s_op;
291 293
294
292 if (sb->s_root) { 295 if (sb->s_root) {
293 shrink_dcache_for_umount(sb); 296 shrink_dcache_for_umount(sb);
294 fsync_super(sb); 297 fsync_super(sb);
295 lock_super(sb); 298 lock_super(sb);
296 sb->s_flags &= ~MS_ACTIVE; 299 sb->s_flags &= ~MS_ACTIVE;
300
301 /*
302 * wait for asynchronous fs operations to finish before going further
303 */
304 async_synchronize_full_special(&sb->s_async_list);
305
297 /* bad name - it should be evict_inodes() */ 306 /* bad name - it should be evict_inodes() */
298 invalidate_inodes(sb); 307 invalidate_inodes(sb);
299 lock_kernel(); 308 lock_kernel();
@@ -449,6 +458,7 @@ void sync_filesystems(int wait)
449 if (sb->s_flags & MS_RDONLY) 458 if (sb->s_flags & MS_RDONLY)
450 continue; 459 continue;
451 sb->s_need_sync_fs = 1; 460 sb->s_need_sync_fs = 1;
461 async_synchronize_full_special(&sb->s_async_list);
452 } 462 }
453 463
454restart: 464restart:
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d7eba77f666e..e38a64d71eff 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1184,6 +1184,11 @@ struct super_block {
1184 * generic_show_options() 1184 * generic_show_options()
1185 */ 1185 */
1186 char *s_options; 1186 char *s_options;
1187
1188 /*
1189 * storage for asynchronous operations
1190 */
1191 struct list_head s_async_list;
1187}; 1192};
1188 1193
1189extern struct timespec current_fs_time(struct super_block *sb); 1194extern struct timespec current_fs_time(struct super_block *sb);