mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 18:43:33 +02:00
ublk: support UBLK_PARAM_TYPE_INTEGRITY in device creation
Add a feature flag UBLK_F_INTEGRITY for a ublk server to request integrity/metadata support when creating a ublk device. The ublk server can also check for the feature flag on the created device or the result of UBLK_U_CMD_GET_FEATURES to tell if the ublk driver supports it. UBLK_F_INTEGRITY requires UBLK_F_USER_COPY, as user copy is the only data copy mode initially supported for integrity data. Add UBLK_PARAM_TYPE_INTEGRITY and struct ublk_param_integrity to struct ublk_params to specify the integrity params of a ublk device. UBLK_PARAM_TYPE_INTEGRITY requires UBLK_F_INTEGRITY and a nonzero metadata_size. The LBMD_PI_CAP_* and LBMD_PI_CSUM_* values from the linux/fs.h UAPI header are used for the flags and csum_type fields. If the UBLK_PARAM_TYPE_INTEGRITY flag is set, validate the integrity parameters and apply them to the blk_integrity limits. The struct ublk_param_integrity validations are based on the checks in blk_validate_integrity_limits(). Any invalid parameters should be rejected before being applied to struct blk_integrity. [csander: drop redundant pi_tuple_size field, use block metadata UAPI constants, add param validation] Signed-off-by: Stanley Zhang <stazhang@purestorage.com> Signed-off-by: Caleb Sander Mateos <csander@purestorage.com> Reviewed-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
e859e7c26a
commit
98bf225685
|
|
@ -44,6 +44,8 @@
|
|||
#include <linux/task_work.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/blk-integrity.h>
|
||||
#include <uapi/linux/fs.h>
|
||||
#include <uapi/linux/ublk_cmd.h>
|
||||
|
||||
#define UBLK_MINORS (1U << MINORBITS)
|
||||
|
|
@ -83,7 +85,8 @@
|
|||
#define UBLK_PARAM_TYPE_ALL \
|
||||
(UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD | \
|
||||
UBLK_PARAM_TYPE_DEVT | UBLK_PARAM_TYPE_ZONED | \
|
||||
UBLK_PARAM_TYPE_DMA_ALIGN | UBLK_PARAM_TYPE_SEGMENT)
|
||||
UBLK_PARAM_TYPE_DMA_ALIGN | UBLK_PARAM_TYPE_SEGMENT | \
|
||||
UBLK_PARAM_TYPE_INTEGRITY)
|
||||
|
||||
struct ublk_uring_cmd_pdu {
|
||||
/*
|
||||
|
|
@ -301,6 +304,11 @@ static inline bool ublk_queue_is_zoned(const struct ublk_queue *ubq)
|
|||
return ubq->flags & UBLK_F_ZONED;
|
||||
}
|
||||
|
||||
static inline bool ublk_dev_support_integrity(const struct ublk_device *ub)
|
||||
{
|
||||
return ub->dev_info.flags & UBLK_F_INTEGRITY;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_ZONED
|
||||
|
||||
struct ublk_zoned_report_desc {
|
||||
|
|
@ -616,6 +624,53 @@ static void ublk_dev_param_basic_apply(struct ublk_device *ub)
|
|||
set_capacity(ub->ub_disk, p->dev_sectors);
|
||||
}
|
||||
|
||||
static int ublk_integrity_flags(u32 flags)
|
||||
{
|
||||
int ret_flags = 0;
|
||||
|
||||
if (flags & LBMD_PI_CAP_INTEGRITY) {
|
||||
flags &= ~LBMD_PI_CAP_INTEGRITY;
|
||||
ret_flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
|
||||
}
|
||||
if (flags & LBMD_PI_CAP_REFTAG) {
|
||||
flags &= ~LBMD_PI_CAP_REFTAG;
|
||||
ret_flags |= BLK_INTEGRITY_REF_TAG;
|
||||
}
|
||||
return flags ? -EINVAL : ret_flags;
|
||||
}
|
||||
|
||||
static int ublk_integrity_pi_tuple_size(u8 csum_type)
|
||||
{
|
||||
switch (csum_type) {
|
||||
case LBMD_PI_CSUM_NONE:
|
||||
return 0;
|
||||
case LBMD_PI_CSUM_IP:
|
||||
case LBMD_PI_CSUM_CRC16_T10DIF:
|
||||
return 8;
|
||||
case LBMD_PI_CSUM_CRC64_NVME:
|
||||
return 16;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static enum blk_integrity_checksum ublk_integrity_csum_type(u8 csum_type)
|
||||
{
|
||||
switch (csum_type) {
|
||||
case LBMD_PI_CSUM_NONE:
|
||||
return BLK_INTEGRITY_CSUM_NONE;
|
||||
case LBMD_PI_CSUM_IP:
|
||||
return BLK_INTEGRITY_CSUM_IP;
|
||||
case LBMD_PI_CSUM_CRC16_T10DIF:
|
||||
return BLK_INTEGRITY_CSUM_CRC;
|
||||
case LBMD_PI_CSUM_CRC64_NVME:
|
||||
return BLK_INTEGRITY_CSUM_CRC64;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return BLK_INTEGRITY_CSUM_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static int ublk_validate_params(const struct ublk_device *ub)
|
||||
{
|
||||
/* basic param is the only one which must be set */
|
||||
|
|
@ -678,6 +733,29 @@ static int ublk_validate_params(const struct ublk_device *ub)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ub->params.types & UBLK_PARAM_TYPE_INTEGRITY) {
|
||||
const struct ublk_param_integrity *p = &ub->params.integrity;
|
||||
int pi_tuple_size = ublk_integrity_pi_tuple_size(p->csum_type);
|
||||
int flags = ublk_integrity_flags(p->flags);
|
||||
|
||||
if (!ublk_dev_support_integrity(ub))
|
||||
return -EINVAL;
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
if (pi_tuple_size < 0)
|
||||
return pi_tuple_size;
|
||||
if (!p->metadata_size)
|
||||
return -EINVAL;
|
||||
if (p->csum_type == LBMD_PI_CSUM_NONE &&
|
||||
p->flags & LBMD_PI_CAP_REFTAG)
|
||||
return -EINVAL;
|
||||
if (p->pi_offset + pi_tuple_size > p->metadata_size)
|
||||
return -EINVAL;
|
||||
if (p->interval_exp < SECTOR_SHIFT ||
|
||||
p->interval_exp > ub->params.basic.logical_bs_shift)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2950,6 +3028,23 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
|
|||
lim.max_segments = ub->params.seg.max_segments;
|
||||
}
|
||||
|
||||
if (ub->params.types & UBLK_PARAM_TYPE_INTEGRITY) {
|
||||
const struct ublk_param_integrity *p = &ub->params.integrity;
|
||||
int pi_tuple_size = ublk_integrity_pi_tuple_size(p->csum_type);
|
||||
|
||||
lim.max_integrity_segments =
|
||||
p->max_integrity_segments ?: USHRT_MAX;
|
||||
lim.integrity = (struct blk_integrity) {
|
||||
.flags = ublk_integrity_flags(p->flags),
|
||||
.csum_type = ublk_integrity_csum_type(p->csum_type),
|
||||
.metadata_size = p->metadata_size,
|
||||
.pi_offset = p->pi_offset,
|
||||
.interval_exp = p->interval_exp,
|
||||
.tag_size = p->tag_size,
|
||||
.pi_tuple_size = pi_tuple_size,
|
||||
};
|
||||
}
|
||||
|
||||
if (wait_for_completion_interruptible(&ub->completion) != 0)
|
||||
return -EINTR;
|
||||
|
||||
|
|
@ -3140,6 +3235,10 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* User copy is required to access integrity buffer */
|
||||
if (info.flags & UBLK_F_INTEGRITY && !(info.flags & UBLK_F_USER_COPY))
|
||||
return -EINVAL;
|
||||
|
||||
/* the created device is always owned by current user */
|
||||
ublk_store_owner_uid_gid(&info.owner_uid, &info.owner_gid);
|
||||
|
||||
|
|
|
|||
|
|
@ -311,6 +311,12 @@
|
|||
*/
|
||||
#define UBLK_F_BUF_REG_OFF_DAEMON (1ULL << 14)
|
||||
|
||||
/*
|
||||
* ublk device supports requests with integrity/metadata buffer.
|
||||
* Requires UBLK_F_USER_COPY.
|
||||
*/
|
||||
#define UBLK_F_INTEGRITY (1ULL << 16)
|
||||
|
||||
/* device state */
|
||||
#define UBLK_S_DEV_DEAD 0
|
||||
#define UBLK_S_DEV_LIVE 1
|
||||
|
|
@ -600,6 +606,17 @@ struct ublk_param_segment {
|
|||
__u8 pad[2];
|
||||
};
|
||||
|
||||
struct ublk_param_integrity {
|
||||
__u32 flags; /* LBMD_PI_CAP_* from linux/fs.h */
|
||||
__u16 max_integrity_segments; /* 0 means no limit */
|
||||
__u8 interval_exp;
|
||||
__u8 metadata_size; /* UBLK_PARAM_TYPE_INTEGRITY requires nonzero */
|
||||
__u8 pi_offset;
|
||||
__u8 csum_type; /* LBMD_PI_CSUM_* from linux/fs.h */
|
||||
__u8 tag_size;
|
||||
__u8 pad[5];
|
||||
};
|
||||
|
||||
struct ublk_params {
|
||||
/*
|
||||
* Total length of parameters, userspace has to set 'len' for both
|
||||
|
|
@ -614,6 +631,7 @@ struct ublk_params {
|
|||
#define UBLK_PARAM_TYPE_ZONED (1 << 3)
|
||||
#define UBLK_PARAM_TYPE_DMA_ALIGN (1 << 4)
|
||||
#define UBLK_PARAM_TYPE_SEGMENT (1 << 5)
|
||||
#define UBLK_PARAM_TYPE_INTEGRITY (1 << 6) /* requires UBLK_F_INTEGRITY */
|
||||
__u32 types; /* types of parameter included */
|
||||
|
||||
struct ublk_param_basic basic;
|
||||
|
|
@ -622,6 +640,7 @@ struct ublk_params {
|
|||
struct ublk_param_zoned zoned;
|
||||
struct ublk_param_dma_align dma;
|
||||
struct ublk_param_segment seg;
|
||||
struct ublk_param_integrity integrity;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user