Contributors: 1
Author Tokens Token Proportion Commits Commit Proportion
Unknown 455 100.00% 1 100.00%
Total 455 1


/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _BACKING_DEV_H
#define _BACKING_DEV_H

#include <linux/device-mapper.h>

#include "pcache_internal.h"

struct pcache_backing_dev_req;
typedef void (*backing_req_end_fn_t)(struct pcache_backing_dev_req *backing_req, int ret);

#define BACKING_DEV_REQ_TYPE_REQ		1
#define BACKING_DEV_REQ_TYPE_KMEM		2

#define BACKING_DEV_REQ_INLINE_BVECS		4

struct pcache_request;
struct pcache_backing_dev_req {
	u8				type;
	struct bio			bio;
	struct pcache_backing_dev	*backing_dev;

	void				*priv_data;
	backing_req_end_fn_t		end_req;

	struct list_head		node;
	int				ret;

	union {
		struct {
			struct pcache_request		*upper_req;
			u32				bio_off;
		} req;
		struct {
			struct bio_vec	inline_bvecs[BACKING_DEV_REQ_INLINE_BVECS];
			struct bio_vec	*bvecs;
			u32		n_vecs;
		} kmem;
	};
};

struct pcache_backing_dev {
	struct pcache_cache		*cache;

	struct dm_dev			*dm_dev;
	mempool_t			req_pool;
	mempool_t			bvec_pool;

	struct list_head		submit_list;
	spinlock_t			submit_lock;
	struct work_struct		req_submit_work;

	struct list_head		complete_list;
	spinlock_t			complete_lock;
	struct work_struct		req_complete_work;

	atomic_t			inflight_reqs;
	wait_queue_head_t		inflight_wq;

	u64				dev_size;
};

struct dm_pcache;
int backing_dev_start(struct dm_pcache *pcache);
void backing_dev_stop(struct dm_pcache *pcache);

struct pcache_backing_dev_req_opts {
	u32 type;
	union {
		struct {
			struct pcache_request *upper_req;
			u32 req_off;
			u32 len;
		} req;
		struct {
			void *data;
			blk_opf_t opf;
			u32 len;
			u64 backing_off;
		} kmem;
	};

	gfp_t gfp_mask;
	backing_req_end_fn_t	end_fn;
	void			*priv_data;
};

static inline u32 backing_dev_req_coalesced_max_len(const void *data, u32 len)
{
	const void *p = data;
	u32 done = 0, in_page, to_advance;
	struct page *first_page, *next_page;

	if (!is_vmalloc_addr(data))
		return len;

	first_page = vmalloc_to_page(p);
advance:
	in_page = PAGE_SIZE - offset_in_page(p);
	to_advance = min_t(u32, in_page, len - done);

	done += to_advance;
	p += to_advance;

	if (done == len)
		return done;

	next_page = vmalloc_to_page(p);
	if (zone_device_pages_have_same_pgmap(first_page, next_page))
		goto advance;

	return done;
}

void backing_dev_req_submit(struct pcache_backing_dev_req *backing_req, bool direct);
void backing_dev_req_end(struct pcache_backing_dev_req *backing_req);
struct pcache_backing_dev_req *backing_dev_req_create(struct pcache_backing_dev *backing_dev,
						struct pcache_backing_dev_req_opts *opts);
struct pcache_backing_dev_req *backing_dev_req_alloc(struct pcache_backing_dev *backing_dev,
						struct pcache_backing_dev_req_opts *opts);
void backing_dev_req_init(struct pcache_backing_dev_req *backing_req,
			struct pcache_backing_dev_req_opts *opts);
void backing_dev_flush(struct pcache_backing_dev *backing_dev);

int pcache_backing_init(void);
void pcache_backing_exit(void);
#endif /* _BACKING_DEV_H */