
From: Andrew Morton <akpm@osdl.org>

Hash the page_uptodate_locks.  <insert performance numbers here>

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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-06-25 01:16:48.000000000 -0700
+++ 25-akpm/fs/buffer.c	2005-06-25 01:16:48.000000000 -0700
@@ -507,13 +507,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;
@@ -536,7 +549,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;
@@ -549,7 +563,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
@@ -561,7 +575,7 @@ static void end_buffer_async_read(struct
 	return;
 
 still_busy:
-	spin_unlock_irqrestore(&page_uptodate_lock, flags);
+	spin_unlock_irqrestore(lock, flags);
 	return;
 }
 
@@ -572,7 +586,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;
@@ -594,7 +611,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;
@@ -605,12 +623,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;
 }
 
_
