Skip to content

Commit

Permalink
scsi: target: iblock: Report space allocation errors
Browse files Browse the repository at this point in the history
When a thin provisioned block device lacks free LBA it ends bio requests
with BLK_STS_NOSPC. Currently iblock treats bio status as a boolean and
terminates failed requests with LOGICAL UNIT COMMUNICATION FAILURE if
the status is non-zero. Thus, initiators see space allocation errors as
I/O errors.

This commit modifies the iblock_req structure to store the status of the
first failed bio instead of the total number of failed bios. The status
is then used to set the specific sense reason.

For BLK_STS_NOSPC the sense reason is set to TCM_SPACE_ALLOCATION_FAILED
as per SBC-3 4.7.3.6.

On Linux initiators:

old:

  $ dd if=/dev/zero of=/dev/sda oflag=direct bs=4k count=1
  dd: error writing '/dev/sda': I/O error

new:

  $ dd if=/dev/zero of=/dev/sda oflag=direct bs=4k count=1
  dd: error writing '/dev/sda': No space left on device

Signed-off-by: Konstantin Shelekhin <k.shelekhin@yadro.com>
Reviewed-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
  • Loading branch information
Konstantin Shelekhin authored and intel-lab-lkp committed Oct 20, 2021
1 parent 7e0ade7 commit 15d4d8f
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 5 deletions.
24 changes: 20 additions & 4 deletions drivers/target/target_core_iblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,20 +305,35 @@ static unsigned long long iblock_emulate_read_cap_with_block_size(
return blocks_long;
}

static sense_reason_t iblock_blk_status_to_reason(blk_status_t status)
{
switch (status) {
case BLK_STS_OK:
return TCM_NO_SENSE;
case BLK_STS_NOSPC:
return TCM_SPACE_ALLOCATION_FAILED;
default:
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
}

static void iblock_complete_cmd(struct se_cmd *cmd)
{
struct iblock_req *ibr = cmd->priv;
u8 status;
sense_reason_t reason;

if (!refcount_dec_and_test(&ibr->pending))
return;

if (atomic_read(&ibr->ib_bio_err_cnt))
reason = iblock_blk_status_to_reason(atomic_read(&ibr->status));

if (reason != TCM_NO_SENSE)
status = SAM_STAT_CHECK_CONDITION;
else
status = SAM_STAT_GOOD;

target_complete_cmd(cmd, status);
target_complete_cmd_with_sense(cmd, status, reason);
kfree(ibr);
}

Expand All @@ -330,9 +345,10 @@ static void iblock_bio_done(struct bio *bio)
if (bio->bi_status) {
pr_err("bio error: %p, err: %d\n", bio, bio->bi_status);
/*
* Bump the ib_bio_err_cnt and release bio.
* Set the error status of the iblock request to the error
* status of the first failed bio.
*/
atomic_inc(&ibr->ib_bio_err_cnt);
atomic_cmpxchg(&ibr->status, BLK_STS_OK, bio->bi_status);
smp_mb__after_atomic();
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/target/target_core_iblock.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

struct iblock_req {
refcount_t pending;
atomic_t ib_bio_err_cnt;
atomic_t status;
} ____cacheline_aligned;

#define IBDF_HAS_UDEV_PATH 0x01
Expand Down

0 comments on commit 15d4d8f

Please sign in to comment.