Merge git://bedivere.hansenpartnership.com/git/scsi-rc-fixes-2.6
[linux-2.6.git] / fs / mbcache.c
index cf4e6cd..8c32ef3 100644 (file)
@@ -76,17 +76,6 @@ EXPORT_SYMBOL(mb_cache_entry_find_first);
 EXPORT_SYMBOL(mb_cache_entry_find_next);
 #endif
 
-struct mb_cache {
-       struct list_head                c_cache_list;
-       const char                      *c_name;
-       atomic_t                        c_entry_count;
-       int                             c_bucket_bits;
-       struct kmem_cache               *c_entry_cache;
-       struct list_head                *c_block_hash;
-       struct list_head                *c_index_hash;
-};
-
-
 /*
  * Global data: list of all mbcache's, lru list, and a spinlock for
  * accessing cache data structures on SMP machines. The lru list is
@@ -101,7 +90,8 @@ static DEFINE_SPINLOCK(mb_cache_spinlock);
  * What the mbcache registers as to get shrunk dynamically.
  */
 
-static int mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask);
+static int mb_cache_shrink_fn(struct shrinker *shrink,
+                             struct shrink_control *sc);
 
 static struct shrinker mb_cache_shrinker = {
        .shrink = mb_cache_shrink_fn,
@@ -167,18 +157,19 @@ forget:
  * gets low.
  *
  * @shrink: (ignored)
- * @nr_to_scan: Number of objects to scan
- * @gfp_mask: (ignored)
+ * @sc: shrink_control passed from reclaim
  *
  * Returns the number of objects which are present in the cache.
  */
 static int
-mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+mb_cache_shrink_fn(struct shrinker *shrink, struct shrink_control *sc)
 {
        LIST_HEAD(free_list);
        struct mb_cache *cache;
        struct mb_cache_entry *entry, *tmp;
        int count = 0;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        mb_debug("trying to free %d entries", nr_to_scan);
        spin_lock(&mb_cache_spinlock);
@@ -243,6 +234,12 @@ mb_cache_create(const char *name, int bucket_bits)
        if (!cache->c_entry_cache)
                goto fail2;
 
+       /*
+        * Set an upper limit on the number of cache entries so that the hash
+        * chains won't grow too long.
+        */
+       cache->c_max_entries = bucket_count << 4;
+
        spin_lock(&mb_cache_spinlock);
        list_add(&cache->c_cache_list, &mb_cache_list);
        spin_unlock(&mb_cache_spinlock);
@@ -333,7 +330,6 @@ mb_cache_destroy(struct mb_cache *cache)
        kfree(cache);
 }
 
-
 /*
  * mb_cache_entry_alloc()
  *
@@ -345,17 +341,29 @@ mb_cache_destroy(struct mb_cache *cache)
 struct mb_cache_entry *
 mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags)
 {
-       struct mb_cache_entry *ce;
-
-       ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags);
-       if (ce) {
+       struct mb_cache_entry *ce = NULL;
+
+       if (atomic_read(&cache->c_entry_count) >= cache->c_max_entries) {
+               spin_lock(&mb_cache_spinlock);
+               if (!list_empty(&mb_cache_lru_list)) {
+                       ce = list_entry(mb_cache_lru_list.next,
+                                       struct mb_cache_entry, e_lru_list);
+                       list_del_init(&ce->e_lru_list);
+                       __mb_cache_entry_unhash(ce);
+               }
+               spin_unlock(&mb_cache_spinlock);
+       }
+       if (!ce) {
+               ce = kmem_cache_alloc(cache->c_entry_cache, gfp_flags);
+               if (!ce)
+                       return NULL;
                atomic_inc(&cache->c_entry_count);
                INIT_LIST_HEAD(&ce->e_lru_list);
                INIT_LIST_HEAD(&ce->e_block_list);
                ce->e_cache = cache;
-               ce->e_used = 1 + MB_CACHE_WRITER;
                ce->e_queued = 0;
        }
+       ce->e_used = 1 + MB_CACHE_WRITER;
        return ce;
 }
 
@@ -536,7 +544,7 @@ __mb_cache_entry_find(struct list_head *l, struct list_head *head,
  * mb_cache_entry_find_first()
  *
  * Find the first cache entry on a given device with a certain key in
- * an additional index. Additonal matches can be found with
+ * an additional index. Additional matches can be found with
  * mb_cache_entry_find_next(). Returns NULL if no match was found. The
  * returned cache entry is locked for shared access ("multiple readers").
  *