From 22a9d645677feefd402befd02edd59b122289ef1 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 7 Jan 2009 08:45:46 -0800 Subject: async: Asynchronous function calls to speed up kernel boot Right now, most of the kernel boot is strictly synchronous, such that various hardware delays are done sequentially. In order to make the kernel boot faster, this patch introduces infrastructure to allow doing some of the initialization steps asynchronously, which will hide significant portions of the hardware delays in practice. In order to not change device order and other similar observables, this patch does NOT do full parallel initialization. Rather, it operates more in the way an out of order CPU does; the work may be done out of order and asynchronous, but the observable effects (instruction retiring for the CPU) are still done in the original sequence. Signed-off-by: Arjan van de Ven --- include/linux/async.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 include/linux/async.h (limited to 'include/linux') diff --git a/include/linux/async.h b/include/linux/async.h new file mode 100644 index 000000000000..c4ecacd0b327 --- /dev/null +++ b/include/linux/async.h @@ -0,0 +1,25 @@ +/* + * async.h: Asynchronous function calls for boot performance + * + * (C) Copyright 2009 Intel Corporation + * Author: Arjan van de Ven + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include + +typedef u64 async_cookie_t; +typedef void (async_func_ptr) (void *data, async_cookie_t cookie); + +extern async_cookie_t async_schedule(async_func_ptr *ptr, void *data); +extern async_cookie_t async_schedule_special(async_func_ptr *ptr, void *data, struct list_head *list); +extern void async_synchronize_full(void); +extern void async_synchronize_full_special(struct list_head *list); +extern void async_synchronize_cookie(async_cookie_t cookie); +extern void async_synchronize_cookie_special(async_cookie_t cookie, struct list_head *list); + -- cgit v1.3-7-g2ca7 From efaee192063a54749c56b7383803e16fe553630e Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Tue, 6 Jan 2009 07:20:54 -0800 Subject: 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 --- fs/inode.c | 20 +++++++++++++------- fs/super.c | 10 ++++++++++ include/linux/fs.h | 5 +++++ 3 files changed, 28 insertions(+), 7 deletions(-) (limited to 'include/linux') 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 @@ #include #include #include +#include /* * This is needed for the following functions: @@ -1138,16 +1139,11 @@ EXPORT_SYMBOL(remove_inode_hash); * I_FREEING is set so that no-one will take a new reference to the inode while * it is being deleted. */ -void generic_delete_inode(struct inode *inode) +static void generic_delete_inode_async(void *data, async_cookie_t cookie) { + struct inode *inode = data; const struct super_operations *op = inode->i_sb->s_op; - list_del_init(&inode->i_list); - list_del_init(&inode->i_sb_list); - inode->i_state |= I_FREEING; - inodes_stat.nr_inodes--; - spin_unlock(&inode_lock); - security_inode_delete(inode); if (op->delete_inode) { @@ -1171,6 +1167,16 @@ void generic_delete_inode(struct inode *inode) destroy_inode(inode); } +void generic_delete_inode(struct inode *inode) +{ + list_del_init(&inode->i_list); + list_del_init(&inode->i_sb_list); + inode->i_state |= I_FREEING; + inodes_stat.nr_inodes--; + spin_unlock(&inode_lock); + async_schedule_special(generic_delete_inode_async, inode, &inode->i_sb->s_async_list); +} + EXPORT_SYMBOL(generic_delete_inode); static 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 @@ #include #include #include +#include #include #include "internal.h" @@ -71,6 +72,7 @@ static struct super_block *alloc_super(struct file_system_type *type) INIT_HLIST_HEAD(&s->s_anon); INIT_LIST_HEAD(&s->s_inodes); INIT_LIST_HEAD(&s->s_dentry_lru); + INIT_LIST_HEAD(&s->s_async_list); init_rwsem(&s->s_umount); mutex_init(&s->s_lock); lockdep_set_class(&s->s_umount, &type->s_umount_key); @@ -289,11 +291,18 @@ void generic_shutdown_super(struct super_block *sb) { const struct super_operations *sop = sb->s_op; + if (sb->s_root) { shrink_dcache_for_umount(sb); fsync_super(sb); lock_super(sb); sb->s_flags &= ~MS_ACTIVE; + + /* + * wait for asynchronous fs operations to finish before going further + */ + async_synchronize_full_special(&sb->s_async_list); + /* bad name - it should be evict_inodes() */ invalidate_inodes(sb); lock_kernel(); @@ -449,6 +458,7 @@ void sync_filesystems(int wait) if (sb->s_flags & MS_RDONLY) continue; sb->s_need_sync_fs = 1; + async_synchronize_full_special(&sb->s_async_list); } restart: 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 { * generic_show_options() */ char *s_options; + + /* + * storage for asynchronous operations + */ + struct list_head s_async_list; }; extern struct timespec current_fs_time(struct super_block *sb); -- cgit v1.3-7-g2ca7