else
x.dname = fsdevice;
+ x.bcache_flags = CACHE_MISCOMPARE_PURGE;
if (!libxfs_init(&x)) {
fputs(_("\nfatal error -- couldn't initialize XFS library\n"),
stderr);
#ifndef __CACHE_H__
#define __CACHE_H__
+/*
+ * initialisation flags
+ */
+/*
+ * xfs_db always writes changes immediately, and so we need to purge buffers
+ * when we get a buffer lookup mismatch due to reading the same block with a
+ * different buffer configuration.
+ */
+#define CACHE_MISCOMPARE_PURGE (1 << 0)
+
+/*
+ * cache object campare return values
+ */
+enum {
+ CACHE_HIT,
+ CACHE_MISS,
+ CACHE_PURGE,
+};
+
#define HASH_CACHE_RATIO 8
/*
};
struct cache {
+ int c_flags; /* behavioural flags */
unsigned int c_maxcount; /* max cache nodes */
unsigned int c_count; /* count of nodes */
pthread_mutex_t c_mutex; /* node count mutex */
unsigned int c_max; /* max nodes ever used */
};
-struct cache *cache_init(unsigned int, struct cache_operations *);
+struct cache *cache_init(int, unsigned int, struct cache_operations *);
void cache_destroy(struct cache *);
void cache_walk(struct cache *, cache_walk_t);
void cache_purge(struct cache *);
int dfd; /* data subvolume file descriptor */
int logfd; /* log subvolume file descriptor */
int rtfd; /* realtime subvolume file descriptor */
+ int icache_flags; /* cache init flags */
+ int bcache_flags; /* cache init flags */
} libxfs_init_t;
#define LIBXFS_EXIT_ON_FAILURE 0x0001 /* exit the program if a call fails */
struct cache *
cache_init(
+ int flags,
unsigned int hashsize,
struct cache_operations *cache_operations)
{
return NULL;
}
+ cache->c_flags = flags;
cache->c_count = 0;
cache->c_max = 0;
cache->c_hits = 0;
return (cache->c_maxcount == cache->c_max);
}
+
+static int
+__cache_node_purge(
+ struct cache * cache,
+ struct cache_node * node)
+{
+ int count;
+ struct cache_mru * mru;
+
+ pthread_mutex_lock(&node->cn_mutex);
+ count = node->cn_count;
+ if (count != 0) {
+ pthread_mutex_unlock(&node->cn_mutex);
+ return count;
+ }
+ mru = &cache->c_mrus[node->cn_priority];
+ pthread_mutex_lock(&mru->cm_mutex);
+ list_del_init(&node->cn_mru);
+ mru->cm_count--;
+ pthread_mutex_unlock(&mru->cm_mutex);
+
+ pthread_mutex_unlock(&node->cn_mutex);
+ pthread_mutex_destroy(&node->cn_mutex);
+ list_del_init(&node->cn_hash);
+ cache->relse(node);
+ return count;
+}
+
/*
* Lookup in the cache hash table. With any luck we'll get a cache
* hit, in which case this will all be over quickly and painlessly.
struct cache_mru * mru;
struct list_head * head;
struct list_head * pos;
+ struct list_head * n;
unsigned int hashidx;
int priority = 0;
+ int purged = 0;
hashidx = cache->hash(key, cache->c_hashsize);
hash = cache->c_hash + hashidx;
for (;;) {
pthread_mutex_lock(&hash->ch_mutex);
- for (pos = head->next; pos != head; pos = pos->next) {
+ for (pos = head->next, n = pos->next; pos != head;
+ pos = n, n = pos->next) {
+ int result;
+
node = list_entry(pos, struct cache_node, cn_hash);
- if (!cache->compare(node, key))
- continue;
+ result = cache->compare(node, key);
+ switch (result) {
+ case CACHE_HIT:
+ break;
+ case CACHE_PURGE:
+ if ((cache->c_flags & CACHE_MISCOMPARE_PURGE) &&
+ !__cache_node_purge(cache, node)) {
+ purged++;
+ hash->ch_count--;
+ }
+ /* FALL THROUGH */
+ case CACHE_MISS:
+ goto next_object;
+ }
+
/*
* node found, bump node's reference count, remove it
* from its MRU list, and update stats.
*nodep = node;
return 0;
+next_object:
+ continue; /* what the hell, gcc? */
}
pthread_mutex_unlock(&hash->ch_mutex);
/*
list_add(&node->cn_hash, &hash->ch_list);
pthread_mutex_unlock(&hash->ch_mutex);
+ if (purged) {
+ pthread_mutex_lock(&cache->c_mutex);
+ cache->c_count -= purged;
+ pthread_mutex_unlock(&cache->c_mutex);
+ }
+
*nodep = node;
return 1;
}
struct list_head * pos;
struct list_head * n;
struct cache_hash * hash;
- struct cache_mru * mru;
int count = -1;
hash = cache->c_hash + cache->hash(key, cache->c_hashsize);
if ((struct cache_node *)pos != node)
continue;
- pthread_mutex_lock(&node->cn_mutex);
- count = node->cn_count;
- if (count != 0) {
- pthread_mutex_unlock(&node->cn_mutex);
- break;
- }
- mru = &cache->c_mrus[node->cn_priority];
- pthread_mutex_lock(&mru->cm_mutex);
- list_del_init(&node->cn_mru);
- mru->cm_count--;
- pthread_mutex_unlock(&mru->cm_mutex);
-
- pthread_mutex_unlock(&node->cn_mutex);
- pthread_mutex_destroy(&node->cn_mutex);
- list_del_init(&node->cn_hash);
- hash->ch_count--;
- cache->relse(node);
+ count = __cache_node_purge(cache, node);
+ if (!count)
+ hash->ch_count--;
break;
}
pthread_mutex_unlock(&hash->ch_mutex);
chdir(curdir);
if (!libxfs_bhash_size)
libxfs_bhash_size = LIBXFS_BHASHSIZE(sbp);
- libxfs_bcache = cache_init(libxfs_bhash_size, &libxfs_bcache_operations);
+ libxfs_bcache = cache_init(a->bcache_flags, libxfs_bhash_size,
+ &libxfs_bcache_operations);
use_xfs_buf_lock = a->usebuflock;
manage_zones(0);
rval = 1;
struct xfs_buf *bp = (struct xfs_buf *)node;
struct xfs_bufkey *bkey = (struct xfs_bufkey *)key;
-#ifdef IO_BCOMPARE_CHECK
if (bp->b_target->dev == bkey->buftarg->dev &&
- bp->b_bn == bkey->blkno &&
- bp->b_bcount != BBTOB(bkey->bblen))
- fprintf(stderr, "%lx: Badness in key lookup (length)\n"
- "bp=(bno 0x%llx, len %u bytes) key=(bno 0x%llx, len %u bytes)\n",
- pthread_self(),
- (unsigned long long)bp->b_bn, (int)bp->b_bcount,
- (unsigned long long)bkey->blkno, BBTOB(bkey->bblen));
+ bp->b_bn == bkey->blkno) {
+ if (bp->b_bcount == BBTOB(bkey->bblen))
+ return CACHE_HIT;
+#ifdef IO_BCOMPARE_CHECK
+ if (!(libxfs_bcache->c_flags & CACHE_MISCOMPARE_PURGE)) {
+ fprintf(stderr,
+ "%lx: Badness in key lookup (length)\n"
+ "bp=(bno 0x%llx, len %u bytes) key=(bno 0x%llx, len %u bytes)\n",
+ pthread_self(),
+ (unsigned long long)bp->b_bn, (int)bp->b_bcount,
+ (unsigned long long)bkey->blkno,
+ BBTOB(bkey->bblen));
+ }
#endif
-
- return (bp->b_target->dev == bkey->buftarg->dev &&
- bp->b_bn == bkey->blkno &&
- bp->b_bcount == BBTOB(bkey->bblen));
+ return CACHE_PURGE;
+ }
+ return CACHE_MISS;
}
void
do_log(_(" - block cache size set to %d entries\n"),
libxfs_bhash_size * HASH_CACHE_RATIO);
- libxfs_bcache = cache_init(libxfs_bhash_size,
+ libxfs_bcache = cache_init(0, libxfs_bhash_size,
&libxfs_bcache_operations);
}