From: Andrew Morton Hash the page_uptodate_locks. Signed-off-by: Andrew Morton --- fs/buffer.c | 34 ++++++++++++++++++++++++++-------- 1 files changed, 26 insertions(+), 8 deletions(-) diff -puN fs/buffer.c~page_uptodate_lock-hashing fs/buffer.c --- 25/fs/buffer.c~page_uptodate_lock-hashing 2005-05-03 15:17:09.000000000 -0700 +++ 25-akpm/fs/buffer.c 2005-05-03 15:31:41.000000000 -0700 @@ -532,13 +532,26 @@ static void free_more_memory(void) } } +struct hashed_spinlock { + spinlock_t lock; +} ____cacheline_aligned_in_smp; + +#define HSL_SIZE 32 + +struct hashed_spinlocks { + struct hashed_spinlock locks[HSL_SIZE]; +}; + /* * I/O completion handler for block_read_full_page() - pages * which come unlocked at the end of I/O. */ static void end_buffer_async_read(struct buffer_head *bh, int uptodate) { - static DEFINE_SPINLOCK(page_uptodate_lock); + static struct hashed_spinlocks locks = { + .locks = { [ 0 ... HSL_SIZE - 1 ] = + { .lock = SPIN_LOCK_UNLOCKED } } }; + spinlock_t *lock; unsigned long flags; struct buffer_head *tmp; struct page *page; @@ -561,7 +574,8 @@ static void end_buffer_async_read(struct * two buffer heads end IO at almost the same time and both * decide that the page is now completely done. */ - spin_lock_irqsave(&page_uptodate_lock, flags); + lock = &locks.locks[page_to_pfn(page) & (HSL_SIZE - 1)].lock; + spin_lock_irqsave(lock, flags); clear_buffer_async_read(bh); unlock_buffer(bh); tmp = bh; @@ -574,7 +588,7 @@ static void end_buffer_async_read(struct } tmp = tmp->b_this_page; } while (tmp != bh); - spin_unlock_irqrestore(&page_uptodate_lock, flags); + spin_unlock_irqrestore(lock, flags); /* * If none of the buffers had errors and they are all @@ -586,7 +600,7 @@ static void end_buffer_async_read(struct return; still_busy: - spin_unlock_irqrestore(&page_uptodate_lock, flags); + spin_unlock_irqrestore(lock, flags); return; } @@ -597,7 +611,10 @@ still_busy: void end_buffer_async_write(struct buffer_head *bh, int uptodate) { char b[BDEVNAME_SIZE]; - static DEFINE_SPINLOCK(page_uptodate_lock); + static struct hashed_spinlocks locks = { + .locks = { [ 0 ... HSL_SIZE - 1 ] = + { .lock = SPIN_LOCK_UNLOCKED } } }; + spinlock_t *lock; unsigned long flags; struct buffer_head *tmp; struct page *page; @@ -619,7 +636,8 @@ void end_buffer_async_write(struct buffe SetPageError(page); } - spin_lock_irqsave(&page_uptodate_lock, flags); + lock = &locks.locks[page_to_pfn(page) & (HSL_SIZE - 1)].lock; + spin_lock_irqsave(lock, flags); clear_buffer_async_write(bh); unlock_buffer(bh); tmp = bh->b_this_page; @@ -630,12 +648,12 @@ void end_buffer_async_write(struct buffe } tmp = tmp->b_this_page; } - spin_unlock_irqrestore(&page_uptodate_lock, flags); + spin_unlock_irqrestore(lock, flags); end_page_writeback(page); return; still_busy: - spin_unlock_irqrestore(&page_uptodate_lock, flags); + spin_unlock_irqrestore(lock, flags); return; } _