| /* 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 */ |