diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2015-09-16 17:26:16 +0200 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-09-25 12:04:41 +0200 |
| commit | 0eb2baeb449d27d6e6208a257dba6be1aad4d476 (patch) | |
| tree | b5a99cbff011e402822b636fbf054c772bf4d591 /hw/scsi/scsi-generic.c | |
| parent | 5e43efb29ae877da131e6c1a4761cd7f4eec5a16 (diff) | |
| download | focaccia-qemu-0eb2baeb449d27d6e6208a257dba6be1aad4d476.tar.gz focaccia-qemu-0eb2baeb449d27d6e6208a257dba6be1aad4d476.zip | |
scsi-generic: let guests recognize readonly=on on passthrough devices
Passed-through SCSI devices can be opened with the readonly=on option. When this happens, Linux filters away write commands so that the guest cannot overwrite the contents of the device. However, the guest does not know that the device is read-only, and accepts writes. The writes only fail later when the page cache is flushed. This patch modifies scsi-generic to modify the MODE SENSE data and set the read-only bit in the device-specific parameters, so that the guest OS treats the disk as write protected. Reviewed-by: Fam Zheng <famz@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/scsi/scsi-generic.c')
| -rw-r--r-- | hw/scsi/scsi-generic.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 1b6350be41..a4626f72c1 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -210,6 +210,20 @@ static void scsi_read_complete(void * opaque, int ret) } blk_set_guest_block_size(s->conf.blk, s->blocksize); + /* Patch MODE SENSE device specific parameters if the BDS is opened + * readonly. + */ + if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) && + blk_is_read_only(s->conf.blk) && + (r->req.cmd.buf[0] == MODE_SENSE || + r->req.cmd.buf[0] == MODE_SENSE_10) && + (r->req.cmd.buf[1] & 0x8) == 0) { + if (r->req.cmd.buf[0] == MODE_SENSE) { + r->buf[2] |= 0x80; + } else { + r->buf[3] |= 0x80; + } + } scsi_req_data(&r->req, len); scsi_req_unref(&r->req); } |