* [0/5] standardized waitqueue hashing
@ 2004-08-28 20:05 William Lee Irwin III
2004-08-28 20:06 ` [1/5] move waitqueue functions to kernel/wait.c William Lee Irwin III
0 siblings, 1 reply; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 20:05 UTC (permalink / raw)
To: linux-kernel; +Cc: akpm
The following patch series consolidates the various instances of
waitqueue hashing to use a uniform structure and share the per-zone
hashtable among all waitqueue hashers. This is expected to increase the
number of hashtable buckets available for waiting on bh's and inodes
and eliminate statically allocated kernel data structures for greater
node locality and reduced kernel image size. Some attempt was made to
look similar to Oleg Nesterov's suggested API in order to provide some
kind of credit for independent invention of something very similar (the
original versions of these patches predated my public postings on the
subject of filtered waitqueues).
These patches have the further benefit and intention of enabling aio
to use filtered wakeups by standardizing the data structure passed to
wake functions so that embedded waitqueue elements in aio structures
may be succesfully passed to the filtered wakeup wake functions, though
this patch series doesn't implement that particular functionality.
Successfully stress-tested on x86-64, and ia64 in recent prior versions.
-- wli
^ permalink raw reply [flat|nested] 11+ messages in thread
* [1/5] move waitqueue functions to kernel/wait.c
2004-08-28 20:05 [0/5] standardized waitqueue hashing William Lee Irwin III
@ 2004-08-28 20:06 ` William Lee Irwin III
2004-08-28 20:08 ` [2/5] consolidate bit waiting code patterns William Lee Irwin III
0 siblings, 1 reply; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 20:06 UTC (permalink / raw)
To: linux-kernel; +Cc: akpm
On Sat, Aug 28, 2004 at 01:05:49PM -0700, William Lee Irwin III wrote:
> These patches have the further benefit and intention of enabling aio
> to use filtered wakeups by standardizing the data structure passed to
> wake functions so that embedded waitqueue elements in aio structures
> may be succesfully passed to the filtered wakeup wake functions, though
> this patch series doesn't implement that particular functionality.
> Successfully stress-tested on x86-64, and ia64 in recent prior versions.
Move waitqueue -related functions not needing static functions in
sched.c to kernel/wait.c
Index: wait-2.6.9-rc1-mm1/kernel/Makefile
===================================================================
--- wait-2.6.9-rc1-mm1.orig/kernel/Makefile 2004-08-28 09:43:20.428470784 -0700
+++ wait-2.6.9-rc1-mm1/kernel/Makefile 2004-08-28 09:45:17.915610024 -0700
@@ -7,7 +7,7 @@
sysctl.o capability.o ptrace.o timer.o user.o \
signal.o sys.o kmod.o workqueue.o pid.o \
rcupdate.o intermodule.o extable.o params.o posix-timers.o \
- kthread.o
+ kthread.o wait.o
obj-$(CONFIG_FUTEX) += futex.o
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
Index: wait-2.6.9-rc1-mm1/kernel/wait.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ wait-2.6.9-rc1-mm1/kernel/wait.c 2004-08-28 09:46:45.808248312 -0700
@@ -0,0 +1,129 @@
+/*
+ * Generic waiting primitives.
+ *
+ * (C) 2004 William Irwin, Oracle
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ unsigned long flags;
+
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ __add_wait_queue(q, wait);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(add_wait_queue);
+
+void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ unsigned long flags;
+
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ __add_wait_queue_tail(q, wait);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(add_wait_queue_exclusive);
+
+void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ __remove_wait_queue(q, wait);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(remove_wait_queue);
+
+
+/*
+ * Note: we use "set_current_state()" _after_ the wait-queue add,
+ * because we need a memory barrier there on SMP, so that any
+ * wake-function that tests for the wait-queue being active
+ * will be guaranteed to see waitqueue addition _or_ subsequent
+ * tests in this thread will see the wakeup having taken place.
+ *
+ * The spin_unlock() itself is semi-permeable and only protects
+ * one way (it only protects stuff inside the critical region and
+ * stops them from bleeding out - it would still allow subsequent
+ * loads to move into the the critical region).
+ */
+void fastcall
+prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ unsigned long flags;
+
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ if (list_empty(&wait->task_list))
+ __add_wait_queue(q, wait);
+ /*
+ * don't alter the task state if this is just going to
+ * queue an async wait queue callback
+ */
+ if (is_sync_wait(wait))
+ set_current_state(state);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(prepare_to_wait);
+
+void fastcall
+prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ unsigned long flags;
+
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ if (list_empty(&wait->task_list))
+ __add_wait_queue_tail(q, wait);
+ /*
+ * don't alter the task state if this is just going to
+ * queue an async wait queue callback
+ */
+ if (is_sync_wait(wait))
+ set_current_state(state);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+EXPORT_SYMBOL(prepare_to_wait_exclusive);
+
+void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ unsigned long flags;
+
+ __set_current_state(TASK_RUNNING);
+ /*
+ * We can check for list emptiness outside the lock
+ * IFF:
+ * - we use the "careful" check that verifies both
+ * the next and prev pointers, so that there cannot
+ * be any half-pending updates in progress on other
+ * CPU's that we haven't seen yet (and that might
+ * still change the stack area.
+ * and
+ * - all other users take the lock (ie we can only
+ * have _one_ other CPU that looks at or modifies
+ * the list).
+ */
+ if (!list_empty_careful(&wait->task_list)) {
+ spin_lock_irqsave(&q->lock, flags);
+ list_del_init(&wait->task_list);
+ spin_unlock_irqrestore(&q->lock, flags);
+ }
+}
+EXPORT_SYMBOL(finish_wait);
+
+int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ int ret = default_wake_function(wait, mode, sync, key);
+
+ if (ret)
+ list_del_init(&wait->task_list);
+ return ret;
+}
+EXPORT_SYMBOL(autoremove_wake_function);
Index: wait-2.6.9-rc1-mm1/kernel/fork.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/kernel/fork.c 2004-08-28 09:43:34.177380632 -0700
+++ wait-2.6.9-rc1-mm1/kernel/fork.c 2004-08-28 09:45:17.925608504 -0700
@@ -102,131 +102,6 @@
free_task(tsk);
}
-void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
-{
- unsigned long flags;
-
- wait->flags &= ~WQ_FLAG_EXCLUSIVE;
- spin_lock_irqsave(&q->lock, flags);
- __add_wait_queue(q, wait);
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-EXPORT_SYMBOL(add_wait_queue);
-
-void fastcall add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)
-{
- unsigned long flags;
-
- wait->flags |= WQ_FLAG_EXCLUSIVE;
- spin_lock_irqsave(&q->lock, flags);
- __add_wait_queue_tail(q, wait);
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-EXPORT_SYMBOL(add_wait_queue_exclusive);
-
-void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
- __remove_wait_queue(q, wait);
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-EXPORT_SYMBOL(remove_wait_queue);
-
-
-/*
- * Note: we use "set_current_state()" _after_ the wait-queue add,
- * because we need a memory barrier there on SMP, so that any
- * wake-function that tests for the wait-queue being active
- * will be guaranteed to see waitqueue addition _or_ subsequent
- * tests in this thread will see the wakeup having taken place.
- *
- * The spin_unlock() itself is semi-permeable and only protects
- * one way (it only protects stuff inside the critical region and
- * stops them from bleeding out - it would still allow subsequent
- * loads to move into the the critical region).
- */
-void fastcall prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
-{
- unsigned long flags;
-
- wait->flags &= ~WQ_FLAG_EXCLUSIVE;
- spin_lock_irqsave(&q->lock, flags);
- if (list_empty(&wait->task_list))
- __add_wait_queue(q, wait);
- /*
- * don't alter the task state if this is just going to
- * queue an async wait queue callback
- */
- if (is_sync_wait(wait))
- set_current_state(state);
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-EXPORT_SYMBOL(prepare_to_wait);
-
-void fastcall
-prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
-{
- unsigned long flags;
-
- wait->flags |= WQ_FLAG_EXCLUSIVE;
- spin_lock_irqsave(&q->lock, flags);
- if (list_empty(&wait->task_list))
- __add_wait_queue_tail(q, wait);
- /*
- * don't alter the task state if this is just going to
- * queue an async wait queue callback
- */
- if (is_sync_wait(wait))
- set_current_state(state);
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-EXPORT_SYMBOL(prepare_to_wait_exclusive);
-
-void fastcall finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
-{
- unsigned long flags;
-
- __set_current_state(TASK_RUNNING);
- /*
- * We can check for list emptiness outside the lock
- * IFF:
- * - we use the "careful" check that verifies both
- * the next and prev pointers, so that there cannot
- * be any half-pending updates in progress on other
- * CPU's that we haven't seen yet (and that might
- * still change the stack area.
- * and
- * - all other users take the lock (ie we can only
- * have _one_ other CPU that looks at or modifies
- * the list).
- */
- if (!list_empty_careful(&wait->task_list)) {
- spin_lock_irqsave(&q->lock, flags);
- list_del_init(&wait->task_list);
- spin_unlock_irqrestore(&q->lock, flags);
- }
-}
-
-EXPORT_SYMBOL(finish_wait);
-
-int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
-{
- int ret = default_wake_function(wait, mode, sync, key);
-
- if (ret)
- list_del_init(&wait->task_list);
- return ret;
-}
-
-EXPORT_SYMBOL(autoremove_wake_function);
-
void __init fork_init(unsigned long mempages)
{
#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR
^ permalink raw reply [flat|nested] 11+ messages in thread
* [2/5] consolidate bit waiting code patterns
2004-08-28 20:06 ` [1/5] move waitqueue functions to kernel/wait.c William Lee Irwin III
@ 2004-08-28 20:08 ` William Lee Irwin III
2004-08-28 20:09 ` [3/5] " William Lee Irwin III
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 20:08 UTC (permalink / raw)
To: linux-kernel; +Cc: akpm
On Sat, Aug 28, 2004 at 01:06:59PM -0700, William Lee Irwin III wrote:
> Move waitqueue -related functions not needing static functions in
> sched.c to kernel/wait.c
Eliminate specialized page and bh waitqueue hashing structures in favor
of a standardized structure, using wake_up_bit() to wake waiters using
the standardized wait_bit_key structure.
Index: wait-2.6.9-rc1-mm1/fs/buffer.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/fs/buffer.c 2004-08-28 09:43:30.305969176 -0700
+++ wait-2.6.9-rc1-mm1/fs/buffer.c 2004-08-28 09:47:21.232862952 -0700
@@ -43,26 +43,6 @@
#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
-struct bh_wait_queue {
- struct buffer_head *bh;
- wait_queue_t wait;
-};
-
-#define __DEFINE_BH_WAIT(name, b, f) \
- struct bh_wait_queue name = { \
- .bh = b, \
- .wait = { \
- .task = current, \
- .flags = f, \
- .func = bh_wake_function, \
- .task_list = \
- LIST_HEAD_INIT(name.wait.task_list),\
- }, \
- }
-#define DEFINE_BH_WAIT(name, bh) __DEFINE_BH_WAIT(name, bh, 0)
-#define DEFINE_BH_WAIT_EXCLUSIVE(name, bh) \
- __DEFINE_BH_WAIT(name, bh, WQ_FLAG_EXCLUSIVE)
-
/*
* Hashed waitqueue_head's for wait_on_buffer()
*/
@@ -93,24 +73,10 @@
wait_queue_head_t *wq = bh_waitq_head(bh);
smp_mb();
- if (waitqueue_active(wq))
- __wake_up(wq, TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE, 1, bh);
+ __wake_up_bit(wq, &bh->b_state, BH_Lock);
}
EXPORT_SYMBOL(wake_up_buffer);
-static int bh_wake_function(wait_queue_t *wait, unsigned mode,
- int sync, void *key)
-{
- struct buffer_head *bh = key;
- struct bh_wait_queue *wq;
-
- wq = container_of(wait, struct bh_wait_queue, wait);
- if (wq->bh != bh || buffer_locked(bh))
- return 0;
- else
- return autoremove_wake_function(wait, mode, sync, key);
-}
-
static void sync_buffer(struct buffer_head *bh)
{
struct block_device *bd;
@@ -124,7 +90,7 @@
void fastcall __lock_buffer(struct buffer_head *bh)
{
wait_queue_head_t *wqh = bh_waitq_head(bh);
- DEFINE_BH_WAIT_EXCLUSIVE(wait, bh);
+ DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Lock);
do {
prepare_to_wait_exclusive(wqh, &wait.wait,
@@ -153,15 +119,13 @@
void __wait_on_buffer(struct buffer_head * bh)
{
wait_queue_head_t *wqh = bh_waitq_head(bh);
- DEFINE_BH_WAIT(wait, bh);
+ DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Lock);
- do {
- prepare_to_wait(wqh, &wait.wait, TASK_UNINTERRUPTIBLE);
- if (buffer_locked(bh)) {
- sync_buffer(bh);
- io_schedule();
- }
- } while (buffer_locked(bh));
+ prepare_to_wait(wqh, &wait.wait, TASK_UNINTERRUPTIBLE);
+ if (buffer_locked(bh)) {
+ sync_buffer(bh);
+ io_schedule();
+ }
finish_wait(wqh, &wait.wait);
}
Index: wait-2.6.9-rc1-mm1/kernel/wait.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/kernel/wait.c 2004-08-28 09:46:45.808248312 -0700
+++ wait-2.6.9-rc1-mm1/kernel/wait.c 2004-08-28 09:47:21.247860672 -0700
@@ -127,3 +127,26 @@
return ret;
}
EXPORT_SYMBOL(autoremove_wake_function);
+
+int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
+{
+ struct wait_bit_key *key = arg;
+ struct wait_bit_queue *wait_bit
+ = container_of(wait, struct wait_bit_queue, wait);
+
+ if (wait_bit->key.flags != key->flags ||
+ wait_bit->key.bit_nr != key->bit_nr ||
+ test_bit(key->bit_nr, key->flags))
+ return 0;
+ else
+ return autoremove_wake_function(wait, mode, sync, key);
+}
+EXPORT_SYMBOL(wake_bit_function);
+
+void fastcall __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
+{
+ struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
+ if (waitqueue_active(wq))
+ __wake_up(wq, TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE, 1, &key);
+}
+EXPORT_SYMBOL(__wake_up_bit);
Index: wait-2.6.9-rc1-mm1/mm/filemap.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/mm/filemap.c 2004-08-28 09:43:39.875514384 -0700
+++ wait-2.6.9-rc1-mm1/mm/filemap.c 2004-08-28 09:47:21.244861128 -0700
@@ -355,40 +355,6 @@
* at a cost of "thundering herd" phenomena during rare hash
* collisions.
*/
-struct page_wait_queue {
- struct page *page;
- int bit;
- wait_queue_t wait;
-};
-
-static int page_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
-{
- struct page *page = key;
- struct page_wait_queue *wq;
-
- wq = container_of(wait, struct page_wait_queue, wait);
- if (wq->page != page || test_bit(wq->bit, &page->flags))
- return 0;
- else
- return autoremove_wake_function(wait, mode, sync, NULL);
-}
-
-#define __DEFINE_PAGE_WAIT(name, p, b, f) \
- struct page_wait_queue name = { \
- .page = p, \
- .bit = b, \
- .wait = { \
- .task = current, \
- .func = page_wake_function, \
- .flags = f, \
- .task_list = LIST_HEAD_INIT(name.wait.task_list),\
- }, \
- }
-
-#define DEFINE_PAGE_WAIT(name, p, b) __DEFINE_PAGE_WAIT(name, p, b, 0)
-#define DEFINE_PAGE_WAIT_EXCLUSIVE(name, p, b) \
- __DEFINE_PAGE_WAIT(name, p, b, WQ_FLAG_EXCLUSIVE)
-
static wait_queue_head_t *page_waitqueue(struct page *page)
{
const struct zone *zone = page_zone(page);
@@ -396,27 +362,16 @@
return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
}
-static void wake_up_page(struct page *page)
-{
- const unsigned int mode = TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE;
- wait_queue_head_t *waitqueue = page_waitqueue(page);
-
- if (waitqueue_active(waitqueue))
- __wake_up(waitqueue, mode, 1, page);
-}
-
void fastcall wait_on_page_bit(struct page *page, int bit_nr)
{
wait_queue_head_t *waitqueue = page_waitqueue(page);
- DEFINE_PAGE_WAIT(wait, page, bit_nr);
+ DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
- do {
- prepare_to_wait(waitqueue, &wait.wait, TASK_UNINTERRUPTIBLE);
- if (test_bit(bit_nr, &page->flags)) {
- sync_page(page);
- io_schedule();
- }
- } while (test_bit(bit_nr, &page->flags));
+ prepare_to_wait(waitqueue, &wait.wait, TASK_UNINTERRUPTIBLE);
+ if (test_bit(bit_nr, &page->flags)) {
+ sync_page(page);
+ io_schedule();
+ }
finish_wait(waitqueue, &wait.wait);
}
@@ -443,7 +398,7 @@
if (!TestClearPageLocked(page))
BUG();
smp_mb__after_clear_bit();
- wake_up_page(page);
+ __wake_up_bit(page_waitqueue(page), &page->flags, PG_locked);
}
EXPORT_SYMBOL(unlock_page);
@@ -459,7 +414,7 @@
BUG();
smp_mb__after_clear_bit();
}
- wake_up_page(page);
+ __wake_up_bit(page_waitqueue(page), &page->flags, PG_writeback);
}
EXPORT_SYMBOL(end_page_writeback);
@@ -475,7 +430,7 @@
void fastcall __lock_page(struct page *page)
{
wait_queue_head_t *wqh = page_waitqueue(page);
- DEFINE_PAGE_WAIT_EXCLUSIVE(wait, page, PG_locked);
+ DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
while (TestSetPageLocked(page)) {
prepare_to_wait_exclusive(wqh, &wait.wait, TASK_UNINTERRUPTIBLE);
Index: wait-2.6.9-rc1-mm1/include/linux/wait.h
===================================================================
--- wait-2.6.9-rc1-mm1.orig/include/linux/wait.h 2004-08-28 09:43:13.546517000 -0700
+++ wait-2.6.9-rc1-mm1/include/linux/wait.h 2004-08-28 09:47:21.236862344 -0700
@@ -37,6 +37,16 @@
struct list_head task_list;
};
+struct wait_bit_key {
+ void *flags;
+ int bit_nr;
+};
+
+struct wait_bit_queue {
+ struct wait_bit_key key;
+ wait_queue_t wait;
+};
+
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
@@ -63,6 +73,9 @@
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
+#define __WAIT_BIT_KEY_INITIALIZER(word, bit) \
+ { .flags = word, .bit_nr = bit, }
+
static inline void init_waitqueue_head(wait_queue_head_t *q)
{
q->lock = SPIN_LOCK_UNLOCKED;
@@ -125,6 +138,7 @@
void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key));
extern void FASTCALL(__wake_up_locked(wait_queue_head_t *q, unsigned int mode));
extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr));
+void FASTCALL(__wake_up_bit(wait_queue_head_t *, void *, int));
#define wake_up(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
#define wake_up_nr(x, nr) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr, NULL)
@@ -277,6 +291,7 @@
wait_queue_t *wait, int state));
void FASTCALL(finish_wait(wait_queue_head_t *q, wait_queue_t *wait));
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
+int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
#define DEFINE_WAIT(name) \
wait_queue_t name = { \
@@ -287,6 +302,17 @@
}, \
}
+#define DEFINE_WAIT_BIT(name, word, bit) \
+ struct wait_bit_queue name = { \
+ .key = __WAIT_BIT_KEY_INITIALIZER(word, bit), \
+ .wait = { \
+ .task = current, \
+ .func = wake_bit_function, \
+ .task_list = \
+ LIST_HEAD_INIT(name.wait.task_list), \
+ }, \
+ }
+
#define init_wait(wait) \
do { \
wait->task = current; \
^ permalink raw reply [flat|nested] 11+ messages in thread
* [3/5] consolidate bit waiting code patterns
2004-08-28 20:08 ` [2/5] consolidate bit waiting code patterns William Lee Irwin III
@ 2004-08-28 20:09 ` William Lee Irwin III
2004-08-28 20:11 ` [4/5] eliminate bh waitqueue hashtable William Lee Irwin III
2004-08-28 20:21 ` [2/5] consolidate bit waiting code patterns William Lee Irwin III
2004-08-28 22:29 ` Andrew Morton
2 siblings, 1 reply; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 20:09 UTC (permalink / raw)
To: linux-kernel; +Cc: akpm
On Sat, Aug 28, 2004 at 01:08:41PM -0700, William Lee Irwin III wrote:
> Eliminate specialized page and bh waitqueue hashing structures in favor
> of a standardized structure, using wake_up_bit() to wake waiters using
> the standardized wait_bit_key structure.
Consolidate bit waiting code patterns for page waitqueues using
__wait_on_bit() and __wait_on_bit_lock().
Index: wait-2.6.9-rc1-mm1/kernel/wait.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/kernel/wait.c 2004-08-28 09:48:39.109023976 -0700
+++ wait-2.6.9-rc1-mm1/kernel/wait.c 2004-08-28 09:49:23.070340840 -0700
@@ -143,6 +143,43 @@
}
EXPORT_SYMBOL(wake_bit_function);
+/*
+ * To allow interruptible waiting and asynchronous (i.e. nonblocking)
+ * waiting, the actions of __wait_on_bit() and __wait_on_bit_lock() are
+ * permitted return codes. Nonzero return codes halt waiting and return.
+ */
+int __sched __wait_on_bit(wait_queue_head_t *wq, struct wait_bit_queue *q,
+ void *word,
+ int bit, int (*action)(void *), unsigned mode)
+{
+ int ret = 0;
+
+ prepare_to_wait(wq, &q->wait, mode);
+ if (test_bit(bit, word))
+ ret = (*action)(word);
+ finish_wait(wq, &q->wait);
+ return ret;
+}
+EXPORT_SYMBOL(__wait_on_bit);
+
+int __sched __wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
+ void *word, int bit,
+ int (*action)(void *), unsigned mode)
+{
+ int ret = 0;
+
+ while (test_and_set_bit(bit, word)) {
+ prepare_to_wait_exclusive(wq, &q->wait, mode);
+ if (test_bit(bit, word)) {
+ if ((ret = (*action)(word)))
+ break;
+ }
+ }
+ finish_wait(wq, &q->wait);
+ return ret;
+}
+EXPORT_SYMBOL(__wait_on_bit_lock);
+
void fastcall __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
{
struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
Index: wait-2.6.9-rc1-mm1/mm/filemap.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/mm/filemap.c 2004-08-28 09:48:39.118022608 -0700
+++ wait-2.6.9-rc1-mm1/mm/filemap.c 2004-08-28 09:49:23.068341144 -0700
@@ -132,9 +132,11 @@
}
EXPORT_SYMBOL(remove_from_page_cache);
-static inline int sync_page(struct page *page)
+static int sync_page(void *word)
{
struct address_space *mapping;
+ struct page *page
+ = container_of((page_flags_t *)word, struct page, flags);
/*
* FIXME, fercrissake. What is this barrier here for?
@@ -142,7 +144,8 @@
smp_mb();
mapping = page_mapping(page);
if (mapping && mapping->a_ops && mapping->a_ops->sync_page)
- return mapping->a_ops->sync_page(page);
+ mapping->a_ops->sync_page(page);
+ io_schedule();
return 0;
}
@@ -362,19 +365,19 @@
return &zone->wait_table[hash_ptr(page, zone->wait_table_bits)];
}
+static inline void wake_up_page(struct page *page, int bit)
+{
+ __wake_up_bit(page_waitqueue(page), &page->flags, bit);
+}
+
void fastcall wait_on_page_bit(struct page *page, int bit_nr)
{
- wait_queue_head_t *waitqueue = page_waitqueue(page);
DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
- prepare_to_wait(waitqueue, &wait.wait, TASK_UNINTERRUPTIBLE);
- if (test_bit(bit_nr, &page->flags)) {
- sync_page(page);
- io_schedule();
- }
- finish_wait(waitqueue, &wait.wait);
+ if (test_bit(bit_nr, &page->flags))
+ __wait_on_bit(page_waitqueue(page), &wait, wait.key.flags,
+ bit_nr, sync_page, TASK_UNINTERRUPTIBLE);
}
-
EXPORT_SYMBOL(wait_on_page_bit);
/**
@@ -398,7 +401,7 @@
if (!TestClearPageLocked(page))
BUG();
smp_mb__after_clear_bit();
- __wake_up_bit(page_waitqueue(page), &page->flags, PG_locked);
+ wake_up_page(page, PG_locked);
}
EXPORT_SYMBOL(unlock_page);
@@ -414,7 +417,7 @@
BUG();
smp_mb__after_clear_bit();
}
- __wake_up_bit(page_waitqueue(page), &page->flags, PG_writeback);
+ wake_up_page(page, PG_writeback);
}
EXPORT_SYMBOL(end_page_writeback);
@@ -429,19 +432,11 @@
*/
void fastcall __lock_page(struct page *page)
{
- wait_queue_head_t *wqh = page_waitqueue(page);
DEFINE_WAIT_BIT(wait, &page->flags, PG_locked);
- while (TestSetPageLocked(page)) {
- prepare_to_wait_exclusive(wqh, &wait.wait, TASK_UNINTERRUPTIBLE);
- if (PageLocked(page)) {
- sync_page(page);
- io_schedule();
- }
- }
- finish_wait(wqh, &wait.wait);
+ __wait_on_bit_lock(page_waitqueue(page), &wait, wait.key.flags,
+ PG_locked, sync_page, TASK_UNINTERRUPTIBLE);
}
-
EXPORT_SYMBOL(__lock_page);
/*
Index: wait-2.6.9-rc1-mm1/include/linux/wait.h
===================================================================
--- wait-2.6.9-rc1-mm1.orig/include/linux/wait.h 2004-08-28 09:48:39.121022152 -0700
+++ wait-2.6.9-rc1-mm1/include/linux/wait.h 2004-08-28 09:49:23.059342512 -0700
@@ -139,6 +139,8 @@
extern void FASTCALL(__wake_up_locked(wait_queue_head_t *q, unsigned int mode));
extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr));
void FASTCALL(__wake_up_bit(wait_queue_head_t *, void *, int));
+int FASTCALL(__wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, void *, int, int (*)(void *), unsigned));
+int FASTCALL(__wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, void *, int, int (*)(void *), unsigned));
#define wake_up(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
#define wake_up_nr(x, nr) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr, NULL)
^ permalink raw reply [flat|nested] 11+ messages in thread
* [4/5] eliminate bh waitqueue hashtable
2004-08-28 20:09 ` [3/5] " William Lee Irwin III
@ 2004-08-28 20:11 ` William Lee Irwin III
2004-08-28 20:12 ` [5/5] eliminate inode " William Lee Irwin III
2004-08-28 22:37 ` [4/5] eliminate bh " Andrew Morton
0 siblings, 2 replies; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 20:11 UTC (permalink / raw)
To: linux-kernel; +Cc: akpm
On Sat, Aug 28, 2004 at 01:09:51PM -0700, William Lee Irwin III wrote:
> Consolidate bit waiting code patterns for page waitqueues using
> __wait_on_bit() and __wait_on_bit_lock().
Eliminate the bh waitqueue hashtable using bit_waitqueue() via
wait_on_bit() and wake_up_bit() to locate the waitqueue head associated
with a bit.
Index: wait-2.6.9-rc1-mm1/fs/buffer.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/fs/buffer.c 2004-08-28 09:48:39.107024280 -0700
+++ wait-2.6.9-rc1-mm1/fs/buffer.c 2004-08-28 09:49:39.441851992 -0700
@@ -43,14 +43,6 @@
#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
-/*
- * Hashed waitqueue_head's for wait_on_buffer()
- */
-#define BH_WAIT_TABLE_ORDER 7
-static struct bh_wait_queue_head {
- wait_queue_head_t wqh;
-} ____cacheline_aligned_in_smp bh_wait_queue_heads[1<<BH_WAIT_TABLE_ORDER];
-
inline void
init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
{
@@ -58,49 +50,31 @@
bh->b_private = private;
}
-/*
- * Return the address of the waitqueue_head to be used for this
- * buffer_head
- */
-wait_queue_head_t *bh_waitq_head(struct buffer_head *bh)
-{
- return &bh_wait_queue_heads[hash_ptr(bh, BH_WAIT_TABLE_ORDER)].wqh;
-}
-EXPORT_SYMBOL(bh_waitq_head);
-
void wake_up_buffer(struct buffer_head *bh)
{
- wait_queue_head_t *wq = bh_waitq_head(bh);
-
smp_mb();
- __wake_up_bit(wq, &bh->b_state, BH_Lock);
+ wake_up_bit(&bh->b_state, BH_Lock);
}
EXPORT_SYMBOL(wake_up_buffer);
-static void sync_buffer(struct buffer_head *bh)
+static int sync_buffer(void *word)
{
struct block_device *bd;
+ struct buffer_head *bh
+ = container_of(word, struct buffer_head, b_state);
smp_mb();
bd = bh->b_bdev;
if (bd)
blk_run_address_space(bd->bd_inode->i_mapping);
+ io_schedule();
+ return 0;
}
void fastcall __lock_buffer(struct buffer_head *bh)
{
- wait_queue_head_t *wqh = bh_waitq_head(bh);
- DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Lock);
-
- do {
- prepare_to_wait_exclusive(wqh, &wait.wait,
- TASK_UNINTERRUPTIBLE);
- if (buffer_locked(bh)) {
- sync_buffer(bh);
- io_schedule();
- }
- } while (test_set_buffer_locked(bh));
- finish_wait(wqh, &wait.wait);
+ wait_on_bit_lock(&bh->b_state, BH_Lock, sync_buffer,
+ TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(__lock_buffer);
@@ -118,15 +92,7 @@
*/
void __wait_on_buffer(struct buffer_head * bh)
{
- wait_queue_head_t *wqh = bh_waitq_head(bh);
- DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Lock);
-
- prepare_to_wait(wqh, &wait.wait, TASK_UNINTERRUPTIBLE);
- if (buffer_locked(bh)) {
- sync_buffer(bh);
- io_schedule();
- }
- finish_wait(wqh, &wait.wait);
+ wait_on_bit(&bh->b_state, BH_Lock, sync_buffer, TASK_UNINTERRUPTIBLE);
}
static void
@@ -3096,14 +3062,11 @@
void __init buffer_init(void)
{
- int i;
int nrpages;
bh_cachep = kmem_cache_create("buffer_head",
sizeof(struct buffer_head), 0,
SLAB_PANIC, init_buffer_head, NULL);
- for (i = 0; i < ARRAY_SIZE(bh_wait_queue_heads); i++)
- init_waitqueue_head(&bh_wait_queue_heads[i].wqh);
/*
* Limit the bh occupancy to 10% of ZONE_NORMAL
Index: wait-2.6.9-rc1-mm1/kernel/wait.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/kernel/wait.c 2004-08-28 09:49:23.070340840 -0700
+++ wait-2.6.9-rc1-mm1/kernel/wait.c 2004-08-28 09:49:39.456849712 -0700
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/wait.h>
+#include <linux/hash.h>
void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
{
@@ -187,3 +188,13 @@
__wake_up(wq, TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE, 1, &key);
}
EXPORT_SYMBOL(__wake_up_bit);
+
+wait_queue_head_t * fastcall bit_waitqueue(void *word, int bit)
+{
+ const int shift = BITS_PER_LONG == 32 ? 5 : 6;
+ const struct zone *zone = page_zone(virt_to_page(word));
+ unsigned long val = (unsigned long)word << shift | bit;
+
+ return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
+}
+EXPORT_SYMBOL(bit_waitqueue);
Index: wait-2.6.9-rc1-mm1/fs/jbd/transaction.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/fs/jbd/transaction.c 2004-08-28 09:42:49.971101008 -0700
+++ wait-2.6.9-rc1-mm1/fs/jbd/transaction.c 2004-08-28 09:49:39.449850776 -0700
@@ -633,21 +633,21 @@
* disk then we cannot do copy-out here. */
if (jh->b_jlist == BJ_Shadow) {
- wait_queue_head_t *wqh;
- DEFINE_WAIT(wait);
+ DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Lock);
+ wait_queue_head_t *wqh
+ = bit_waitqueue(&bh->b_state, BH_Lock);
JBUFFER_TRACE(jh, "on shadow: sleep");
jbd_unlock_bh_state(bh);
/* commit wakes up all shadow buffers after IO */
- wqh = bh_waitq_head(bh);
for ( ; ; ) {
- prepare_to_wait(wqh, &wait,
+ prepare_to_wait(wqh, &wait.wait,
TASK_UNINTERRUPTIBLE);
if (jh->b_jlist != BJ_Shadow)
break;
schedule();
}
- finish_wait(wqh, &wait);
+ finish_wait(wqh, &wait.wait);
goto repeat;
}
Index: wait-2.6.9-rc1-mm1/include/linux/wait.h
===================================================================
--- wait-2.6.9-rc1-mm1.orig/include/linux/wait.h 2004-08-28 09:49:23.059342512 -0700
+++ wait-2.6.9-rc1-mm1/include/linux/wait.h 2004-08-28 09:49:39.453850168 -0700
@@ -24,6 +24,7 @@
#include <linux/stddef.h>
#include <linux/spinlock.h>
#include <asm/system.h>
+#include <asm/current.h>
typedef struct __wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int sync, void *key);
@@ -141,6 +142,22 @@
void FASTCALL(__wake_up_bit(wait_queue_head_t *, void *, int));
int FASTCALL(__wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, void *, int, int (*)(void *), unsigned));
int FASTCALL(__wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, void *, int, int (*)(void *), unsigned));
+wait_queue_head_t *FASTCALL(bit_waitqueue(void *, int));
+
+/**
+ * wake_up_bit - wake up a waiter on a bit
+ * @word: the word being waited on, a kernel virtual address
+ * @bit: the bit of the word being waited on
+ *
+ * There is a standard hashed waitqueue table for generic use. This
+ * is the part of the hashtable's accessor API that wakes up waiters
+ * on a bit. For instance, if one were to have waiters on a bitflag,
+ * one would call wake_up_bit() after clearing the bit.
+ */
+static inline void wake_up_bit(void *word, int bit)
+{
+ __wake_up_bit(bit_waitqueue(word, bit), word, bit);
+}
#define wake_up(x) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1, NULL)
#define wake_up_nr(x, nr) __wake_up(x, TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr, NULL)
@@ -321,6 +338,62 @@
wait->func = autoremove_wake_function; \
INIT_LIST_HEAD(&wait->task_list); \
} while (0)
+
+/**
+ * wait_on_bit - wait for a bit to be cleared
+ * @word: the word being waited on, a kernel virtual address
+ * @bit: the bit of the word being waited on
+ * @action: the function used to sleep, which may take special actions
+ * @mode: the task state to sleep in
+ *
+ * There is a standard hashed waitqueue table for generic use. This
+ * is the part of the hashtable's accessor API that waits on a bit.
+ * For instance, if one were to have waiters on a bitflag, one would
+ * call wait_on_bit() in threads waiting for the bit to clear.
+ * One uses wait_on_bit() where one is waiting for the bit to clear,
+ * but has no intention of setting it.
+ */
+static inline int wait_on_bit(void *word, int bit,
+ int (*action)(void *), unsigned mode)
+{
+ DEFINE_WAIT_BIT(q, word, bit);
+ wait_queue_head_t *wqh;
+
+ if (!test_bit(bit, word))
+ return 0;
+
+ wqh = bit_waitqueue(word, bit);
+ return __wait_on_bit(wqh, &q, word, bit, action, mode);
+}
+
+/**
+ * wait_on_bit_lock - wait for a bit to be cleared, when wanting to set it
+ * @word: the word being waited on, a kernel virtual address
+ * @bit: the bit of the word being waited on
+ * @action: the function used to sleep, which may take special actions
+ * @mode: the task state to sleep in
+ *
+ * There is a standard hashed waitqueue table for generic use. This
+ * is the part of the hashtable's accessor API that waits on a bit
+ * when one intends to set it, for instance, trying to lock bitflags.
+ * For instance, if one were to have waiters trying to set bitflag
+ * and waiting for it to clear before setting it, one would call
+ * wait_on_bit() in threads waiting to be able to set the bit.
+ * One uses wait_on_bit_lock() where one is waiting for the bit to
+ * clear with the intention of setting it, and when done, clearing it.
+ */
+static inline int wait_on_bit_lock(void *word, int bit,
+ int (*action)(void *), unsigned mode)
+{
+ DEFINE_WAIT_BIT(q, word, bit);
+ wait_queue_head_t *wqh;
+
+ if (!test_bit(bit, word))
+ return 0;
+
+ wqh = bit_waitqueue(word, bit);
+ return __wait_on_bit_lock(wqh, &q, word, bit, action, mode);
+}
#endif /* __KERNEL__ */
^ permalink raw reply [flat|nested] 11+ messages in thread
* [5/5] eliminate inode waitqueue hashtable
2004-08-28 20:11 ` [4/5] eliminate bh waitqueue hashtable William Lee Irwin III
@ 2004-08-28 20:12 ` William Lee Irwin III
2004-08-28 22:37 ` [4/5] eliminate bh " Andrew Morton
1 sibling, 0 replies; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 20:12 UTC (permalink / raw)
To: linux-kernel; +Cc: akpm
On Sat, Aug 28, 2004 at 01:11:07PM -0700, William Lee Irwin III wrote:
> Eliminate the bh waitqueue hashtable using bit_waitqueue() via
> wait_on_bit() and wake_up_bit() to locate the waitqueue head associated
> with a bit.
Eliminate the inode waitqueue hashtable using bit_waitqueue() via
wait_on_bit() and wake_up_bit() to locate the waitqueue head associated
with a bit.
Index: wait-2.6.9-rc1-mm1/include/linux/fs.h
===================================================================
--- wait-2.6.9-rc1-mm1.orig/include/linux/fs.h 2004-08-28 09:43:24.899791040 -0700
+++ wait-2.6.9-rc1-mm1/include/linux/fs.h 2004-08-28 09:50:30.834039192 -0700
@@ -1057,6 +1057,7 @@
#define I_NEW 64
#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
+#define __I_LOCK 3 /* I_LOCK == 1 << __I_LOCK */
extern void __mark_inode_dirty(struct inode *, int);
static inline void mark_inode_dirty(struct inode *inode)
Index: wait-2.6.9-rc1-mm1/fs/inode.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/fs/inode.c 2004-08-28 09:43:23.419016152 -0700
+++ wait-2.6.9-rc1-mm1/fs/inode.c 2004-08-28 09:50:30.827040256 -0700
@@ -1257,37 +1257,10 @@
#endif
-/*
- * Hashed waitqueues for wait_on_inode(). The table is pretty small - the
- * kernel doesn't lock many inodes at the same time.
- */
-#define I_WAIT_TABLE_ORDER 3
-static struct i_wait_queue_head {
- wait_queue_head_t wqh;
-} ____cacheline_aligned_in_smp i_wait_queue_heads[1<<I_WAIT_TABLE_ORDER];
-
-/*
- * Return the address of the waitqueue_head to be used for this inode
- */
-static wait_queue_head_t *i_waitq_head(struct inode *inode)
+int inode_wait(void *word)
{
- return &i_wait_queue_heads[hash_ptr(inode, I_WAIT_TABLE_ORDER)].wqh;
-}
-
-void __wait_on_inode(struct inode *inode)
-{
- DECLARE_WAITQUEUE(wait, current);
- wait_queue_head_t *wq = i_waitq_head(inode);
-
- add_wait_queue(wq, &wait);
-repeat:
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (inode->i_state & I_LOCK) {
- schedule();
- goto repeat;
- }
- remove_wait_queue(wq, &wait);
- __set_current_state(TASK_RUNNING);
+ schedule();
+ return 0;
}
/*
@@ -1296,36 +1269,39 @@
* that it isn't found. This is because iget will immediately call
* ->read_inode, and we want to be sure that evidence of the deletion is found
* by ->read_inode.
- *
- * This call might return early if an inode which shares the waitq is woken up.
- * This is most easily handled by the caller which will loop around again
- * looking for the inode.
- *
* This is called with inode_lock held.
*/
static void __wait_on_freeing_inode(struct inode *inode)
{
- DECLARE_WAITQUEUE(wait, current);
- wait_queue_head_t *wq = i_waitq_head(inode);
+ wait_queue_head_t *wq;
+ DEFINE_WAIT_BIT(wait, &inode->i_state, __I_LOCK);
- add_wait_queue(wq, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
+ /*
+ * I_FREEING and I_CLEAR are cleared in process context under
+ * inode_lock, so we have to give the tasks who would clear them
+ * a chance to run and acquire inode_lock.
+ */
+ if (!(inode->i_state & I_LOCK)) {
+ spin_unlock(&inode_lock);
+ yield();
+ spin_lock(&inode_lock);
+ return;
+ }
+ wq = bit_waitqueue(&inode->i_state, __I_LOCK);
+ prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
spin_unlock(&inode_lock);
schedule();
- remove_wait_queue(wq, &wait);
+ finish_wait(wq, &wait.wait);
spin_lock(&inode_lock);
}
void wake_up_inode(struct inode *inode)
{
- wait_queue_head_t *wq = i_waitq_head(inode);
-
/*
* Prevent speculative execution through spin_unlock(&inode_lock);
*/
smp_mb();
- if (waitqueue_active(wq))
- wake_up_all(wq);
+ wake_up_bit(&inode->i_state, __I_LOCK);
}
EXPORT_SYMBOL(wake_up_inode);
@@ -1361,11 +1337,6 @@
void __init inode_init(unsigned long mempages)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(i_wait_queue_heads); i++)
- init_waitqueue_head(&i_wait_queue_heads[i].wqh);
-
/* inode slab cache */
inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),
0, SLAB_PANIC, init_once, NULL);
Index: wait-2.6.9-rc1-mm1/kernel/wait.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/kernel/wait.c 2004-08-28 09:49:39.456849712 -0700
+++ wait-2.6.9-rc1-mm1/kernel/wait.c 2004-08-28 09:50:30.842037976 -0700
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
+#include <linux/mm.h>
#include <linux/wait.h>
#include <linux/hash.h>
Index: wait-2.6.9-rc1-mm1/fs/fs-writeback.c
===================================================================
--- wait-2.6.9-rc1-mm1.orig/fs/fs-writeback.c 2004-08-28 09:43:21.401322888 -0700
+++ wait-2.6.9-rc1-mm1/fs/fs-writeback.c 2004-08-28 09:50:30.840038280 -0700
@@ -240,6 +240,8 @@
__writeback_single_inode(struct inode *inode,
struct writeback_control *wbc)
{
+ wait_queue_head_t *wqh;
+
if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_LOCK)) {
list_move(&inode->i_list, &inode->i_sb->s_dirty);
return 0;
@@ -248,12 +250,18 @@
/*
* It's a data-integrity sync. We must wait.
*/
- while (inode->i_state & I_LOCK) {
- __iget(inode);
- spin_unlock(&inode_lock);
- __wait_on_inode(inode);
- iput(inode);
- spin_lock(&inode_lock);
+ if (inode->i_state & I_LOCK) {
+ DEFINE_WAIT_BIT(wq, &inode->i_state, __I_LOCK);
+
+ wqh = bit_waitqueue(&inode->i_state, __I_LOCK);
+ do {
+ __iget(inode);
+ spin_unlock(&inode_lock);
+ __wait_on_bit(wqh, &wq, &inode->i_state, __I_LOCK,
+ inode_wait, TASK_UNINTERRUPTIBLE);
+ iput(inode);
+ spin_lock(&inode_lock);
+ } while (inode->i_state & I_LOCK);
}
return __sync_single_inode(inode, wbc);
}
Index: wait-2.6.9-rc1-mm1/include/linux/writeback.h
===================================================================
--- wait-2.6.9-rc1-mm1.orig/include/linux/writeback.h 2004-08-28 09:43:02.320223656 -0700
+++ wait-2.6.9-rc1-mm1/include/linux/writeback.h 2004-08-28 09:50:30.836038888 -0700
@@ -68,7 +68,7 @@
*/
void writeback_inodes(struct writeback_control *wbc);
void wake_up_inode(struct inode *inode);
-void __wait_on_inode(struct inode * inode);
+int inode_wait(void *);
void sync_inodes_sb(struct super_block *, int wait);
void sync_inodes(int wait);
@@ -76,8 +76,8 @@
static inline void wait_on_inode(struct inode *inode)
{
might_sleep();
- if (inode->i_state & I_LOCK)
- __wait_on_inode(inode);
+ wait_on_bit(&inode->i_state, __I_LOCK, inode_wait,
+ TASK_UNINTERRUPTIBLE);
}
/*
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [2/5] consolidate bit waiting code patterns
2004-08-28 20:08 ` [2/5] consolidate bit waiting code patterns William Lee Irwin III
2004-08-28 20:09 ` [3/5] " William Lee Irwin III
@ 2004-08-28 20:21 ` William Lee Irwin III
2004-08-28 22:29 ` Andrew Morton
2 siblings, 0 replies; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 20:21 UTC (permalink / raw)
To: linux-kernel; +Cc: akpm
On Sat, Aug 28, 2004 at 01:08:41PM -0700, William Lee Irwin III wrote:
> Eliminate specialized page and bh waitqueue hashing structures in favor
> of a standardized structure, using wake_up_bit() to wake waiters using
> the standardized wait_bit_key structure.
>
> Index: wait-2.6.9-rc1-mm1/fs/buffer.c
> ===================================================================
> --- wait-2.6.9-rc1-mm1.orig/fs/buffer.c 2004-08-28 09:43:30.305969176 -0700
> +++ wait-2.6.9-rc1-mm1/fs/buffer.c 2004-08-28 09:47:21.232862952 -0700
> @@ -43,26 +43,6 @@
>
> #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
Sorry, the Subject: line should have been titled "standardize bit
waiting data type".
-- wli
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [2/5] consolidate bit waiting code patterns
2004-08-28 20:08 ` [2/5] consolidate bit waiting code patterns William Lee Irwin III
2004-08-28 20:09 ` [3/5] " William Lee Irwin III
2004-08-28 20:21 ` [2/5] consolidate bit waiting code patterns William Lee Irwin III
@ 2004-08-28 22:29 ` Andrew Morton
2004-08-28 22:33 ` William Lee Irwin III
2 siblings, 1 reply; 11+ messages in thread
From: Andrew Morton @ 2004-08-28 22:29 UTC (permalink / raw)
To: William Lee Irwin III; +Cc: linux-kernel
William Lee Irwin III <wli@holomorphy.com> wrote:
>
> +void fastcall __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
> +{
> + struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
> + if (waitqueue_active(wq))
> + __wake_up(wq, TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE, 1, &key);
> +}
The waitqueue_active() test needs a preceding barrier. Did it
come from somewhere else, implicitly?
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [2/5] consolidate bit waiting code patterns
2004-08-28 22:29 ` Andrew Morton
@ 2004-08-28 22:33 ` William Lee Irwin III
0 siblings, 0 replies; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 22:33 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel
William Lee Irwin III <wli@holomorphy.com> wrote:
>> +void fastcall __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
>> +{
>> + struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
>> + if (waitqueue_active(wq))
>> + __wake_up(wq, TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE, 1, &key);
>> +}
On Sat, Aug 28, 2004 at 03:29:04PM -0700, Andrew Morton wrote:
> The waitqueue_active() test needs a preceding barrier. Did it
> come from somewhere else, implicitly?
Yes, it comes from clearing the bit prior to calling this for wakeup.
-- wli
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [4/5] eliminate bh waitqueue hashtable
2004-08-28 20:11 ` [4/5] eliminate bh waitqueue hashtable William Lee Irwin III
2004-08-28 20:12 ` [5/5] eliminate inode " William Lee Irwin III
@ 2004-08-28 22:37 ` Andrew Morton
2004-08-28 23:09 ` William Lee Irwin III
1 sibling, 1 reply; 11+ messages in thread
From: Andrew Morton @ 2004-08-28 22:37 UTC (permalink / raw)
To: William Lee Irwin III; +Cc: linux-kernel
William Lee Irwin III <wli@holomorphy.com> wrote:
>
> +static inline int wait_on_bit(void *word, int bit,
> + int (*action)(void *), unsigned mode)
> +{
> + DEFINE_WAIT_BIT(q, word, bit);
> + wait_queue_head_t *wqh;
> +
> + if (!test_bit(bit, word))
> + return 0;
> +
> + wqh = bit_waitqueue(word, bit);
> + return __wait_on_bit(wqh, &q, word, bit, action, mode);
> +}
This is still all inlined. Given that we're going to schedule away,
don't you think we should out-of-line the slowpath? As I said yesterday:
static inline int wait_on_bit(...)
{
if (test_bit(...))
return out_of_line_wait_on_bit(...);
return 0;
}
I merged this latest batch into -mm.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [4/5] eliminate bh waitqueue hashtable
2004-08-28 22:37 ` [4/5] eliminate bh " Andrew Morton
@ 2004-08-28 23:09 ` William Lee Irwin III
0 siblings, 0 replies; 11+ messages in thread
From: William Lee Irwin III @ 2004-08-28 23:09 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel
On Sat, Aug 28, 2004 at 03:37:28PM -0700, Andrew Morton wrote:
> This is still all inlined. Given that we're going to schedule away,
> don't you think we should out-of-line the slowpath? As I said yesterday:
> static inline int wait_on_bit(...)
> {
> if (test_bit(...))
> return out_of_line_wait_on_bit(...);
> return 0;
> }
> I merged this latest batch into -mm.
Neither bit_waitqueue() nor __wait_on_bit() are inlined, but it is
possible to reduce things to only one call site. I'll send in that
update if you've not done it yourself after I get a chance to see
what's been merged.
-- wli
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2004-08-28 23:09 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-08-28 20:05 [0/5] standardized waitqueue hashing William Lee Irwin III
2004-08-28 20:06 ` [1/5] move waitqueue functions to kernel/wait.c William Lee Irwin III
2004-08-28 20:08 ` [2/5] consolidate bit waiting code patterns William Lee Irwin III
2004-08-28 20:09 ` [3/5] " William Lee Irwin III
2004-08-28 20:11 ` [4/5] eliminate bh waitqueue hashtable William Lee Irwin III
2004-08-28 20:12 ` [5/5] eliminate inode " William Lee Irwin III
2004-08-28 22:37 ` [4/5] eliminate bh " Andrew Morton
2004-08-28 23:09 ` William Lee Irwin III
2004-08-28 20:21 ` [2/5] consolidate bit waiting code patterns William Lee Irwin III
2004-08-28 22:29 ` Andrew Morton
2004-08-28 22:33 ` William Lee Irwin III
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox