/* SPDX-License-Identifier: GPL-2.0 */ /* * xloop_file_fmt_qcow.h * * QCOW file format driver for the xloop device module. * * Ported QCOW2 implementation of the QEMU project (GPL-2.0): * Declarations for the QCOW2 file format. * * The copyright (C) 2004-2006 of the original code is owned by Fabrice Bellard. * * Copyright (C) 2019 Manuel Bentele */ #ifndef _LINUX_XLOOP_FILE_FMT_QCOW_H #define _LINUX_XLOOP_FILE_FMT_QCOW_H #include #include #include #include #ifdef CONFIG_ZSTD_DECOMPRESS #include #endif #ifdef CONFIG_DEBUG_FS #include #endif #include "xloop_file_fmt.h" #ifdef CONFIG_DEBUG_DRIVER #define ASSERT(x) \ do { \ if (!(x)) { \ printk(KERN_EMERG "assertion failed %s: %d: %s\n", \ __FILE__, __LINE__, #x); \ BUG(); \ } \ } while (0) #else #define ASSERT(x) do { } while (0) #endif #define KiB (1024) #define MiB (1024 * 1024) #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) #define QCOW_CRYPT_NONE 0 #define QCOW_CRYPT_AES 1 #define QCOW_CRYPT_LUKS 2 #define QCOW_MAX_CRYPT_CLUSTERS 32 #define QCOW_MAX_SNAPSHOTS 65536 /* Field widths in QCOW mean normal cluster offsets cannot reach * 64PB; depending on cluster size, compressed clusters can have a * smaller limit (64PB for up to 16k clusters, then ramps down to * 512TB for 2M clusters). */ #define QCOW_MAX_CLUSTER_OFFSET ((1ULL << 56) - 1) /* 8 MB refcount table is enough for 2 PB images at 64k cluster size * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ #define QCOW_MAX_REFTABLE_SIZE (8 * MiB) /* 32 MB L1 table is enough for 2 PB images at 64k cluster size * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ #define QCOW_MAX_L1_SIZE (32 * MiB) /* Allow for an average of 1k per snapshot table entry, should be plenty of * space for snapshot names and IDs */ #define QCOW_MAX_SNAPSHOTS_SIZE (1024 * QCOW_MAX_SNAPSHOTS) /* Bitmap header extension constraints */ #define QCOW_MAX_BITMAPS 65535 #define QCOW_MAX_BITMAP_DIRECTORY_SIZE (1024 * QCOW_MAX_BITMAPS) /* indicate that the refcount of the referenced cluster is exactly one. */ #define QCOW_OFLAG_COPIED (1ULL << 63) /* indicate that the cluster is compressed (they never have the copied flag) */ #define QCOW_OFLAG_COMPRESSED (1ULL << 62) /* The cluster reads as all zeros */ #define QCOW_OFLAG_ZERO (1ULL << 0) #define QCOW_EXTL2_SUBCLUSTERS_PER_CLUSTER 32 /* The subcluster X [0..31] is allocated */ #define QCOW_OFLAG_SUB_ALLOC(X) (1ULL << (X)) /* The subcluster X [0..31] reads as zeroes */ #define QCOW_OFLAG_SUB_ZERO(X) (QCOW_OFLAG_SUB_ALLOC(X) << 32) /* Subclusters [X, Y) (0 <= X <= Y <= 32) are allocated */ #define QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) \ (QCOW_OFLAG_SUB_ALLOC(Y) - QCOW_OFLAG_SUB_ALLOC(X)) /* Subclusters [X, Y) (0 <= X <= Y <= 32) read as zeroes */ #define QCOW_OFLAG_SUB_ZERO_RANGE(X, Y) \ (QCOW_OFLAG_SUB_ALLOC_RANGE(X, Y) << 32) /* L2 entry bitmap with all allocation bits set */ #define QCOW_L2_BITMAP_ALL_ALLOC (QCOW_OFLAG_SUB_ALLOC_RANGE(0, 32)) /* L2 entry bitmap with all "read as zeroes" bits set */ #define QCOW_L2_BITMAP_ALL_ZEROES (QCOW_OFLAG_SUB_ZERO_RANGE(0, 32)) /* Size of normal and extended L2 entries */ #define QCOW_L2E_SIZE_NORMAL (sizeof(u64)) #define QCOW_L2E_SIZE_EXTENDED (sizeof(u64) * 2) /* Size of L1 table entries */ #define QCOW_L1E_SIZE (sizeof(u64)) /* Size of reftable entries */ #define QCOW_REFTABLE_ENTRY_SIZE (sizeof(u64)) #define QCOW_MIN_CLUSTER_BITS 9 #define QCOW_MAX_CLUSTER_BITS 21 /* Defined in the qcow2 spec (compressed cluster descriptor) */ #define QCOW_COMPRESSED_SECTOR_SIZE 512U #define QCOW_COMPRESSED_SECTOR_MASK (~(QCOW_COMPRESSED_SECTOR_SIZE - 1)) /* Must be at least 2 to cover COW */ #define QCOW_MIN_L2_CACHE_SIZE 2 /* cache entries */ /* Must be at least 4 to cover all cases of refcount table growth */ #define QCOW_MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */ #define QCOW_DEFAULT_L2_CACHE_MAX_SIZE (32 * MiB) #define QCOW_DEFAULT_CACHE_CLEAN_INTERVAL 600 /* seconds */ #define QCOW_DEFAULT_CLUSTER_SIZE 65536 /* Buffer size for debugfs file buffer to display QCOW header information */ #define QCOW_HEADER_BUF_LEN 1024 /* Buffer size for debugfs file buffer to receive and display offset and * cluster offset information */ #define QCOW_OFFSET_BUF_LEN 32 #define QCOW_CLUSTER_BUF_LEN 256 struct xloop_file_fmt_qcow_header { u32 magic; u32 version; u64 backing_file_offset; u32 backing_file_size; u32 cluster_bits; u64 size; /* in bytes */ u32 crypt_method; u32 l1_size; u64 l1_table_offset; u64 refcount_table_offset; u32 refcount_table_clusters; u32 nb_snapshots; u64 snapshots_offset; /* The following fields are only valid for version >= 3 */ u64 incompatible_features; u64 compatible_features; u64 autoclear_features; u32 refcount_order; u32 header_length; /* Additional fields */ u8 compression_type; /* header must be a multiple of 8 */ u8 padding[7]; } __attribute__((packed)); struct xloop_file_fmt_qcow_snapshot_header { /* header is 8 byte aligned */ u64 l1_table_offset; u32 l1_size; u16 id_str_size; u16 name_size; u32 date_sec; u32 date_nsec; u64 vm_clock_nsec; u32 vm_state_size; /* Size of all extra data, including QCowSnapshotExtraData if available */ u32 extra_data_size; /* Data beyond QCowSnapshotExtraData, if any */ void *unknown_extra_data; } __attribute__((packed)); enum { QCOW_FEAT_TYPE_INCOMPATIBLE = 0, QCOW_FEAT_TYPE_COMPATIBLE = 1, QCOW_FEAT_TYPE_AUTOCLEAR = 2, }; /* incompatible feature bits */ enum { QCOW_INCOMPAT_DIRTY_BITNR = 0, QCOW_INCOMPAT_CORRUPT_BITNR = 1, QCOW_INCOMPAT_DATA_FILE_BITNR = 2, QCOW_INCOMPAT_COMPRESSION_BITNR = 3, QCOW_INCOMPAT_EXTL2_BITNR = 4, QCOW_INCOMPAT_DIRTY = 1 << QCOW_INCOMPAT_DIRTY_BITNR, QCOW_INCOMPAT_CORRUPT = 1 << QCOW_INCOMPAT_CORRUPT_BITNR, QCOW_INCOMPAT_DATA_FILE = 1 << QCOW_INCOMPAT_DATA_FILE_BITNR, QCOW_INCOMPAT_COMPRESSION = 1 << QCOW_INCOMPAT_COMPRESSION_BITNR, QCOW_INCOMPAT_EXTL2 = 1 << QCOW_INCOMPAT_EXTL2_BITNR, QCOW_INCOMPAT_MASK = QCOW_INCOMPAT_DIRTY | QCOW_INCOMPAT_CORRUPT | QCOW_INCOMPAT_DATA_FILE | QCOW_INCOMPAT_COMPRESSION | QCOW_INCOMPAT_EXTL2, }; /* compatible feature bits */ enum { QCOW_COMPAT_LAZY_REFCOUNTS_BITNR = 0, QCOW_COMPAT_LAZY_REFCOUNTS = 1 << QCOW_COMPAT_LAZY_REFCOUNTS_BITNR, QCOW_COMPAT_FEAT_MASK = QCOW_COMPAT_LAZY_REFCOUNTS, }; /* autoclear feature bits */ enum { QCOW_AUTOCLEAR_BITMAPS_BITNR = 0, QCOW_AUTOCLEAR_DATA_FILE_RAW_BITNR = 1, QCOW_AUTOCLEAR_BITMAPS = 1 << QCOW_AUTOCLEAR_BITMAPS_BITNR, QCOW_AUTOCLEAR_DATA_FILE_RAW = 1 << QCOW_AUTOCLEAR_DATA_FILE_RAW_BITNR, QCOW_AUTOCLEAR_MASK = QCOW_AUTOCLEAR_BITMAPS | QCOW_AUTOCLEAR_DATA_FILE_RAW, }; enum xloop_file_fmt_qcow_compression_type { QCOW_COMPRESSION_TYPE_ZLIB, QCOW_COMPRESSION_TYPE_ZSTD, }; struct xloop_file_fmt_qcow_data { u64 size; int cluster_bits; int cluster_size; int l2_slice_size; int subcluster_bits; int subcluster_size; int subclusters_per_cluster; int l2_bits; int l2_size; int l1_size; int l1_vm_state_index; int refcount_block_bits; int refcount_block_size; int csize_shift; int csize_mask; u64 cluster_offset_mask; u64 l1_table_offset; u64 *l1_table; struct xloop_file_fmt_qcow_cache *l2_table_cache; struct xloop_file_fmt_qcow_cache *refcount_block_cache; u64 *refcount_table; u64 refcount_table_offset; u32 refcount_table_size; u32 max_refcount_table_index; /* Last used entry in refcount_table */ u64 free_cluster_index; u64 free_byte_offset; u32 crypt_method_header; u64 snapshots_offset; int snapshots_size; unsigned int nb_snapshots; u32 nb_bitmaps; u64 bitmap_directory_size; u64 bitmap_directory_offset; int qcow_version; bool use_lazy_refcounts; int refcount_order; int refcount_bits; u64 refcount_max; u64 incompatible_features; u64 compatible_features; u64 autoclear_features; /* ZLIB specific data */ z_streamp zlib_dstrm; /* ZSTD specific data */ #ifdef CONFIG_ZSTD_DECOMPRESS void *zstd_dworkspace; ZSTD_DStream *zstd_dstrm; #endif /* used to cache last compressed QCOW cluster */ u8 *cmp_out_buf; u64 cmp_last_coffset; /* * Compression type used for the image. Default: 0 - ZLIB * The image compression type is set on image creation. * For now, the only way to change the compression type * is to convert the image with the desired compression type set. */ enum xloop_file_fmt_qcow_compression_type compression_type; /* debugfs entries */ #ifdef CONFIG_DEBUG_FS struct dentry *dbgfs_dir; struct dentry *dbgfs_file_qcow_header; char dbgfs_file_qcow_header_buf[QCOW_HEADER_BUF_LEN]; struct dentry *dbgfs_file_qcow_offset; char dbgfs_file_qcow_offset_buf[QCOW_OFFSET_BUF_LEN]; char dbgfs_file_qcow_cluster_buf[QCOW_CLUSTER_BUF_LEN]; u64 dbgfs_qcow_offset; struct mutex dbgfs_qcow_offset_mutex; #endif }; struct xloop_file_fmt_qcow_cow_region { /** * Offset of the COW region in bytes from the start of the first * cluster touched by the request. */ unsigned offset; /** Number of bytes to copy */ unsigned nb_bytes; }; /* * In images with standard L2 entries all clusters are treated as if * they had one subcluster so xloop_file_fmt_qcow_cluster_type and * xloop_file_fmt_qcow_subcluster_type can be mapped to each other and * have the exact same meaning (QCOW_SUBCLUSTER_UNALLOCATED_ALLOC cannot * happen in these images). * * In images with extended L2 entries xloop_file_fmt_qcow_cluster_type * refers to the complete cluster and xloop_file_fmt_qcow_subcluster_type * to each of the individual subclusters, so there are several possible * combinations: * * |--------------+---------------------------| * | Cluster type | Possible subcluster types | * |--------------+---------------------------| * | UNALLOCATED | UNALLOCATED_PLAIN | * | | ZERO_PLAIN | * |--------------+---------------------------| * | NORMAL | UNALLOCATED_ALLOC | * | | ZERO_ALLOC | * | | NORMAL | * |--------------+---------------------------| * | COMPRESSED | COMPRESSED | * |--------------+---------------------------| * * QCOW_SUBCLUSTER_INVALID means that the L2 entry is incorrect and * the image should be marked corrupt. */ enum xloop_file_fmt_qcow_cluster_type { QCOW_CLUSTER_UNALLOCATED, QCOW_CLUSTER_ZERO_PLAIN, QCOW_CLUSTER_ZERO_ALLOC, QCOW_CLUSTER_NORMAL, QCOW_CLUSTER_COMPRESSED, }; enum xloop_file_fmt_qcow_subcluster_type { QCOW_SUBCLUSTER_UNALLOCATED_PLAIN, QCOW_SUBCLUSTER_UNALLOCATED_ALLOC, QCOW_SUBCLUSTER_ZERO_PLAIN, QCOW_SUBCLUSTER_ZERO_ALLOC, QCOW_SUBCLUSTER_NORMAL, QCOW_SUBCLUSTER_COMPRESSED, QCOW_SUBCLUSTER_INVALID, }; enum xloop_file_fmt_qcow_metadata_overlap { QCOW_OL_MAIN_HEADER_BITNR = 0, QCOW_OL_ACTIVE_L1_BITNR = 1, QCOW_OL_ACTIVE_L2_BITNR = 2, QCOW_OL_REFCOUNT_TABLE_BITNR = 3, QCOW_OL_REFCOUNT_BLOCK_BITNR = 4, QCOW_OL_SNAPSHOT_TABLE_BITNR = 5, QCOW_OL_INACTIVE_L1_BITNR = 6, QCOW_OL_INACTIVE_L2_BITNR = 7, QCOW_OL_BITMAP_DIRECTORY_BITNR = 8, QCOW_OL_MAX_BITNR = 9, QCOW_OL_NONE = 0, QCOW_OL_MAIN_HEADER = (1 << QCOW_OL_MAIN_HEADER_BITNR), QCOW_OL_ACTIVE_L1 = (1 << QCOW_OL_ACTIVE_L1_BITNR), QCOW_OL_ACTIVE_L2 = (1 << QCOW_OL_ACTIVE_L2_BITNR), QCOW_OL_REFCOUNT_TABLE = (1 << QCOW_OL_REFCOUNT_TABLE_BITNR), QCOW_OL_REFCOUNT_BLOCK = (1 << QCOW_OL_REFCOUNT_BLOCK_BITNR), QCOW_OL_SNAPSHOT_TABLE = (1 << QCOW_OL_SNAPSHOT_TABLE_BITNR), QCOW_OL_INACTIVE_L1 = (1 << QCOW_OL_INACTIVE_L1_BITNR), /* NOTE: Checking overlaps with inactive L2 tables will result in bdrv * reads. */ QCOW_OL_INACTIVE_L2 = (1 << QCOW_OL_INACTIVE_L2_BITNR), QCOW_OL_BITMAP_DIRECTORY = (1 << QCOW_OL_BITMAP_DIRECTORY_BITNR), }; /* Perform all overlap checks which can be done in constant time */ #define QCOW_OL_CONSTANT \ (QCOW_OL_MAIN_HEADER | QCOW_OL_ACTIVE_L1 | QCOW_OL_REFCOUNT_TABLE | \ QCOW_OL_SNAPSHOT_TABLE | QCOW_OL_BITMAP_DIRECTORY) /* Perform all overlap checks which don't require disk access */ #define QCOW_OL_CACHED \ (QCOW_OL_CONSTANT | QCOW_OL_ACTIVE_L2 | QCOW_OL_REFCOUNT_BLOCK | \ QCOW_OL_INACTIVE_L1) /* Perform all overlap checks */ #define QCOW_OL_ALL \ (QCOW_OL_CACHED | QCOW_OL_INACTIVE_L2) #define QCOW_L1E_OFFSET_MASK 0x00fffffffffffe00ULL #define QCOW_L2E_OFFSET_MASK 0x00fffffffffffe00ULL #define QCOW_L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL static inline bool xloop_file_fmt_qcow_has_subclusters( struct xloop_file_fmt_qcow_data *qcow_data) { return qcow_data->incompatible_features & QCOW_INCOMPAT_EXTL2; } static inline size_t xloop_file_fmt_qcow_l2_entry_size( struct xloop_file_fmt_qcow_data *qcow_data) { return xloop_file_fmt_qcow_has_subclusters(qcow_data) ? QCOW_L2E_SIZE_EXTENDED : QCOW_L2E_SIZE_NORMAL; } static inline u64 xloop_file_fmt_qcow_get_l2_entry( struct xloop_file_fmt_qcow_data *qcow_data, u64 *l2_slice, int idx) { idx *= xloop_file_fmt_qcow_l2_entry_size(qcow_data) / sizeof(u64); return be64_to_cpu(l2_slice[idx]); } static inline u64 xloop_file_fmt_qcow_get_l2_bitmap( struct xloop_file_fmt_qcow_data *qcow_data, u64 *l2_slice, int idx) { if (xloop_file_fmt_qcow_has_subclusters(qcow_data)) { idx *= xloop_file_fmt_qcow_l2_entry_size(qcow_data) / sizeof(u64); return be64_to_cpu(l2_slice[idx + 1]); } else { return 0; /* For convenience only; this value has no meaning. */ } } static inline bool xloop_file_fmt_qcow_has_data_file( struct xloop_file_fmt_qcow_data *qcow_data) { /* At the moment, there is no support for copy on write! */ return false; } static inline bool xloop_file_fmt_qcow_data_file_is_raw( struct xloop_file_fmt_qcow_data *qcow_data) { return !!(qcow_data->autoclear_features & QCOW_AUTOCLEAR_DATA_FILE_RAW); } static inline s64 xloop_file_fmt_qcow_start_of_cluster( struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return offset & ~(qcow_data->cluster_size - 1); } static inline s64 xloop_file_fmt_qcow_offset_into_cluster( struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return offset & (qcow_data->cluster_size - 1); } static inline s64 xloop_file_fmt_qcow_offset_into_subcluster( struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return offset & (qcow_data->subcluster_size - 1); } static inline s64 xloop_file_fmt_qcow_size_to_clusters( struct xloop_file_fmt_qcow_data *qcow_data, u64 size) { return (size + (qcow_data->cluster_size - 1)) >> qcow_data->cluster_bits; } static inline s64 xloop_file_fmt_qcow_size_to_l1( struct xloop_file_fmt_qcow_data *qcow_data, s64 size) { int shift = qcow_data->cluster_bits + qcow_data->l2_bits; return (size + (1ULL << shift) - 1) >> shift; } static inline int xloop_file_fmt_qcow_offset_to_l1_index( struct xloop_file_fmt_qcow_data *qcow_data, u64 offset) { return offset >> (qcow_data->l2_bits + qcow_data->cluster_bits); } static inline int xloop_file_fmt_qcow_offset_to_l2_index( struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return (offset >> qcow_data->cluster_bits) & (qcow_data->l2_size - 1); } static inline int xloop_file_fmt_qcow_offset_to_l2_slice_index( struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return (offset >> qcow_data->cluster_bits) & (qcow_data->l2_slice_size - 1); } static inline int xloop_file_fmt_qcow_offset_to_sc_index( struct xloop_file_fmt_qcow_data *qcow_data, s64 offset) { return (offset >> qcow_data->subcluster_bits) & (qcow_data->subclusters_per_cluster - 1); } static inline s64 xloop_file_fmt_qcow_vm_state_offset( struct xloop_file_fmt_qcow_data *qcow_data) { return (s64)qcow_data->l1_vm_state_index << (qcow_data->cluster_bits + qcow_data->l2_bits); } static inline enum xloop_file_fmt_qcow_cluster_type xloop_file_fmt_qcow_get_cluster_type(struct xloop_file_fmt *xlo_fmt, u64 l2_entry) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; if (l2_entry & QCOW_OFLAG_COMPRESSED) { return QCOW_CLUSTER_COMPRESSED; } else if (l2_entry & QCOW_OFLAG_ZERO) { if (l2_entry & QCOW_L2E_OFFSET_MASK) { return QCOW_CLUSTER_ZERO_ALLOC; } return QCOW_CLUSTER_ZERO_PLAIN; } else if (!(l2_entry & QCOW_L2E_OFFSET_MASK)) { /* Offset 0 generally means unallocated, but it is ambiguous * with external data files because 0 is a valid offset there. * However, all clusters in external data files always have * refcount 1, so we can rely on QCOW_OFLAG_COPIED to * disambiguate. */ if (xloop_file_fmt_qcow_has_data_file(qcow_data) && (l2_entry & QCOW_OFLAG_COPIED)) { return QCOW_CLUSTER_NORMAL; } else { return QCOW_CLUSTER_UNALLOCATED; } } else { return QCOW_CLUSTER_NORMAL; } } /* * In an image without subsclusters @l2_bitmap is ignored and * @sc_index must be 0. * Return QCOW_SUBCLUSTER_INVALID if an invalid l2 entry is detected * (this checks the whole entry and bitmap, not only the bits related * to subcluster @sc_index). */ static inline enum xloop_file_fmt_qcow_subcluster_type xloop_file_fmt_qcow_get_subcluster_type(struct xloop_file_fmt *xlo_fmt, u64 l2_entry, u64 l2_bitmap, unsigned int sc_index) { struct xloop_file_fmt_qcow_data *qcow_data = xlo_fmt->private_data; enum xloop_file_fmt_qcow_cluster_type type = xloop_file_fmt_qcow_get_cluster_type(xlo_fmt, l2_entry); ASSERT(sc_index < qcow_data->subclusters_per_cluster); if (xloop_file_fmt_qcow_has_subclusters(qcow_data)) { switch (type) { case QCOW_CLUSTER_COMPRESSED: return QCOW_SUBCLUSTER_COMPRESSED; case QCOW_CLUSTER_NORMAL: if ((l2_bitmap >> 32) & l2_bitmap) { return QCOW_SUBCLUSTER_INVALID; } else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) { return QCOW_SUBCLUSTER_ZERO_ALLOC; } else if (l2_bitmap & QCOW_OFLAG_SUB_ALLOC(sc_index)) { return QCOW_SUBCLUSTER_NORMAL; } else { return QCOW_SUBCLUSTER_UNALLOCATED_ALLOC; } case QCOW_CLUSTER_UNALLOCATED: if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) { return QCOW_SUBCLUSTER_INVALID; } else if (l2_bitmap & QCOW_OFLAG_SUB_ZERO(sc_index)) { return QCOW_SUBCLUSTER_ZERO_PLAIN; } else { return QCOW_SUBCLUSTER_UNALLOCATED_PLAIN; } default: /* not reachable */ ASSERT(false); return QCOW_SUBCLUSTER_INVALID; } } else { switch (type) { case QCOW_CLUSTER_COMPRESSED: return QCOW_SUBCLUSTER_COMPRESSED; case QCOW_CLUSTER_ZERO_PLAIN: return QCOW_SUBCLUSTER_ZERO_PLAIN; case QCOW_CLUSTER_ZERO_ALLOC: return QCOW_SUBCLUSTER_ZERO_ALLOC; case QCOW_CLUSTER_NORMAL: return QCOW_SUBCLUSTER_NORMAL; case QCOW_CLUSTER_UNALLOCATED: return QCOW_SUBCLUSTER_UNALLOCATED_PLAIN; default: /* not reachable */ ASSERT(false); return QCOW_SUBCLUSTER_INVALID; } } } #ifdef CONFIG_DEBUG_FS static inline const char *xloop_file_fmt_qcow_get_subcluster_name( const enum xloop_file_fmt_qcow_subcluster_type type) { static const char *subcluster_names[] = { "QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN", "QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC", "QCOW2_SUBCLUSTER_ZERO_PLAIN", "QCOW2_SUBCLUSTER_ZERO_ALLOC", "QCOW2_SUBCLUSTER_NORMAL", "QCOW2_SUBCLUSTER_COMPRESSED", "QCOW2_SUBCLUSTER_INVALID" }; return subcluster_names[type]; } #endif #endif