ext4: fix deadlock due to mbcache entry corruption
[linux-2.6-block.git] / fs / mbcache.c
index e272ad738faff04b7d24cf86dd115f60182c289c..2a4b8b549e934de32204e30ddab6d6a05fe84860 100644 (file)
@@ -100,8 +100,9 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
        atomic_set(&entry->e_refcnt, 2);
        entry->e_key = key;
        entry->e_value = value;
-       entry->e_reusable = reusable;
-       entry->e_referenced = 0;
+       entry->e_flags = 0;
+       if (reusable)
+               set_bit(MBE_REUSABLE_B, &entry->e_flags);
        head = mb_cache_entry_head(cache, key);
        hlist_bl_lock(head);
        hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
@@ -165,7 +166,8 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
        while (node) {
                entry = hlist_bl_entry(node, struct mb_cache_entry,
                                       e_hash_list);
-               if (entry->e_key == key && entry->e_reusable &&
+               if (entry->e_key == key &&
+                   test_bit(MBE_REUSABLE_B, &entry->e_flags) &&
                    atomic_inc_not_zero(&entry->e_refcnt))
                        goto out;
                node = node->next;
@@ -284,7 +286,7 @@ EXPORT_SYMBOL(mb_cache_entry_delete_or_get);
 void mb_cache_entry_touch(struct mb_cache *cache,
                          struct mb_cache_entry *entry)
 {
-       entry->e_referenced = 1;
+       set_bit(MBE_REFERENCED_B, &entry->e_flags);
 }
 EXPORT_SYMBOL(mb_cache_entry_touch);
 
@@ -309,9 +311,9 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache,
                entry = list_first_entry(&cache->c_list,
                                         struct mb_cache_entry, e_list);
                /* Drop initial hash reference if there is no user */
-               if (entry->e_referenced ||
+               if (test_bit(MBE_REFERENCED_B, &entry->e_flags) ||
                    atomic_cmpxchg(&entry->e_refcnt, 1, 0) != 1) {
-                       entry->e_referenced = 0;
+                       clear_bit(MBE_REFERENCED_B, &entry->e_flags);
                        list_move_tail(&entry->e_list, &cache->c_list);
                        continue;
                }