drivers/md/dm-pcache/cache.c

Source file repositories/reference/linux-study-clean/drivers/md/dm-pcache/cache.c

File Facts

System
Linux kernel
Corpus path
drivers/md/dm-pcache/cache.c
Extension
.c
Size
11556 bytes
Lines
450
Domain
Driver Families
Bucket
drivers/md
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (cache_decode_key_tail(cache) || cache_decode_dirty_tail(cache)) {
			pcache_dev_err(pcache, "Corrupted key tail or dirty tail.\n");
			return -EIO;
		}
	}

	return 0;
}

static int get_seg_id(struct pcache_cache *cache,
		      struct pcache_cache_segment *prev_cache_seg,
		      bool new_cache, u32 *seg_id)
{
	struct dm_pcache *pcache = CACHE_TO_PCACHE(cache);
	struct pcache_cache_dev *cache_dev = cache->cache_dev;
	int ret;

	if (new_cache) {
		ret = cache_dev_get_empty_segment_id(cache_dev, seg_id);
		if (ret) {
			pcache_dev_err(pcache, "no available segment\n");
			goto err;
		}

		if (prev_cache_seg)
			cache_seg_set_next_seg(prev_cache_seg, *seg_id);
		else
			cache_info_set_seg_id(cache, *seg_id);
	} else {
		if (prev_cache_seg) {
			struct pcache_segment_info *prev_seg_info;

			prev_seg_info = &prev_cache_seg->cache_seg_info;
			if (!segment_info_has_next(prev_seg_info)) {
				ret = -EFAULT;
				goto err;
			}
			*seg_id = prev_cache_seg->cache_seg_info.next_seg;
		} else {
			*seg_id = cache->cache_info.seg_id;
		}
	}
	return 0;
err:
	return ret;
}

static int cache_segs_init(struct pcache_cache *cache)
{
	struct pcache_cache_segment *prev_cache_seg = NULL;
	struct pcache_cache_info *cache_info = &cache->cache_info;
	bool new_cache = !(cache->cache_info.flags & PCACHE_CACHE_FLAGS_INIT_DONE);
	u32 seg_id;
	int ret;
	u32 i;

	for (i = 0; i < cache_info->n_segs; i++) {
		ret = get_seg_id(cache, prev_cache_seg, new_cache, &seg_id);
		if (ret)
			goto err;

		ret = cache_seg_init(cache, seg_id, i, new_cache);
		if (ret)
			goto err;

		prev_cache_seg = &cache->segments[i];
	}
	return 0;
err:
	return ret;
}

static int cache_init_req_keys(struct pcache_cache *cache, u32 n_paral)
{
	struct dm_pcache *pcache = CACHE_TO_PCACHE(cache);
	u32 n_subtrees;
	int ret;
	u32 i, cpu;

	/* Calculate number of cache trees based on the device size */
	n_subtrees = DIV_ROUND_UP(cache->dev_size << SECTOR_SHIFT, PCACHE_CACHE_SUBTREE_SIZE);
	ret = cache_tree_init(cache, &cache->req_key_tree, n_subtrees);
	if (ret)
		goto err;

	cache->n_ksets = n_paral;
	cache->ksets = kvcalloc(cache->n_ksets, PCACHE_KSET_SIZE, GFP_KERNEL);
	if (!cache->ksets) {
		ret = -ENOMEM;
		goto req_tree_exit;

Annotation

Implementation Notes