summaryrefslogtreecommitdiff
path: root/fs/xfs/pagebuf/page_buf.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2003-02-19 01:06:44 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2003-02-19 01:06:44 -0800
commitb76a852bfb51ffe25505bab3dfd87ddbc821c2aa (patch)
tree25e4f88a1d60f92c7f00f19e835a23d1502c5c82 /fs/xfs/pagebuf/page_buf.c
parent612cbdcf44289e81a4327d8f67fcc41e07ad33c3 (diff)
parent6ab007bf3fd8db711771db1e93880213a63ecd38 (diff)
Merge bk://are.twiddle.net/axp-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
Diffstat (limited to 'fs/xfs/pagebuf/page_buf.c')
-rw-r--r--fs/xfs/pagebuf/page_buf.c78
1 files changed, 54 insertions, 24 deletions
diff --git a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c
index 5663f6d4b4..05e086ad25 100644
--- a/fs/xfs/pagebuf/page_buf.c
+++ b/fs/xfs/pagebuf/page_buf.c
@@ -119,9 +119,9 @@ pb_trace_func(
STATIC kmem_cache_t *pagebuf_cache;
STATIC void pagebuf_daemon_wakeup(int);
+STATIC void pagebuf_delwri_queue(page_buf_t *, int);
STATIC struct workqueue_struct *pagebuf_workqueue;
-
/*
* Pagebuf module configuration parameters, exported via
* /proc/sys/vm/pagebuf
@@ -155,35 +155,37 @@ struct pbstats pbstats;
* Pagebuf hashing
*/
-#define NBITS 5
-#define NHASH (1<<NBITS)
-
+/* This structure must be a power of 2 long for the hash to work */
typedef struct {
struct list_head pb_hash;
int pb_count;
spinlock_t pb_hash_lock;
} pb_hash_t;
-STATIC pb_hash_t pbhash[NHASH];
+static pb_hash_t *pbhash;
+static unsigned int pb_hash_mask;
+static unsigned int pb_hash_shift;
+static unsigned int pb_order;
#define pb_hash(pb) &pbhash[pb->pb_hash_index]
-STATIC int
+/*
+ * This hash is the same one as used on the Linux buffer cache,
+ * see fs/buffer.c
+ */
+
+#define _hashfn(dev,block) \
+ ((((dev)<<(pb_hash_shift - 6)) ^ ((dev)<<(pb_hash_shift - 9))) ^ \
+ (((block)<<(pb_hash_shift - 6)) ^ ((block) >> 13) ^ \
+ ((block) << (pb_hash_shift - 12))))
+
+static inline int
_bhash(
dev_t dev,
loff_t base)
{
- int bit, hval;
-
base >>= 9;
- /*
- * dev_t is 16 bits, loff_t is always 64 bits
- */
- base ^= dev;
- for (bit = hval = 0; base != 0 && bit < sizeof(base) * 8; bit += NBITS) {
- hval ^= (int)base & (NHASH-1);
- base >>= NBITS;
- }
- return hval;
+
+ return (_hashfn(dev, base) & pb_hash_mask);
}
/*
@@ -1516,7 +1518,7 @@ STATIC int pbd_active = 1;
STATIC LIST_HEAD(pbd_delwrite_queue);
STATIC spinlock_t pbd_delwrite_lock = SPIN_LOCK_UNLOCKED;
-void
+STATIC void
pagebuf_delwri_queue(
page_buf_t *pb,
int unlock)
@@ -1862,7 +1864,39 @@ pagebuf_shaker(void)
int __init
pagebuf_init(void)
{
- int i;
+ int order, mempages, i;
+ unsigned int nr_hash;
+ extern int xfs_physmem;
+
+ mempages = xfs_physmem >>= 16;
+ mempages *= sizeof(pb_hash_t);
+ for (order = 0; (1 << order) < mempages; order++)
+ ;
+
+ if (order > 3) order = 3; /* cap us at 2K buckets */
+
+ do {
+ unsigned long tmp;
+
+ nr_hash = (PAGE_SIZE << order) / sizeof(pb_hash_t);
+ nr_hash = 1 << (ffs(nr_hash) - 1);
+ pb_hash_mask = (nr_hash - 1);
+ tmp = nr_hash;
+ pb_hash_shift = 0;
+ while((tmp >>= 1UL) != 0UL)
+ pb_hash_shift++;
+
+ pbhash = (pb_hash_t *)
+ __get_free_pages(GFP_KERNEL, order);
+ pb_order = order;
+ } while (pbhash == NULL && --order > 0);
+ printk("pagebuf cache hash table entries: %d (order: %d, %ld bytes)\n",
+ nr_hash, order, (PAGE_SIZE << order));
+
+ for(i = 0; i < nr_hash; i++) {
+ spin_lock_init(&pbhash[i].pb_hash_lock);
+ INIT_LIST_HEAD(&pbhash[i].pb_hash);
+ }
pagebuf_table_header = register_sysctl_table(pagebuf_root_table, 1);
@@ -1880,11 +1914,6 @@ pagebuf_init(void)
return -ENOMEM;
}
- for (i = 0; i < NHASH; i++) {
- spin_lock_init(&pbhash[i].pb_hash_lock);
- INIT_LIST_HEAD(&pbhash[i].pb_hash);
- }
-
#ifdef PAGEBUF_TRACE
pb_trace.buf = (pagebuf_trace_t *)kmalloc(
PB_TRACE_BUFSIZE * sizeof(pagebuf_trace_t), GFP_KERNEL);
@@ -1911,6 +1940,7 @@ pagebuf_terminate(void)
kmem_cache_destroy(pagebuf_cache);
kmem_shake_deregister(pagebuf_shaker);
+ free_pages((unsigned long)pbhash, pb_order);
unregister_sysctl_table(pagebuf_table_header);
#ifdef CONFIG_PROC_FS