From 4fc18ff9bb50ce6675619acb03b94c809b91a2c8 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Wed, 29 Oct 2014 03:14:29 +0000 Subject: [PATCH] Implement better handling for ENOSPC error for both CTL and CAM. This makes VMWare VAAI Thin Provisioning Stun primitive activate, pausing the virtual machine, when backing storage (ZFS pool) is getting overflowed. MFC after: 1 week Sponsored by: iXsystems, Inc. --- sys/cam/ctl/ctl_backend_block.c | 17 ++++++++++------- sys/cam/ctl/ctl_error.c | 12 ++++++++++++ sys/cam/ctl/ctl_error.h | 1 + sys/cam/scsi/scsi_all.c | 2 +- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c index 2d3c368bf83..0cce29f3979 100644 --- a/sys/cam/ctl/ctl_backend_block.c +++ b/sys/cam/ctl/ctl_backend_block.c @@ -501,6 +501,8 @@ ctl_be_block_biodone(struct bio *bio) if (beio->num_errors > 0) { if (error == EOPNOTSUPP) { ctl_set_invalid_opcode(&io->scsiio); + } else if (error == ENOSPC) { + ctl_set_space_alloc_fail(&io->scsiio); } else if (beio->bio_cmd == BIO_FLUSH) { /* XXX KDM is there is a better error here? */ ctl_set_internal_failure(&io->scsiio, @@ -711,14 +713,12 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, char path_str[32]; ctl_scsi_path_string(io, path_str, sizeof(path_str)); - /* - * XXX KDM ZFS returns ENOSPC when the underlying - * filesystem fills up. What kind of SCSI error should we - * return for that? - */ printf("%s%s command returned errno %d\n", path_str, (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", error); - ctl_set_medium_error(&io->scsiio); + if (error == ENOSPC) { + ctl_set_space_alloc_fail(&io->scsiio); + } else + ctl_set_medium_error(&io->scsiio); ctl_complete_beio(beio); return; } @@ -804,7 +804,10 @@ ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, * return the I/O to the user. */ if (error != 0) { - ctl_set_medium_error(&io->scsiio); + if (error == ENOSPC) { + ctl_set_space_alloc_fail(&io->scsiio); + } else + ctl_set_medium_error(&io->scsiio); ctl_complete_beio(beio); return; } diff --git a/sys/cam/ctl/ctl_error.c b/sys/cam/ctl/ctl_error.c index d2edb2a9571..b6a8b89d133 100644 --- a/sys/cam/ctl/ctl_error.c +++ b/sys/cam/ctl/ctl_error.c @@ -805,6 +805,18 @@ ctl_set_task_aborted(struct ctl_scsiio *ctsio) ctsio->io_hdr.status = CTL_CMD_ABORTED; } +void +ctl_set_space_alloc_fail(struct ctl_scsiio *ctsio) +{ + /* "Space allocation failed write protect" */ + ctl_set_sense(ctsio, + /*current_error*/ 1, + /*sense_key*/ SSD_KEY_DATA_PROTECT, + /*asc*/ 0x27, + /*ascq*/ 0x07, + SSD_ELEM_NONE); +} + void ctl_set_success(struct ctl_scsiio *ctsio) { diff --git a/sys/cam/ctl/ctl_error.h b/sys/cam/ctl/ctl_error.h index 034d14bff99..d7d82aa392a 100644 --- a/sys/cam/ctl/ctl_error.h +++ b/sys/cam/ctl/ctl_error.h @@ -81,6 +81,7 @@ void ctl_set_reservation_conflict(struct ctl_scsiio *ctsio); void ctl_set_queue_full(struct ctl_scsiio *ctsio); void ctl_set_busy(struct ctl_scsiio *ctsio); void ctl_set_task_aborted(struct ctl_scsiio *ctsio); +void ctl_set_space_alloc_fail(struct ctl_scsiio *ctsio); void ctl_set_success(struct ctl_scsiio *ctsio); #endif /* _CTL_ERROR_H_ */ diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index d61d4522163..959eda9125a 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -1733,7 +1733,7 @@ static struct asc_table_entry asc_table[] = { { SST(0x27, 0x06, SS_RDEF, /* XXX TBD */ "Conditional write protect") }, /* D B */ - { SST(0x27, 0x07, SS_RDEF, /* XXX TBD */ + { SST(0x27, 0x07, SS_FATAL | ENOSPC, "Space allocation failed write protect") }, /* DTLPWROMAEBKVF */ { SST(0x28, 0x00, SS_FATAL | ENXIO,