[stgt] [PATCH] Initial SANITIZE support

FUJITA Tomonori fujita.tomonori at lab.ntt.co.jp
Thu Aug 1 00:23:39 CEST 2013


On Sun, 21 Jul 2013 11:34:21 -0700
Ronnie Sahlberg <ronniesahlberg at gmail.com> wrote:

> Add support for the SANITIZE opcode and implement
> BLOCK_ERASE (similar to UNMAP) OVERWRITE and EXIT_FAILURE_MODE
> service actions.
> 
> All commands except INQUIRY, REPORT_LUNS and REQUEST SENSE are failed
> with NOT_READY/SANITIZE_IN_PGROGRESS while a sanitize is
> active or a SANITIZE has failed but not yet been cleared.
> 
> Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
> ---
>  usr/bs_rdwr.c |  181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  usr/sbc.c     |  188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  usr/scsi.c    |    5 ++
>  usr/scsi.h    |    8 +++
>  usr/spc.c     |   48 +++++++++++++++
>  usr/spc.h     |    5 +-
>  usr/target.c  |    6 ++
>  usr/tgtd.h    |    9 +++
>  8 files changed, 444 insertions(+), 6 deletions(-)
> 
> diff --git a/usr/bs_rdwr.c b/usr/bs_rdwr.c
> index 47d2d99..148fc72 100644
> --- a/usr/bs_rdwr.c
> +++ b/usr/bs_rdwr.c
> @@ -58,6 +58,170 @@ static void bs_sync_sync_range(struct scsi_cmd *cmd, uint32_t length,
>  		set_medium_error(result, key, asc);
>  }
>  
> +static void sanitize_write_buffer(struct scsi_cmd *cmd,
> +		int buf_size, const char *buf,
> +		int *result, uint8_t *key, uint16_t *asc)
> +{
> +	uint64_t offset = 0;
> +
> +	while (offset != cmd->dev->size) {
> +		size_t count, pos;
> +
> +		if (cmd->dev->size - offset > buf_size)
> +			count = buf_size;
> +		else
> +			count = cmd->dev->size - offset;
> +
> +		pos = 0;
> +		while (pos != count) {
> +			size_t written;
> +
> +			written = pwrite64(cmd->dev->fd,
> +					buf + pos, count - pos, offset + pos);
> +			if (written == -1) {
> +				eprintf("Write failed during sanitize\n");
> +				*result = SAM_STAT_CHECK_CONDITION;
> +				*key = MEDIUM_ERROR;
> +				*asc = ASC_WRITE_ERROR;
> +				return;
> +			}
> +			pos += written;
> +			fdatasync(cmd->dev->fd);
> +		}
> +		offset += count;
> +	}
> +}
> +
> +static void sanitize_block_erase(struct scsi_cmd *cmd,
> +		int *result, uint8_t *key, uint16_t *asc)
> +{
> +	int fd = cmd->dev->fd;
> +
> +	cmd->dev->sanitize_state = LU_SANITIZE_RUNNING;
> +	if (unmap_file_region(fd, 0, cmd->dev->size) != 0) {
> +		eprintf("Failed to punch hole for"
> +			" SANITIZE"
> +			" length:%" PRIu64 "\n",
> +			cmd->dev->size);
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = HARDWARE_ERROR;
> +		*asc = ASC_INTERNAL_TGT_FAILURE;
> +		cmd->dev->sanitize_state = LU_SANITIZE_FAILURE;
> +		return;
> +	}
> +	cmd->dev->sanitize_state = LU_SANITIZE_NONE;
> +}
> +
> +#define SANITIZE_BATCHSIZE 16384
> +
> +static void sanitize_overwrite(struct scsi_cmd *cmd,
> +		int *result, uint8_t *key, uint16_t *asc)
> +{
> +	int blocksize = 1 << cmd->dev->blk_shift;
> +	char *buf;
> +	int param_len;
> +	char *param = scsi_get_out_buffer(cmd);
> +	int invert, ocount, pattern_len;
> +	int i, offset;
> +
> +	param_len = scsi_get_out_length(cmd);
> +	if (param_len <= 4 || param_len >= blocksize + 5) {
> +		eprintf("Invalid data-out size for sanitize overwrite:%d\n",
> +			param_len);
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +	invert = !!(param[0] & 0x80);
> +	ocount = param[0] & 0x1f;
> +	pattern_len = get_unaligned_be16(&param[2]);
> +
> +	if (!ocount) {
> +		eprintf("Invalid overwrite count for sanitize overwrite:%d\n",
> +			ocount);
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +	if (!pattern_len) {
> +		eprintf("Initialization pattern length was 0\n");
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +	if (pattern_len > blocksize) {
> +		eprintf("Initialization pattern length was > blocksize. " \
> +			"%d > %d\n", pattern_len, blocksize);
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +	if (pattern_len + 4 != param_len) {
> +		eprintf("Initialization pattern length does not match"
> +			" data-out size. %d but data-out is %d\n",
> +			pattern_len, param_len);
> +
> +		*result = SAM_STAT_CHECK_CONDITION;
> +		*key = ILLEGAL_REQUEST;
> +		*asc = ASC_INVALID_FIELD_IN_CDB;
> +		return;
> +	}
> +
> +
> +	cmd->dev->sanitize_state = LU_SANITIZE_RUNNING;
> +
> +	/* allocate a bunch of blocks so we can batch
> +	 * writes to the medium.
> +	 */
> +	buf = malloc(blocksize * SANITIZE_BATCHSIZE);
> +
> +	/* and fill it with the initialization pattern */
> +	offset = 0;
> +	while (offset != blocksize * SANITIZE_BATCHSIZE) {
> +		int count;
> +
> +		count = blocksize * SANITIZE_BATCHSIZE - offset;
> +		if (count > pattern_len)
> +			count = pattern_len;
> +
> +		memcpy(buf + offset, param + 4, count);
> +		offset += count;
> +	}
> +
> +	if (invert && !(ocount & 0x01)) {
> +		int j;
> +		for (j = 0; j < blocksize * SANITIZE_BATCHSIZE; j++)
> +			buf[j] = ~buf[j];
> +	}
> +
> +	for (i = 0; i < ocount; i++) {
> +		sanitize_write_buffer(cmd, blocksize * SANITIZE_BATCHSIZE,
> +			buf,
> +			result, key, asc);
> +
> +		if (invert) {
> +			int j;
> +			for (j = 0; j < blocksize * SANITIZE_BATCHSIZE; j++)
> +				buf[j] = ~buf[j];
> +		}
> +	}
> +
> +	free(buf);
> +	cmd->dev->sanitize_state = LU_SANITIZE_NONE;
> +}

Instead of adding new functions to usr/bs_rdwr.c, can we use the
existing functions for write/sync usr/bs_rdwr.c? With such way,
SANITIZE can be implemented easily with other backing store code.
--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the stgt mailing list