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