From c1d4096b0f033d0a52c542f0948403783c3682e9 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 30 Oct 2014 19:23:46 +0800 Subject: [PATCH] iscsi: Refuse to open as writable if the LUN is write protected Before, when a write protected iSCSI target is attached as scsi-disk with BDRV_O_RDWR, we report it as writable, while in fact all writes will fail. One way to improve this is to report write protect flag as true to guest, but a even better way is to refuse using a write protected LUN to guest. Target write protect flag is checked with a mode sense query. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- block/iscsi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/block/iscsi.c b/block/iscsi.c index 233f46285c..3485d622ec 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1219,6 +1219,40 @@ static void iscsi_attach_aio_context(BlockDriverState *bs, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); } +static bool iscsi_is_write_protected(IscsiLun *iscsilun) +{ + struct scsi_task *task; + struct scsi_mode_sense *ms = NULL; + bool wrprotected = false; + + task = iscsi_modesense6_sync(iscsilun->iscsi, iscsilun->lun, + 1, SCSI_MODESENSE_PC_CURRENT, + 0x3F, 0, 255); + if (task == NULL) { + error_report("iSCSI: Failed to send MODE_SENSE(6) command: %s", + iscsi_get_error(iscsilun->iscsi)); + goto out; + } + + if (task->status != SCSI_STATUS_GOOD) { + error_report("iSCSI: Failed MODE_SENSE(6), LUN assumed writable"); + goto out; + } + ms = scsi_datain_unmarshall(task); + if (!ms) { + error_report("iSCSI: Failed to unmarshall MODE_SENSE(6) data: %s", + iscsi_get_error(iscsilun->iscsi)); + goto out; + } + wrprotected = ms->device_specific_parameter & 0x80; + +out: + if (task) { + scsi_free_scsi_task(task); + } + return wrprotected; +} + /* * We support iscsi url's on the form * iscsi://[%@][:]// @@ -1339,6 +1373,14 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, scsi_free_scsi_task(task); task = NULL; + /* Check the write protect flag of the LUN if we want to write */ + if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && + iscsi_is_write_protected(iscsilun)) { + error_setg(errp, "Cannot open a write protected LUN as read-write"); + ret = -EACCES; + goto out; + } + iscsi_readcapacity_sync(iscsilun, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); -- 2.11.4.GIT