xref: /aosp_15_r20/external/ublksrv/qcow2/qcow2_meta.h (revision 94c4a1e103eb1715230460aab379dff275992c20)
1*94c4a1e1SFrank Piva // SPDX-License-Identifier: GPL-2.0
2*94c4a1e1SFrank Piva #ifndef UBLK_QCOW2_META_H_
3*94c4a1e1SFrank Piva #define UBLK_QCOW2_META_H_
4*94c4a1e1SFrank Piva 
5*94c4a1e1SFrank Piva #include "qcow2_common.h"
6*94c4a1e1SFrank Piva 
7*94c4a1e1SFrank Piva class Qcow2State;
8*94c4a1e1SFrank Piva class Qcow2Header;
9*94c4a1e1SFrank Piva 
10*94c4a1e1SFrank Piva /*
11*94c4a1e1SFrank Piva  * Class design:
12*94c4a1e1SFrank Piva  * 1) copy constructor / operator assign overloading /
13*94c4a1e1SFrank Piva  *
14*94c4a1e1SFrank Piva  * 2) one friend function for dumping object
15*94c4a1e1SFrank Piva  *
16*94c4a1e1SFrank Piva  *
17*94c4a1e1SFrank Piva  * Loading meta:
18*94c4a1e1SFrank Piva  *
19*94c4a1e1SFrank Piva  *
20*94c4a1e1SFrank Piva  * Flushing meta:
21*94c4a1e1SFrank Piva  */
22*94c4a1e1SFrank Piva class Qcow2Meta {
23*94c4a1e1SFrank Piva protected:
24*94c4a1e1SFrank Piva #ifdef DEBUG_QCOW2_META_OBJ
25*94c4a1e1SFrank Piva 	const char *id;
26*94c4a1e1SFrank Piva #endif
27*94c4a1e1SFrank Piva 	Qcow2Header	&header;
28*94c4a1e1SFrank Piva 	void *addr;	//buffer address
29*94c4a1e1SFrank Piva 	u64   offset;	//offset in host image
30*94c4a1e1SFrank Piva 	u32   buf_sz;	//buffer size
31*94c4a1e1SFrank Piva 	u32   data_len; //current data length in the buffer, valid iff update is
32*94c4a1e1SFrank Piva 			//true
33*94c4a1e1SFrank Piva 
34*94c4a1e1SFrank Piva #define QCOW2_META_DIRTY    (1U << 0)
35*94c4a1e1SFrank Piva #define QCOW2_META_UPDATE   (1U << 1)
36*94c4a1e1SFrank Piva 
37*94c4a1e1SFrank Piva //l1 & refcount table is top meta, set in constructor, should only
38*94c4a1e1SFrank Piva //be used for flush meta
39*94c4a1e1SFrank Piva #define QCOW2_META_TOP       (1U << 2)
40*94c4a1e1SFrank Piva 
41*94c4a1e1SFrank Piva //the meta slice is being flushed to image
42*94c4a1e1SFrank Piva #define QCOW2_META_FLUSHING  (1U << 3)
43*94c4a1e1SFrank Piva 
44*94c4a1e1SFrank Piva #define QCOW2_META_PREP_FLUSH (1U << 4)
45*94c4a1e1SFrank Piva 
46*94c4a1e1SFrank Piva //set for L1/L2 meta
47*94c4a1e1SFrank Piva #define QCOW2_META_MAPPING   (1U << 5)
48*94c4a1e1SFrank Piva 
49*94c4a1e1SFrank Piva //only used for .reset()
50*94c4a1e1SFrank Piva #define QCOW2_META_DONT_ALLOC_BUF   (1U << 6)
51*94c4a1e1SFrank Piva 
52*94c4a1e1SFrank Piva //evicted from lru cache, and may be in loading or flushing, and will
53*94c4a1e1SFrank Piva //be freed after loading or flushing is done.
54*94c4a1e1SFrank Piva //
55*94c4a1e1SFrank Piva //But can't be re-dirtied any more, so slice marked as EVICTED is readonly
56*94c4a1e1SFrank Piva #define QCOW2_META_EVICTED   (1U << 7)
57*94c4a1e1SFrank Piva 	u32	flags;
58*94c4a1e1SFrank Piva 
59*94c4a1e1SFrank Piva 	int	refcnt;
60*94c4a1e1SFrank Piva public:
61*94c4a1e1SFrank Piva 	virtual int load(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u32 len, bool sync);
62*94c4a1e1SFrank Piva 	virtual int flush(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u64 off,
63*94c4a1e1SFrank Piva 			u32 len);
64*94c4a1e1SFrank Piva 	Qcow2Meta(Qcow2Header &h, u64 off, u32 buf_sz, const char *, u32 f);
65*94c4a1e1SFrank Piva 	virtual ~Qcow2Meta();
66*94c4a1e1SFrank Piva 	void zero_buf();
67*94c4a1e1SFrank Piva 	virtual void show(const char *f = "", int line = 0);
68*94c4a1e1SFrank Piva 
69*94c4a1e1SFrank Piva #ifdef DEBUG_QCOW2_META_OBJ
get_id()70*94c4a1e1SFrank Piva 	const char *get_id() {
71*94c4a1e1SFrank Piva 		return id;
72*94c4a1e1SFrank Piva 	}
73*94c4a1e1SFrank Piva #endif
set_evicted()74*94c4a1e1SFrank Piva 	void set_evicted() {
75*94c4a1e1SFrank Piva 		flags |= QCOW2_META_EVICTED;
76*94c4a1e1SFrank Piva 	}
get_evicted()77*94c4a1e1SFrank Piva 	bool get_evicted() {
78*94c4a1e1SFrank Piva 		return flags & QCOW2_META_EVICTED;
79*94c4a1e1SFrank Piva 	}
80*94c4a1e1SFrank Piva 
set_dirty(unsigned int idx,bool val)81*94c4a1e1SFrank Piva 	void set_dirty(unsigned int idx, bool val) {
82*94c4a1e1SFrank Piva 		if (val)
83*94c4a1e1SFrank Piva 			flags |= QCOW2_META_DIRTY;
84*94c4a1e1SFrank Piva 		else
85*94c4a1e1SFrank Piva 			flags &= ~QCOW2_META_DIRTY;
86*94c4a1e1SFrank Piva 	}
87*94c4a1e1SFrank Piva 
get_dirty(unsigned int idx)88*94c4a1e1SFrank Piva 	bool get_dirty(unsigned int idx) const {
89*94c4a1e1SFrank Piva 		return flags & QCOW2_META_DIRTY;
90*94c4a1e1SFrank Piva 	}
91*94c4a1e1SFrank Piva 
get_offset()92*94c4a1e1SFrank Piva 	u64 get_offset() const {
93*94c4a1e1SFrank Piva 		return offset;
94*94c4a1e1SFrank Piva 	}
95*94c4a1e1SFrank Piva 
get_buf_size()96*94c4a1e1SFrank Piva 	u64 get_buf_size() const {
97*94c4a1e1SFrank Piva 		return buf_sz;
98*94c4a1e1SFrank Piva 	}
99*94c4a1e1SFrank Piva 
get_data_len()100*94c4a1e1SFrank Piva 	u32 get_data_len() const {
101*94c4a1e1SFrank Piva 		return data_len;
102*94c4a1e1SFrank Piva 	}
get_update()103*94c4a1e1SFrank Piva 	bool get_update() const {
104*94c4a1e1SFrank Piva 		return !!(flags & QCOW2_META_UPDATE);
105*94c4a1e1SFrank Piva 	}
set_update(bool val)106*94c4a1e1SFrank Piva 	void set_update(bool val) {
107*94c4a1e1SFrank Piva 		if (val)
108*94c4a1e1SFrank Piva 			flags |= QCOW2_META_UPDATE;
109*94c4a1e1SFrank Piva 		else
110*94c4a1e1SFrank Piva 			flags &= ~QCOW2_META_UPDATE;
111*94c4a1e1SFrank Piva 	}
112*94c4a1e1SFrank Piva 
is_top_meta()113*94c4a1e1SFrank Piva 	bool is_top_meta() const
114*94c4a1e1SFrank Piva 	{
115*94c4a1e1SFrank Piva 		return !!(flags & QCOW2_META_TOP);
116*94c4a1e1SFrank Piva 	}
117*94c4a1e1SFrank Piva 
is_mapping_meta()118*94c4a1e1SFrank Piva 	bool is_mapping_meta() const
119*94c4a1e1SFrank Piva 	{
120*94c4a1e1SFrank Piva 		return !!(flags & QCOW2_META_MAPPING);
121*94c4a1e1SFrank Piva 	}
122*94c4a1e1SFrank Piva 
is_flushing()123*94c4a1e1SFrank Piva 	bool is_flushing() const {
124*94c4a1e1SFrank Piva 		return !!(flags & QCOW2_META_FLUSHING);
125*94c4a1e1SFrank Piva 	}
126*94c4a1e1SFrank Piva 
get_flags()127*94c4a1e1SFrank Piva 	unsigned get_flags() const {
128*94c4a1e1SFrank Piva 		return flags;
129*94c4a1e1SFrank Piva 	}
130*94c4a1e1SFrank Piva 
read_ref()131*94c4a1e1SFrank Piva 	int read_ref() const {
132*94c4a1e1SFrank Piva 		return refcnt;
133*94c4a1e1SFrank Piva 	}
134*94c4a1e1SFrank Piva 
get_prep_flush()135*94c4a1e1SFrank Piva 	bool get_prep_flush() const {
136*94c4a1e1SFrank Piva 		return !!(flags & QCOW2_META_PREP_FLUSH);
137*94c4a1e1SFrank Piva 	}
138*94c4a1e1SFrank Piva 
set_prep_flush(bool val)139*94c4a1e1SFrank Piva 	void set_prep_flush(bool val)
140*94c4a1e1SFrank Piva 	{
141*94c4a1e1SFrank Piva 		if (val)
142*94c4a1e1SFrank Piva 			flags |= QCOW2_META_PREP_FLUSH;
143*94c4a1e1SFrank Piva 		else
144*94c4a1e1SFrank Piva 			flags &= ~QCOW2_META_PREP_FLUSH;
145*94c4a1e1SFrank Piva 	}
146*94c4a1e1SFrank Piva };
147*94c4a1e1SFrank Piva 
148*94c4a1e1SFrank Piva #define  QCOW2_EXT_MAGIC_END 0
149*94c4a1e1SFrank Piva #define  QCOW2_EXT_MAGIC_BACKING_FORMAT 0xe2792aca
150*94c4a1e1SFrank Piva #define  QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
151*94c4a1e1SFrank Piva #define  QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77
152*94c4a1e1SFrank Piva #define  QCOW2_EXT_MAGIC_BITMAPS 0x23852875
153*94c4a1e1SFrank Piva #define  QCOW2_EXT_MAGIC_DATA_FILE 0x44415441
154*94c4a1e1SFrank Piva 
155*94c4a1e1SFrank Piva class Qcow2HeaderExt {
156*94c4a1e1SFrank Piva private:
157*94c4a1e1SFrank Piva 	u64 offset;
158*94c4a1e1SFrank Piva public:
159*94c4a1e1SFrank Piva 	u32 type;
160*94c4a1e1SFrank Piva 	u32 len;
161*94c4a1e1SFrank Piva 
Qcow2HeaderExt(char * addr,u64 off)162*94c4a1e1SFrank Piva 	Qcow2HeaderExt(char *addr, u64 off): offset(off)
163*94c4a1e1SFrank Piva 	{
164*94c4a1e1SFrank Piva 		u32 *buf = (u32 *)(addr + offset);
165*94c4a1e1SFrank Piva 		type = be32_to_cpu(buf[0]);
166*94c4a1e1SFrank Piva 
167*94c4a1e1SFrank Piva 		buf = (u32 *)(addr + offset + 4);
168*94c4a1e1SFrank Piva 		len = be32_to_cpu(buf[0]);
169*94c4a1e1SFrank Piva 	}
170*94c4a1e1SFrank Piva 
~Qcow2HeaderExt()171*94c4a1e1SFrank Piva 	virtual ~Qcow2HeaderExt() {}
172*94c4a1e1SFrank Piva 
dump()173*94c4a1e1SFrank Piva 	virtual void dump() const
174*94c4a1e1SFrank Piva 	{
175*94c4a1e1SFrank Piva 		qcow2_log("%s: type %x len %d\n",
176*94c4a1e1SFrank Piva 				typeid(*this).name(), type, len);
177*94c4a1e1SFrank Piva 	}
178*94c4a1e1SFrank Piva };
179*94c4a1e1SFrank Piva 
180*94c4a1e1SFrank Piva class Qcow2HeaderExtString : public Qcow2HeaderExt {
181*94c4a1e1SFrank Piva public:
182*94c4a1e1SFrank Piva 	std::string str;
183*94c4a1e1SFrank Piva 
Qcow2HeaderExtString(char * addr,u64 offset)184*94c4a1e1SFrank Piva 	Qcow2HeaderExtString(char *addr, u64 offset):
185*94c4a1e1SFrank Piva 		Qcow2HeaderExt(addr, offset), str((char *)addr, 0, len)
186*94c4a1e1SFrank Piva 	{
187*94c4a1e1SFrank Piva 	}
188*94c4a1e1SFrank Piva 
dump()189*94c4a1e1SFrank Piva 	virtual void dump() const
190*94c4a1e1SFrank Piva 	{
191*94c4a1e1SFrank Piva 		qcow2_log("%s: type %x len %d string %s\n",
192*94c4a1e1SFrank Piva 				typeid(*this).name(), type, len, str.c_str());
193*94c4a1e1SFrank Piva 	}
194*94c4a1e1SFrank Piva };
195*94c4a1e1SFrank Piva 
196*94c4a1e1SFrank Piva class Qcow2HeaderExtFeatureNameTable : public Qcow2HeaderExt {
197*94c4a1e1SFrank Piva public:
198*94c4a1e1SFrank Piva 	struct feature_entry {
199*94c4a1e1SFrank Piva 		char feature_type;
200*94c4a1e1SFrank Piva 		char bit_num;
201*94c4a1e1SFrank Piva 		char feature_name[46];
202*94c4a1e1SFrank Piva 	};
203*94c4a1e1SFrank Piva 	typedef std::valarray<feature_entry> ArrayFeature;
204*94c4a1e1SFrank Piva 	ArrayFeature __a;
205*94c4a1e1SFrank Piva 
206*94c4a1e1SFrank Piva 	Qcow2HeaderExtFeatureNameTable(char *addr, u64 offset);
~Qcow2HeaderExtFeatureNameTable()207*94c4a1e1SFrank Piva 	~Qcow2HeaderExtFeatureNameTable() {};
208*94c4a1e1SFrank Piva 	void dump() const;
209*94c4a1e1SFrank Piva };
210*94c4a1e1SFrank Piva 
211*94c4a1e1SFrank Piva class Qcow2HeaderExtBitmaps : public Qcow2HeaderExt {
212*94c4a1e1SFrank Piva public:
213*94c4a1e1SFrank Piva 	u32  nr_bitmap;
214*94c4a1e1SFrank Piva 	u64  bitmap_directory_size;
215*94c4a1e1SFrank Piva 	u64  bitmap_directory_offset;
Qcow2HeaderExtBitmaps(char * addr,u64 offset)216*94c4a1e1SFrank Piva 	Qcow2HeaderExtBitmaps(char *addr, u64 offset):
217*94c4a1e1SFrank Piva 		Qcow2HeaderExt(addr, offset)
218*94c4a1e1SFrank Piva 	{
219*94c4a1e1SFrank Piva 		nr_bitmap = be32_to_cpu(*(u32 *)(addr + offset + 8));
220*94c4a1e1SFrank Piva 		bitmap_directory_size = be64_to_cpu(*(u64 *)(addr +
221*94c4a1e1SFrank Piva 					offset + 12));
222*94c4a1e1SFrank Piva 		bitmap_directory_offset = be64_to_cpu(*(u64 *)(addr +
223*94c4a1e1SFrank Piva 					offset + 20));
224*94c4a1e1SFrank Piva 	}
dump()225*94c4a1e1SFrank Piva 	virtual void dump() const
226*94c4a1e1SFrank Piva 	{
227*94c4a1e1SFrank Piva 		qcow2_log("%s: type %x len %d nr_bitmap %d bitmap_dir(offset %lx sz %lu)\n",
228*94c4a1e1SFrank Piva 				typeid(*this).name(), type, len,
229*94c4a1e1SFrank Piva 				nr_bitmap, bitmap_directory_offset,
230*94c4a1e1SFrank Piva 				bitmap_directory_size);
231*94c4a1e1SFrank Piva 	}
232*94c4a1e1SFrank Piva };
233*94c4a1e1SFrank Piva 
234*94c4a1e1SFrank Piva class Qcow2HeaderExtEncHeader : public Qcow2HeaderExt {
235*94c4a1e1SFrank Piva public:
236*94c4a1e1SFrank Piva 	u64  enc_offset;
237*94c4a1e1SFrank Piva 	u64  enc_len;
Qcow2HeaderExtEncHeader(char * addr,u64 offset)238*94c4a1e1SFrank Piva 	Qcow2HeaderExtEncHeader(char *addr, u64 offset):
239*94c4a1e1SFrank Piva 		Qcow2HeaderExt(addr, offset)
240*94c4a1e1SFrank Piva 	{
241*94c4a1e1SFrank Piva 		enc_offset = be64_to_cpu(*(u64 *)(addr +
242*94c4a1e1SFrank Piva 					offset + 8));
243*94c4a1e1SFrank Piva 		enc_len = be64_to_cpu(*(u64 *)(addr +
244*94c4a1e1SFrank Piva 					offset + 16));
245*94c4a1e1SFrank Piva 	}
dump()246*94c4a1e1SFrank Piva 	virtual void dump() const
247*94c4a1e1SFrank Piva 	{
248*94c4a1e1SFrank Piva 		qcow2_log("%s: type %x len %d enc(offset %" PRIx64 " sz %" PRIu64 ")\n",
249*94c4a1e1SFrank Piva 				typeid(*this).name(), type, len,
250*94c4a1e1SFrank Piva 				enc_offset, enc_len);
251*94c4a1e1SFrank Piva 	}
252*94c4a1e1SFrank Piva };
253*94c4a1e1SFrank Piva 
254*94c4a1e1SFrank Piva #define __INLINE_SET_GET(type, prop, v2_val)			\
255*94c4a1e1SFrank Piva type get_##prop() const						\
256*94c4a1e1SFrank Piva {								\
257*94c4a1e1SFrank Piva 	if (offsetof(QCowHeader, prop) >= 72 && version == 2)	\
258*94c4a1e1SFrank Piva 		return v2_val;					\
259*94c4a1e1SFrank Piva 	switch(sizeof(type)) {					\
260*94c4a1e1SFrank Piva 	case 8:							\
261*94c4a1e1SFrank Piva 		return be64_to_cpu(((QCowHeader*)addr)->prop);	\
262*94c4a1e1SFrank Piva 	case 4:							\
263*94c4a1e1SFrank Piva 		return be32_to_cpu(((QCowHeader*)addr)->prop);	\
264*94c4a1e1SFrank Piva 	case 2:							\
265*94c4a1e1SFrank Piva 		return be16_to_cpu(((QCowHeader*)addr)->prop);	\
266*94c4a1e1SFrank Piva 	case 1:							\
267*94c4a1e1SFrank Piva 		return ((QCowHeader*)addr)->prop;		\
268*94c4a1e1SFrank Piva 	}							\
269*94c4a1e1SFrank Piva }								\
270*94c4a1e1SFrank Piva void set_##prop(type v)						\
271*94c4a1e1SFrank Piva {								\
272*94c4a1e1SFrank Piva 	QCowHeader *h = (QCowHeader *)addr;			\
273*94c4a1e1SFrank Piva 	if (offsetof(QCowHeader, prop) >= 72 && version == 2)	\
274*94c4a1e1SFrank Piva 		return;						\
275*94c4a1e1SFrank Piva 	switch(sizeof(type)) {					\
276*94c4a1e1SFrank Piva 	case 8:							\
277*94c4a1e1SFrank Piva 		h->prop = cpu_to_be64(v);			\
278*94c4a1e1SFrank Piva 		break;						\
279*94c4a1e1SFrank Piva 	case 4:							\
280*94c4a1e1SFrank Piva 		h->prop = cpu_to_be32(v);			\
281*94c4a1e1SFrank Piva 		break;						\
282*94c4a1e1SFrank Piva 	case 2:							\
283*94c4a1e1SFrank Piva 		h->prop = cpu_to_be16(v);			\
284*94c4a1e1SFrank Piva 		break;						\
285*94c4a1e1SFrank Piva 	case 1:							\
286*94c4a1e1SFrank Piva 		h->prop = v;					\
287*94c4a1e1SFrank Piva 		break;						\
288*94c4a1e1SFrank Piva 	}							\
289*94c4a1e1SFrank Piva 	Qcow2Meta::set_dirty(-1, true);				\
290*94c4a1e1SFrank Piva }
291*94c4a1e1SFrank Piva 
292*94c4a1e1SFrank Piva #define INLINE_SET_GET(type, prop) __INLINE_SET_GET(type, prop, 0)
293*94c4a1e1SFrank Piva 
294*94c4a1e1SFrank Piva class Qcow2Header: public Qcow2Meta {
295*94c4a1e1SFrank Piva private:
296*94c4a1e1SFrank Piva 	int populate();
297*94c4a1e1SFrank Piva 	Qcow2HeaderExtString		*backingfile_format_name;
298*94c4a1e1SFrank Piva 	Qcow2HeaderExtString		*ext_data_file_name;
299*94c4a1e1SFrank Piva 	Qcow2HeaderExtFeatureNameTable	*feature_name_table;
300*94c4a1e1SFrank Piva 	Qcow2HeaderExtBitmaps		*bitmaps;
301*94c4a1e1SFrank Piva 	Qcow2HeaderExtEncHeader		*enc_header_pointer;
302*94c4a1e1SFrank Piva public:
303*94c4a1e1SFrank Piva 	const u32 magic;
304*94c4a1e1SFrank Piva 	const u32 version;
305*94c4a1e1SFrank Piva 	const u32 cluster_bits;
306*94c4a1e1SFrank Piva 	const u32 refcount_order;
307*94c4a1e1SFrank Piva 
308*94c4a1e1SFrank Piva 	//this way looks ugly, but just for retrieve qs in destructor of
309*94c4a1e1SFrank Piva 	//Qcow2SliceMeta
310*94c4a1e1SFrank Piva 	Qcow2State &qs;
311*94c4a1e1SFrank Piva 
312*94c4a1e1SFrank Piva 	Qcow2Header(Qcow2State &qs);
313*94c4a1e1SFrank Piva 	virtual ~Qcow2Header();
314*94c4a1e1SFrank Piva 	virtual int load(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u32 len, bool sync);
315*94c4a1e1SFrank Piva 	virtual int flush(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u64 off,
316*94c4a1e1SFrank Piva 			u32 len);
317*94c4a1e1SFrank Piva 	void dump_ext() const;
318*94c4a1e1SFrank Piva 
319*94c4a1e1SFrank Piva 	INLINE_SET_GET(u32, magic);
320*94c4a1e1SFrank Piva 	INLINE_SET_GET(u32, version);
321*94c4a1e1SFrank Piva 	INLINE_SET_GET(u64, backing_file_offset);
322*94c4a1e1SFrank Piva 	INLINE_SET_GET(u32, backing_file_size);
323*94c4a1e1SFrank Piva 	INLINE_SET_GET(u32, cluster_bits);
324*94c4a1e1SFrank Piva 	INLINE_SET_GET(u64, size);
325*94c4a1e1SFrank Piva 	INLINE_SET_GET(u32, crypt_method);
326*94c4a1e1SFrank Piva 	INLINE_SET_GET(u32, l1_size);
327*94c4a1e1SFrank Piva 	INLINE_SET_GET(u64, l1_table_offset);
328*94c4a1e1SFrank Piva 	INLINE_SET_GET(u64, refcount_table_offset);
329*94c4a1e1SFrank Piva 	INLINE_SET_GET(u32, refcount_table_clusters);
330*94c4a1e1SFrank Piva 	INLINE_SET_GET(u32, nb_snapshots);
331*94c4a1e1SFrank Piva 	INLINE_SET_GET(u64, snapshots_offset);
332*94c4a1e1SFrank Piva 	__INLINE_SET_GET(u64, incompatible_features, 0);
333*94c4a1e1SFrank Piva 	__INLINE_SET_GET(u64, compatible_features, 0);
334*94c4a1e1SFrank Piva 	__INLINE_SET_GET(u64, autoclear_features, 0);
335*94c4a1e1SFrank Piva 	__INLINE_SET_GET(u32, refcount_order, 4);
336*94c4a1e1SFrank Piva 	__INLINE_SET_GET(u32, header_length, 72);
337*94c4a1e1SFrank Piva 	__INLINE_SET_GET(u8, compression_type, 0);
338*94c4a1e1SFrank Piva 
339*94c4a1e1SFrank Piva 	friend std::ostream & operator<<(std::ostream &os, const Qcow2Header &h);
340*94c4a1e1SFrank Piva 
is_extended_l2_entries()341*94c4a1e1SFrank Piva 	bool is_extended_l2_entries() {
342*94c4a1e1SFrank Piva 		return get_incompatible_features() & 0x8;
343*94c4a1e1SFrank Piva 	}
344*94c4a1e1SFrank Piva };
345*94c4a1e1SFrank Piva 
346*94c4a1e1SFrank Piva class Qcow2MappingMeta: public Qcow2Meta {
347*94c4a1e1SFrank Piva private:
348*94c4a1e1SFrank Piva 	IOWaiters io_waiters;
349*94c4a1e1SFrank Piva protected:
350*94c4a1e1SFrank Piva 	u32 entry_bits_order;
351*94c4a1e1SFrank Piva 	s32 next_free_idx;	//cache the next free idx
352*94c4a1e1SFrank Piva 
353*94c4a1e1SFrank Piva 	//deprecate now
entry_val_is_dirty(u64 val)354*94c4a1e1SFrank Piva 	bool entry_val_is_dirty(u64 val) {
355*94c4a1e1SFrank Piva 		qcow2_assert(false);
356*94c4a1e1SFrank Piva 		return true;
357*94c4a1e1SFrank Piva 	}
358*94c4a1e1SFrank Piva 
359*94c4a1e1SFrank Piva 	int __flush(Qcow2State &qs, const qcow2_io_ctx_t &ioc,
360*94c4a1e1SFrank Piva 		u64 off, u32 len, bool run_fsync = false);
361*94c4a1e1SFrank Piva 	int clear_dirty_entries(Qcow2State &qs,
362*94c4a1e1SFrank Piva 		const qcow2_io_ctx_t &ioc, u64 off, u32 len);
363*94c4a1e1SFrank Piva public:
364*94c4a1e1SFrank Piva 	Qcow2MappingMeta(Qcow2State &qs, u64 off, u32 buf_sz,
365*94c4a1e1SFrank Piva 			const char *cls_name, u32 f);
get_nr_entries()366*94c4a1e1SFrank Piva 	s32 get_nr_entries() {
367*94c4a1e1SFrank Piva 		return (buf_sz << 3) >> entry_bits_order;
368*94c4a1e1SFrank Piva 	}
get_next_free_idx()369*94c4a1e1SFrank Piva 	s32 get_next_free_idx() {
370*94c4a1e1SFrank Piva 		return next_free_idx;
371*94c4a1e1SFrank Piva 	}
set_next_free_idx(s32 idx)372*94c4a1e1SFrank Piva 	void set_next_free_idx(s32 idx) {
373*94c4a1e1SFrank Piva 		if (idx < get_nr_entries())
374*94c4a1e1SFrank Piva 			next_free_idx = idx;
375*94c4a1e1SFrank Piva 	}
376*94c4a1e1SFrank Piva 
add_waiter(unsigned tag)377*94c4a1e1SFrank Piva 	void add_waiter(unsigned tag) {
378*94c4a1e1SFrank Piva 		io_waiters.add_waiter(tag);
379*94c4a1e1SFrank Piva 	}
380*94c4a1e1SFrank Piva 
add_waiter_idx(unsigned tag,unsigned entry_idx)381*94c4a1e1SFrank Piva 	void add_waiter_idx(unsigned tag, unsigned entry_idx) {
382*94c4a1e1SFrank Piva 		io_waiters.add_waiter_idx(tag, entry_idx);
383*94c4a1e1SFrank Piva 	}
384*94c4a1e1SFrank Piva 
wakeup_all(const struct ublksrv_queue * q,unsigned my_tag)385*94c4a1e1SFrank Piva 	void wakeup_all(const struct ublksrv_queue *q, unsigned my_tag) {
386*94c4a1e1SFrank Piva 		io_waiters.wakeup_all(q, my_tag);
387*94c4a1e1SFrank Piva 	}
388*94c4a1e1SFrank Piva 
wakeup_all_idx(const struct ublksrv_queue * q,unsigned my_tag,unsigned entry_idx)389*94c4a1e1SFrank Piva 	void wakeup_all_idx(const struct ublksrv_queue *q,
390*94c4a1e1SFrank Piva 			unsigned my_tag, unsigned entry_idx) {
391*94c4a1e1SFrank Piva 		io_waiters.wakeup_all_idx(q, my_tag, entry_idx);
392*94c4a1e1SFrank Piva 	}
393*94c4a1e1SFrank Piva 
394*94c4a1e1SFrank Piva 	virtual u64  get_entry(u32 idx) = 0;
395*94c4a1e1SFrank Piva 	virtual void set_entry(u32 idx, u64 val) = 0;
396*94c4a1e1SFrank Piva 	virtual int flush(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u64 off,
397*94c4a1e1SFrank Piva 			u32 len) = 0;
398*94c4a1e1SFrank Piva 
399*94c4a1e1SFrank Piva 	//both load() and flush() should be async, and done() needs to be called
400*94c4a1e1SFrank Piva 	//after both load() and flush() meta IO are done.
401*94c4a1e1SFrank Piva 	virtual void io_done(Qcow2State &qs, const struct ublksrv_queue *q,
402*94c4a1e1SFrank Piva 			const struct io_uring_cqe *cqe);
403*94c4a1e1SFrank Piva };
404*94c4a1e1SFrank Piva 
405*94c4a1e1SFrank Piva class Qcow2TopTable: public Qcow2MappingMeta {
406*94c4a1e1SFrank Piva private:
407*94c4a1e1SFrank Piva 	u32 flush_blk_idx;
408*94c4a1e1SFrank Piva 
409*94c4a1e1SFrank Piva protected:
410*94c4a1e1SFrank Piva 	u32 min_bs_bits;
411*94c4a1e1SFrank Piva 	std::vector <bool> dirty;
412*94c4a1e1SFrank Piva public:
413*94c4a1e1SFrank Piva 	Qcow2TopTable(Qcow2State &qs, u64 off, u32 buf_sz,
414*94c4a1e1SFrank Piva 			const char *cls_name, u32 f);
415*94c4a1e1SFrank Piva 
is_flushing(u32 idx)416*94c4a1e1SFrank Piva 	bool is_flushing(u32 idx) {
417*94c4a1e1SFrank Piva 		if (Qcow2Meta::is_flushing() && idx == flush_blk_idx)
418*94c4a1e1SFrank Piva 			return true;
419*94c4a1e1SFrank Piva 		return false;
420*94c4a1e1SFrank Piva 	}
421*94c4a1e1SFrank Piva 
get_blk_dirty(u32 idx)422*94c4a1e1SFrank Piva 	bool get_blk_dirty(u32 idx)
423*94c4a1e1SFrank Piva 	{
424*94c4a1e1SFrank Piva 		return dirty[idx];
425*94c4a1e1SFrank Piva 	}
426*94c4a1e1SFrank Piva 
set_blk_dirty(u32 idx,bool val)427*94c4a1e1SFrank Piva 	void set_blk_dirty(u32 idx, bool val)
428*94c4a1e1SFrank Piva 	{
429*94c4a1e1SFrank Piva 		dirty[idx] = val;
430*94c4a1e1SFrank Piva 	}
431*94c4a1e1SFrank Piva 
dirty_blks()432*94c4a1e1SFrank Piva 	u32 dirty_blks() {
433*94c4a1e1SFrank Piva 		u32 total = 0;
434*94c4a1e1SFrank Piva 
435*94c4a1e1SFrank Piva 		for (int i = 0; i < dirty.size(); i++)
436*94c4a1e1SFrank Piva 			if (dirty[i])
437*94c4a1e1SFrank Piva 				total += 1;
438*94c4a1e1SFrank Piva 		return total;
439*94c4a1e1SFrank Piva 	}
440*94c4a1e1SFrank Piva 
dirty_blk_size()441*94c4a1e1SFrank Piva 	u32 dirty_blk_size() {
442*94c4a1e1SFrank Piva 		return dirty.size();
443*94c4a1e1SFrank Piva 	}
444*94c4a1e1SFrank Piva 
get_1st_dirty_blk()445*94c4a1e1SFrank Piva 	int get_1st_dirty_blk() {
446*94c4a1e1SFrank Piva 		for (int i = 0; i < dirty.size(); i++)
447*94c4a1e1SFrank Piva 			if (dirty[i])
448*94c4a1e1SFrank Piva 				return i;
449*94c4a1e1SFrank Piva 		return -1;
450*94c4a1e1SFrank Piva 	}
451*94c4a1e1SFrank Piva 
set_flush_blk_idx(u32 idx)452*94c4a1e1SFrank Piva 	void set_flush_blk_idx(u32 idx)
453*94c4a1e1SFrank Piva 	{
454*94c4a1e1SFrank Piva 		flush_blk_idx = idx;
455*94c4a1e1SFrank Piva 	}
456*94c4a1e1SFrank Piva 
get_flush_blk_idx()457*94c4a1e1SFrank Piva 	u32 get_flush_blk_idx()
458*94c4a1e1SFrank Piva 	{
459*94c4a1e1SFrank Piva 		return flush_blk_idx;
460*94c4a1e1SFrank Piva 	}
461*94c4a1e1SFrank Piva 
single_entry_order()462*94c4a1e1SFrank Piva 	u64 single_entry_order() const
463*94c4a1e1SFrank Piva 	{
464*94c4a1e1SFrank Piva 		if (is_mapping_meta())
465*94c4a1e1SFrank Piva 			return (2 * header.cluster_bits - 3);
466*94c4a1e1SFrank Piva 		return 2 * header.cluster_bits + 3 - header.refcount_order;
467*94c4a1e1SFrank Piva 	}
468*94c4a1e1SFrank Piva 
469*94c4a1e1SFrank Piva 	bool prep_flush(const qcow2_io_ctx_t &ioc, u32 blk_idx);
470*94c4a1e1SFrank Piva 	void unprep_flush(u32 blk_idx);
471*94c4a1e1SFrank Piva 
472*94c4a1e1SFrank Piva 	virtual void io_done(Qcow2State &qs, const struct ublksrv_queue *q,
473*94c4a1e1SFrank Piva 			const struct io_uring_cqe *);
474*94c4a1e1SFrank Piva 	virtual int flush(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u64 off, u32 len);
475*94c4a1e1SFrank Piva 	bool has_dirty_slices(Qcow2State &qs, int idx);
476*94c4a1e1SFrank Piva };
477*94c4a1e1SFrank Piva 
478*94c4a1e1SFrank Piva //allocating detection needs to review!!!
479*94c4a1e1SFrank Piva class Qcow2L1Table: public Qcow2TopTable {
480*94c4a1e1SFrank Piva public:
offset_to_idx(u64 virt_offset)481*94c4a1e1SFrank Piva 	u32  offset_to_idx(u64 virt_offset) {
482*94c4a1e1SFrank Piva 		u32 cluster_bits = header.cluster_bits;
483*94c4a1e1SFrank Piva 		bool has_extended_l2_entries = header.is_extended_l2_entries();
484*94c4a1e1SFrank Piva 		u32 idx = (virt_offset >> cluster_bits) >>
485*94c4a1e1SFrank Piva 			(cluster_bits - 3 - !!has_extended_l2_entries);
486*94c4a1e1SFrank Piva 
487*94c4a1e1SFrank Piva 		return idx;
488*94c4a1e1SFrank Piva 	}
489*94c4a1e1SFrank Piva 
get_entry_fast(u32 idx)490*94c4a1e1SFrank Piva 	u64  get_entry_fast(u32 idx) {
491*94c4a1e1SFrank Piva 		u64 val = be64_to_cpu(((const u64 *)addr)[idx]);
492*94c4a1e1SFrank Piva 
493*94c4a1e1SFrank Piva 		return val;
494*94c4a1e1SFrank Piva 	}
495*94c4a1e1SFrank Piva 
set_entry_fast(u32 idx,u64 val)496*94c4a1e1SFrank Piva 	void set_entry_fast(u32 idx, u64 val) {
497*94c4a1e1SFrank Piva 		unsigned i = idx >> (min_bs_bits - 3);
498*94c4a1e1SFrank Piva 
499*94c4a1e1SFrank Piva 		((u64 *)addr)[idx] = cpu_to_be64(val);
500*94c4a1e1SFrank Piva 		set_dirty(idx, true);
501*94c4a1e1SFrank Piva 
502*94c4a1e1SFrank Piva 		qcow2_assert(i < dirty.size());
503*94c4a1e1SFrank Piva 		dirty[i] = true;
504*94c4a1e1SFrank Piva 	}
505*94c4a1e1SFrank Piva 
entry_allocated(u64 entry)506*94c4a1e1SFrank Piva 	bool entry_allocated(u64 entry) {
507*94c4a1e1SFrank Piva 		return entry != 0;
508*94c4a1e1SFrank Piva 	}
509*94c4a1e1SFrank Piva 
entry_is_dirty(u32 idx)510*94c4a1e1SFrank Piva 	bool entry_is_dirty(u32 idx) {
511*94c4a1e1SFrank Piva 		return entry_val_is_dirty(get_entry(idx));
512*94c4a1e1SFrank Piva 	}
513*94c4a1e1SFrank Piva 
514*94c4a1e1SFrank Piva 	Qcow2L1Table(Qcow2State &qs);
515*94c4a1e1SFrank Piva 	virtual int load(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u32 len, bool sync);
516*94c4a1e1SFrank Piva 	virtual u64  get_entry(u32 idx);
517*94c4a1e1SFrank Piva 	virtual void set_entry(u32 idx, u64 val);
518*94c4a1e1SFrank Piva 	void dump();
519*94c4a1e1SFrank Piva };
520*94c4a1e1SFrank Piva 
521*94c4a1e1SFrank Piva class Qcow2RefcountTable: public Qcow2TopTable {
522*94c4a1e1SFrank Piva public:
offset_to_idx(u64 virt_offset)523*94c4a1e1SFrank Piva 	u32  offset_to_idx(u64 virt_offset) {
524*94c4a1e1SFrank Piva 		u32 cluster_bits = header.cluster_bits;
525*94c4a1e1SFrank Piva 		u32 idx = (virt_offset >> cluster_bits) >>
526*94c4a1e1SFrank Piva 			(cluster_bits + 3 - header.refcount_order);
527*94c4a1e1SFrank Piva 
528*94c4a1e1SFrank Piva 		return idx;
529*94c4a1e1SFrank Piva 	}
set_entry_fast(u32 idx,u64 val)530*94c4a1e1SFrank Piva 	void set_entry_fast(u32 idx, u64 val) {
531*94c4a1e1SFrank Piva 		unsigned i = idx >> (min_bs_bits - 3);
532*94c4a1e1SFrank Piva 
533*94c4a1e1SFrank Piva 		((u64 *)addr)[idx] = cpu_to_be64(val);
534*94c4a1e1SFrank Piva 		set_dirty(idx, true);
535*94c4a1e1SFrank Piva 
536*94c4a1e1SFrank Piva 		qcow2_assert(i < dirty.size());
537*94c4a1e1SFrank Piva 		dirty[i] = true;
538*94c4a1e1SFrank Piva 	}
get_entry_fast(u32 idx)539*94c4a1e1SFrank Piva 	u64  get_entry_fast(u32 idx) {
540*94c4a1e1SFrank Piva 		return be64_to_cpu(((u64 *)addr)[idx]);
541*94c4a1e1SFrank Piva 	}
entry_is_dirty(u32 idx)542*94c4a1e1SFrank Piva 	bool entry_is_dirty(u32 idx) {
543*94c4a1e1SFrank Piva 		return entry_val_is_dirty(get_entry(idx));
544*94c4a1e1SFrank Piva 	}
545*94c4a1e1SFrank Piva 
546*94c4a1e1SFrank Piva 	Qcow2RefcountTable(Qcow2State &qs);
547*94c4a1e1SFrank Piva 	virtual int load(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u32 len, bool sync);
548*94c4a1e1SFrank Piva 	virtual u64  get_entry(u32 idx);
549*94c4a1e1SFrank Piva 	virtual void set_entry(u32 idx, u64 val);
550*94c4a1e1SFrank Piva 	void dump();
551*94c4a1e1SFrank Piva };
552*94c4a1e1SFrank Piva 
553*94c4a1e1SFrank Piva class Qcow2SliceMeta: public Qcow2MappingMeta {
554*94c4a1e1SFrank Piva protected:
555*94c4a1e1SFrank Piva 	bool prep_flush(const qcow2_io_ctx_t &ioc);
556*94c4a1e1SFrank Piva 	void unprep_flush();
557*94c4a1e1SFrank Piva 	virtual void wait_clusters(Qcow2State &qs, const qcow2_io_ctx_t &ioc);
558*94c4a1e1SFrank Piva #ifdef DEBUG_QCOW2_META_VALIDATE
559*94c4a1e1SFrank Piva 	void *validate_addr;
560*94c4a1e1SFrank Piva #endif
561*94c4a1e1SFrank Piva public:
562*94c4a1e1SFrank Piva 	unsigned int parent_idx; //parent's this entry points to us
563*94c4a1e1SFrank Piva 
564*94c4a1e1SFrank Piva 	Qcow2SliceMeta(Qcow2State &qs, u64 off, u32 buf_sz,
565*94c4a1e1SFrank Piva 			const char *cls_name, u32 p_idx, u32 f);
566*94c4a1e1SFrank Piva 	virtual int load(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u32 len, bool sync);
567*94c4a1e1SFrank Piva 	virtual int flush(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u64 off,
568*94c4a1e1SFrank Piva 			u32 len) = 0;
569*94c4a1e1SFrank Piva 	virtual void dump() = 0;
570*94c4a1e1SFrank Piva 	virtual ~Qcow2SliceMeta();
571*94c4a1e1SFrank Piva 	virtual void get_dirty_range(u64 *start, u64 *end) = 0;
572*94c4a1e1SFrank Piva 
573*94c4a1e1SFrank Piva 	//both load() and flush() should be async, and done() needs to be called
574*94c4a1e1SFrank Piva 	//after both load() and flush() meta IO are done.
575*94c4a1e1SFrank Piva 	virtual void io_done(Qcow2State &qs, const struct ublksrv_queue *q,
576*94c4a1e1SFrank Piva 			const struct io_uring_cqe *cqe);
577*94c4a1e1SFrank Piva 	int zero_my_cluster(Qcow2State &qs, const qcow2_io_ctx_t &ioc);
578*94c4a1e1SFrank Piva 
579*94c4a1e1SFrank Piva 	void reclaim_me();
580*94c4a1e1SFrank Piva 
get_offset()581*94c4a1e1SFrank Piva 	u64 get_offset() const {
582*94c4a1e1SFrank Piva 		return offset;
583*94c4a1e1SFrank Piva 	}
584*94c4a1e1SFrank Piva 
get_ref()585*94c4a1e1SFrank Piva 	void get_ref() {
586*94c4a1e1SFrank Piva 		qcow2_assert(refcnt > 0);
587*94c4a1e1SFrank Piva 		refcnt += 1;
588*94c4a1e1SFrank Piva 	}
589*94c4a1e1SFrank Piva 
put_ref()590*94c4a1e1SFrank Piva 	void put_ref() {
591*94c4a1e1SFrank Piva 		qcow2_assert(refcnt > 0);
592*94c4a1e1SFrank Piva 		if (--refcnt == 0)
593*94c4a1e1SFrank Piva 			reclaim_me();
594*94c4a1e1SFrank Piva 	}
595*94c4a1e1SFrank Piva 
596*94c4a1e1SFrank Piva 	//In theory, virt_offset() should be implemented as virtual function.
597*94c4a1e1SFrank Piva 	//However, it is actually one helper for fast path, so move it to
598*94c4a1e1SFrank Piva 	//parent class, and use base flag to return the proper return value.
virt_offset()599*94c4a1e1SFrank Piva 	u64 virt_offset() {
600*94c4a1e1SFrank Piva 		if (is_mapping_meta()) {
601*94c4a1e1SFrank Piva 			u64 base = ((u64)parent_idx) << (header.cluster_bits -
602*94c4a1e1SFrank Piva 					3 + header.cluster_bits);
603*94c4a1e1SFrank Piva 			u64 clusters = (get_offset() &
604*94c4a1e1SFrank Piva 				((1ULL << header.cluster_bits) - 1)) >> 3;
605*94c4a1e1SFrank Piva 
606*94c4a1e1SFrank Piva 			return base + (clusters << header.cluster_bits);
607*94c4a1e1SFrank Piva 		}
608*94c4a1e1SFrank Piva 
609*94c4a1e1SFrank Piva 		const u64 single_entry_order = 2 * header.cluster_bits +
610*94c4a1e1SFrank Piva 			3 - header.refcount_order;
611*94c4a1e1SFrank Piva 		u32 slice_idx = (get_offset() & ((1U << header.cluster_bits) - 1)) >>
612*94c4a1e1SFrank Piva 			QCOW2_PARA::REFCOUNT_BLK_SLICE_BITS;
613*94c4a1e1SFrank Piva 		u32 slice_virt_bits = header.cluster_bits + 3 -
614*94c4a1e1SFrank Piva 			header.refcount_order + QCOW2_PARA::REFCOUNT_BLK_SLICE_BITS;
615*94c4a1e1SFrank Piva 
616*94c4a1e1SFrank Piva 		return ((u64)parent_idx << single_entry_order) +
617*94c4a1e1SFrank Piva 			((u64)slice_idx << slice_virt_bits);
618*94c4a1e1SFrank Piva 	}
619*94c4a1e1SFrank Piva #ifdef DEBUG_QCOW2_META_VALIDATE
620*94c4a1e1SFrank Piva 	void io_done_validate(Qcow2State &qs, const struct ublksrv_queue *q,
621*94c4a1e1SFrank Piva 			const struct io_uring_cqe *cqe);
622*94c4a1e1SFrank Piva #else
io_done_validate(Qcow2State & qs,const struct ublksrv_queue * q,const struct io_uring_cqe * cqe)623*94c4a1e1SFrank Piva 	void io_done_validate(Qcow2State &qs, const struct ublksrv_queue *q,
624*94c4a1e1SFrank Piva 			const struct io_uring_cqe *cqe) {}
625*94c4a1e1SFrank Piva #endif
626*94c4a1e1SFrank Piva };
627*94c4a1e1SFrank Piva 
628*94c4a1e1SFrank Piva class Qcow2RefcountBlock: public Qcow2SliceMeta {
629*94c4a1e1SFrank Piva public:
630*94c4a1e1SFrank Piva 	unsigned dirty_start_idx;
get_entry_fast(u32 idx)631*94c4a1e1SFrank Piva 	u64  get_entry_fast(u32 idx) {
632*94c4a1e1SFrank Piva 		switch (header.refcount_order) {
633*94c4a1e1SFrank Piva 		case 0:
634*94c4a1e1SFrank Piva 		return (((const u8 *)addr)[idx / 8] >> (idx % 8)) & 0x1;
635*94c4a1e1SFrank Piva 
636*94c4a1e1SFrank Piva 		case 1:
637*94c4a1e1SFrank Piva 		return (((const u8 *)addr)[idx / 4] >> (2 * (idx % 4))) & 0x3;
638*94c4a1e1SFrank Piva 
639*94c4a1e1SFrank Piva 		case 2:
640*94c4a1e1SFrank Piva 		return (((const u8 *)addr)[idx / 2] >> (4 * (idx % 2))) & 0xf;
641*94c4a1e1SFrank Piva 
642*94c4a1e1SFrank Piva 		case 3:
643*94c4a1e1SFrank Piva 		return ((const u8 *)addr)[idx];
644*94c4a1e1SFrank Piva 
645*94c4a1e1SFrank Piva 		case 4:
646*94c4a1e1SFrank Piva 		return be16_to_cpu(((const u16 *)addr)[idx]);
647*94c4a1e1SFrank Piva 
648*94c4a1e1SFrank Piva 		case 5:
649*94c4a1e1SFrank Piva 		return be32_to_cpu(((const u32 *)addr)[idx]);
650*94c4a1e1SFrank Piva 
651*94c4a1e1SFrank Piva 		case 6:
652*94c4a1e1SFrank Piva 		return be64_to_cpu(((const u64 *)addr)[idx]);
653*94c4a1e1SFrank Piva 		}
654*94c4a1e1SFrank Piva 		return 0;
655*94c4a1e1SFrank Piva 	}
656*94c4a1e1SFrank Piva 
set_entry_fast(u32 idx,u64 val)657*94c4a1e1SFrank Piva 	void set_entry_fast(u32 idx, u64 val) {
658*94c4a1e1SFrank Piva 		switch (header.refcount_order) {
659*94c4a1e1SFrank Piva 		case 0:
660*94c4a1e1SFrank Piva 			qcow2_assert(!(val >> 1));
661*94c4a1e1SFrank Piva 			((u8 *)addr)[idx / 8] &= ~(0x1 << (idx % 8));
662*94c4a1e1SFrank Piva 			((u8 *)addr)[idx / 8] |= val << (idx % 8);
663*94c4a1e1SFrank Piva 			break;
664*94c4a1e1SFrank Piva 		case 1:
665*94c4a1e1SFrank Piva 			qcow2_assert(!(val >> 2));
666*94c4a1e1SFrank Piva 			((u8 *)addr)[idx / 4] &= ~(0x3 << (2 * (idx % 4)));
667*94c4a1e1SFrank Piva 			((u8 *)addr)[idx / 4] |= val << (2 * (idx % 4));
668*94c4a1e1SFrank Piva 			break;
669*94c4a1e1SFrank Piva 		case 2:
670*94c4a1e1SFrank Piva 			qcow2_assert(!(val >> 4));
671*94c4a1e1SFrank Piva 			((u8 *)addr)[idx / 2] &= ~(0xf << (4 * (idx % 2)));
672*94c4a1e1SFrank Piva 			((u8 *)addr)[idx / 2] |= val << (4 * (idx % 2));
673*94c4a1e1SFrank Piva 			break;
674*94c4a1e1SFrank Piva 		case 3:
675*94c4a1e1SFrank Piva 			qcow2_assert(!(val >> 8));
676*94c4a1e1SFrank Piva 			((u8 *)addr)[idx] = val;
677*94c4a1e1SFrank Piva 			break;
678*94c4a1e1SFrank Piva 		case 4:
679*94c4a1e1SFrank Piva 			qcow2_assert(!(val >> 16));
680*94c4a1e1SFrank Piva 			((u16 *)addr)[idx] = cpu_to_be16(val);
681*94c4a1e1SFrank Piva 			break;
682*94c4a1e1SFrank Piva 		case 5:
683*94c4a1e1SFrank Piva 			qcow2_assert(!(val >> 32));
684*94c4a1e1SFrank Piva 			((u32 *)addr)[idx] = cpu_to_be32(val);
685*94c4a1e1SFrank Piva 			break;
686*94c4a1e1SFrank Piva 		case 6:
687*94c4a1e1SFrank Piva 			((u64 *)addr)[idx] = cpu_to_be64(val);
688*94c4a1e1SFrank Piva 			break;
689*94c4a1e1SFrank Piva 		}
690*94c4a1e1SFrank Piva 		set_dirty(idx, true);
691*94c4a1e1SFrank Piva 		if (dirty_start_idx == ((unsigned)-1))
692*94c4a1e1SFrank Piva 			dirty_start_idx = idx;
693*94c4a1e1SFrank Piva 	}
694*94c4a1e1SFrank Piva 
entry_is_dirty(u32 idx)695*94c4a1e1SFrank Piva 	bool entry_is_dirty(u32 idx) {
696*94c4a1e1SFrank Piva 		return idx >= dirty_start_idx;
697*94c4a1e1SFrank Piva 	}
698*94c4a1e1SFrank Piva 
699*94c4a1e1SFrank Piva 	Qcow2RefcountBlock(Qcow2State &qs, u64 off, u32 p_idx, u32 f);
700*94c4a1e1SFrank Piva 	void reset(Qcow2State &qs, u64 off, u32 p_idx, u32 f);
701*94c4a1e1SFrank Piva 	virtual ~Qcow2RefcountBlock();
702*94c4a1e1SFrank Piva 	virtual u64  get_entry(u32 idx);
703*94c4a1e1SFrank Piva 	virtual void set_entry(u32 idx, u64 val);
704*94c4a1e1SFrank Piva 	virtual int flush(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u64 off,
705*94c4a1e1SFrank Piva 			u32 len);
706*94c4a1e1SFrank Piva 	virtual void dump();
707*94c4a1e1SFrank Piva 	virtual void get_dirty_range(u64 *start, u64 *end);
708*94c4a1e1SFrank Piva };
709*94c4a1e1SFrank Piva 
710*94c4a1e1SFrank Piva //allocating detection needs to review!!!
711*94c4a1e1SFrank Piva class Qcow2L2Table: public Qcow2SliceMeta {
712*94c4a1e1SFrank Piva private:
713*94c4a1e1SFrank Piva 	//the two is valid only iff this slice is dirty
714*94c4a1e1SFrank Piva 	u64 dirty_start, dirty_end;
715*94c4a1e1SFrank Piva public:
get_entry_fast(u32 idx)716*94c4a1e1SFrank Piva 	u64  get_entry_fast(u32 idx) {
717*94c4a1e1SFrank Piva 		u64 val = be64_to_cpu(((const u64 *)addr)[idx]);
718*94c4a1e1SFrank Piva 
719*94c4a1e1SFrank Piva 		return val;
720*94c4a1e1SFrank Piva 	}
721*94c4a1e1SFrank Piva 
get_extended_entry(u32 idx)722*94c4a1e1SFrank Piva 	u64  get_extended_entry(u32 idx) {
723*94c4a1e1SFrank Piva 		return 0;
724*94c4a1e1SFrank Piva 	}
725*94c4a1e1SFrank Piva 
set_entry_fast(u32 idx,u64 val)726*94c4a1e1SFrank Piva 	void set_entry_fast(u32 idx, u64 val) {
727*94c4a1e1SFrank Piva 		((u64 *)addr)[idx] = cpu_to_be64(val);
728*94c4a1e1SFrank Piva 		set_dirty(idx, true);
729*94c4a1e1SFrank Piva 	}
730*94c4a1e1SFrank Piva 
entry_allocated(u64 entry)731*94c4a1e1SFrank Piva 	bool entry_allocated(u64 entry) {
732*94c4a1e1SFrank Piva 		return entry != 0;
733*94c4a1e1SFrank Piva 	}
734*94c4a1e1SFrank Piva 
entry_is_dirty(u32 idx)735*94c4a1e1SFrank Piva 	bool entry_is_dirty(u32 idx) {
736*94c4a1e1SFrank Piva 		return entry_val_is_dirty(get_entry(idx));
737*94c4a1e1SFrank Piva 	}
738*94c4a1e1SFrank Piva 
739*94c4a1e1SFrank Piva 	Qcow2L2Table(Qcow2State &qs, u64 off, u32 p_idx, u32 f);
740*94c4a1e1SFrank Piva 	void reset(Qcow2State &qs, u64 off, u32 p_idx, u32 f);
741*94c4a1e1SFrank Piva 	virtual ~Qcow2L2Table();
742*94c4a1e1SFrank Piva 	virtual u64  get_entry(u32 idx);
743*94c4a1e1SFrank Piva 	virtual void set_entry(u32 idx, u64 val);
744*94c4a1e1SFrank Piva 	virtual int flush(Qcow2State &qs, const qcow2_io_ctx_t &ioc, u64 off,
745*94c4a1e1SFrank Piva 			u32 len);
746*94c4a1e1SFrank Piva 	virtual void dump();
747*94c4a1e1SFrank Piva 	virtual void get_dirty_range(u64 *start, u64 *end);
748*94c4a1e1SFrank Piva 	//virtual int flush(Qcow2State &qs, qcow2_io_ctx_t ioc, bool auto_free = false);
749*94c4a1e1SFrank Piva 	virtual void io_done(Qcow2State &qs, const struct ublksrv_queue *q,
750*94c4a1e1SFrank Piva 			const struct io_uring_cqe *cqe);
751*94c4a1e1SFrank Piva #ifdef DEBUG_QCOW2_META_VALIDATE
752*94c4a1e1SFrank Piva 	void check(Qcow2State &qs, const char *func, int line);
753*94c4a1e1SFrank Piva 	void check_duplicated_clusters(Qcow2State &qs, int tag,
754*94c4a1e1SFrank Piva 			const char *func, int line);
755*94c4a1e1SFrank Piva #else
check(Qcow2State & qs,const char * func,int line)756*94c4a1e1SFrank Piva 	void check(Qcow2State &qs, const char *func, int line) {}
check_duplicated_clusters(Qcow2State & qs,int tag,const char * func,int line)757*94c4a1e1SFrank Piva 	void check_duplicated_clusters(Qcow2State &qs, int tag,
758*94c4a1e1SFrank Piva 			const char *func, int line) {}
759*94c4a1e1SFrank Piva #endif
760*94c4a1e1SFrank Piva };
761*94c4a1e1SFrank Piva 
762*94c4a1e1SFrank Piva #endif
763