* [PATCH 0/2] Push the asynchronous function call concept a little further
@ 2009-01-06 21:06 Arjan van de Ven
2009-01-06 21:07 ` [PATCH 1/2] async: allow for multiple independent synchronization domains Arjan van de Ven
2009-01-06 21:08 ` [PATCH 2/2] async: make the final inode deletion an asynchronous event Arjan van de Ven
0 siblings, 2 replies; 3+ messages in thread
From: Arjan van de Ven @ 2009-01-06 21:06 UTC (permalink / raw)
To: linux-kernel; +Cc: linux-fs, torvalds
Hi,
the 2 patches in this series try to push the asynchronous function call
concept a little further;
the first patch allows for creating multiple queues so that you can do
synchronization on your own queue without creating congestion in the
one global queue (for example, as used in the 2nd patch, a per
superblock queue).
the second patch uses a per superblock queue to make the last part of
file deletion (the actual removal of the file content from disk)
using the async function call concept.
The cut is done after the inode is removed from the VFS (and where the
code can and does sleep), but before calling into the filesystem to do
the actual removal. The locking etc around this should be safe due to
the sleep-ability and the fact that the inode is already out of the VFS
namespaces (eg it's in I_FREEING).
On my testbox, rm -rf of a kernel tree went from 11.6 to 8.6 seconds
with this; with smaller rm's I expect the gain to be more (to the point
where applications that only occasionally delete files no longer will
stutter around this as much).
--
Arjan van de Ven Intel Open Source Technology Centre
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] async: allow for multiple independent synchronization domains
2009-01-06 21:06 [PATCH 0/2] Push the asynchronous function call concept a little further Arjan van de Ven
@ 2009-01-06 21:07 ` Arjan van de Ven
2009-01-06 21:08 ` [PATCH 2/2] async: make the final inode deletion an asynchronous event Arjan van de Ven
1 sibling, 0 replies; 3+ messages in thread
From: Arjan van de Ven @ 2009-01-06 21:07 UTC (permalink / raw)
To: linux-kernel; +Cc: Arjan van de Ven, linux-fs, torvalds
>From 6353d3c8c9e11127961c2f366abc8ea0c7cb0e92 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Tue, 6 Jan 2009 07:19:33 -0800
Subject: [PATCH] async: allow for multiple independent synchronization domains
for a wider use of async function calls it's nice to have multiple
domains for synchronization, for example, in the VFS world each superblock
would be its own domain.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
include/linux/async.h | 4 ++++
kernel/async.c | 49 +++++++++++++++++++++++++++++++++++--------------
2 files changed, 39 insertions(+), 14 deletions(-)
diff --git a/include/linux/async.h b/include/linux/async.h
index 678d4fd..6f0a3ba 100644
--- a/include/linux/async.h
+++ b/include/linux/async.h
@@ -11,11 +11,15 @@
*/
#include <linux/types.h>
+#include <linux/list.h>
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);
diff --git a/kernel/async.c b/kernel/async.c
index 8ecebf5..652804b 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -57,7 +57,6 @@ asynchronous and synchronous parts of the kernel.
#include <asm/atomic.h>
static async_cookie_t next_cookie = 1;
-static async_cookie_t lowest_in_progress = 1;
static LIST_HEAD(async_pending);
@@ -69,6 +68,7 @@ struct async_entry {
async_cookie_t cookie;
async_func_ptr *func;
void *data;
+ struct list_head *running;
};
static DECLARE_WAIT_QUEUE_HEAD(async_done);
@@ -83,20 +83,20 @@ extern int initcall_debug;
/*
* MUST be called with the lock held!
*/
-static void __recalc_lowest_in_progress(void)
+static async_cookie_t __lowest_in_progress(struct list_head *running)
{
struct async_entry *entry;
if (!list_empty(&async_pending)) {
entry = list_first_entry(&async_pending,
struct async_entry, list);
- lowest_in_progress = entry->cookie;
- } else if (!list_empty(&async_running)) {
- entry = list_first_entry(&async_running,
+ return entry->cookie;
+ } else if (!list_empty(running)) {
+ entry = list_first_entry(running,
struct async_entry, list);
- lowest_in_progress = entry->cookie;
+ return entry->cookie;
} else {
/* nothing in progress... next_cookie is "infinity" */
- lowest_in_progress = next_cookie;
+ return next_cookie;
}
}
@@ -142,12 +142,9 @@ static void run_one_entry(void)
kfree(entry);
atomic_dec(&entry_count);
- /* 6) update the lowest_in_progress value */
- __recalc_lowest_in_progress();
-
spin_unlock_irqrestore(&async_lock, flags);
- /* 7) wake up any waiters. */
+ /* 6) wake up any waiters. */
wake_up(&async_done);
return;
@@ -156,7 +153,7 @@ out:
}
-async_cookie_t async_schedule(async_func_ptr *ptr, void *data)
+static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct list_head *running)
{
struct async_entry *entry;
unsigned long flags;
@@ -176,6 +173,7 @@ async_cookie_t async_schedule(async_func_ptr *ptr, void *data)
}
entry->func = ptr;
entry->data = data;
+ entry->running = running;
spin_lock_irqsave(&async_lock, flags);
newcookie = entry->cookie = next_cookie++;
@@ -185,15 +183,32 @@ async_cookie_t async_schedule(async_func_ptr *ptr, void *data)
wake_up(&async_new);
return newcookie;
}
+
+async_cookie_t async_schedule(async_func_ptr *ptr, void *data)
+{
+ return __async_schedule(ptr, data, &async_pending);
+}
EXPORT_SYMBOL_GPL(async_schedule);
+async_cookie_t async_schedule_special(async_func_ptr *ptr, void *data, struct list_head *running)
+{
+ return __async_schedule(ptr, data, running);
+}
+EXPORT_SYMBOL_GPL(async_schedule_special);
+
void async_synchronize_full(void)
{
async_synchronize_cookie(next_cookie);
}
EXPORT_SYMBOL_GPL(async_synchronize_full);
-void async_synchronize_cookie(async_cookie_t cookie)
+void async_synchronize_full_special(struct list_head *list)
+{
+ async_synchronize_cookie_special(next_cookie, list);
+}
+EXPORT_SYMBOL_GPL(async_synchronize_full_special);
+
+void async_synchronize_cookie_special(async_cookie_t cookie, struct list_head *running)
{
ktime_t starttime, delta, endtime;
@@ -202,7 +217,7 @@ void async_synchronize_cookie(async_cookie_t cookie)
starttime = ktime_get();
}
- wait_event(async_done, lowest_in_progress >= cookie);
+ wait_event(async_done, __lowest_in_progress(running) >= cookie);
if (initcall_debug) {
endtime = ktime_get();
@@ -212,6 +227,12 @@ void async_synchronize_cookie(async_cookie_t cookie)
task_pid_nr(current), ktime_to_ns(delta) >> 10);
}
}
+EXPORT_SYMBOL_GPL(async_synchronize_cookie_special);
+
+void async_synchronize_cookie(async_cookie_t cookie)
+{
+ async_synchronize_cookie_special(cookie, &async_running);
+}
EXPORT_SYMBOL_GPL(async_synchronize_cookie);
--
1.5.5.1
--
Arjan van de Ven Intel Open Source Technology Centre
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] async: make the final inode deletion an asynchronous event
2009-01-06 21:06 [PATCH 0/2] Push the asynchronous function call concept a little further Arjan van de Ven
2009-01-06 21:07 ` [PATCH 1/2] async: allow for multiple independent synchronization domains Arjan van de Ven
@ 2009-01-06 21:08 ` Arjan van de Ven
1 sibling, 0 replies; 3+ messages in thread
From: Arjan van de Ven @ 2009-01-06 21:08 UTC (permalink / raw)
To: Arjan van de Ven; +Cc: linux-kernel, linux-fs, torvalds
>From fc952f480bc4aec90e189b28196ecd7079d0b778 Mon Sep 17 00:00:00 2001
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Tue, 6 Jan 2009 07:20:54 -0800
Subject: [PATCH] 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>
---
fs/inode.c | 20 +++++++++++++-------
fs/super.c | 10 ++++++++++
include/linux/fs.h | 5 +++++
3 files changed, 28 insertions(+), 7 deletions(-)
diff --git a/fs/inode.c b/fs/inode.c
index 7de1cda..a4b9696 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -22,6 +22,7 @@
#include <linux/bootmem.h>
#include <linux/inotify.h>
#include <linux/mount.h>
+#include <linux/async.h>
/*
* This is needed for the following functions:
@@ -1136,16 +1137,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) {
@@ -1169,6 +1165,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 ddba069..a0b103a 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -38,6 +38,7 @@
#include <linux/kobject.h>
#include <linux/mutex.h>
#include <linux/file.h>
+#include <linux/async.h>
#include <asm/uaccess.h>
#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 f2a3010..c64a299 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1185,6 +1185,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);
--
1.5.5.1
--
Arjan van de Ven Intel Open Source Technology Centre
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2009-01-06 21:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-06 21:06 [PATCH 0/2] Push the asynchronous function call concept a little further Arjan van de Ven
2009-01-06 21:07 ` [PATCH 1/2] async: allow for multiple independent synchronization domains Arjan van de Ven
2009-01-06 21:08 ` [PATCH 2/2] async: make the final inode deletion an asynchronous event Arjan van de Ven
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox