diff options
| author | Andrew Morton <akpm@zip.com.au> | 2002-08-13 01:07:54 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-08-13 01:07:54 -0700 |
| commit | 88d37bdd020ef914ed2c0253d056671687efd91e (patch) | |
| tree | 87b014d074c85d0e33b6f24fda92f8689e0a15be | |
| parent | 8e4f2fd31bf737abb392e694898a1496157623b5 (diff) | |
[PATCH] reduced locking in buffer.c
Replace the buffer lru spinlock protection with local_irq_disable and a
cross-CPU call to invalidate them.
| -rw-r--r-- | fs/buffer.c | 75 |
1 files changed, 48 insertions, 27 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 6ea12c2e1248..bebac5237a09 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1274,15 +1274,32 @@ __bread_slow(struct block_device *bdev, sector_t block, int size) * * This is a transparent caching front-end to sb_bread(), sb_getblk() and * sb_find_get_block(). + * + * The LRUs themselves only need locking against invalidate_bh_lrus. We use + * a local interrupt disable for that. */ -#define BH_LRU_SIZE 7 +#define BH_LRU_SIZE 8 static struct bh_lru { - spinlock_t lock; struct buffer_head *bhs[BH_LRU_SIZE]; } ____cacheline_aligned_in_smp bh_lrus[NR_CPUS]; +#ifdef CONFIG_SMP +#define bh_lru_lock() local_irq_disable() +#define bh_lru_unlock() local_irq_enable() +#else +#define bh_lru_lock() preempt_disable() +#define bh_lru_unlock() preempt_enable() +#endif + +static inline void check_irqs_on(void) +{ +#ifdef irqs_disabled + BUG_ON(irqs_disabled()); +#endif +} + /* * The LRU management algorithm is dopey-but-simple. Sorry. */ @@ -1294,8 +1311,9 @@ static void bh_lru_install(struct buffer_head *bh) if (bh == NULL) return; - lru = &bh_lrus[get_cpu()]; - spin_lock(&lru->lock); + check_irqs_on(); + bh_lru_lock(); + lru = &bh_lrus[smp_processor_id()]; if (lru->bhs[0] != bh) { struct buffer_head *bhs[BH_LRU_SIZE]; int in; @@ -1321,8 +1339,7 @@ static void bh_lru_install(struct buffer_head *bh) bhs[out++] = NULL; memcpy(lru->bhs, bhs, sizeof(bhs)); } - spin_unlock(&lru->lock); - put_cpu(); + bh_lru_unlock(); if (evictee) { touch_buffer(evictee); @@ -1337,8 +1354,9 @@ lookup_bh(struct block_device *bdev, sector_t block, int size) struct bh_lru *lru; int i; - lru = &bh_lrus[get_cpu()]; - spin_lock(&lru->lock); + check_irqs_on(); + bh_lru_lock(); + lru = &bh_lrus[smp_processor_id()]; for (i = 0; i < BH_LRU_SIZE; i++) { struct buffer_head *bh = lru->bhs[i]; @@ -1356,8 +1374,7 @@ lookup_bh(struct block_device *bdev, sector_t block, int size) break; } } - spin_unlock(&lru->lock); - put_cpu(); + bh_lru_unlock(); return ret; } @@ -1404,25 +1421,32 @@ __bread(struct block_device *bdev, sector_t block, int size) EXPORT_SYMBOL(__bread); /* - * This is called rarely - at unmount. + * invalidate_bh_lrus() is called rarely - at unmount. Because it is only for + * unmount it only needs to ensure that all buffers from the target device are + * invalidated on return and it doesn't need to worry about new buffers from + * that device being added - the unmount code has to prevent that. */ -static void invalidate_bh_lrus(void) +static void invalidate_bh_lru(void *arg) { - int cpu_idx; - - for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++) - spin_lock(&bh_lrus[cpu_idx].lock); - for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++) { - int i; + const int cpu = get_cpu(); + int i; - for (i = 0; i < BH_LRU_SIZE; i++) { - brelse(bh_lrus[cpu_idx].bhs[i]); - bh_lrus[cpu_idx].bhs[i] = NULL; - } + for (i = 0; i < BH_LRU_SIZE; i++) { + brelse(bh_lrus[cpu].bhs[i]); + bh_lrus[cpu].bhs[i] = NULL; } - for (cpu_idx = 0; cpu_idx < NR_CPUS; cpu_idx++) - spin_unlock(&bh_lrus[cpu_idx].lock); + put_cpu(); } + +static void invalidate_bh_lrus(void) +{ + preempt_disable(); + invalidate_bh_lru(NULL); + smp_call_function(invalidate_bh_lru, NULL, 1, 1); + preempt_enable(); +} + + void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long offset) @@ -2545,9 +2569,6 @@ void __init buffer_init(void) { int i; - for (i = 0; i < NR_CPUS; i++) - spin_lock_init(&bh_lrus[i].lock); - bh_cachep = kmem_cache_create("buffer_head", sizeof(struct buffer_head), 0, SLAB_HWCACHE_ALIGN, init_buffer_head, NULL); |
