xref: /aosp_15_r20/external/ublksrv/qcow2/qcow2_common.h (revision 94c4a1e103eb1715230460aab379dff275992c20)
1 // SPDX-License-Identifier: GPL-2.0
2 #ifndef UBLK_QCOW2_COMMON_H_
3 #define UBLK_QCOW2_COMMON_H_
4 
5 #include "ublksrv_tgt.h"
6 
7 #define qcow2_assert(x)  ublk_assert(x)
8 
9 #ifdef DEBUG
10 #define QCOW2_DEBUG  DEBUG
11 #else
12 #undef QCOW2_DEBUG
13 #endif
14 
15 #define UBLK_DBG_QCOW2_FLUSH   (1U << 16)
16 #define UBLK_DBG_QCOW2_META_L2  (1U << 17)
17 #define UBLK_DBG_QCOW2_META_L1  (1U << 18)
18 #define UBLK_DBG_QCOW2_META_RB  (1U << 19)
19 #define UBLK_DBG_QCOW2_IO_WAITER  (1U << 20)
20 #define UBLK_DBG_QCOW2_ALLOCATOR  (1U << 21)
21 
22 #define UBLK_DBG_QCOW2_META (UBLK_DBG_QCOW2_META_L2 | UBLK_DBG_QCOW2_META_RB)
23 
24 enum QCOW2_PARA {
25 #ifdef DEBUG_QCOW2_META_STRESS
26 	REFCOUNT_BLK_MAX_CACHE_BYTES = 8U << 10,
27 #else
28 	REFCOUNT_BLK_MAX_CACHE_BYTES = 256U << 10,
29 #endif
30 	REFCOUNT_BLK_SLICE_BITS = 12,
31 	REFCOUNT_BLK_SLICE_BYTES = 1U << REFCOUNT_BLK_SLICE_BITS,
32 
33 #ifdef DEBUG_QCOW2_META_STRESS
34 	L2_TABLE_MAX_CACHE_BYTES = 1U << 13,
35 #else
36 	L2_TABLE_MAX_CACHE_BYTES = 1U << 20,
37 #endif
38 	L2_TABLE_SLICE_BITS = 12,
39 	L2_TABLE_SLICE_BYTES = 1U << L2_TABLE_SLICE_BITS,
40 
41 #ifdef DEBUG_QCOW2_META_STRESS
42 	META_MAX_TAGS = 1,
43 #else
44 	META_MAX_TAGS = 16,
45 #endif
46 	//at most 500ms delay if not any slice is running of
47 	//lru cache, otherwise the flush is started immediately
48 	MAX_META_FLUSH_DELAY_MS = 500,
49 };
50 
51 #define qcow2_log ublk_log
52 
53 //be careful
54 //#DEBUG_QCOW2_META_OBJ, still required for some meta debug
55 
56 #ifdef QCOW2_DEBUG
alloc_log(const char * fmt,...)57 static inline void alloc_log(const char *fmt, ...)
58 {
59     va_list ap;
60 
61     va_start(ap, fmt);
62     ublk_dbg(UBLK_DBG_QCOW2_ALLOCATOR, fmt, ap);
63 }
64 
flush_log(const char * fmt,...)65 static inline void flush_log(const char *fmt, ...)
66 {
67     va_list ap;
68 
69     va_start(ap, fmt);
70     ublk_dbg(UBLK_DBG_QCOW2_FLUSH, fmt, ap);
71 }
72 
qcow2_io_log(const char * fmt,...)73 static inline void qcow2_io_log(const char *fmt, ...)
74 {
75     va_list ap;
76 
77     va_start(ap, fmt);
78     ublk_dbg(UBLK_DBG_IO, fmt, ap);
79 }
80 
81 #else
82 #define alloc_log(...)  do {}while(0)
83 #define flush_log(...)  do {}while(0)
84 #define qcow2_io_log(...)  do {}while(0)
85 #endif
86 
87 /*
88  * 00 ~ 11: tag
89  * 12 ~ 23: qid
90  * 24 ~ 31: type_id, 0 ~ 254: meta, 255: data,
91  * 	so which meta data can be looked up via this type_id in each io
92  */
93 class qcow2_io_ctx_t {
94 public:
95 	u32 data;
96 
get_tag()97 	u32 get_tag() const {
98 		return data & 0xfff;
99 	}
100 
get_qid()101 	u32 get_qid() const {
102 		return (data >> 12) & 0xfff;
103 	}
104 
get_type()105 	u32 get_type() const {
106 		return (data >> 24) & 0xff;
107 	}
108 
set_type(u8 type)109 	void set_type(u8 type) {
110 		data &= 0x00ffffff;
111 		data |= type << 24;
112 	}
113 
qcow2_io_ctx_t()114 	qcow2_io_ctx_t() {
115 		data = 255U << 24;
116 	}
qcow2_io_ctx_t(u32 val)117 	qcow2_io_ctx_t(u32 val) {
118 		data = val;
119 	}
qcow2_io_ctx_t(u32 tag,u32 qid)120 	qcow2_io_ctx_t(u32 tag, u32 qid) {
121 		data = (qid << 12) | tag;
122 	}
qcow2_io_ctx_t(u32 tag,u32 qid,u8 type)123 	qcow2_io_ctx_t(u32 tag, u32 qid, u8 type) {
124 		data = (type << 24) | (qid << 12) | tag;
125 	}
126 	qcow2_io_ctx_t operator=(const u32 val) {
127 		return qcow2_io_ctx_t(val);
128 	}
129 };
130 
131 
132 //L1 max size is 32MB which can have 4M entries, so at most 22 bits
133 //needed, so define QCOW2_TAG_BITS as 10, so the upper 22 bits can
134 //hold entry index.
135 #define	QCOW2_TAG_BITS	10
136 #define	QCOW2_MAX_QUEUE_DEPTH	(1U<<10)
137 
138 class IOWaiters {
139 private:
140 	//io waiters for this meta data, once this meta is updated,
141 	//call resume() on each io in io_waiters, so before io ctx
142 	//is waiting, it has to be added to io_waiters.
143 	//
144 	//Support to wait on single entry update, and the entry index
145 	//is stored in bit 31~12, tag is stored in bit 11~0. All one
146 	//entry index means that waitting on whole meta data.
147 	//
148 	std::unordered_set<unsigned int> io_waiters;
149 
__mapping_meta_add_waiter(unsigned tag,unsigned entry_idx)150 	void __mapping_meta_add_waiter(unsigned tag, unsigned entry_idx) {
151 		unsigned val;
152 
153 		qcow2_assert(!(tag & ~(QCOW2_MAX_QUEUE_DEPTH - 1)));
154 		qcow2_assert(!(entry_idx & ~((1U << (32 - QCOW2_TAG_BITS)) - 1)));
155 
156 		val = tag | (entry_idx << QCOW2_TAG_BITS);
157 		io_waiters.insert(val);
158 	}
159 	void __mapping_meta_wakeup_all(const struct ublksrv_queue *q,
160 			unsigned my_tag, unsigned entry_idx, bool all);
161 public:
162 	IOWaiters();
163 	void add_waiter(unsigned tag);
164 	void add_waiter_idx(unsigned tag, unsigned entry_idx);
165 	void wakeup_all(const struct ublksrv_queue *q, unsigned my_tag);
166 	void wakeup_all_idx(const struct ublksrv_queue *q,
167 			unsigned my_tag, unsigned entry_idx);
168 };
169 
170 #endif
171