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);