xref: /linux/drivers/md/dm-pcache/cache_req.c (revision 4466dd3d719cca113308e8ae539adf7b3d68c985)
11d57628fSDongsheng Yang // SPDX-License-Identifier: GPL-2.0-or-later
21d57628fSDongsheng Yang 
31d57628fSDongsheng Yang #include "cache.h"
41d57628fSDongsheng Yang #include "backing_dev.h"
51d57628fSDongsheng Yang #include "cache_dev.h"
61d57628fSDongsheng Yang #include "dm_pcache.h"
71d57628fSDongsheng Yang 
81d57628fSDongsheng Yang static int cache_data_head_init(struct pcache_cache *cache)
91d57628fSDongsheng Yang {
101d57628fSDongsheng Yang 	struct pcache_cache_segment *next_seg;
111d57628fSDongsheng Yang 	struct pcache_cache_data_head *data_head;
121d57628fSDongsheng Yang 
131d57628fSDongsheng Yang 	data_head = get_data_head(cache);
141d57628fSDongsheng Yang 	next_seg = get_cache_segment(cache);
151d57628fSDongsheng Yang 	if (!next_seg)
161d57628fSDongsheng Yang 		return -EBUSY;
171d57628fSDongsheng Yang 
181d57628fSDongsheng Yang 	cache_seg_get(next_seg);
191d57628fSDongsheng Yang 	data_head->head_pos.cache_seg = next_seg;
201d57628fSDongsheng Yang 	data_head->head_pos.seg_off = 0;
211d57628fSDongsheng Yang 
221d57628fSDongsheng Yang 	return 0;
231d57628fSDongsheng Yang }
241d57628fSDongsheng Yang 
251d57628fSDongsheng Yang /**
261d57628fSDongsheng Yang  * cache_data_alloc - Allocate data for a cache key.
271d57628fSDongsheng Yang  * @cache: Pointer to the cache structure.
281d57628fSDongsheng Yang  * @key: Pointer to the cache key to allocate data for.
291d57628fSDongsheng Yang  *
301d57628fSDongsheng Yang  * This function tries to allocate space from the cache segment specified by the
311d57628fSDongsheng Yang  * data head. If the remaining space in the segment is insufficient to allocate
321d57628fSDongsheng Yang  * the requested length for the cache key, it will allocate whatever is available
331d57628fSDongsheng Yang  * and adjust the key's length accordingly. This function does not allocate
341d57628fSDongsheng Yang  * space that crosses segment boundaries.
351d57628fSDongsheng Yang  */
361d57628fSDongsheng Yang static int cache_data_alloc(struct pcache_cache *cache, struct pcache_cache_key *key)
371d57628fSDongsheng Yang {
381d57628fSDongsheng Yang 	struct pcache_cache_data_head *data_head;
391d57628fSDongsheng Yang 	struct pcache_cache_pos *head_pos;
401d57628fSDongsheng Yang 	struct pcache_cache_segment *cache_seg;
411d57628fSDongsheng Yang 	u32 seg_remain;
421d57628fSDongsheng Yang 	u32 allocated = 0, to_alloc;
431d57628fSDongsheng Yang 	int ret = 0;
441d57628fSDongsheng Yang 
451d57628fSDongsheng Yang 	preempt_disable();
461d57628fSDongsheng Yang 	data_head = get_data_head(cache);
471d57628fSDongsheng Yang again:
481d57628fSDongsheng Yang 	to_alloc = key->len - allocated;
491d57628fSDongsheng Yang 	if (!data_head->head_pos.cache_seg) {
501d57628fSDongsheng Yang 		seg_remain = 0;
511d57628fSDongsheng Yang 	} else {
521d57628fSDongsheng Yang 		cache_pos_copy(&key->cache_pos, &data_head->head_pos);
531d57628fSDongsheng Yang 		key->seg_gen = key->cache_pos.cache_seg->gen;
541d57628fSDongsheng Yang 
551d57628fSDongsheng Yang 		head_pos = &data_head->head_pos;
561d57628fSDongsheng Yang 		cache_seg = head_pos->cache_seg;
571d57628fSDongsheng Yang 		seg_remain = cache_seg_remain(head_pos);
581d57628fSDongsheng Yang 	}
591d57628fSDongsheng Yang 
601d57628fSDongsheng Yang 	if (seg_remain > to_alloc) {
611d57628fSDongsheng Yang 		/* If remaining space in segment is sufficient for the cache key, allocate it. */
621d57628fSDongsheng Yang 		cache_pos_advance(head_pos, to_alloc);
631d57628fSDongsheng Yang 		allocated += to_alloc;
641d57628fSDongsheng Yang 		cache_seg_get(cache_seg);
651d57628fSDongsheng Yang 	} else if (seg_remain) {
661d57628fSDongsheng Yang 		/* If remaining space is not enough, allocate the remaining space and adjust the cache key length. */
671d57628fSDongsheng Yang 		cache_pos_advance(head_pos, seg_remain);
681d57628fSDongsheng Yang 		key->len = seg_remain;
691d57628fSDongsheng Yang 
701d57628fSDongsheng Yang 		/* Get for key: obtain a reference to the cache segment for the key. */
711d57628fSDongsheng Yang 		cache_seg_get(cache_seg);
721d57628fSDongsheng Yang 		/* Put for head_pos->cache_seg: release the reference for the current head's segment. */
731d57628fSDongsheng Yang 		cache_seg_put(head_pos->cache_seg);
741d57628fSDongsheng Yang 		head_pos->cache_seg = NULL;
751d57628fSDongsheng Yang 	} else {
761d57628fSDongsheng Yang 		/* Initialize a new data head if no segment is available. */
771d57628fSDongsheng Yang 		ret = cache_data_head_init(cache);
781d57628fSDongsheng Yang 		if (ret)
791d57628fSDongsheng Yang 			goto out;
801d57628fSDongsheng Yang 
811d57628fSDongsheng Yang 		goto again;
821d57628fSDongsheng Yang 	}
831d57628fSDongsheng Yang 
841d57628fSDongsheng Yang out:
851d57628fSDongsheng Yang 	preempt_enable();
861d57628fSDongsheng Yang 
871d57628fSDongsheng Yang 	return ret;
881d57628fSDongsheng Yang }
891d57628fSDongsheng Yang 
901d57628fSDongsheng Yang static int cache_copy_from_req_bio(struct pcache_cache *cache, struct pcache_cache_key *key,
911d57628fSDongsheng Yang 				struct pcache_request *pcache_req, u32 bio_off)
921d57628fSDongsheng Yang {
931d57628fSDongsheng Yang 	struct pcache_cache_pos *pos = &key->cache_pos;
941d57628fSDongsheng Yang 	struct pcache_segment *segment;
951d57628fSDongsheng Yang 
961d57628fSDongsheng Yang 	segment = &pos->cache_seg->segment;
971d57628fSDongsheng Yang 
981d57628fSDongsheng Yang 	return segment_copy_from_bio(segment, pos->seg_off, key->len, pcache_req->bio, bio_off);
991d57628fSDongsheng Yang }
1001d57628fSDongsheng Yang 
1011d57628fSDongsheng Yang static int cache_copy_to_req_bio(struct pcache_cache *cache, struct pcache_request *pcache_req,
1021d57628fSDongsheng Yang 			    u32 bio_off, u32 len, struct pcache_cache_pos *pos, u64 key_gen)
1031d57628fSDongsheng Yang {
1041d57628fSDongsheng Yang 	struct pcache_cache_segment *cache_seg = pos->cache_seg;
1051d57628fSDongsheng Yang 	struct pcache_segment *segment = &cache_seg->segment;
1061d57628fSDongsheng Yang 	int ret;
1071d57628fSDongsheng Yang 
1081d57628fSDongsheng Yang 	spin_lock(&cache_seg->gen_lock);
1091d57628fSDongsheng Yang 	if (key_gen < cache_seg->gen) {
1101d57628fSDongsheng Yang 		spin_unlock(&cache_seg->gen_lock);
1111d57628fSDongsheng Yang 		return -EINVAL;
1121d57628fSDongsheng Yang 	}
1131d57628fSDongsheng Yang 
1141d57628fSDongsheng Yang 	ret = segment_copy_to_bio(segment, pos->seg_off, len, pcache_req->bio, bio_off);
1151d57628fSDongsheng Yang 	spin_unlock(&cache_seg->gen_lock);
1161d57628fSDongsheng Yang 
1171d57628fSDongsheng Yang 	return ret;
1181d57628fSDongsheng Yang }
1191d57628fSDongsheng Yang 
1201d57628fSDongsheng Yang /**
1211d57628fSDongsheng Yang  * miss_read_end_req - Handle the end of a miss read request.
1221d57628fSDongsheng Yang  * @backing_req: Pointer to the request structure.
1231d57628fSDongsheng Yang  * @read_ret: Return value of read.
1241d57628fSDongsheng Yang  *
1251d57628fSDongsheng Yang  * This function is called when a backing request to read data from
1261d57628fSDongsheng Yang  * the backing_dev is completed. If the key associated with the request
1271d57628fSDongsheng Yang  * is empty (a placeholder), it allocates cache space for the key,
1281d57628fSDongsheng Yang  * copies the data read from the bio into the cache, and updates
1291d57628fSDongsheng Yang  * the key's status. If the key has been overwritten by a write
1301d57628fSDongsheng Yang  * request during this process, it will be deleted from the cache
1311d57628fSDongsheng Yang  * tree and no further action will be taken.
1321d57628fSDongsheng Yang  */
1331d57628fSDongsheng Yang static void miss_read_end_req(struct pcache_backing_dev_req *backing_req, int read_ret)
1341d57628fSDongsheng Yang {
1351d57628fSDongsheng Yang 	void *priv_data = backing_req->priv_data;
1361d57628fSDongsheng Yang 	struct pcache_request *pcache_req = backing_req->req.upper_req;
1371d57628fSDongsheng Yang 	struct pcache_cache *cache = backing_req->backing_dev->cache;
1381d57628fSDongsheng Yang 	int ret;
1391d57628fSDongsheng Yang 
1401d57628fSDongsheng Yang 	if (priv_data) {
1411d57628fSDongsheng Yang 		struct pcache_cache_key *key;
1421d57628fSDongsheng Yang 		struct pcache_cache_subtree *cache_subtree;
1431d57628fSDongsheng Yang 
1441d57628fSDongsheng Yang 		key = (struct pcache_cache_key *)priv_data;
1451d57628fSDongsheng Yang 		cache_subtree = key->cache_subtree;
1461d57628fSDongsheng Yang 
1471d57628fSDongsheng Yang 		/* if this key was deleted from cache_subtree by a write, key->flags should be cleared,
1481d57628fSDongsheng Yang 		 * so if cache_key_empty() return true, this key is still in cache_subtree
1491d57628fSDongsheng Yang 		 */
1501d57628fSDongsheng Yang 		spin_lock(&cache_subtree->tree_lock);
1511d57628fSDongsheng Yang 		if (cache_key_empty(key)) {
1521d57628fSDongsheng Yang 			/* Check if the backing request was successful. */
1531d57628fSDongsheng Yang 			if (read_ret) {
1541d57628fSDongsheng Yang 				cache_key_delete(key);
1551d57628fSDongsheng Yang 				goto unlock;
1561d57628fSDongsheng Yang 			}
1571d57628fSDongsheng Yang 
1581d57628fSDongsheng Yang 			/* Allocate cache space for the key and copy data from the backing_dev. */
1591d57628fSDongsheng Yang 			ret = cache_data_alloc(cache, key);
1601d57628fSDongsheng Yang 			if (ret) {
1611d57628fSDongsheng Yang 				cache_key_delete(key);
1621d57628fSDongsheng Yang 				goto unlock;
1631d57628fSDongsheng Yang 			}
1641d57628fSDongsheng Yang 
1651d57628fSDongsheng Yang 			ret = cache_copy_from_req_bio(cache, key, pcache_req, backing_req->req.bio_off);
1661d57628fSDongsheng Yang 			if (ret) {
1671d57628fSDongsheng Yang 				cache_seg_put(key->cache_pos.cache_seg);
1681d57628fSDongsheng Yang 				cache_key_delete(key);
1691d57628fSDongsheng Yang 				goto unlock;
1701d57628fSDongsheng Yang 			}
1711d57628fSDongsheng Yang 			key->flags &= ~PCACHE_CACHE_KEY_FLAGS_EMPTY;
1721d57628fSDongsheng Yang 			key->flags |= PCACHE_CACHE_KEY_FLAGS_CLEAN;
1731d57628fSDongsheng Yang 
1741d57628fSDongsheng Yang 			/* Append the key to the cache. */
1751d57628fSDongsheng Yang 			ret = cache_key_append(cache, key, false);
1761d57628fSDongsheng Yang 			if (ret) {
1771d57628fSDongsheng Yang 				cache_seg_put(key->cache_pos.cache_seg);
1781d57628fSDongsheng Yang 				cache_key_delete(key);
1791d57628fSDongsheng Yang 				goto unlock;
1801d57628fSDongsheng Yang 			}
1811d57628fSDongsheng Yang 		}
1821d57628fSDongsheng Yang unlock:
1831d57628fSDongsheng Yang 		spin_unlock(&cache_subtree->tree_lock);
1841d57628fSDongsheng Yang 		cache_key_put(key);
1851d57628fSDongsheng Yang 	}
1861d57628fSDongsheng Yang }
1871d57628fSDongsheng Yang 
1881d57628fSDongsheng Yang /**
1891d57628fSDongsheng Yang  * submit_cache_miss_req - Submit a backing request when cache data is missing
1901d57628fSDongsheng Yang  * @cache: The cache context that manages cache operations
1911d57628fSDongsheng Yang  * @backing_req: The cache request containing information about the read request
1921d57628fSDongsheng Yang  *
1931d57628fSDongsheng Yang  * This function is used to handle cases where a cache read request cannot locate
1941d57628fSDongsheng Yang  * the required data in the cache. When such a miss occurs during `cache_subtree_walk`,
1951d57628fSDongsheng Yang  * it triggers a backing read request to fetch data from the backing storage.
1961d57628fSDongsheng Yang  *
1971d57628fSDongsheng Yang  * If `pcache_req->priv_data` is set, it points to a `pcache_cache_key`, representing
1981d57628fSDongsheng Yang  * a new cache key to be inserted into the cache. The function calls `cache_key_insert`
1991d57628fSDongsheng Yang  * to attempt adding the key. On insertion failure, it releases the key reference and
2001d57628fSDongsheng Yang  * clears `priv_data` to avoid further processing.
2011d57628fSDongsheng Yang  */
2021d57628fSDongsheng Yang static void submit_cache_miss_req(struct pcache_cache *cache, struct pcache_backing_dev_req *backing_req)
2031d57628fSDongsheng Yang {
2041d57628fSDongsheng Yang 	if (backing_req->priv_data) {
2051d57628fSDongsheng Yang 		struct pcache_cache_key *key;
2061d57628fSDongsheng Yang 
2071d57628fSDongsheng Yang 		/* Attempt to insert the key into the cache if priv_data is set */
2081d57628fSDongsheng Yang 		key = (struct pcache_cache_key *)backing_req->priv_data;
2091d57628fSDongsheng Yang 		cache_key_insert(&cache->req_key_tree, key, true);
2101d57628fSDongsheng Yang 	}
2111d57628fSDongsheng Yang 	backing_dev_req_submit(backing_req, false);
2121d57628fSDongsheng Yang }
2131d57628fSDongsheng Yang 
2141d57628fSDongsheng Yang static void cache_miss_req_free(struct pcache_backing_dev_req *backing_req)
2151d57628fSDongsheng Yang {
2161d57628fSDongsheng Yang 	struct pcache_cache_key *key;
2171d57628fSDongsheng Yang 
2181d57628fSDongsheng Yang 	if (backing_req->priv_data) {
2191d57628fSDongsheng Yang 		key = backing_req->priv_data;
2201d57628fSDongsheng Yang 		backing_req->priv_data = NULL;
2211d57628fSDongsheng Yang 		cache_key_put(key); /* for ->priv_data */
2221d57628fSDongsheng Yang 		cache_key_put(key); /* for init ref in alloc */
2231d57628fSDongsheng Yang 	}
2241d57628fSDongsheng Yang 
2251d57628fSDongsheng Yang 	backing_dev_req_end(backing_req);
2261d57628fSDongsheng Yang }
2271d57628fSDongsheng Yang 
2281d57628fSDongsheng Yang static struct pcache_backing_dev_req *cache_miss_req_alloc(struct pcache_cache *cache,
2291d57628fSDongsheng Yang 							   struct pcache_request *parent,
2301d57628fSDongsheng Yang 							   gfp_t gfp_mask)
2311d57628fSDongsheng Yang {
2321d57628fSDongsheng Yang 	struct pcache_backing_dev *backing_dev = cache->backing_dev;
2331d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req;
2341d57628fSDongsheng Yang 	struct pcache_cache_key *key = NULL;
2351d57628fSDongsheng Yang 	struct pcache_backing_dev_req_opts req_opts = { 0 };
2361d57628fSDongsheng Yang 
2371d57628fSDongsheng Yang 	req_opts.type = BACKING_DEV_REQ_TYPE_REQ;
2381d57628fSDongsheng Yang 	req_opts.gfp_mask = gfp_mask;
2391d57628fSDongsheng Yang 	req_opts.req.upper_req = parent;
2401d57628fSDongsheng Yang 
2411d57628fSDongsheng Yang 	backing_req = backing_dev_req_alloc(backing_dev, &req_opts);
2421d57628fSDongsheng Yang 	if (!backing_req)
2431d57628fSDongsheng Yang 		return NULL;
2441d57628fSDongsheng Yang 
2451d57628fSDongsheng Yang 	key = cache_key_alloc(&cache->req_key_tree, gfp_mask);
2461d57628fSDongsheng Yang 	if (!key)
2471d57628fSDongsheng Yang 		goto free_backing_req;
2481d57628fSDongsheng Yang 
2491d57628fSDongsheng Yang 	cache_key_get(key);
2501d57628fSDongsheng Yang 	backing_req->priv_data = key;
2511d57628fSDongsheng Yang 
2521d57628fSDongsheng Yang 	return backing_req;
2531d57628fSDongsheng Yang 
2541d57628fSDongsheng Yang free_backing_req:
2551d57628fSDongsheng Yang 	cache_miss_req_free(backing_req);
2561d57628fSDongsheng Yang 	return NULL;
2571d57628fSDongsheng Yang }
2581d57628fSDongsheng Yang 
2591d57628fSDongsheng Yang static void cache_miss_req_init(struct pcache_cache *cache,
2601d57628fSDongsheng Yang 				struct pcache_backing_dev_req *backing_req,
2611d57628fSDongsheng Yang 				struct pcache_request *parent,
2621d57628fSDongsheng Yang 				u32 off, u32 len, bool insert_key)
2631d57628fSDongsheng Yang {
2641d57628fSDongsheng Yang 	struct pcache_cache_key *key;
2651d57628fSDongsheng Yang 	struct pcache_backing_dev_req_opts req_opts = { 0 };
2661d57628fSDongsheng Yang 
2671d57628fSDongsheng Yang 	req_opts.type = BACKING_DEV_REQ_TYPE_REQ;
2681d57628fSDongsheng Yang 	req_opts.req.upper_req = parent;
2691d57628fSDongsheng Yang 	req_opts.req.req_off = off;
2701d57628fSDongsheng Yang 	req_opts.req.len = len;
2711d57628fSDongsheng Yang 	req_opts.end_fn = miss_read_end_req;
2721d57628fSDongsheng Yang 
2731d57628fSDongsheng Yang 	backing_dev_req_init(backing_req, &req_opts);
2741d57628fSDongsheng Yang 
2751d57628fSDongsheng Yang 	if (insert_key) {
2761d57628fSDongsheng Yang 		key = backing_req->priv_data;
2771d57628fSDongsheng Yang 		key->off = parent->off + off;
2781d57628fSDongsheng Yang 		key->len = len;
2791d57628fSDongsheng Yang 		key->flags |= PCACHE_CACHE_KEY_FLAGS_EMPTY;
2801d57628fSDongsheng Yang 	} else {
2811d57628fSDongsheng Yang 		key = backing_req->priv_data;
2821d57628fSDongsheng Yang 		backing_req->priv_data = NULL;
2831d57628fSDongsheng Yang 		cache_key_put(key);
2841d57628fSDongsheng Yang 		cache_key_put(key);
2851d57628fSDongsheng Yang 	}
2861d57628fSDongsheng Yang }
2871d57628fSDongsheng Yang 
2881d57628fSDongsheng Yang static struct pcache_backing_dev_req *get_pre_alloc_req(struct pcache_cache_subtree_walk_ctx *ctx)
2891d57628fSDongsheng Yang {
2901d57628fSDongsheng Yang 	struct pcache_cache *cache = ctx->cache_tree->cache;
2911d57628fSDongsheng Yang 	struct pcache_request *pcache_req = ctx->pcache_req;
2921d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req;
2931d57628fSDongsheng Yang 
2941d57628fSDongsheng Yang 	if (ctx->pre_alloc_req) {
2951d57628fSDongsheng Yang 		backing_req = ctx->pre_alloc_req;
2961d57628fSDongsheng Yang 		ctx->pre_alloc_req = NULL;
2971d57628fSDongsheng Yang 
2981d57628fSDongsheng Yang 		return backing_req;
2991d57628fSDongsheng Yang 	}
3001d57628fSDongsheng Yang 
3011d57628fSDongsheng Yang 	return cache_miss_req_alloc(cache, pcache_req, GFP_NOWAIT);
3021d57628fSDongsheng Yang }
3031d57628fSDongsheng Yang 
3041d57628fSDongsheng Yang /*
3051d57628fSDongsheng Yang  * In the process of walking the cache tree to locate cached data, this
3061d57628fSDongsheng Yang  * function handles the situation where the requested data range lies
3071d57628fSDongsheng Yang  * entirely before an existing cache node (`key_tmp`). This outcome
3081d57628fSDongsheng Yang  * signifies that the target data is absent from the cache (cache miss).
3091d57628fSDongsheng Yang  *
3101d57628fSDongsheng Yang  * To fulfill this portion of the read request, the function creates a
3111d57628fSDongsheng Yang  * backing request (`backing_req`) for the missing data range represented
3121d57628fSDongsheng Yang  * by `key`. It then appends this request to the submission list in the
3131d57628fSDongsheng Yang  * `ctx`, which will later be processed to retrieve the data from backing
3141d57628fSDongsheng Yang  * storage. After setting up the backing request, `req_done` in `ctx` is
3151d57628fSDongsheng Yang  * updated to reflect the length of the handled range, and the range
3161d57628fSDongsheng Yang  * in `key` is adjusted by trimming off the portion that is now handled.
3171d57628fSDongsheng Yang  *
3181d57628fSDongsheng Yang  * The scenario handled here:
3191d57628fSDongsheng Yang  *
3201d57628fSDongsheng Yang  *	  |--------|			  key_tmp (existing cached range)
3211d57628fSDongsheng Yang  * |====|					   key (requested range, preceding key_tmp)
3221d57628fSDongsheng Yang  *
3231d57628fSDongsheng Yang  * Since `key` is before `key_tmp`, it signifies that the requested data
3241d57628fSDongsheng Yang  * range is missing in the cache (cache miss) and needs retrieval from
3251d57628fSDongsheng Yang  * backing storage.
3261d57628fSDongsheng Yang  */
3271d57628fSDongsheng Yang static int read_before(struct pcache_cache_key *key, struct pcache_cache_key *key_tmp,
3281d57628fSDongsheng Yang 		struct pcache_cache_subtree_walk_ctx *ctx)
3291d57628fSDongsheng Yang {
3301d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req;
3311d57628fSDongsheng Yang 	struct pcache_cache *cache = ctx->cache_tree->cache;
3321d57628fSDongsheng Yang 
3331d57628fSDongsheng Yang 	/*
3341d57628fSDongsheng Yang 	 * In this scenario, `key` represents a range that precedes `key_tmp`,
3351d57628fSDongsheng Yang 	 * meaning the requested data range is missing from the cache tree
3361d57628fSDongsheng Yang 	 * and must be retrieved from the backing_dev.
3371d57628fSDongsheng Yang 	 */
3381d57628fSDongsheng Yang 	backing_req = get_pre_alloc_req(ctx);
3391d57628fSDongsheng Yang 	if (!backing_req)
3401d57628fSDongsheng Yang 		return SUBTREE_WALK_RET_NEED_REQ;
3411d57628fSDongsheng Yang 
3421d57628fSDongsheng Yang 	cache_miss_req_init(cache, backing_req, ctx->pcache_req, ctx->req_done, key->len, true);
3431d57628fSDongsheng Yang 
3441d57628fSDongsheng Yang 	list_add(&backing_req->node, ctx->submit_req_list);
3451d57628fSDongsheng Yang 	ctx->req_done += key->len;
3461d57628fSDongsheng Yang 	cache_key_cutfront(key, key->len);
3471d57628fSDongsheng Yang 
3481d57628fSDongsheng Yang 	return SUBTREE_WALK_RET_OK;
3491d57628fSDongsheng Yang }
3501d57628fSDongsheng Yang 
3511d57628fSDongsheng Yang /*
3521d57628fSDongsheng Yang  * During cache_subtree_walk, this function manages a scenario where part of the
3531d57628fSDongsheng Yang  * requested data range overlaps with an existing cache node (`key_tmp`).
3541d57628fSDongsheng Yang  *
3551d57628fSDongsheng Yang  *	 |----------------|  key_tmp (existing cached range)
3561d57628fSDongsheng Yang  * |===========|		   key (requested range, overlapping the tail of key_tmp)
3571d57628fSDongsheng Yang  */
3581d57628fSDongsheng Yang static int read_overlap_tail(struct pcache_cache_key *key, struct pcache_cache_key *key_tmp,
3591d57628fSDongsheng Yang 		struct pcache_cache_subtree_walk_ctx *ctx)
3601d57628fSDongsheng Yang {
3611d57628fSDongsheng Yang 	struct pcache_cache *cache = ctx->cache_tree->cache;
3621d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req;
3631d57628fSDongsheng Yang 	u32 io_len;
3641d57628fSDongsheng Yang 	int ret;
3651d57628fSDongsheng Yang 
3661d57628fSDongsheng Yang 	/*
3671d57628fSDongsheng Yang 	 * Calculate the length of the non-overlapping portion of `key`
3681d57628fSDongsheng Yang 	 * before `key_tmp`, representing the data missing in the cache.
3691d57628fSDongsheng Yang 	 */
3701d57628fSDongsheng Yang 	io_len = cache_key_lstart(key_tmp) - cache_key_lstart(key);
3711d57628fSDongsheng Yang 	if (io_len) {
3721d57628fSDongsheng Yang 		backing_req = get_pre_alloc_req(ctx);
3731d57628fSDongsheng Yang 		if (!backing_req)
3741d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_NEED_REQ;
3751d57628fSDongsheng Yang 
3761d57628fSDongsheng Yang 		cache_miss_req_init(cache, backing_req, ctx->pcache_req, ctx->req_done, io_len, true);
3771d57628fSDongsheng Yang 
3781d57628fSDongsheng Yang 		list_add(&backing_req->node, ctx->submit_req_list);
3791d57628fSDongsheng Yang 		ctx->req_done += io_len;
3801d57628fSDongsheng Yang 		cache_key_cutfront(key, io_len);
3811d57628fSDongsheng Yang 	}
3821d57628fSDongsheng Yang 
3831d57628fSDongsheng Yang 	/*
3841d57628fSDongsheng Yang 	 * Handle the overlapping portion by calculating the length of
3851d57628fSDongsheng Yang 	 * the remaining data in `key` that coincides with `key_tmp`.
3861d57628fSDongsheng Yang 	 */
3871d57628fSDongsheng Yang 	io_len = cache_key_lend(key) - cache_key_lstart(key_tmp);
3881d57628fSDongsheng Yang 	if (cache_key_empty(key_tmp)) {
3891d57628fSDongsheng Yang 		backing_req = get_pre_alloc_req(ctx);
3901d57628fSDongsheng Yang 		if (!backing_req)
3911d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_NEED_REQ;
3921d57628fSDongsheng Yang 
3931d57628fSDongsheng Yang 		cache_miss_req_init(cache, backing_req, ctx->pcache_req, ctx->req_done, io_len, false);
3941d57628fSDongsheng Yang 		submit_cache_miss_req(cache, backing_req);
3951d57628fSDongsheng Yang 	} else {
3961d57628fSDongsheng Yang 		ret = cache_copy_to_req_bio(ctx->cache_tree->cache, ctx->pcache_req, ctx->req_done,
3971d57628fSDongsheng Yang 					io_len, &key_tmp->cache_pos, key_tmp->seg_gen);
3981d57628fSDongsheng Yang 		if (ret) {
3991d57628fSDongsheng Yang 			if (ret == -EINVAL) {
4001d57628fSDongsheng Yang 				cache_key_delete(key_tmp);
4011d57628fSDongsheng Yang 				return SUBTREE_WALK_RET_RESEARCH;
4021d57628fSDongsheng Yang 			}
4031d57628fSDongsheng Yang 
4041d57628fSDongsheng Yang 			ctx->ret = ret;
4051d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_ERR;
4061d57628fSDongsheng Yang 		}
4071d57628fSDongsheng Yang 	}
4081d57628fSDongsheng Yang 
4091d57628fSDongsheng Yang 	ctx->req_done += io_len;
4101d57628fSDongsheng Yang 	cache_key_cutfront(key, io_len);
4111d57628fSDongsheng Yang 
4121d57628fSDongsheng Yang 	return SUBTREE_WALK_RET_OK;
4131d57628fSDongsheng Yang }
4141d57628fSDongsheng Yang 
4151d57628fSDongsheng Yang /*
4161d57628fSDongsheng Yang  *    |----|          key_tmp (existing cached range)
4171d57628fSDongsheng Yang  * |==========|       key (requested range)
4181d57628fSDongsheng Yang  */
4191d57628fSDongsheng Yang static int read_overlap_contain(struct pcache_cache_key *key, struct pcache_cache_key *key_tmp,
4201d57628fSDongsheng Yang 		struct pcache_cache_subtree_walk_ctx *ctx)
4211d57628fSDongsheng Yang {
4221d57628fSDongsheng Yang 	struct pcache_cache *cache = ctx->cache_tree->cache;
4231d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req;
4241d57628fSDongsheng Yang 	u32 io_len;
4251d57628fSDongsheng Yang 	int ret;
4261d57628fSDongsheng Yang 
4271d57628fSDongsheng Yang 	/*
4281d57628fSDongsheng Yang 	 * Calculate the non-overlapping part of `key` before `key_tmp`
4291d57628fSDongsheng Yang 	 * to identify the missing data length.
4301d57628fSDongsheng Yang 	 */
4311d57628fSDongsheng Yang 	io_len = cache_key_lstart(key_tmp) - cache_key_lstart(key);
4321d57628fSDongsheng Yang 	if (io_len) {
4331d57628fSDongsheng Yang 		backing_req = get_pre_alloc_req(ctx);
4341d57628fSDongsheng Yang 		if (!backing_req)
4351d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_NEED_REQ;
4361d57628fSDongsheng Yang 
4371d57628fSDongsheng Yang 		cache_miss_req_init(cache, backing_req, ctx->pcache_req, ctx->req_done, io_len, true);
4381d57628fSDongsheng Yang 
4391d57628fSDongsheng Yang 		list_add(&backing_req->node, ctx->submit_req_list);
4401d57628fSDongsheng Yang 
4411d57628fSDongsheng Yang 		ctx->req_done += io_len;
4421d57628fSDongsheng Yang 		cache_key_cutfront(key, io_len);
4431d57628fSDongsheng Yang 	}
4441d57628fSDongsheng Yang 
4451d57628fSDongsheng Yang 	/*
4461d57628fSDongsheng Yang 	 * Handle the overlapping portion between `key` and `key_tmp`.
4471d57628fSDongsheng Yang 	 */
4481d57628fSDongsheng Yang 	io_len = key_tmp->len;
4491d57628fSDongsheng Yang 	if (cache_key_empty(key_tmp)) {
4501d57628fSDongsheng Yang 		backing_req = get_pre_alloc_req(ctx);
4511d57628fSDongsheng Yang 		if (!backing_req)
4521d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_NEED_REQ;
4531d57628fSDongsheng Yang 
4541d57628fSDongsheng Yang 		cache_miss_req_init(cache, backing_req, ctx->pcache_req, ctx->req_done, io_len, false);
4551d57628fSDongsheng Yang 		submit_cache_miss_req(cache, backing_req);
4561d57628fSDongsheng Yang 	} else {
4571d57628fSDongsheng Yang 		ret = cache_copy_to_req_bio(ctx->cache_tree->cache, ctx->pcache_req, ctx->req_done,
4581d57628fSDongsheng Yang 					io_len, &key_tmp->cache_pos, key_tmp->seg_gen);
4591d57628fSDongsheng Yang 		if (ret) {
4601d57628fSDongsheng Yang 			if (ret == -EINVAL) {
4611d57628fSDongsheng Yang 				cache_key_delete(key_tmp);
4621d57628fSDongsheng Yang 				return SUBTREE_WALK_RET_RESEARCH;
4631d57628fSDongsheng Yang 			}
4641d57628fSDongsheng Yang 
4651d57628fSDongsheng Yang 			ctx->ret = ret;
4661d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_ERR;
4671d57628fSDongsheng Yang 		}
4681d57628fSDongsheng Yang 	}
4691d57628fSDongsheng Yang 
4701d57628fSDongsheng Yang 	ctx->req_done += io_len;
4711d57628fSDongsheng Yang 	cache_key_cutfront(key, io_len);
4721d57628fSDongsheng Yang 
4731d57628fSDongsheng Yang 	return SUBTREE_WALK_RET_OK;
4741d57628fSDongsheng Yang }
4751d57628fSDongsheng Yang 
4761d57628fSDongsheng Yang /*
4771d57628fSDongsheng Yang  *	 |-----------|		key_tmp (existing cached range)
4781d57628fSDongsheng Yang  *	   |====|			key (requested range, fully within key_tmp)
4791d57628fSDongsheng Yang  *
4801d57628fSDongsheng Yang  * If `key_tmp` contains valid cached data, this function copies the relevant
4811d57628fSDongsheng Yang  * portion to the request's bio. Otherwise, it sends a backing request to
4821d57628fSDongsheng Yang  * fetch the required data range.
4831d57628fSDongsheng Yang  */
4841d57628fSDongsheng Yang static int read_overlap_contained(struct pcache_cache_key *key, struct pcache_cache_key *key_tmp,
4851d57628fSDongsheng Yang 		struct pcache_cache_subtree_walk_ctx *ctx)
4861d57628fSDongsheng Yang {
4871d57628fSDongsheng Yang 	struct pcache_cache *cache = ctx->cache_tree->cache;
4881d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req;
4891d57628fSDongsheng Yang 	struct pcache_cache_pos pos;
4901d57628fSDongsheng Yang 	int ret;
4911d57628fSDongsheng Yang 
4921d57628fSDongsheng Yang 	/*
4931d57628fSDongsheng Yang 	 * Check if `key_tmp` is empty, indicating a miss. If so, initiate
4941d57628fSDongsheng Yang 	 * a backing request to fetch the required data for `key`.
4951d57628fSDongsheng Yang 	 */
4961d57628fSDongsheng Yang 	if (cache_key_empty(key_tmp)) {
4971d57628fSDongsheng Yang 		backing_req = get_pre_alloc_req(ctx);
4981d57628fSDongsheng Yang 		if (!backing_req)
4991d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_NEED_REQ;
5001d57628fSDongsheng Yang 
5011d57628fSDongsheng Yang 		cache_miss_req_init(cache, backing_req, ctx->pcache_req, ctx->req_done, key->len, false);
5021d57628fSDongsheng Yang 		submit_cache_miss_req(cache, backing_req);
5031d57628fSDongsheng Yang 	} else {
5041d57628fSDongsheng Yang 		cache_pos_copy(&pos, &key_tmp->cache_pos);
5051d57628fSDongsheng Yang 		cache_pos_advance(&pos, cache_key_lstart(key) - cache_key_lstart(key_tmp));
5061d57628fSDongsheng Yang 
5071d57628fSDongsheng Yang 		ret = cache_copy_to_req_bio(ctx->cache_tree->cache, ctx->pcache_req, ctx->req_done,
5081d57628fSDongsheng Yang 					key->len, &pos, key_tmp->seg_gen);
5091d57628fSDongsheng Yang 		if (ret) {
5101d57628fSDongsheng Yang 			if (ret == -EINVAL) {
5111d57628fSDongsheng Yang 				cache_key_delete(key_tmp);
5121d57628fSDongsheng Yang 				return SUBTREE_WALK_RET_RESEARCH;
5131d57628fSDongsheng Yang 			}
5141d57628fSDongsheng Yang 
5151d57628fSDongsheng Yang 			ctx->ret = ret;
5161d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_ERR;
5171d57628fSDongsheng Yang 		}
5181d57628fSDongsheng Yang 	}
5191d57628fSDongsheng Yang 
5201d57628fSDongsheng Yang 	ctx->req_done += key->len;
5211d57628fSDongsheng Yang 	cache_key_cutfront(key, key->len);
5221d57628fSDongsheng Yang 
5231d57628fSDongsheng Yang 	return SUBTREE_WALK_RET_OK;
5241d57628fSDongsheng Yang }
5251d57628fSDongsheng Yang 
5261d57628fSDongsheng Yang /*
5271d57628fSDongsheng Yang  *	 |--------|		  key_tmp (existing cached range)
5281d57628fSDongsheng Yang  *	   |==========|	  key (requested range, overlapping the head of key_tmp)
5291d57628fSDongsheng Yang  */
5301d57628fSDongsheng Yang static int read_overlap_head(struct pcache_cache_key *key, struct pcache_cache_key *key_tmp,
5311d57628fSDongsheng Yang 		struct pcache_cache_subtree_walk_ctx *ctx)
5321d57628fSDongsheng Yang {
5331d57628fSDongsheng Yang 	struct pcache_cache *cache = ctx->cache_tree->cache;
5341d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req;
5351d57628fSDongsheng Yang 	struct pcache_cache_pos pos;
5361d57628fSDongsheng Yang 	u32 io_len;
5371d57628fSDongsheng Yang 	int ret;
5381d57628fSDongsheng Yang 
5391d57628fSDongsheng Yang 	io_len = cache_key_lend(key_tmp) - cache_key_lstart(key);
5401d57628fSDongsheng Yang 
5411d57628fSDongsheng Yang 	if (cache_key_empty(key_tmp)) {
5421d57628fSDongsheng Yang 		backing_req = get_pre_alloc_req(ctx);
5431d57628fSDongsheng Yang 		if (!backing_req)
5441d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_NEED_REQ;
5451d57628fSDongsheng Yang 
5461d57628fSDongsheng Yang 		cache_miss_req_init(cache, backing_req, ctx->pcache_req, ctx->req_done, io_len, false);
5471d57628fSDongsheng Yang 		submit_cache_miss_req(cache, backing_req);
5481d57628fSDongsheng Yang 	} else {
5491d57628fSDongsheng Yang 		cache_pos_copy(&pos, &key_tmp->cache_pos);
5501d57628fSDongsheng Yang 		cache_pos_advance(&pos, cache_key_lstart(key) - cache_key_lstart(key_tmp));
5511d57628fSDongsheng Yang 
5521d57628fSDongsheng Yang 		ret = cache_copy_to_req_bio(ctx->cache_tree->cache, ctx->pcache_req, ctx->req_done,
5531d57628fSDongsheng Yang 					io_len, &pos, key_tmp->seg_gen);
5541d57628fSDongsheng Yang 		if (ret) {
5551d57628fSDongsheng Yang 			if (ret == -EINVAL) {
5561d57628fSDongsheng Yang 				cache_key_delete(key_tmp);
5571d57628fSDongsheng Yang 				return SUBTREE_WALK_RET_RESEARCH;
5581d57628fSDongsheng Yang 			}
5591d57628fSDongsheng Yang 
5601d57628fSDongsheng Yang 			ctx->ret = ret;
5611d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_ERR;
5621d57628fSDongsheng Yang 		}
5631d57628fSDongsheng Yang 	}
5641d57628fSDongsheng Yang 
5651d57628fSDongsheng Yang 	ctx->req_done += io_len;
5661d57628fSDongsheng Yang 	cache_key_cutfront(key, io_len);
5671d57628fSDongsheng Yang 
5681d57628fSDongsheng Yang 	return SUBTREE_WALK_RET_OK;
5691d57628fSDongsheng Yang }
5701d57628fSDongsheng Yang 
5711d57628fSDongsheng Yang /**
5721d57628fSDongsheng Yang  * read_walk_finally - Finalizes the cache read tree walk by submitting any
5731d57628fSDongsheng Yang  *					 remaining backing requests
5741d57628fSDongsheng Yang  * @ctx:	Context structure holding information about the cache,
5751d57628fSDongsheng Yang  *		read request, and submission list
5761d57628fSDongsheng Yang  * @ret:	the return value after this walk.
5771d57628fSDongsheng Yang  *
5781d57628fSDongsheng Yang  * This function is called at the end of the `cache_subtree_walk` during a
5791d57628fSDongsheng Yang  * cache read operation. It completes the walk by checking if any data
5801d57628fSDongsheng Yang  * requested by `key` was not found in the cache tree, and if so, it sends
5811d57628fSDongsheng Yang  * a backing request to retrieve that data. Then, it iterates through the
5821d57628fSDongsheng Yang  * submission list of backing requests created during the walk, removing
5831d57628fSDongsheng Yang  * each request from the list and submitting it.
5841d57628fSDongsheng Yang  *
5851d57628fSDongsheng Yang  * The scenario managed here includes:
5861d57628fSDongsheng Yang  * - Sending a backing request for the remaining length of `key` if it was
5871d57628fSDongsheng Yang  *   not fulfilled by existing cache entries.
5881d57628fSDongsheng Yang  * - Iterating through `ctx->submit_req_list` to submit each backing request
5891d57628fSDongsheng Yang  *   enqueued during the walk.
5901d57628fSDongsheng Yang  *
5911d57628fSDongsheng Yang  * This ensures all necessary backing requests for cache misses are submitted
5921d57628fSDongsheng Yang  * to the backing storage to retrieve any data that could not be found in
5931d57628fSDongsheng Yang  * the cache.
5941d57628fSDongsheng Yang  */
5951d57628fSDongsheng Yang static int read_walk_finally(struct pcache_cache_subtree_walk_ctx *ctx, int ret)
5961d57628fSDongsheng Yang {
5971d57628fSDongsheng Yang 	struct pcache_cache *cache = ctx->cache_tree->cache;
5981d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req, *next_req;
5991d57628fSDongsheng Yang 	struct pcache_cache_key *key = ctx->key;
6001d57628fSDongsheng Yang 
6011d57628fSDongsheng Yang 	list_for_each_entry_safe(backing_req, next_req, ctx->submit_req_list, node) {
6021d57628fSDongsheng Yang 		list_del_init(&backing_req->node);
6031d57628fSDongsheng Yang 		submit_cache_miss_req(ctx->cache_tree->cache, backing_req);
6041d57628fSDongsheng Yang 	}
6051d57628fSDongsheng Yang 
6061d57628fSDongsheng Yang 	if (ret != SUBTREE_WALK_RET_OK)
6071d57628fSDongsheng Yang 		return ret;
6081d57628fSDongsheng Yang 
6091d57628fSDongsheng Yang 	if (key->len) {
6101d57628fSDongsheng Yang 		backing_req = get_pre_alloc_req(ctx);
6111d57628fSDongsheng Yang 		if (!backing_req)
6121d57628fSDongsheng Yang 			return SUBTREE_WALK_RET_NEED_REQ;
6131d57628fSDongsheng Yang 
6141d57628fSDongsheng Yang 		cache_miss_req_init(cache, backing_req, ctx->pcache_req, ctx->req_done, key->len, true);
6151d57628fSDongsheng Yang 		submit_cache_miss_req(cache, backing_req);
6161d57628fSDongsheng Yang 		ctx->req_done += key->len;
6171d57628fSDongsheng Yang 	}
6181d57628fSDongsheng Yang 
6191d57628fSDongsheng Yang 	return SUBTREE_WALK_RET_OK;
6201d57628fSDongsheng Yang }
6211d57628fSDongsheng Yang 
6221d57628fSDongsheng Yang /*
6231d57628fSDongsheng Yang  * This function is used within `cache_subtree_walk` to determine whether the
6241d57628fSDongsheng Yang  * read operation has covered the requested data length. It compares the
6251d57628fSDongsheng Yang  * amount of data processed (`ctx->req_done`) with the total data length
6261d57628fSDongsheng Yang  * specified in the original request (`ctx->pcache_req->data_len`).
6271d57628fSDongsheng Yang  *
6281d57628fSDongsheng Yang  * If `req_done` meets or exceeds the required data length, the function
6291d57628fSDongsheng Yang  * returns `true`, indicating the walk is complete. Otherwise, it returns `false`,
6301d57628fSDongsheng Yang  * signaling that additional data processing is needed to fulfill the request.
6311d57628fSDongsheng Yang  */
6321d57628fSDongsheng Yang static bool read_walk_done(struct pcache_cache_subtree_walk_ctx *ctx)
6331d57628fSDongsheng Yang {
6341d57628fSDongsheng Yang 	return (ctx->req_done >= ctx->pcache_req->data_len);
6351d57628fSDongsheng Yang }
6361d57628fSDongsheng Yang 
6371d57628fSDongsheng Yang /**
6381d57628fSDongsheng Yang  * cache_read - Process a read request by traversing the cache tree
6391d57628fSDongsheng Yang  * @cache:	 Cache structure holding cache trees and related configurations
6401d57628fSDongsheng Yang  * @pcache_req:   Request structure with information about the data to read
6411d57628fSDongsheng Yang  *
6421d57628fSDongsheng Yang  * This function attempts to fulfill a read request by traversing the cache tree(s)
6431d57628fSDongsheng Yang  * to locate cached data for the requested range. If parts of the data are missing
6441d57628fSDongsheng Yang  * in the cache, backing requests are generated to retrieve the required segments.
6451d57628fSDongsheng Yang  *
6461d57628fSDongsheng Yang  * The function operates by initializing a key for the requested data range and
6471d57628fSDongsheng Yang  * preparing a context (`walk_ctx`) to manage the cache tree traversal. The context
6481d57628fSDongsheng Yang  * includes pointers to functions (e.g., `read_before`, `read_overlap_tail`) that handle
6491d57628fSDongsheng Yang  * specific conditions encountered during the traversal. The `walk_finally` and `walk_done`
6501d57628fSDongsheng Yang  * functions manage the end stages of the traversal, while the `delete_key_list` and
6511d57628fSDongsheng Yang  * `submit_req_list` lists track any keys to be deleted or requests to be submitted.
6521d57628fSDongsheng Yang  *
6531d57628fSDongsheng Yang  * The function first calculates the requested range and checks if it fits within the
6541d57628fSDongsheng Yang  * current cache tree (based on the tree's size limits). It then locks the cache tree
6551d57628fSDongsheng Yang  * and performs a search to locate any matching keys. If there are outdated keys,
6561d57628fSDongsheng Yang  * these are deleted, and the search is restarted to ensure accurate data retrieval.
6571d57628fSDongsheng Yang  *
6581d57628fSDongsheng Yang  * If the requested range spans multiple cache trees, the function moves on to the
6591d57628fSDongsheng Yang  * next tree once the current range has been processed. This continues until the
6601d57628fSDongsheng Yang  * entire requested data length has been handled.
6611d57628fSDongsheng Yang  */
6621d57628fSDongsheng Yang static int cache_read(struct pcache_cache *cache, struct pcache_request *pcache_req)
6631d57628fSDongsheng Yang {
6641d57628fSDongsheng Yang 	struct pcache_cache_key key_data = { .off = pcache_req->off, .len = pcache_req->data_len };
6651d57628fSDongsheng Yang 	struct pcache_cache_subtree *cache_subtree;
6661d57628fSDongsheng Yang 	struct pcache_cache_key *key_tmp = NULL, *key_next;
6671d57628fSDongsheng Yang 	struct rb_node *prev_node = NULL;
6681d57628fSDongsheng Yang 	struct pcache_cache_key *key = &key_data;
6691d57628fSDongsheng Yang 	struct pcache_cache_subtree_walk_ctx walk_ctx = { 0 };
6701d57628fSDongsheng Yang 	struct pcache_backing_dev_req *backing_req, *next_req;
6711d57628fSDongsheng Yang 	LIST_HEAD(delete_key_list);
6721d57628fSDongsheng Yang 	LIST_HEAD(submit_req_list);
6731d57628fSDongsheng Yang 	int ret;
6741d57628fSDongsheng Yang 
6751d57628fSDongsheng Yang 	walk_ctx.cache_tree = &cache->req_key_tree;
6761d57628fSDongsheng Yang 	walk_ctx.req_done = 0;
6771d57628fSDongsheng Yang 	walk_ctx.pcache_req = pcache_req;
6781d57628fSDongsheng Yang 	walk_ctx.before = read_before;
6791d57628fSDongsheng Yang 	walk_ctx.overlap_tail = read_overlap_tail;
6801d57628fSDongsheng Yang 	walk_ctx.overlap_head = read_overlap_head;
6811d57628fSDongsheng Yang 	walk_ctx.overlap_contain = read_overlap_contain;
6821d57628fSDongsheng Yang 	walk_ctx.overlap_contained = read_overlap_contained;
6831d57628fSDongsheng Yang 	walk_ctx.walk_finally = read_walk_finally;
6841d57628fSDongsheng Yang 	walk_ctx.walk_done = read_walk_done;
6851d57628fSDongsheng Yang 	walk_ctx.delete_key_list = &delete_key_list;
6861d57628fSDongsheng Yang 	walk_ctx.submit_req_list = &submit_req_list;
6871d57628fSDongsheng Yang 
6881d57628fSDongsheng Yang next:
6891d57628fSDongsheng Yang 	key->off = pcache_req->off + walk_ctx.req_done;
6901d57628fSDongsheng Yang 	key->len = pcache_req->data_len - walk_ctx.req_done;
6911d57628fSDongsheng Yang 	if (key->len > PCACHE_CACHE_SUBTREE_SIZE - (key->off & PCACHE_CACHE_SUBTREE_SIZE_MASK))
6921d57628fSDongsheng Yang 		key->len = PCACHE_CACHE_SUBTREE_SIZE - (key->off & PCACHE_CACHE_SUBTREE_SIZE_MASK);
6931d57628fSDongsheng Yang 
6941d57628fSDongsheng Yang 	cache_subtree = get_subtree(&cache->req_key_tree, key->off);
6951d57628fSDongsheng Yang 	spin_lock(&cache_subtree->tree_lock);
6961d57628fSDongsheng Yang search:
6971d57628fSDongsheng Yang 	prev_node = cache_subtree_search(cache_subtree, key, NULL, NULL, &delete_key_list);
6981d57628fSDongsheng Yang 	if (!list_empty(&delete_key_list)) {
6991d57628fSDongsheng Yang 		list_for_each_entry_safe(key_tmp, key_next, &delete_key_list, list_node) {
7001d57628fSDongsheng Yang 			list_del_init(&key_tmp->list_node);
7011d57628fSDongsheng Yang 			cache_key_delete(key_tmp);
7021d57628fSDongsheng Yang 		}
7031d57628fSDongsheng Yang 		goto search;
7041d57628fSDongsheng Yang 	}
7051d57628fSDongsheng Yang 
7061d57628fSDongsheng Yang 	walk_ctx.start_node = prev_node;
7071d57628fSDongsheng Yang 	walk_ctx.key = key;
7081d57628fSDongsheng Yang 
7091d57628fSDongsheng Yang 	ret = cache_subtree_walk(&walk_ctx);
7101d57628fSDongsheng Yang 	if (ret == SUBTREE_WALK_RET_RESEARCH)
7111d57628fSDongsheng Yang 		goto search;
7121d57628fSDongsheng Yang 	spin_unlock(&cache_subtree->tree_lock);
7131d57628fSDongsheng Yang 
7141d57628fSDongsheng Yang 	if (ret == SUBTREE_WALK_RET_ERR) {
7151d57628fSDongsheng Yang 		ret = walk_ctx.ret;
7161d57628fSDongsheng Yang 		goto out;
7171d57628fSDongsheng Yang 	}
7181d57628fSDongsheng Yang 
7191d57628fSDongsheng Yang 	if (ret == SUBTREE_WALK_RET_NEED_REQ) {
7201d57628fSDongsheng Yang 		walk_ctx.pre_alloc_req = cache_miss_req_alloc(cache, pcache_req, GFP_NOIO);
7211d57628fSDongsheng Yang 		pcache_dev_debug(CACHE_TO_PCACHE(cache), "allocate pre_alloc_req with GFP_NOIO");
7221d57628fSDongsheng Yang 	}
7231d57628fSDongsheng Yang 
7241d57628fSDongsheng Yang 	if (walk_ctx.req_done < pcache_req->data_len)
7251d57628fSDongsheng Yang 		goto next;
7261d57628fSDongsheng Yang 	ret = 0;
7271d57628fSDongsheng Yang out:
7281d57628fSDongsheng Yang 	if (walk_ctx.pre_alloc_req)
7291d57628fSDongsheng Yang 		cache_miss_req_free(walk_ctx.pre_alloc_req);
7301d57628fSDongsheng Yang 
7311d57628fSDongsheng Yang 	list_for_each_entry_safe(backing_req, next_req, &submit_req_list, node) {
7321d57628fSDongsheng Yang 		list_del_init(&backing_req->node);
7331d57628fSDongsheng Yang 		backing_dev_req_end(backing_req);
7341d57628fSDongsheng Yang 	}
7351d57628fSDongsheng Yang 
7361d57628fSDongsheng Yang 	return ret;
7371d57628fSDongsheng Yang }
7381d57628fSDongsheng Yang 
7391d57628fSDongsheng Yang static int cache_write(struct pcache_cache *cache, struct pcache_request *pcache_req)
7401d57628fSDongsheng Yang {
7411d57628fSDongsheng Yang 	struct pcache_cache_subtree *cache_subtree;
7421d57628fSDongsheng Yang 	struct pcache_cache_key *key;
7431d57628fSDongsheng Yang 	u64 offset = pcache_req->off;
7441d57628fSDongsheng Yang 	u32 length = pcache_req->data_len;
7451d57628fSDongsheng Yang 	u32 io_done = 0;
7461d57628fSDongsheng Yang 	int ret;
7471d57628fSDongsheng Yang 
7481d57628fSDongsheng Yang 	while (true) {
7491d57628fSDongsheng Yang 		if (io_done >= length)
7501d57628fSDongsheng Yang 			break;
7511d57628fSDongsheng Yang 
7521d57628fSDongsheng Yang 		key = cache_key_alloc(&cache->req_key_tree, GFP_NOIO);
7531d57628fSDongsheng Yang 		key->off = offset + io_done;
7541d57628fSDongsheng Yang 		key->len = length - io_done;
7551d57628fSDongsheng Yang 		if (key->len > PCACHE_CACHE_SUBTREE_SIZE - (key->off & PCACHE_CACHE_SUBTREE_SIZE_MASK))
7561d57628fSDongsheng Yang 			key->len = PCACHE_CACHE_SUBTREE_SIZE - (key->off & PCACHE_CACHE_SUBTREE_SIZE_MASK);
7571d57628fSDongsheng Yang 
7581d57628fSDongsheng Yang 		ret = cache_data_alloc(cache, key);
7591d57628fSDongsheng Yang 		if (ret) {
7601d57628fSDongsheng Yang 			cache_key_put(key);
7611d57628fSDongsheng Yang 			goto err;
7621d57628fSDongsheng Yang 		}
7631d57628fSDongsheng Yang 
7641d57628fSDongsheng Yang 		ret = cache_copy_from_req_bio(cache, key, pcache_req, io_done);
7651d57628fSDongsheng Yang 		if (ret) {
7661d57628fSDongsheng Yang 			cache_seg_put(key->cache_pos.cache_seg);
7671d57628fSDongsheng Yang 			cache_key_put(key);
7681d57628fSDongsheng Yang 			goto err;
7691d57628fSDongsheng Yang 		}
7701d57628fSDongsheng Yang 
7711d57628fSDongsheng Yang 		cache_subtree = get_subtree(&cache->req_key_tree, key->off);
7721d57628fSDongsheng Yang 		spin_lock(&cache_subtree->tree_lock);
7731d57628fSDongsheng Yang 		cache_key_insert(&cache->req_key_tree, key, true);
7741d57628fSDongsheng Yang 		ret = cache_key_append(cache, key, pcache_req->bio->bi_opf & REQ_FUA);
7751d57628fSDongsheng Yang 		if (ret) {
7761d57628fSDongsheng Yang 			cache_seg_put(key->cache_pos.cache_seg);
7771d57628fSDongsheng Yang 			cache_key_delete(key);
7781d57628fSDongsheng Yang 			goto unlock;
7791d57628fSDongsheng Yang 		}
7801d57628fSDongsheng Yang 
7811d57628fSDongsheng Yang 		io_done += key->len;
7821d57628fSDongsheng Yang 		spin_unlock(&cache_subtree->tree_lock);
7831d57628fSDongsheng Yang 	}
7841d57628fSDongsheng Yang 
7851d57628fSDongsheng Yang 	return 0;
7861d57628fSDongsheng Yang unlock:
7871d57628fSDongsheng Yang 	spin_unlock(&cache_subtree->tree_lock);
7881d57628fSDongsheng Yang err:
7891d57628fSDongsheng Yang 	return ret;
7901d57628fSDongsheng Yang }
7911d57628fSDongsheng Yang 
7921d57628fSDongsheng Yang /**
7931d57628fSDongsheng Yang  * cache_flush - Flush all ksets to persist any pending cache data
7941d57628fSDongsheng Yang  * @cache: Pointer to the cache structure
7951d57628fSDongsheng Yang  *
7961d57628fSDongsheng Yang  * This function iterates through all ksets associated with the provided `cache`
7971d57628fSDongsheng Yang  * and ensures that any data marked for persistence is written to media. For each
7981d57628fSDongsheng Yang  * kset, it acquires the kset lock, then invokes `cache_kset_close`, which handles
7991d57628fSDongsheng Yang  * the persistence logic for that kset.
8001d57628fSDongsheng Yang  *
8011d57628fSDongsheng Yang  * If `cache_kset_close` encounters an error, the function exits immediately with
8021d57628fSDongsheng Yang  * the respective error code, preventing the flush operation from proceeding to
8031d57628fSDongsheng Yang  * subsequent ksets.
8041d57628fSDongsheng Yang  */
8051d57628fSDongsheng Yang int cache_flush(struct pcache_cache *cache)
8061d57628fSDongsheng Yang {
8071d57628fSDongsheng Yang 	struct pcache_cache_kset *kset;
808*4466dd3dSQianfeng Rong 	int ret;
809*4466dd3dSQianfeng Rong 	u32 i;
8101d57628fSDongsheng Yang 
8111d57628fSDongsheng Yang 	for (i = 0; i < cache->n_ksets; i++) {
8121d57628fSDongsheng Yang 		kset = get_kset(cache, i);
8131d57628fSDongsheng Yang 
8141d57628fSDongsheng Yang 		spin_lock(&kset->kset_lock);
8151d57628fSDongsheng Yang 		ret = cache_kset_close(cache, kset);
8161d57628fSDongsheng Yang 		spin_unlock(&kset->kset_lock);
8171d57628fSDongsheng Yang 
8181d57628fSDongsheng Yang 		if (ret)
8191d57628fSDongsheng Yang 			return ret;
8201d57628fSDongsheng Yang 	}
8211d57628fSDongsheng Yang 
8221d57628fSDongsheng Yang 	return 0;
8231d57628fSDongsheng Yang }
8241d57628fSDongsheng Yang 
8251d57628fSDongsheng Yang int pcache_cache_handle_req(struct pcache_cache *cache, struct pcache_request *pcache_req)
8261d57628fSDongsheng Yang {
8271d57628fSDongsheng Yang 	struct bio *bio = pcache_req->bio;
8281d57628fSDongsheng Yang 
8291d57628fSDongsheng Yang 	if (unlikely(bio->bi_opf & REQ_PREFLUSH))
8301d57628fSDongsheng Yang 		return cache_flush(cache);
8311d57628fSDongsheng Yang 
8321d57628fSDongsheng Yang 	if (bio_data_dir(bio) == READ)
8331d57628fSDongsheng Yang 		return cache_read(cache, pcache_req);
8341d57628fSDongsheng Yang 
8351d57628fSDongsheng Yang 	return cache_write(cache, pcache_req);
8361d57628fSDongsheng Yang }
837