Add support for reporting the Deallocated or Unwritten Logical Block Error (DULBE). Rely on the block status flags reported by the block layer and consider any block with the BDRV_BLOCK_ZERO flag to be deallocated. Multiple factors affect when a Write Zeroes command result in deallocation of blocks. * the underlying file system block size * the blockdev format * the 'discard' and 'logical_block_size' parameters format | discard | wz (512B) wz (4KiB) wz (64KiB) ----------------------------------------------------- qcow2 ignore n n y qcow2 unmap n n y raw ignore n y y raw unmap n y y So, this works best with an image in raw format and 4KiB LBAs, since holes can then be punched on a per-block basis (this assumes a file system with a 4kb block size, YMMV). A qcow2 image, uses a cluster size of 64KiB by default and blocks will only be marked deallocated if a full cluster is zeroed or discarded. However, this *is* consistent with the spec since Write Zeroes "should" deallocate the block if the Deallocate attribute is set and "may" deallocate if the Deallocate attribute is not set. Thus, we always try to deallocate (the BDRV_REQ_MAY_UNMAP flag is always set). Signed-off-by: Klaus Jensen <k.jensen@samsung.com> Reviewed-by: Keith Busch <kbusch@kernel.org>
79 lines
1.7 KiB
C
79 lines
1.7 KiB
C
/*
|
|
* QEMU NVM Express Virtual Namespace
|
|
*
|
|
* Copyright (c) 2019 CNEX Labs
|
|
* Copyright (c) 2020 Samsung Electronics
|
|
*
|
|
* Authors:
|
|
* Klaus Jensen <k.jensen@samsung.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See the
|
|
* COPYING file in the top-level directory.
|
|
*
|
|
*/
|
|
|
|
#ifndef NVME_NS_H
|
|
#define NVME_NS_H
|
|
|
|
#define TYPE_NVME_NS "nvme-ns"
|
|
#define NVME_NS(obj) \
|
|
OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
|
|
|
|
typedef struct NvmeNamespaceParams {
|
|
uint32_t nsid;
|
|
} NvmeNamespaceParams;
|
|
|
|
typedef struct NvmeNamespace {
|
|
DeviceState parent_obj;
|
|
BlockConf blkconf;
|
|
int32_t bootindex;
|
|
int64_t size;
|
|
NvmeIdNs id_ns;
|
|
|
|
NvmeNamespaceParams params;
|
|
|
|
struct {
|
|
uint32_t err_rec;
|
|
} features;
|
|
} NvmeNamespace;
|
|
|
|
static inline uint32_t nvme_nsid(NvmeNamespace *ns)
|
|
{
|
|
if (ns) {
|
|
return ns->params.nsid;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns)
|
|
{
|
|
NvmeIdNs *id_ns = &ns->id_ns;
|
|
return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
|
|
}
|
|
|
|
static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
|
|
{
|
|
return nvme_ns_lbaf(ns)->ds;
|
|
}
|
|
|
|
/* calculate the number of LBAs that the namespace can accomodate */
|
|
static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns)
|
|
{
|
|
return ns->size >> nvme_ns_lbads(ns);
|
|
}
|
|
|
|
/* convert an LBA to the equivalent in bytes */
|
|
static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
|
|
{
|
|
return lba << nvme_ns_lbads(ns);
|
|
}
|
|
|
|
typedef struct NvmeCtrl NvmeCtrl;
|
|
|
|
int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
|
|
void nvme_ns_drain(NvmeNamespace *ns);
|
|
void nvme_ns_flush(NvmeNamespace *ns);
|
|
|
|
#endif /* NVME_NS_H */
|