All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers
@ 2017-08-22 13:18 Paolo Bonzini
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 01/10] scsi: rename scsi_convert_sense Paolo Bonzini
                   ` (13 more replies)
  0 siblings, 14 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

SCSI persistent Reservations allow restricting access to block devices
to specific initiators in a shared storage setup.  When implementing
clustering of virtual machines, it is a common requirement for virtual
machines to send persistent reservation SCSI commands.  However,
the operating system restricts sending these commands to unprivileged
programs because incorrect usage can disrupt regular operation of the
storage fabric.

With these patches, the scsi-block and scsi-generic SCSI passthrough
devices learn to delegate the implementation of persistent reservations to
a separate object, the "persistent reservation manager".  The persistent
reservation manager talks to a separate privileged program, with a very
simple protocol based on SCM_RIGHTS.  In addition to invoking PERSISTENT
RESERVATION OUT and PERSISTENT RESERVATION IN commands, the privileged
component can also use libmpathpersist so that persistent reservations
are applied to all paths in a multipath setting.

Patches 1-5 introduce a common scsi/ directory used by block/iscsi.c,
hw/scsi/* and now by the persistent reservation helper.

Patch 6 defines the abstract QOM class and plugs it into block/file-posix.c.

Patch 7 to 9 introduce the privileged helper program, while patch 10
defines the concrete QOM class that talks to it.

Paolo

Paolo Bonzini (10):
  scsi: rename scsi_convert_sense
  scsi: move non-emulation specific code to scsi/
  scsi: introduce scsi_build_sense
  scsi: introduce sg_io_sense_from_errno
  scsi: move block/scsi.h to include/scsi/constants.h
  scsi, file-posix: add support for persistent reservation management
  io: add qio_channel_read/write_all
  scsi: build qemu-pr-helper
  scsi: add multipath support to qemu-pr-helper
  scsi: add persistent reservation manager using qemu-pr-helper

 MAINTAINERS                                |   7 +
 Makefile                                   |  12 +-
 Makefile.objs                              |   3 +-
 block/file-posix.c                         |  30 +
 block/iscsi.c                              |   2 +-
 configure                                  |  59 +-
 docs/interop/pr-helper.rst                 |  78 +++
 docs/pr-manager.rst                        | 111 ++++
 hw/block/virtio-blk.c                      |   2 +-
 hw/scsi/megasas.c                          |   2 +-
 hw/scsi/mptendian.c                        |   2 +-
 hw/scsi/mptsas.c                           |   2 +-
 hw/scsi/scsi-bus.c                         | 411 +-----------
 hw/scsi/scsi-disk.c                        |   6 +-
 hw/scsi/scsi-generic.c                     |  50 +-
 hw/scsi/spapr_vscsi.c                      |   2 +-
 hw/scsi/virtio-scsi-dataplane.c            |   2 +-
 hw/scsi/virtio-scsi.c                      |   2 +-
 hw/scsi/vmw_pvscsi.c                       |   2 +-
 hw/usb/dev-uas.c                           |   2 +-
 include/hw/ide/internal.h                  |   2 +-
 include/hw/scsi/scsi.h                     |  94 +--
 include/io/channel.h                       |  36 +-
 include/{block/scsi.h => scsi/constants.h} |   2 -
 include/scsi/pr-manager.h                  |  57 ++
 include/scsi/utils.h                       | 127 ++++
 io/channel.c                               |  54 ++
 qapi/block-core.json                       |   4 +
 scsi/Makefile.objs                         |   3 +
 scsi/pr-helper.h                           |  13 +
 scsi/pr-manager-helper.c                   | 288 +++++++++
 scsi/pr-manager.c                          | 109 ++++
 scsi/qemu-pr-helper.c                      | 964 +++++++++++++++++++++++++++++
 scsi/utils.c                               | 464 ++++++++++++++
 tests/virtio-scsi-test.c                   |   2 +-
 vl.c                                       |   3 +-
 36 files changed, 2442 insertions(+), 567 deletions(-)
 create mode 100644 docs/interop/pr-helper.rst
 create mode 100644 docs/pr-manager.rst
 rename include/{block/scsi.h => scsi/constants.h} (99%)
 create mode 100644 include/scsi/pr-manager.h
 create mode 100644 include/scsi/utils.h
 create mode 100644 scsi/Makefile.objs
 create mode 100644 scsi/pr-helper.h
 create mode 100644 scsi/pr-manager-helper.c
 create mode 100644 scsi/pr-manager.c
 create mode 100644 scsi/qemu-pr-helper.c
 create mode 100644 scsi/utils.c

-- 
2.13.5

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 01/10] scsi: rename scsi_convert_sense
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-22 13:38   ` Philippe Mathieu-Daudé
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 02/10] scsi: move non-emulation specific code to scsi/ Paolo Bonzini
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

After introducing the scsi/ subdirectory, there will be a scsi_build_sense
function that is the same as scsi_req_build_sense but without needing
a SCSIRequest.  The existing scsi_build_sense function gets in the way,
remove it.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi/scsi-bus.c     | 10 +++++-----
 hw/scsi/scsi-disk.c    |  4 ++--
 include/hw/scsi/scsi.h |  4 ++--
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index e364410a23..890f8fcc83 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -769,7 +769,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
         return 0;
     }
 
-    ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
+    ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true);
 
     /*
      * FIXME: clearing unit attention conditions upon autosense should be done
@@ -790,7 +790,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
 
 int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
 {
-    return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
+    return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed);
 }
 
 void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
@@ -1510,12 +1510,12 @@ const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
 };
 
 /*
- * scsi_build_sense
+ * scsi_convert_sense
  *
  * Convert between fixed and descriptor sense buffers
  */
-int scsi_build_sense(uint8_t *in_buf, int in_len,
-                     uint8_t *buf, int len, bool fixed)
+int scsi_convert_sense(uint8_t *in_buf, int in_len,
+                       uint8_t *buf, int len, bool fixed)
 {
     bool fixed_in;
     SCSISense sense;
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 5f1e5e8070..0a1f4ef0c7 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -1978,8 +1978,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
         break;
     case REQUEST_SENSE:
         /* Just return "NO SENSE".  */
-        buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
-                                  (req->cmd.buf[1] & 1) == 0);
+        buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
+                                    (req->cmd.buf[1] & 1) == 0);
         if (buflen < 0) {
             goto illegal_request;
         }
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 6b85786dbf..6ef67fb504 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -244,8 +244,8 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
 uint32_t scsi_data_cdb_xfer(uint8_t *buf);
 uint32_t scsi_cdb_xfer(uint8_t *buf);
 int scsi_cdb_length(uint8_t *buf);
-int scsi_build_sense(uint8_t *in_buf, int in_len,
-                     uint8_t *buf, int len, bool fixed);
+int scsi_convert_sense(uint8_t *in_buf, int in_len,
+                       uint8_t *buf, int len, bool fixed);
 
 SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
                             uint32_t tag, uint32_t lun, void *hba_private);
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 02/10] scsi: move non-emulation specific code to scsi/
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 01/10] scsi: rename scsi_convert_sense Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-22 13:34   ` Philippe Mathieu-Daudé
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 03/10] scsi: introduce scsi_build_sense Paolo Bonzini
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

There is a bunch of SCSI code that is shared by block/iscsi.c and
hw/scsi, and the introduction of the persistent reservation helper
will add more instances of this.  There is also include/block/scsi.h,
which actually is not part of the core block layer.

Create a directory for this kind of shared code.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 MAINTAINERS            |   7 +
 Makefile.objs          |   2 +-
 hw/scsi/scsi-bus.c     | 397 ------------------------------------------------
 hw/scsi/scsi-generic.c |   8 -
 include/block/scsi.h   |   2 -
 include/hw/scsi/scsi.h |  94 +-----------
 include/scsi/utils.h   | 116 ++++++++++++++
 scsi/Makefile.objs     |   1 +
 scsi/utils.c           | 403 +++++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 529 insertions(+), 501 deletions(-)
 create mode 100644 include/scsi/utils.h
 create mode 100644 scsi/Makefile.objs
 create mode 100644 scsi/utils.c

diff --git a/MAINTAINERS b/MAINTAINERS
index ccee28b12d..fa6e21cd38 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1213,6 +1213,13 @@ F: migration/block*
 F: include/block/aio.h
 T: git git://github.com/stefanha/qemu.git block
 
+Block SCSI subsystem
+M: Paolo Bonzini <pbonzini@redhat.com>
+L: qemu-block@nongnu.org
+S: Supported
+F: include/scsi/*
+F: scsi/*
+
 Block Jobs
 M: Jeff Cody <jcody@redhat.com>
 L: qemu-block@nongnu.org
diff --git a/Makefile.objs b/Makefile.objs
index 24a4ea08b8..f68aa3b60d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -11,7 +11,7 @@ chardev-obj-y = chardev/
 
 block-obj-y += nbd/
 block-obj-y += block.o blockjob.o
-block-obj-y += block/
+block-obj-y += block/ scsi/
 block-obj-y += qemu-io-cmds.o
 block-obj-$(CONFIG_REPLICATION) += replication.o
 
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 890f8fcc83..300912d213 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -935,36 +935,6 @@ static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
     return xfer * unit;
 }
 
-uint32_t scsi_data_cdb_xfer(uint8_t *buf)
-{
-    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
-        return 256;
-    } else {
-        return scsi_cdb_xfer(buf);
-    }
-}
-
-uint32_t scsi_cdb_xfer(uint8_t *buf)
-{
-    switch (buf[0] >> 5) {
-    case 0:
-        return buf[4];
-        break;
-    case 1:
-    case 2:
-        return lduw_be_p(&buf[7]);
-        break;
-    case 4:
-        return ldl_be_p(&buf[10]) & 0xffffffffULL;
-        break;
-    case 5:
-        return ldl_be_p(&buf[6]) & 0xffffffffULL;
-        break;
-    default:
-        return -1;
-    }
-}
-
 static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
 {
     cmd->xfer = scsi_cdb_xfer(buf);
@@ -1277,53 +1247,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
     }
 }
 
-static uint64_t scsi_cmd_lba(SCSICommand *cmd)
-{
-    uint8_t *buf = cmd->buf;
-    uint64_t lba;
-
-    switch (buf[0] >> 5) {
-    case 0:
-        lba = ldl_be_p(&buf[0]) & 0x1fffff;
-        break;
-    case 1:
-    case 2:
-    case 5:
-        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
-        break;
-    case 4:
-        lba = ldq_be_p(&buf[2]);
-        break;
-    default:
-        lba = -1;
-
-    }
-    return lba;
-}
-
-int scsi_cdb_length(uint8_t *buf) {
-    int cdb_len;
-
-    switch (buf[0] >> 5) {
-    case 0:
-        cdb_len = 6;
-        break;
-    case 1:
-    case 2:
-        cdb_len = 10;
-        break;
-    case 4:
-        cdb_len = 16;
-        break;
-    case 5:
-        cdb_len = 12;
-        break;
-    default:
-        cdb_len = -1;
-    }
-    return cdb_len;
-}
-
 int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
 {
     int rc;
@@ -1370,326 +1293,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
     }
 }
 
-/*
- * Predefined sense codes
- */
-
-/* No sense data available */
-const struct SCSISense sense_code_NO_SENSE = {
-    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
-};
-
-/* LUN not ready, Manual intervention required */
-const struct SCSISense sense_code_LUN_NOT_READY = {
-    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
-};
-
-/* LUN not ready, Medium not present */
-const struct SCSISense sense_code_NO_MEDIUM = {
-    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
-};
-
-/* LUN not ready, medium removal prevented */
-const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
-    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
-};
-
-/* Hardware error, internal target failure */
-const struct SCSISense sense_code_TARGET_FAILURE = {
-    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
-};
-
-/* Illegal request, invalid command operation code */
-const struct SCSISense sense_code_INVALID_OPCODE = {
-    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
-};
-
-/* Illegal request, LBA out of range */
-const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
-    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
-};
-
-/* Illegal request, Invalid field in CDB */
-const struct SCSISense sense_code_INVALID_FIELD = {
-    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
-};
-
-/* Illegal request, Invalid field in parameter list */
-const struct SCSISense sense_code_INVALID_PARAM = {
-    .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
-};
-
-/* Illegal request, Parameter list length error */
-const struct SCSISense sense_code_INVALID_PARAM_LEN = {
-    .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
-};
-
-/* Illegal request, LUN not supported */
-const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
-    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
-};
-
-/* Illegal request, Saving parameters not supported */
-const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
-    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
-};
-
-/* Illegal request, Incompatible medium installed */
-const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
-    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
-};
-
-/* Illegal request, medium removal prevented */
-const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
-    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
-};
-
-/* Illegal request, Invalid Transfer Tag */
-const struct SCSISense sense_code_INVALID_TAG = {
-    .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
-};
-
-/* Command aborted, I/O process terminated */
-const struct SCSISense sense_code_IO_ERROR = {
-    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
-};
-
-/* Command aborted, I_T Nexus loss occurred */
-const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
-    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
-};
-
-/* Command aborted, Logical Unit failure */
-const struct SCSISense sense_code_LUN_FAILURE = {
-    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
-};
-
-/* Command aborted, Overlapped Commands Attempted */
-const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
-    .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
-};
-
-/* Unit attention, Capacity data has changed */
-const struct SCSISense sense_code_CAPACITY_CHANGED = {
-    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
-};
-
-/* Unit attention, Power on, reset or bus device reset occurred */
-const struct SCSISense sense_code_RESET = {
-    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
-};
-
-/* Unit attention, No medium */
-const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
-    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
-};
-
-/* Unit attention, Medium may have changed */
-const struct SCSISense sense_code_MEDIUM_CHANGED = {
-    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
-};
-
-/* Unit attention, Reported LUNs data has changed */
-const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
-    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
-};
-
-/* Unit attention, Device internal reset */
-const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
-    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
-};
-
-/* Data Protection, Write Protected */
-const struct SCSISense sense_code_WRITE_PROTECTED = {
-    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
-};
-
-/* Data Protection, Space Allocation Failed Write Protect */
-const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
-    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
-};
-
-/*
- * scsi_convert_sense
- *
- * Convert between fixed and descriptor sense buffers
- */
-int scsi_convert_sense(uint8_t *in_buf, int in_len,
-                       uint8_t *buf, int len, bool fixed)
-{
-    bool fixed_in;
-    SCSISense sense;
-    if (!fixed && len < 8) {
-        return 0;
-    }
-
-    if (in_len == 0) {
-        sense.key = NO_SENSE;
-        sense.asc = 0;
-        sense.ascq = 0;
-    } else {
-        fixed_in = (in_buf[0] & 2) == 0;
-
-        if (fixed == fixed_in) {
-            memcpy(buf, in_buf, MIN(len, in_len));
-            return MIN(len, in_len);
-        }
-
-        if (fixed_in) {
-            sense.key = in_buf[2];
-            sense.asc = in_buf[12];
-            sense.ascq = in_buf[13];
-        } else {
-            sense.key = in_buf[1];
-            sense.asc = in_buf[2];
-            sense.ascq = in_buf[3];
-        }
-    }
-
-    memset(buf, 0, len);
-    if (fixed) {
-        /* Return fixed format sense buffer */
-        buf[0] = 0x70;
-        buf[2] = sense.key;
-        buf[7] = 10;
-        buf[12] = sense.asc;
-        buf[13] = sense.ascq;
-        return MIN(len, SCSI_SENSE_LEN);
-    } else {
-        /* Return descriptor format sense buffer */
-        buf[0] = 0x72;
-        buf[1] = sense.key;
-        buf[2] = sense.asc;
-        buf[3] = sense.ascq;
-        return 8;
-    }
-}
-
-const char *scsi_command_name(uint8_t cmd)
-{
-    static const char *names[] = {
-        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
-        [ REWIND                   ] = "REWIND",
-        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
-        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
-        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
-        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
-        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
-        [ READ_6                   ] = "READ_6",
-        [ WRITE_6                  ] = "WRITE_6",
-        [ SET_CAPACITY             ] = "SET_CAPACITY",
-        [ READ_REVERSE             ] = "READ_REVERSE",
-        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
-        [ SPACE                    ] = "SPACE",
-        [ INQUIRY                  ] = "INQUIRY",
-        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
-        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
-        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
-        [ MODE_SELECT              ] = "MODE_SELECT",
-        [ RESERVE                  ] = "RESERVE",
-        [ RELEASE                  ] = "RELEASE",
-        [ COPY                     ] = "COPY",
-        [ ERASE                    ] = "ERASE",
-        [ MODE_SENSE               ] = "MODE_SENSE",
-        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
-        /* LOAD_UNLOAD and START_STOP use the same operation code */
-        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
-        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
-        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
-        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
-        [ READ_10                  ] = "READ_10",
-        [ WRITE_10                 ] = "WRITE_10",
-        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
-        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
-        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
-        [ VERIFY_10                ] = "VERIFY_10",
-        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
-        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
-        [ SEARCH_LOW               ] = "SEARCH_LOW",
-        [ SET_LIMITS               ] = "SET_LIMITS",
-        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
-        /* READ_POSITION and PRE_FETCH use the same operation code */
-        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
-        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
-        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
-        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
-        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
-        [ COMPARE                  ] = "COMPARE",
-        [ COPY_VERIFY              ] = "COPY_VERIFY",
-        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
-        [ READ_BUFFER              ] = "READ_BUFFER",
-        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
-        [ READ_LONG_10             ] = "READ_LONG_10",
-        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
-        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
-        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
-        [ UNMAP                    ] = "UNMAP",
-        [ READ_TOC                 ] = "READ_TOC",
-        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
-        [ SANITIZE                 ] = "SANITIZE",
-        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
-        [ LOG_SELECT               ] = "LOG_SELECT",
-        [ LOG_SENSE                ] = "LOG_SENSE",
-        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
-        [ RESERVE_10               ] = "RESERVE_10",
-        [ RELEASE_10               ] = "RELEASE_10",
-        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
-        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
-        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
-        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
-        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
-        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
-        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
-        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
-        [ READ_16                  ] = "READ_16",
-        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
-        [ WRITE_16                 ] = "WRITE_16",
-        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
-        [ VERIFY_16                ] = "VERIFY_16",
-        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
-        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
-        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
-        [ LOCATE_16                ] = "LOCATE_16",
-        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
-        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
-        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
-        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
-        [ REPORT_LUNS              ] = "REPORT_LUNS",
-        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
-        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
-        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
-        [ READ_12                  ] = "READ_12",
-        [ WRITE_12                 ] = "WRITE_12",
-        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
-        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
-        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
-        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
-        [ VERIFY_12                ] = "VERIFY_12",
-        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
-        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
-        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
-        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
-        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
-        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
-        [ READ_CD                  ] = "READ_CD",
-        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
-        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
-        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
-        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
-        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
-        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
-        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
-        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
-        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
-        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
-        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
-    };
-
-    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
-        return "*UNKNOWN*";
-    return names[cmd];
-}
-
 SCSIRequest *scsi_req_ref(SCSIRequest *req)
 {
     assert(req->refcount > 0);
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 7e1cbab77e..7a8f500934 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -36,14 +36,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
 #include <scsi/sg.h>
 #include "block/scsi.h"
 
-#define SG_ERR_DRIVER_TIMEOUT  0x06
-#define SG_ERR_DRIVER_SENSE    0x08
-
-#define SG_ERR_DID_OK          0x00
-#define SG_ERR_DID_NO_CONNECT  0x01
-#define SG_ERR_DID_BUS_BUSY    0x02
-#define SG_ERR_DID_TIME_OUT    0x03
-
 #ifndef MAX_UINT
 #define MAX_UINT ((unsigned int)-1)
 #endif
diff --git a/include/block/scsi.h b/include/block/scsi.h
index cdf0a58a07..a141dd71f8 100644
--- a/include/block/scsi.h
+++ b/include/block/scsi.h
@@ -150,8 +150,6 @@
 #define READ_CD               0xbe
 #define SEND_DVD_STRUCTURE    0xbf
 
-const char *scsi_command_name(uint8_t cmd);
-
 /*
  * SERVICE ACTION IN subcodes
  */
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 6ef67fb504..23a8ee6a7d 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -4,45 +4,20 @@
 #include "hw/qdev.h"
 #include "hw/block/block.h"
 #include "sysemu/sysemu.h"
+#include "scsi/utils.h"
 #include "qemu/notify.h"
 
 #define MAX_SCSI_DEVS	255
 
-#define SCSI_CMD_BUF_SIZE      16
-#define SCSI_SENSE_LEN         18
-#define SCSI_SENSE_LEN_SCANNER 32
-#define SCSI_INQUIRY_LEN       36
-
 typedef struct SCSIBus SCSIBus;
 typedef struct SCSIBusInfo SCSIBusInfo;
-typedef struct SCSICommand SCSICommand;
 typedef struct SCSIDevice SCSIDevice;
 typedef struct SCSIRequest SCSIRequest;
 typedef struct SCSIReqOps SCSIReqOps;
 
-enum SCSIXferMode {
-    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
-    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
-    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
-};
-
-typedef struct SCSISense {
-    uint8_t key;
-    uint8_t asc;
-    uint8_t ascq;
-} SCSISense;
-
 #define SCSI_SENSE_BUF_SIZE_OLD 96
 #define SCSI_SENSE_BUF_SIZE 252
 
-struct SCSICommand {
-    uint8_t buf[SCSI_CMD_BUF_SIZE];
-    int len;
-    size_t xfer;
-    uint64_t lba;
-    enum SCSIXferMode mode;
-};
-
 struct SCSIRequest {
     SCSIBus           *bus;
     SCSIDevice        *dev;
@@ -180,73 +155,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
 void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated);
 void scsi_legacy_handle_cmdline(void);
 
-/*
- * Predefined sense codes
- */
-
-/* No sense data available */
-extern const struct SCSISense sense_code_NO_SENSE;
-/* LUN not ready, Manual intervention required */
-extern const struct SCSISense sense_code_LUN_NOT_READY;
-/* LUN not ready, Medium not present */
-extern const struct SCSISense sense_code_NO_MEDIUM;
-/* LUN not ready, medium removal prevented */
-extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
-/* Hardware error, internal target failure */
-extern const struct SCSISense sense_code_TARGET_FAILURE;
-/* Illegal request, invalid command operation code */
-extern const struct SCSISense sense_code_INVALID_OPCODE;
-/* Illegal request, LBA out of range */
-extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
-/* Illegal request, Invalid field in CDB */
-extern const struct SCSISense sense_code_INVALID_FIELD;
-/* Illegal request, Invalid field in parameter list */
-extern const struct SCSISense sense_code_INVALID_PARAM;
-/* Illegal request, Parameter list length error */
-extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
-/* Illegal request, LUN not supported */
-extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
-/* Illegal request, Saving parameters not supported */
-extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
-/* Illegal request, Incompatible format */
-extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
-/* Illegal request, medium removal prevented */
-extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
-/* Illegal request, Invalid Transfer Tag */
-extern const struct SCSISense sense_code_INVALID_TAG;
-/* Command aborted, I/O process terminated */
-extern const struct SCSISense sense_code_IO_ERROR;
-/* Command aborted, I_T Nexus loss occurred */
-extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
-/* Command aborted, Logical Unit failure */
-extern const struct SCSISense sense_code_LUN_FAILURE;
-/* Command aborted, Overlapped Commands Attempted */
-extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
-/* LUN not ready, Capacity data has changed */
-extern const struct SCSISense sense_code_CAPACITY_CHANGED;
-/* LUN not ready, Medium not present */
-extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
-/* Unit attention, Power on, reset or bus device reset occurred */
-extern const struct SCSISense sense_code_RESET;
-/* Unit attention, Medium may have changed*/
-extern const struct SCSISense sense_code_MEDIUM_CHANGED;
-/* Unit attention, Reported LUNs data has changed */
-extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
-/* Unit attention, Device internal reset */
-extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
-/* Data Protection, Write Protected */
-extern const struct SCSISense sense_code_WRITE_PROTECTED;
-/* Data Protection, Space Allocation Failed Write Protect */
-extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
-
-#define SENSE_CODE(x) sense_code_ ## x
-
-uint32_t scsi_data_cdb_xfer(uint8_t *buf);
-uint32_t scsi_cdb_xfer(uint8_t *buf);
-int scsi_cdb_length(uint8_t *buf);
-int scsi_convert_sense(uint8_t *in_buf, int in_len,
-                       uint8_t *buf, int len, bool fixed);
-
 SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
                             uint32_t tag, uint32_t lun, void *hba_private);
 SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
diff --git a/include/scsi/utils.h b/include/scsi/utils.h
new file mode 100644
index 0000000000..35a74436bf
--- /dev/null
+++ b/include/scsi/utils.h
@@ -0,0 +1,116 @@
+#ifndef SCSI_UTILS_H
+#define SCSI_UTILS_H 1
+
+#ifdef CONFIG_LINUX
+#include <scsi/sg.h>
+#endif
+
+#define SCSI_CMD_BUF_SIZE      16
+#define SCSI_SENSE_LEN         18
+#define SCSI_SENSE_LEN_SCANNER 32
+#define SCSI_INQUIRY_LEN       36
+
+enum SCSIXferMode {
+    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
+    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
+    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
+};
+
+typedef struct SCSICommand {
+    uint8_t buf[SCSI_CMD_BUF_SIZE];
+    int len;
+    size_t xfer;
+    uint64_t lba;
+    enum SCSIXferMode mode;
+} SCSICommand;
+
+typedef struct SCSISense {
+    uint8_t key;
+    uint8_t asc;
+    uint8_t ascq;
+} SCSISense;
+
+/*
+ * Predefined sense codes
+ */
+
+/* No sense data available */
+extern const struct SCSISense sense_code_NO_SENSE;
+/* LUN not ready, Manual intervention required */
+extern const struct SCSISense sense_code_LUN_NOT_READY;
+/* LUN not ready, Medium not present */
+extern const struct SCSISense sense_code_NO_MEDIUM;
+/* LUN not ready, medium removal prevented */
+extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
+/* Hardware error, internal target failure */
+extern const struct SCSISense sense_code_TARGET_FAILURE;
+/* Illegal request, invalid command operation code */
+extern const struct SCSISense sense_code_INVALID_OPCODE;
+/* Illegal request, LBA out of range */
+extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
+/* Illegal request, Invalid field in CDB */
+extern const struct SCSISense sense_code_INVALID_FIELD;
+/* Illegal request, Invalid field in parameter list */
+extern const struct SCSISense sense_code_INVALID_PARAM;
+/* Illegal request, Parameter list length error */
+extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
+/* Illegal request, LUN not supported */
+extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
+/* Illegal request, Saving parameters not supported */
+extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
+/* Illegal request, Incompatible format */
+extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
+/* Illegal request, medium removal prevented */
+extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
+/* Illegal request, Invalid Transfer Tag */
+extern const struct SCSISense sense_code_INVALID_TAG;
+/* Command aborted, I/O process terminated */
+extern const struct SCSISense sense_code_IO_ERROR;
+/* Command aborted, I_T Nexus loss occurred */
+extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
+/* Command aborted, Logical Unit failure */
+extern const struct SCSISense sense_code_LUN_FAILURE;
+/* Command aborted, Overlapped Commands Attempted */
+extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
+/* LUN not ready, Capacity data has changed */
+extern const struct SCSISense sense_code_CAPACITY_CHANGED;
+/* LUN not ready, Medium not present */
+extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
+/* Unit attention, Power on, reset or bus device reset occurred */
+extern const struct SCSISense sense_code_RESET;
+/* Unit attention, Medium may have changed*/
+extern const struct SCSISense sense_code_MEDIUM_CHANGED;
+/* Unit attention, Reported LUNs data has changed */
+extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
+/* Unit attention, Device internal reset */
+extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
+/* Data Protection, Write Protected */
+extern const struct SCSISense sense_code_WRITE_PROTECTED;
+/* Data Protection, Space Allocation Failed Write Protect */
+extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
+
+#define SENSE_CODE(x) sense_code_ ## x
+
+int scsi_convert_sense(uint8_t *in_buf, int in_len,
+                       uint8_t *buf, int len, bool fixed);
+const char *scsi_command_name(uint8_t cmd);
+
+uint64_t scsi_cmd_lba(SCSICommand *cmd);
+uint32_t scsi_data_cdb_xfer(uint8_t *buf);
+uint32_t scsi_cdb_xfer(uint8_t *buf);
+int scsi_cdb_length(uint8_t *buf);
+
+/* Linux SG_IO interface.  */
+#ifdef CONFIG_LINUX
+#define SG_ERR_DRIVER_TIMEOUT  0x06
+#define SG_ERR_DRIVER_SENSE    0x08
+
+#define SG_ERR_DID_OK          0x00
+#define SG_ERR_DID_NO_CONNECT  0x01
+#define SG_ERR_DID_BUS_BUSY    0x02
+#define SG_ERR_DID_TIME_OUT    0x03
+
+#define SG_ERR_DRIVER_SENSE    0x08
+#endif
+
+#endif
diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
new file mode 100644
index 0000000000..31b82a5a36
--- /dev/null
+++ b/scsi/Makefile.objs
@@ -0,0 +1 @@
+block-obj-y += utils.o
diff --git a/scsi/utils.c b/scsi/utils.c
new file mode 100644
index 0000000000..0db727591f
--- /dev/null
+++ b/scsi/utils.c
@@ -0,0 +1,403 @@
+#include "qemu/osdep.h"
+#include "block/scsi.h"
+#include "scsi/utils.h"
+#include "qemu/bswap.h"
+
+uint32_t scsi_data_cdb_xfer(uint8_t *buf)
+{
+    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
+        return 256;
+    } else {
+        return scsi_cdb_xfer(buf);
+    }
+}
+
+uint32_t scsi_cdb_xfer(uint8_t *buf)
+{
+    switch (buf[0] >> 5) {
+    case 0:
+        return buf[4];
+        break;
+    case 1:
+    case 2:
+        return lduw_be_p(&buf[7]);
+        break;
+    case 4:
+        return ldl_be_p(&buf[10]) & 0xffffffffULL;
+        break;
+    case 5:
+        return ldl_be_p(&buf[6]) & 0xffffffffULL;
+        break;
+    default:
+        return -1;
+    }
+}
+
+uint64_t scsi_cmd_lba(SCSICommand *cmd)
+{
+    uint8_t *buf = cmd->buf;
+    uint64_t lba;
+
+    switch (buf[0] >> 5) {
+    case 0:
+        lba = ldl_be_p(&buf[0]) & 0x1fffff;
+        break;
+    case 1:
+    case 2:
+    case 5:
+        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
+        break;
+    case 4:
+        lba = ldq_be_p(&buf[2]);
+        break;
+    default:
+        lba = -1;
+
+    }
+    return lba;
+}
+
+int scsi_cdb_length(uint8_t *buf)
+{
+    int cdb_len;
+
+    switch (buf[0] >> 5) {
+    case 0:
+        cdb_len = 6;
+        break;
+    case 1:
+    case 2:
+        cdb_len = 10;
+        break;
+    case 4:
+        cdb_len = 16;
+        break;
+    case 5:
+        cdb_len = 12;
+        break;
+    default:
+        cdb_len = -1;
+    }
+    return cdb_len;
+}
+
+/*
+ * Predefined sense codes
+ */
+
+/* No sense data available */
+const struct SCSISense sense_code_NO_SENSE = {
+    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
+};
+
+/* LUN not ready, Manual intervention required */
+const struct SCSISense sense_code_LUN_NOT_READY = {
+    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
+};
+
+/* LUN not ready, Medium not present */
+const struct SCSISense sense_code_NO_MEDIUM = {
+    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
+};
+
+/* LUN not ready, medium removal prevented */
+const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
+    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
+};
+
+/* Hardware error, internal target failure */
+const struct SCSISense sense_code_TARGET_FAILURE = {
+    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
+};
+
+/* Illegal request, invalid command operation code */
+const struct SCSISense sense_code_INVALID_OPCODE = {
+    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
+};
+
+/* Illegal request, LBA out of range */
+const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
+    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
+};
+
+/* Illegal request, Invalid field in CDB */
+const struct SCSISense sense_code_INVALID_FIELD = {
+    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
+};
+
+/* Illegal request, Invalid field in parameter list */
+const struct SCSISense sense_code_INVALID_PARAM = {
+    .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
+};
+
+/* Illegal request, Parameter list length error */
+const struct SCSISense sense_code_INVALID_PARAM_LEN = {
+    .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
+};
+
+/* Illegal request, LUN not supported */
+const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
+};
+
+/* Illegal request, Saving parameters not supported */
+const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
+};
+
+/* Illegal request, Incompatible medium installed */
+const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
+    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
+};
+
+/* Illegal request, medium removal prevented */
+const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
+};
+
+/* Illegal request, Invalid Transfer Tag */
+const struct SCSISense sense_code_INVALID_TAG = {
+    .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
+};
+
+/* Command aborted, I/O process terminated */
+const struct SCSISense sense_code_IO_ERROR = {
+    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
+};
+
+/* Command aborted, I_T Nexus loss occurred */
+const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
+    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
+};
+
+/* Command aborted, Logical Unit failure */
+const struct SCSISense sense_code_LUN_FAILURE = {
+    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
+};
+
+/* Command aborted, Overlapped Commands Attempted */
+const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
+    .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
+};
+
+/* Unit attention, Capacity data has changed */
+const struct SCSISense sense_code_CAPACITY_CHANGED = {
+    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
+};
+
+/* Unit attention, Power on, reset or bus device reset occurred */
+const struct SCSISense sense_code_RESET = {
+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
+};
+
+/* Unit attention, No medium */
+const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
+    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
+};
+
+/* Unit attention, Medium may have changed */
+const struct SCSISense sense_code_MEDIUM_CHANGED = {
+    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
+};
+
+/* Unit attention, Reported LUNs data has changed */
+const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
+    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
+};
+
+/* Unit attention, Device internal reset */
+const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
+};
+
+/* Data Protection, Write Protected */
+const struct SCSISense sense_code_WRITE_PROTECTED = {
+    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
+};
+
+/* Data Protection, Space Allocation Failed Write Protect */
+const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
+    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
+};
+
+/*
+ * scsi_convert_sense
+ *
+ * Convert between fixed and descriptor sense buffers
+ */
+int scsi_convert_sense(uint8_t *in_buf, int in_len,
+                       uint8_t *buf, int len, bool fixed)
+{
+    bool fixed_in;
+    SCSISense sense;
+    if (!fixed && len < 8) {
+        return 0;
+    }
+
+    if (in_len == 0) {
+        sense.key = NO_SENSE;
+        sense.asc = 0;
+        sense.ascq = 0;
+    } else {
+        fixed_in = (in_buf[0] & 2) == 0;
+
+        if (fixed == fixed_in) {
+            memcpy(buf, in_buf, MIN(len, in_len));
+            return MIN(len, in_len);
+        }
+
+        if (fixed_in) {
+            sense.key = in_buf[2];
+            sense.asc = in_buf[12];
+            sense.ascq = in_buf[13];
+        } else {
+            sense.key = in_buf[1];
+            sense.asc = in_buf[2];
+            sense.ascq = in_buf[3];
+        }
+    }
+
+    memset(buf, 0, len);
+    if (fixed) {
+        /* Return fixed format sense buffer */
+        buf[0] = 0x70;
+        buf[2] = sense.key;
+        buf[7] = 10;
+        buf[12] = sense.asc;
+        buf[13] = sense.ascq;
+        return MIN(len, SCSI_SENSE_LEN);
+    } else {
+        /* Return descriptor format sense buffer */
+        buf[0] = 0x72;
+        buf[1] = sense.key;
+        buf[2] = sense.asc;
+        buf[3] = sense.ascq;
+        return 8;
+    }
+}
+
+const char *scsi_command_name(uint8_t cmd)
+{
+    static const char *names[] = {
+        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
+        [ REWIND                   ] = "REWIND",
+        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
+        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
+        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
+        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
+        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
+        [ READ_6                   ] = "READ_6",
+        [ WRITE_6                  ] = "WRITE_6",
+        [ SET_CAPACITY             ] = "SET_CAPACITY",
+        [ READ_REVERSE             ] = "READ_REVERSE",
+        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
+        [ SPACE                    ] = "SPACE",
+        [ INQUIRY                  ] = "INQUIRY",
+        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
+        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
+        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
+        [ MODE_SELECT              ] = "MODE_SELECT",
+        [ RESERVE                  ] = "RESERVE",
+        [ RELEASE                  ] = "RELEASE",
+        [ COPY                     ] = "COPY",
+        [ ERASE                    ] = "ERASE",
+        [ MODE_SENSE               ] = "MODE_SENSE",
+        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
+        /* LOAD_UNLOAD and START_STOP use the same operation code */
+        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
+        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
+        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
+        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
+        [ READ_10                  ] = "READ_10",
+        [ WRITE_10                 ] = "WRITE_10",
+        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
+        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
+        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
+        [ VERIFY_10                ] = "VERIFY_10",
+        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
+        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
+        [ SEARCH_LOW               ] = "SEARCH_LOW",
+        [ SET_LIMITS               ] = "SET_LIMITS",
+        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
+        /* READ_POSITION and PRE_FETCH use the same operation code */
+        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
+        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
+        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
+        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
+        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
+        [ COMPARE                  ] = "COMPARE",
+        [ COPY_VERIFY              ] = "COPY_VERIFY",
+        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
+        [ READ_BUFFER              ] = "READ_BUFFER",
+        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
+        [ READ_LONG_10             ] = "READ_LONG_10",
+        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
+        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
+        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
+        [ UNMAP                    ] = "UNMAP",
+        [ READ_TOC                 ] = "READ_TOC",
+        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
+        [ SANITIZE                 ] = "SANITIZE",
+        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
+        [ LOG_SELECT               ] = "LOG_SELECT",
+        [ LOG_SENSE                ] = "LOG_SENSE",
+        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
+        [ RESERVE_10               ] = "RESERVE_10",
+        [ RELEASE_10               ] = "RELEASE_10",
+        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
+        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
+        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
+        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
+        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
+        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
+        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
+        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
+        [ READ_16                  ] = "READ_16",
+        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
+        [ WRITE_16                 ] = "WRITE_16",
+        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
+        [ VERIFY_16                ] = "VERIFY_16",
+        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
+        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
+        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
+        [ LOCATE_16                ] = "LOCATE_16",
+        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
+        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
+        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
+        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
+        [ REPORT_LUNS              ] = "REPORT_LUNS",
+        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
+        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
+        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
+        [ READ_12                  ] = "READ_12",
+        [ WRITE_12                 ] = "WRITE_12",
+        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
+        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
+        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
+        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
+        [ VERIFY_12                ] = "VERIFY_12",
+        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
+        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
+        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
+        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
+        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
+        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
+        [ READ_CD                  ] = "READ_CD",
+        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
+        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
+        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
+        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
+        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
+        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
+        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
+        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
+        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
+        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
+        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
+    };
+
+    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) {
+        return "*UNKNOWN*";
+    }
+    return names[cmd];
+}
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 03/10] scsi: introduce scsi_build_sense
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 01/10] scsi: rename scsi_convert_sense Paolo Bonzini
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 02/10] scsi: move non-emulation specific code to scsi/ Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-22 13:35   ` Philippe Mathieu-Daudé
  2017-08-30 13:39   ` Stefan Hajnoczi
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno Paolo Bonzini
                   ` (10 subsequent siblings)
  13 siblings, 2 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

Move more knowledge of sense data format out of hw/scsi/scsi-bus.c
for reusability.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi/scsi-bus.c   |  8 +-------
 include/scsi/utils.h |  2 ++
 scsi/utils.c         | 11 +++++++++++
 3 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 300912d213..f71218f02a 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -797,13 +797,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
 {
     trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
                                sense.key, sense.asc, sense.ascq);
-    memset(req->sense, 0, 18);
-    req->sense[0] = 0x70;
-    req->sense[2] = sense.key;
-    req->sense[7] = 10;
-    req->sense[12] = sense.asc;
-    req->sense[13] = sense.ascq;
-    req->sense_len = 18;
+    req->sense_len = scsi_build_sense(req->sense, sense);
 }
 
 static void scsi_req_enqueue_internal(SCSIRequest *req)
diff --git a/include/scsi/utils.h b/include/scsi/utils.h
index 35a74436bf..76c3db98c0 100644
--- a/include/scsi/utils.h
+++ b/include/scsi/utils.h
@@ -30,6 +30,8 @@ typedef struct SCSISense {
     uint8_t ascq;
 } SCSISense;
 
+int scsi_build_sense(uint8_t *buf, SCSISense sense);
+
 /*
  * Predefined sense codes
  */
diff --git a/scsi/utils.c b/scsi/utils.c
index 0db727591f..54d6d4486a 100644
--- a/scsi/utils.c
+++ b/scsi/utils.c
@@ -81,6 +81,17 @@ int scsi_cdb_length(uint8_t *buf)
     return cdb_len;
 }
 
+int scsi_build_sense(uint8_t *buf, SCSISense sense)
+{
+    memset(buf, 0, 18);
+    buf[0] = 0x70;
+    buf[2] = sense.key;
+    buf[7] = 10;
+    buf[12] = sense.asc;
+    buf[13] = sense.ascq;
+    return 18;
+}
+
 /*
  * Predefined sense codes
  */
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (2 preceding siblings ...)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 03/10] scsi: introduce scsi_build_sense Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-22 13:45   ` Philippe Mathieu-Daudé
  2017-08-30 13:41   ` Stefan Hajnoczi
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 05/10] scsi: move block/scsi.h to include/scsi/constants.h Paolo Bonzini
                   ` (9 subsequent siblings)
  13 siblings, 2 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for
reusability.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi/scsi-generic.c | 40 +++++++---------------------------------
 include/scsi/utils.h   |  3 +++
 scsi/utils.c           | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+), 33 deletions(-)

diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 7a8f500934..04c687ee76 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -81,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
 static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
 {
     int status;
+    SCSISense sense;
 
     assert(r->req.aiocb == NULL);
 
@@ -88,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
         scsi_req_cancel_complete(&r->req);
         goto done;
     }
-    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
-        r->req.sense_len = r->io_header.sb_len_wr;
-    }
-
-    if (ret != 0) {
-        switch (ret) {
-        case -EDOM:
-            status = TASK_SET_FULL;
-            break;
-        case -ENOMEM:
-            status = CHECK_CONDITION;
-            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
-            break;
-        default:
-            status = CHECK_CONDITION;
-            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
-            break;
-        }
-    } else {
-        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
-            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
-            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
-            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
-            status = BUSY;
-            BADF("Driver Timeout\n");
-        } else if (r->io_header.host_status) {
-            status = CHECK_CONDITION;
-            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
-        } else if (r->io_header.status) {
-            status = r->io_header.status;
-        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
-            status = CHECK_CONDITION;
+    status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
+    if (status == CHECK_CONDITION) {
+        if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
+            r->req.sense_len = r->io_header.sb_len_wr;
         } else {
-            status = GOOD;
+            scsi_req_build_sense(&r->req, sense);
         }
     }
+
     DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
             r, r->req.tag, status);
 
diff --git a/include/scsi/utils.h b/include/scsi/utils.h
index 76c3db98c0..c12b34f2e5 100644
--- a/include/scsi/utils.h
+++ b/include/scsi/utils.h
@@ -113,6 +113,9 @@ int scsi_cdb_length(uint8_t *buf);
 #define SG_ERR_DID_TIME_OUT    0x03
 
 #define SG_ERR_DRIVER_SENSE    0x08
+
+int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
+                           SCSISense *sense);
 #endif
 
 #endif
diff --git a/scsi/utils.c b/scsi/utils.c
index 54d6d4486a..ca5b058a73 100644
--- a/scsi/utils.c
+++ b/scsi/utils.c
@@ -412,3 +412,38 @@ const char *scsi_command_name(uint8_t cmd)
     }
     return names[cmd];
 }
+
+#ifdef CONFIG_LINUX
+int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
+                           SCSISense *sense)
+{
+    if (errno_value != 0) {
+        switch (errno_value) {
+        case EDOM:
+            return TASK_SET_FULL;
+        case ENOMEM:
+            *sense = SENSE_CODE(TARGET_FAILURE);
+            return CHECK_CONDITION;
+        default:
+            *sense = SENSE_CODE(IO_ERROR);
+            return CHECK_CONDITION;
+        }
+    } else {
+        if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
+            io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
+            io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
+            (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
+            return BUSY;
+        } else if (io_hdr->host_status) {
+            *sense = SENSE_CODE(I_T_NEXUS_LOSS);
+            return CHECK_CONDITION;
+        } else if (io_hdr->status) {
+            return io_hdr->status;
+        } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
+            return CHECK_CONDITION;
+        } else {
+            return GOOD;
+        }
+    }
+}
+#endif
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 05/10] scsi: move block/scsi.h to include/scsi/constants.h
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (3 preceding siblings ...)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-22 13:37   ` Philippe Mathieu-Daudé
  2017-08-30 13:41   ` Stefan Hajnoczi
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management Paolo Bonzini
                   ` (8 subsequent siblings)
  13 siblings, 2 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

Complete the transition by renaming this header, which was
shared by block/iscsi.c and the SCSI emulation code.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 block/iscsi.c                              | 2 +-
 hw/block/virtio-blk.c                      | 2 +-
 hw/scsi/megasas.c                          | 2 +-
 hw/scsi/mptendian.c                        | 2 +-
 hw/scsi/mptsas.c                           | 2 +-
 hw/scsi/scsi-bus.c                         | 2 +-
 hw/scsi/scsi-disk.c                        | 2 +-
 hw/scsi/scsi-generic.c                     | 2 +-
 hw/scsi/spapr_vscsi.c                      | 2 +-
 hw/scsi/virtio-scsi-dataplane.c            | 2 +-
 hw/scsi/virtio-scsi.c                      | 2 +-
 hw/scsi/vmw_pvscsi.c                       | 2 +-
 hw/usb/dev-uas.c                           | 2 +-
 include/hw/ide/internal.h                  | 2 +-
 include/{block/scsi.h => scsi/constants.h} | 0
 scsi/utils.c                               | 2 +-
 tests/virtio-scsi-test.c                   | 2 +-
 17 files changed, 16 insertions(+), 16 deletions(-)
 rename include/{block/scsi.h => scsi/constants.h} (100%)

diff --git a/block/iscsi.c b/block/iscsi.c
index d557c99668..c43c0953e1 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -34,7 +34,7 @@
 #include "qemu/bitops.h"
 #include "qemu/bitmap.h"
 #include "block/block_int.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "qemu/iov.h"
 #include "qemu/uuid.h"
 #include "qmp-commands.h"
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index a16ac75090..05d1440786 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -22,7 +22,7 @@
 #include "sysemu/blockdev.h"
 #include "hw/virtio/virtio-blk.h"
 #include "dataplane/virtio-blk.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #ifdef __linux__
 # include <scsi/sg.h>
 #endif
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 734fdaef90..0db68aacee 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -27,7 +27,7 @@
 #include "hw/pci/msix.h"
 #include "qemu/iov.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "trace.h"
 #include "qapi/error.h"
 #include "mfi.h"
diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c
index b7fe2a2a36..3415229b5e 100644
--- a/hw/scsi/mptendian.c
+++ b/hw/scsi/mptendian.c
@@ -28,7 +28,7 @@
 #include "hw/pci/msi.h"
 #include "qemu/iov.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "trace.h"
 
 #include "mptsas.h"
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index 765ab53c34..8bae8f543e 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -30,7 +30,7 @@
 #include "hw/pci/msi.h"
 #include "qemu/iov.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "trace.h"
 #include "qapi/error.h"
 #include "mptsas.h"
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index f71218f02a..b9244606f8 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -3,7 +3,7 @@
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "hw/qdev.h"
 #include "sysemu/block-backend.h"
 #include "sysemu/blockdev.h"
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 0a1f4ef0c7..5faf6682c5 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -32,7 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/block-backend.h"
 #include "sysemu/blockdev.h"
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 04c687ee76..bd0d9ff355 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -34,7 +34,7 @@ do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
 do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
 
 #include <scsi/sg.h>
-#include "block/scsi.h"
+#include "scsi/constants.h"
 
 #ifndef MAX_UINT
 #define MAX_UINT ((unsigned int)-1)
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index 55ee48c4da..360db53ac8 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -36,7 +36,7 @@
 #include "cpu.h"
 #include "hw/hw.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "srp.h"
 #include "hw/qdev.h"
 #include "hw/ppc/spapr.h"
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 944ea4eb53..add4b3f4a4 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -17,7 +17,7 @@
 #include "qemu/error-report.h"
 #include "sysemu/block-backend.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "hw/virtio/virtio-bus.h"
 #include "hw/virtio/virtio-access.h"
 
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index eb639442d1..823a1e9a42 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -21,7 +21,7 @@
 #include "qemu/iov.h"
 #include "sysemu/block-backend.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "hw/virtio/virtio-bus.h"
 #include "hw/virtio/virtio-access.h"
 
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index 77d8b6f9e2..6d3f0bf11d 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -28,7 +28,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "hw/pci/msi.h"
 #include "vmw_pvscsi.h"
 #include "trace.h"
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index fffc424396..c218b53f09 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -19,7 +19,7 @@
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
 #include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 
 /* --------------------------------------------------------------------- */
 
diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
index 482a9512be..63a99e0366 100644
--- a/include/hw/ide/internal.h
+++ b/include/hw/ide/internal.h
@@ -11,7 +11,7 @@
 #include "sysemu/dma.h"
 #include "sysemu/sysemu.h"
 #include "hw/block/block.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
diff --git a/include/block/scsi.h b/include/scsi/constants.h
similarity index 100%
rename from include/block/scsi.h
rename to include/scsi/constants.h
diff --git a/scsi/utils.c b/scsi/utils.c
index ca5b058a73..eedd5f45b4 100644
--- a/scsi/utils.c
+++ b/scsi/utils.c
@@ -1,5 +1,5 @@
 #include "qemu/osdep.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "scsi/utils.h"
 #include "qemu/bswap.h"
 
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
index 87a3b6e81a..082d323541 100644
--- a/tests/virtio-scsi-test.c
+++ b/tests/virtio-scsi-test.c
@@ -10,7 +10,7 @@
 
 #include "qemu/osdep.h"
 #include "libqtest.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
 #include "libqos/libqos-pc.h"
 #include "libqos/libqos-spapr.h"
 #include "libqos/virtio.h"
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (4 preceding siblings ...)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 05/10] scsi: move block/scsi.h to include/scsi/constants.h Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-23  4:13   ` Fam Zheng
                     ` (3 more replies)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all Paolo Bonzini
                   ` (7 subsequent siblings)
  13 siblings, 4 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

It is a common requirement for virtual machine to send persistent
reservations, but this currently requires either running QEMU with
CAP_SYS_RAWIO, or using out-of-tree patches that let an unprivileged
QEMU bypass Linux's filter on SG_IO commands.

As an alternative mechanism, the next patches will introduce a
privileged helper to run persistent reservation commands without
expanding QEMU's attack surface unnecessarily.

The helper is invoked through a "pr-manager" QOM object, to which
file-posix.c passes SG_IO requests for PERSISTENT RESERVE OUT and
PERSISTENT RESERVE IN commands.  For example:

  $ qemu-system-x86_64
      -device virtio-scsi \
      -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
      -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
      -device scsi-block,drive=hd

or:

  $ qemu-system-x86_64
      -device virtio-scsi \
      -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
      -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
      -device scsi-block,drive=hd

Multiple pr-manager implementations are conceivable and possible, though
only one is implemented right now.  For example, a pr-manager could:

- talk directly to the multipath daemon from a privileged QEMU
  (i.e. QEMU links to libmpathpersist); this makes reservation work
  properly with multipath, but still requires CAP_SYS_RAWIO

- use the Linux IOC_PR_* ioctls (they require CAP_SYS_ADMIN though)

- more interestingly, implement reservations directly in QEMU
  through file system locks or a shared database (e.g. sqlite)

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile.objs             |   1 +
 block/file-posix.c        |  30 +++++++++++++
 docs/pr-manager.rst       |  51 ++++++++++++++++++++++
 include/scsi/pr-manager.h |  57 ++++++++++++++++++++++++
 qapi/block-core.json      |   4 ++
 scsi/Makefile.objs        |   2 +
 scsi/pr-manager.c         | 109 ++++++++++++++++++++++++++++++++++++++++++++++
 vl.c                      |   3 +-
 8 files changed, 256 insertions(+), 1 deletion(-)
 create mode 100644 docs/pr-manager.rst
 create mode 100644 include/scsi/pr-manager.h
 create mode 100644 scsi/pr-manager.c

diff --git a/Makefile.objs b/Makefile.objs
index f68aa3b60d..64bebd05db 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -168,6 +168,7 @@ trace-events-subdirs += qapi
 trace-events-subdirs += accel/tcg
 trace-events-subdirs += accel/kvm
 trace-events-subdirs += nbd
+trace-events-subdirs += scsi
 
 trace-events-files = $(SRC_PATH)/trace-events $(trace-events-subdirs:%=$(SRC_PATH)/%/trace-events)
 
diff --git a/block/file-posix.c b/block/file-posix.c
index f4de022ae0..47aadbf45d 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -34,6 +34,9 @@
 #include "qapi/util.h"
 #include "qapi/qmp/qstring.h"
 
+#include "scsi/pr-manager.h"
+#include "scsi/constants.h"
+
 #if defined(__APPLE__) && (__MACH__)
 #include <paths.h>
 #include <sys/param.h>
@@ -156,6 +159,8 @@ typedef struct BDRVRawState {
     bool page_cache_inconsistent:1;
     bool has_fallocate;
     bool needs_alignment;
+
+    PRManager *pr_mgr;
 } BDRVRawState;
 
 typedef struct BDRVRawReopenState {
@@ -403,6 +408,11 @@ static QemuOptsList raw_runtime_opts = {
             .type = QEMU_OPT_STRING,
             .help = "file locking mode (on/off/auto, default: auto)",
         },
+        {
+            .name = "pr-manager",
+            .type = QEMU_OPT_STRING,
+            .help = "id of persistent reservation manager object (default: none)",
+        },
         { /* end of list */ }
     },
 };
@@ -414,6 +424,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
     QemuOpts *opts;
     Error *local_err = NULL;
     const char *filename = NULL;
+    const char *str;
     BlockdevAioOptions aio, aio_default;
     int fd, ret;
     struct stat st;
@@ -478,6 +489,16 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
         abort();
     }
 
+    str = qemu_opt_get(opts, "pr-manager");
+    if (str) {
+        s->pr_mgr = pr_manager_lookup(str, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            ret = -EINVAL;
+            goto fail;
+        }
+    }
+
     s->open_flags = open_flags;
     raw_parse_flags(bdrv_flags, &s->open_flags);
 
@@ -2600,6 +2621,15 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
     if (fd_open(bs) < 0)
         return NULL;
 
+    if (req == SG_IO && s->pr_mgr) {
+        struct sg_io_hdr *io_hdr = buf;
+        if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT ||
+            io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) {
+            return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs),
+                                      s->fd, io_hdr, cb, opaque);
+        }
+    }
+
     acb = g_new(RawPosixAIOData, 1);
     acb->bs = bs;
     acb->aio_type = QEMU_AIO_IOCTL;
diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
new file mode 100644
index 0000000000..b6089fb57c
--- /dev/null
+++ b/docs/pr-manager.rst
@@ -0,0 +1,51 @@
+======================================
+Persistent reservation managers
+======================================
+
+SCSI persistent Reservations allow restricting access to block devices
+to specific initiators in a shared storage setup.  When implementing
+clustering of virtual machines, it is a common requirement for virtual
+machines to send persistent reservation SCSI commands.  However,
+the operating system restricts sending these commands to unprivileged
+programs because incorrect usage can disrupt regular operation of the
+storage fabric.
+
+For this reason, QEMU's SCSI passthrough devices, ``scsi-block``
+and ``scsi-generic`` (both are only available on Linux) can delegate
+implementation of persistent reservations to a separate object,
+the "persistent reservation manager".  Only PERSISTENT RESERVE OUT and
+PERSISTENT RESERVE IN commands are passed to the persistent reservation
+manager object; other commands are processed by QEMU as usual.
+
+-----------------------------------------
+Defining a persistent reservation manager
+-----------------------------------------
+
+A persistent reservation manager is an instance of a subclass of the
+"pr-manager" QOM class.
+
+Right now only one subclass is defined, ``pr-manager-helper``, which
+forwards the commands to an external privileged helper program
+over Unix sockets.  The helper program only allows sending persistent
+reservation commands to devices for which QEMU has a file descriptor,
+so that QEMU will not be able to effect persistent reservations
+unless it has access to both the socket and the device.
+
+``pr-manager-helper`` has a single string property, ``path``, which
+accepts the path to the helper program's Unix socket.  For example,
+the following command line defines a ``pr-manager-helper`` object and
+attaches it to a SCSI passthrough device::
+
+      $ qemu-system-x86_64
+          -device virtio-scsi \
+          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
+          -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
+          -device scsi-block,drive=hd
+
+Alternatively, using ``-blockdev``::
+
+      $ qemu-system-x86_64
+          -device virtio-scsi \
+          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
+          -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
+          -device scsi-block,drive=hd
diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h
new file mode 100644
index 0000000000..d523be218f
--- /dev/null
+++ b/include/scsi/pr-manager.h
@@ -0,0 +1,57 @@
+#ifndef PR_MANAGER_H
+#define PR_MANAGER_H
+
+#include "qom/object.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/visitor.h"
+#include "qom/object_interfaces.h"
+#include "block/aio.h"
+
+#define TYPE_PR_MANAGER "pr-manager"
+
+#define PR_MANAGER_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PRManagerClass, (klass), TYPE_PR_MANAGER)
+#define PR_MANAGER_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PRManagerClass, (obj), TYPE_PR_MANAGER)
+#define PR_MANAGER(obj) \
+     OBJECT_CHECK(PRManager, (obj), TYPE_PR_MANAGER)
+
+struct sg_io_hdr;
+
+typedef struct PRManager {
+    /* <private> */
+    Object parent;
+} PRManager;
+
+/**
+ * PRManagerClass:
+ * @parent_class: the base class
+ * @run: callback invoked in thread pool context
+ */
+typedef struct PRManagerClass {
+    /* <private> */
+    ObjectClass parent_class;
+
+    /* <public> */
+    int (*run)(PRManager *pr_mgr, int fd, struct sg_io_hdr *hdr);
+} PRManagerClass;
+
+BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
+                               AioContext *ctx, int fd,
+                               struct sg_io_hdr *hdr,
+                               BlockCompletionFunc *complete,
+                               void *opaque);
+
+#ifdef CONFIG_LINUX
+PRManager *pr_manager_lookup(const char *id, Error **errp);
+#else
+static inline PRManager *pr_manager_lookup(const char *id,
+                                                              Error **errp)
+{
+    /* The classes do not exist at all!  */
+    error_setg(errp, "No persistent reservation manager with id '%s'", id);
+    return NULL;
+}
+#endif
+
+#endif
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 833c602150..5ec663ab0d 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2191,6 +2191,9 @@
 # Driver specific block device options for the file backend.
 #
 # @filename:    path to the image file
+# @pr-manager:  the if for the object that will handle persistent reservations
+#               for this device (default: forward the commands via SG_IO,
+#               since 2.11)
 # @aio:         AIO backend (default: threads) (since: 2.8)
 # @locking:     whether to enable file locking. If set to 'auto', only enable
 #               when Open File Descriptor (OFD) locking API is available
@@ -2200,6 +2203,7 @@
 ##
 { 'struct': 'BlockdevOptionsFile',
   'data': { 'filename': 'str',
+            '*pr-manager': 'str',
             '*locking': 'OnOffAuto',
             '*aio': 'BlockdevAioOptions' } }
 
diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
index 31b82a5a36..5496d2ae6a 100644
--- a/scsi/Makefile.objs
+++ b/scsi/Makefile.objs
@@ -1 +1,3 @@
 block-obj-y += utils.o
+
+block-obj-$(CONFIG_LINUX) += pr-manager.o
diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c
new file mode 100644
index 0000000000..e80f8d9b31
--- /dev/null
+++ b/scsi/pr-manager.c
@@ -0,0 +1,109 @@
+/*
+ * Persistent reservation manager abstract class
+ *
+ * Copyright (c) 2017 Red Hat, Inc.
+ *
+ * Author: Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This code is licensed under the LGPL.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "block/aio.h"
+#include "block/thread-pool.h"
+#include "scsi/pr-manager.h"
+#include "scsi/trace.h"
+
+#include <scsi/sg.h>
+
+typedef struct PRManagerData {
+    PRManager *pr_mgr;
+    struct sg_io_hdr *hdr;
+    int fd;
+} PRManagerData;
+
+static int pr_manager_worker(void *opaque)
+{
+    PRManagerData *data = opaque;
+    PRManager *pr_mgr = data->pr_mgr;
+    PRManagerClass *pr_mgr_class =
+        PR_MANAGER_GET_CLASS(pr_mgr);
+    struct sg_io_hdr *hdr = data->hdr;
+    int fd = data->fd;
+    int r;
+
+    g_free(data);
+    trace_pr_manager_run(fd, hdr->cmdp[0], hdr->cmdp[1]);
+
+    /* The is was taken in pr_manager_execute.  */
+    r = pr_mgr_class->run(pr_mgr, fd, hdr);
+    object_unref(OBJECT(pr_mgr));
+    return r;
+}
+
+
+BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
+                               AioContext *ctx, int fd,
+                               struct sg_io_hdr *hdr,
+                               BlockCompletionFunc *complete,
+                               void *opaque)
+{
+    PRManagerData *data = g_new(PRManagerData, 1);
+    ThreadPool *pool = aio_get_thread_pool(ctx);
+
+    trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1], opaque);
+    data->pr_mgr = pr_mgr;
+    data->fd = fd;
+    data->hdr = hdr;
+
+    /* The matching object_unref is in pr_manager_worker.  */
+    object_ref(OBJECT(pr_mgr));
+    return thread_pool_submit_aio(pool, pr_manager_worker,
+                                  data, complete, opaque);
+}
+
+static const TypeInfo pr_manager_info = {
+    .parent = TYPE_OBJECT,
+    .name = TYPE_PR_MANAGER,
+    .class_size = sizeof(PRManagerClass),
+    .abstract = true,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_USER_CREATABLE },
+        { }
+    }
+};
+
+PRManager *pr_manager_lookup(const char *id, Error **errp)
+{
+    Object *obj;
+    PRManager *pr_mgr;
+
+    obj = object_resolve_path_component(object_get_objects_root(), id);
+    if (!obj) {
+        error_setg(errp, "No persistent reservation manager with id '%s'", id);
+        return NULL;
+    }
+
+    pr_mgr = (PRManager *)
+        object_dynamic_cast(obj,
+                            TYPE_PR_MANAGER);
+    if (!pr_mgr) {
+        error_setg(errp,
+                   "Object with id '%s' is not a persistent reservation manager",
+                   id);
+        return NULL;
+    }
+
+    return pr_mgr;
+}
+
+static void
+pr_manager_register_types(void)
+{
+    type_register_static(&pr_manager_info);
+}
+
+
+type_init(pr_manager_register_types);
diff --git a/vl.c b/vl.c
index 8e247cc2a2..af0e6576ab 100644
--- a/vl.c
+++ b/vl.c
@@ -2811,7 +2811,8 @@ static int machine_set_property(void *opaque,
  */
 static bool object_create_initial(const char *type)
 {
-    if (g_str_equal(type, "rng-egd")) {
+    if (g_str_equal(type, "rng-egd") ||
+        g_str_has_prefix(type, "pr-manager-")) {
         return false;
     }
 
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (5 preceding siblings ...)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-23  5:08   ` Fam Zheng
                     ` (2 more replies)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper Paolo Bonzini
                   ` (6 subsequent siblings)
  13 siblings, 3 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz, Daniel P . Berrange

It is pretty common to read a fixed-size buffer from a socket.  Add a
function that does this, either with multiple reads (on blocking sockets)
or by yielding if called from a coroutine.

Cc: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/io/channel.h | 36 ++++++++++++++++++++++++++++++++++-
 io/channel.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/include/io/channel.h b/include/io/channel.h
index db9bb022a1..9cfb4d081f 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -299,7 +299,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc,
                            Error **errp);
 
 /**
- * qio_channel_readv:
+ * qio_channel_read:
  * @ioc: the channel object
  * @buf: the memory region to read data into
  * @buflen: the length of @buf
@@ -315,6 +315,23 @@ ssize_t qio_channel_read(QIOChannel *ioc,
                          Error **errp);
 
 /**
+ * qio_channel_read_all:
+ * @ioc: the channel object
+ * @buf: the memory region to read data into
+ * @buflen: the number of bytes to @buf
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Reads @buflen bytes into @buf, possibly blocking or (if the
+ * channel is non-blocking) yielding from the current coroutine
+ * multiple times until the entire content is read.  Otherwise
+ * behaves as qio_channel_read().
+ */
+ssize_t coroutine_fn qio_channel_read_all(QIOChannel *ioc,
+                                          char *buf,
+                                          size_t buflen,
+                                          Error **errp);
+
+/**
  * qio_channel_write:
  * @ioc: the channel object
  * @buf: the memory regions to send data from
@@ -331,6 +348,23 @@ ssize_t qio_channel_write(QIOChannel *ioc,
                           Error **errp);
 
 /**
+ * qio_channel_write_all:
+ * @ioc: the channel object
+ * @buf: the memory region to write data into
+ * @buflen: the number of bytes to @buf
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Writes @buflen bytes from @buf, possibly blocking or (if the
+ * channel is non-blocking) yielding from the current coroutine
+ * multiple times until the entire content is written.  Otherwise
+ * behaves as qio_channel_write().
+ */
+ssize_t coroutine_fn qio_channel_write_all(QIOChannel *ioc,
+                                           const char *buf,
+                                           size_t buflen,
+                                           Error **errp);
+
+/**
  * qio_channel_set_blocking:
  * @ioc: the channel object
  * @enabled: the blocking flag state
diff --git a/io/channel.c b/io/channel.c
index 1cfb8b33a2..7ab3f4eede 100644
--- a/io/channel.c
+++ b/io/channel.c
@@ -113,6 +113,60 @@ ssize_t qio_channel_read(QIOChannel *ioc,
 }
 
 
+ssize_t qio_channel_read_all(QIOChannel *ioc,
+                             char *buf,
+                             size_t buflen,
+                             Error **errp)
+{
+    ssize_t total = 0;
+    while (buflen > 0) {
+        ssize_t n_read = qio_channel_read(ioc, buf, buflen, errp);
+
+        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
+            assert(ioc->ctx);
+            qio_channel_yield(ioc, G_IO_IN);
+            continue;
+        }
+        if (n_read < 0) {
+            return n_read;
+        }
+
+        buf += n_read;
+        total += n_read;
+        buflen -= n_read;
+    }
+
+    return total;
+}
+
+
+ssize_t qio_channel_write_all(QIOChannel *ioc,
+                              const char *buf,
+                              size_t buflen,
+                              Error **errp)
+{
+    ssize_t total = 0;
+    while (buflen > 0) {
+        ssize_t n_written = qio_channel_write(ioc, buf, buflen, errp);
+
+        if (n_written == QIO_CHANNEL_ERR_BLOCK) {
+            assert(ioc->ctx);
+            qio_channel_yield(ioc, G_IO_OUT);
+            continue;
+        }
+        if (n_written < 0) {
+            return n_written;
+        }
+
+        buf += n_written;
+        total += n_written;
+        buflen -= n_written;
+    }
+
+    return total;
+}
+
+
 ssize_t qio_channel_write(QIOChannel *ioc,
                           const char *buf,
                           size_t buflen,
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (6 preceding siblings ...)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-22 14:34   ` Marc-André Lureau
                     ` (3 more replies)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper Paolo Bonzini
                   ` (5 subsequent siblings)
  13 siblings, 4 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

Introduce a privileged helper to run persistent reservation commands.
This lets virtual machines send persistent reservations without using
CAP_SYS_RAWIO or out-of-tree patches.  The helper uses Unix permissions
and SCM_RIGHTS to restrict access to processes that can access its socket
and prove that they have an open file descriptor for a raw SCSI device.

The next patch will also correct the usage of persistent reservations
with multipath devices.

It would also be possible to support for Linux's IOC_PR_* ioctls in
the future, to support NVMe devices.  For now, however, only SCSI is
supported.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile                   |   9 +-
 configure                  |   2 +-
 docs/interop/pr-helper.rst |  78 ++++++
 docs/pr-manager.rst        |  33 +++
 scsi/pr-helper.h           |  13 +
 scsi/qemu-pr-helper.c      | 657 +++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 790 insertions(+), 2 deletions(-)
 create mode 100644 docs/interop/pr-helper.rst
 create mode 100644 scsi/pr-helper.h
 create mode 100644 scsi/qemu-pr-helper.c

diff --git a/Makefile b/Makefile
index 97a58a0f4e..bfd4f69ecd 100644
--- a/Makefile
+++ b/Makefile
@@ -209,6 +209,9 @@ ifdef BUILD_DOCS
 DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
 DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
 DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7
+ifdef CONFIG_LINUX
+DOCS+=scsi/qemu-pr-helper.8
+endif
 ifdef CONFIG_VIRTFS
 DOCS+=fsdev/virtfs-proxy-helper.1
 endif
@@ -384,6 +387,8 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
 fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
 fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
 
+scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
+
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
 
@@ -491,7 +496,7 @@ clean:
 	rm -f *.msi
 	find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
 	rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
-	rm -f fsdev/*.pod
+	rm -f fsdev/*.pod scsi/*.pod
 	rm -f qemu-img-cmds.h
 	rm -f ui/shader/*-vert.h ui/shader/*-frag.h
 	@# May not be present in GENERATED_FILES
@@ -590,6 +595,7 @@ endif
 ifdef CONFIG_VIRTFS
 	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 	$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
+	$(INSTALL_DATA) scsi/qemu-pr-helper.8 "$(DESTDIR)$(mandir)/man8"
 endif
 
 install-datadir:
@@ -718,6 +724,7 @@ qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
 qemu.1: qemu-option-trace.texi
 qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi
 fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
+scsi/qemu-pr-helper.8: scsi/qemu-pr-helper.texi
 qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
 qemu-ga.8: qemu-ga.texi
 
diff --git a/configure b/configure
index dd73cce62f..772aff18d6 100755
--- a/configure
+++ b/configure
@@ -6545,7 +6545,7 @@ fi
 
 # build tree in object directory in case the source is not in the current directory
 DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
-DIRS="$DIRS docs docs/interop fsdev"
+DIRS="$DIRS docs docs/interop fsdev scsi"
 DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
 DIRS="$DIRS roms/seabios roms/vgabios"
 DIRS="$DIRS qapi-generated"
diff --git a/docs/interop/pr-helper.rst b/docs/interop/pr-helper.rst
new file mode 100644
index 0000000000..765174c31f
--- /dev/null
+++ b/docs/interop/pr-helper.rst
@@ -0,0 +1,78 @@
+..
+
+======================================
+Persistent reservation helper protocol
+======================================
+
+QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
+can delegate implementation of persistent reservations to an external
+(and typically privilege) program.  Persistent Reservations allow
+restricting access to block devices to specific initiators in a shared
+storage setup.
+
+For a more detailed reference please refer the the SCSI Primary
+Commands standard, specifically the section on Reservations and the
+"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.
+
+This document describes the socket protocol used between QEMU's
+``pr-manager-helper`` object and the external program.
+
+.. contents::
+
+Connection and initialization
+-----------------------------
+
+After connecting to the helper program's socket, the helper starts a simple
+feature negotiation process by writing four bytes corresponding to
+the features it exposes (``supported_features``).  QEMU also writes
+four bytes corresponding to the desired features of the helper program
+(``requested_features``).
+
+If a bit is 1 in ``requested_features`` and 0 in ``supported_features``,
+the corresponding feature is not supported by the helper and the connection
+is closed.  On the other hand, it is acceptable for a bit to be 0 in
+``requested_features`` and 1 in ``supported_features``; in this case,
+he helper will not enable the feature.
+
+Right now no feature is defined, so the two parts always write four
+zero bytes.
+
+All data transmitted on the socket is big-endian.
+
+Command format
+--------------
+
+A command consists of a request and a response.  A request consists
+of a 16-byte SCSI CDB.  A file descriptor must be passed to the helper
+together with the SCSI CDB using ancillary data.
+
+The CDB has the following limitations:
+
+- the command (stored in the first byte) must be one of 0x5E
+  (PERSISTENT RESERVE IN) or 0x5F (PERSISTENT RESERVE OUT).
+
+- the allocation length (stored in bytes 7-8 of the CDB for PERSISTENT
+  RESERVE IN) or parameter list length (stored in bytes 5-8 of the CDB
+  for PERSISTENT RESERVE OUT) is limited to 8 KiB.
+
+For PERSISTENT RESERVE OUT, the parameter list is sent right after the
+CDB.
+
+The helper's reply has the following fixed structure:
+
+- 4 bytes for the SCSI status
+
+- 96 bytes for the SCSI sense data
+
+The sense data is always sent to keep the protocol simple, even though
+it is only valid if the SCSI status is CHECK CONDITION (0x02).
+
+For PERSISTENT RESERVE IN, the data is sent right after the sense
+data if the SCSI status is GOOD (0x00).
+
+It is invalid to send multiple commands concurrently on the same
+socket.  It is however possible to connect multiple sockets to the
+helper and send multiple commands to the helper for one or more
+file descriptors.
+
+If the protocol is violated, the helper closes the socket.
diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
index b6089fb57c..7107e59fb8 100644
--- a/docs/pr-manager.rst
+++ b/docs/pr-manager.rst
@@ -49,3 +49,36 @@ Alternatively, using ``-blockdev``::
           -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
           -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
           -device scsi-block,drive=hd
+
+----------------------------------
+Invoking :program:`qemu-pr-helper`
+----------------------------------
+
+QEMU provides an implementation of the persistent reservation helper,
+called :program:`qemu-pr-helper`.  The helper should be started as a
+system service and supports the following option:
+
+-d, --daemon              run in the background
+-q, --quiet               decrease verbosity
+-f, --pidfile=path        PID file when running as a daemon
+-k, --socket=path         path to the socket
+-T, --trace=trace-opts    tracing options
+
+By default, the socket and PID file are placed in the runtime state
+directory, for example :file:`/var/run/qemu-pr-helper.sock` and
+:file:`/var/run/qemu-pr-helper.pid`.  The PID file is not created
+unless :option:`-d` is passed too.
+
+:program:`qemu-pr-helper` can also use the systemd socket activation
+protocol.  In this case, the systemd socket unit should specify a
+Unix stream socket, like this::
+
+    [Socket]
+    ListenStream=/var/run/qemu-pr-helper.sock
+
+After connecting to the socket, :program:`qemu-pr-helper`` can optionally drop
+root privileges, except for those capabilities that are needed for
+its operation.  To do this, add the following options:
+
+-u, --user=user           user to drop privileges to
+-g, --group=group         group to drop privileges to
diff --git a/scsi/pr-helper.h b/scsi/pr-helper.h
new file mode 100644
index 0000000000..2c7ccc9928
--- /dev/null
+++ b/scsi/pr-helper.h
@@ -0,0 +1,13 @@
+#ifndef QEMU_PR_HELPER_H
+#define QEMU_PR_HELPER_H 1
+
+#define PR_HELPER_CDB_SIZE     16
+#define PR_HELPER_SENSE_SIZE   96
+#define PR_HELPER_DATA_SIZE    8192
+
+typedef struct PRHelperResponse {
+    int32_t result;
+    uint8_t sense[PR_HELPER_SENSE_SIZE];
+} PRHelperResponse;
+
+#endif
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
new file mode 100644
index 0000000000..d52234af0f
--- /dev/null
+++ b/scsi/qemu-pr-helper.c
@@ -0,0 +1,657 @@
+/*
+ * Helper to forward persistent reservation commands to libmpathpersist
+ *
+ * Copyright (C) 2017 Red Hat, Inc. <pbonzini@redhat.com>
+ *
+ * Author: Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include <getopt.h>
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "qemu/main-loop.h"
+#include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu/bswap.h"
+#include "qemu/log.h"
+#include "qemu/systemd.h"
+#include "qapi/util.h"
+#include "qapi/qmp/qstring.h"
+#include "io/channel-socket.h"
+#include "trace/control.h"
+#include "qemu-version.h"
+
+#include "block/aio.h"
+#include "block/thread-pool.h"
+
+#include "scsi/constants.h"
+#include "scsi/utils.h"
+#include "pr-helper.h"
+#include <sys/ioctl.h>
+#include <linux/dm-ioctl.h>
+#include <scsi/sg.h>
+
+#ifdef CONFIG_LIBCAP
+#include <cap-ng.h>
+#endif
+#include <pwd.h>
+#include <grp.h>
+
+
+#define PR_OUT_FIXED_PARAM_SIZE 24
+
+static char *socket_path;
+static char *pidfile;
+static enum { RUNNING, TERMINATE, TERMINATING } state;
+static QIOChannelSocket *server_ioc;
+static int server_watch;
+static int num_active_sockets = 1;
+static int verbose;
+
+#ifdef CONFIG_LIBCAP
+static int uid = -1;
+static int gid = -1;
+#endif
+
+static void usage(const char *name)
+{
+    (printf) (
+"Usage: %s [OPTIONS] FILE\n"
+"Persistent Reservation helper program for QEMU\n"
+"\n"
+"  -h, --help                display this help and exit\n"
+"  -V, --version             output version information and exit\n"
+"\n"
+"  -d, --daemon              run in the background\n"
+"  -f, --pidfile=PATH        PID file when running as a daemon\n"
+"                            (default '%s')\n"
+"  -k, --socket=PATH         path to the unix socket\n"
+"                            (default '%s')\n"
+"  -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+"                            specify tracing options\n"
+#ifdef CONFIG_LIBCAP
+"  -u, --user=USER           user to drop privileges to\n"
+"  -g, --group=GROUP         group to drop privileges to\n"
+#endif
+"\n"
+QEMU_HELP_BOTTOM "\n"
+    , name, pidfile, socket_path);
+}
+
+static void version(const char *name)
+{
+    printf(
+"%s " QEMU_VERSION QEMU_PKGVERSION "\n"
+"Written by Paolo Bonzini.\n"
+"\n"
+QEMU_COPYRIGHT "\n"
+"This is free software; see the source for copying conditions.  There is NO\n"
+"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
+    , name);
+}
+
+/* SG_IO support */
+
+typedef struct PRHelperSGIOData {
+    int fd;
+    const uint8_t *cdb;
+    uint8_t *sense;
+    uint8_t *buf;
+    int sz;
+    int dir;
+} PRHelperSGIOData;
+
+static int do_sgio_worker(void *opaque)
+{
+    PRHelperSGIOData *data = opaque;
+    struct sg_io_hdr io_hdr;
+    int ret;
+    int status;
+    SCSISense sense_code;
+
+    memset(data->sense, 0, PR_HELPER_SENSE_SIZE);
+    memset(&io_hdr, 0, sizeof(io_hdr));
+    io_hdr.interface_id = 'S';
+    io_hdr.cmd_len = PR_HELPER_CDB_SIZE;
+    io_hdr.cmdp = (uint8_t *)data->cdb;
+    io_hdr.sbp = data->sense;
+    io_hdr.mx_sb_len = PR_HELPER_SENSE_SIZE;
+    io_hdr.timeout = 1;
+    io_hdr.dxfer_direction = data->dir;
+    io_hdr.dxferp = (char *)data->buf;
+    io_hdr.dxfer_len = data->sz;
+    ret = ioctl(data->fd, SG_IO, &io_hdr);
+    status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr,
+                                    &sense_code);
+    if (status == CHECK_CONDITION &&
+        !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) {
+        scsi_build_sense(data->sense, sense_code);
+    }
+
+    return status;
+}
+
+static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
+                    uint8_t *buf, int sz, int dir)
+{
+    ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
+
+    PRHelperSGIOData data = {
+        .fd = fd,
+        .cdb = cdb,
+        .sense = sense,
+        .buf = buf,
+        .sz = sz,
+        .dir = dir,
+    };
+
+    return thread_pool_submit_co(pool, do_sgio_worker, &data);
+}
+
+static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
+                    uint8_t *data, int sz)
+{
+    return do_sgio(fd, cdb, sense, data, sz,
+                   SG_DXFER_FROM_DEV);
+}
+
+static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
+                     const uint8_t *param, int sz)
+{
+    return do_sgio(fd, cdb, sense, (uint8_t *)param, sz,
+                   SG_DXFER_TO_DEV);
+}
+
+/* Client */
+
+typedef struct PRHelperClient {
+    QIOChannelSocket *ioc;
+    Coroutine *co;
+    int fd;
+    uint8_t data[PR_HELPER_DATA_SIZE];
+} PRHelperClient;
+
+typedef struct PRHelperRequest {
+    int fd;
+    size_t sz;
+    uint8_t cdb[PR_HELPER_CDB_SIZE];
+} PRHelperRequest;
+
+static int prh_read(PRHelperClient *client, void *buf, int sz, Error **errp)
+{
+    while (sz > 0) {
+        int *fds = NULL;
+        size_t nfds = 0;
+        int i;
+        struct iovec iov;
+        ssize_t n_read;
+
+        iov.iov_base = buf;
+        iov.iov_len = sz;
+        n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1,
+                                        &fds, &nfds, errp);
+
+        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
+            qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN);
+            continue;
+        }
+        if (n_read <= 0) {
+            return n_read ? n_read : -1;
+        }
+
+        /* Stash one file descriptor per request.  */
+        if (nfds) {
+            for (i = 0; i < nfds; i++) {
+                if (client->fd == -1) {
+                    client->fd = fds[i++];
+                } else {
+                    close(fds[i]);
+                }
+            }
+            g_free(fds);
+        }
+
+        buf += n_read;
+        sz -= n_read;
+    }
+
+    return 0;
+}
+
+static int prh_read_request(PRHelperClient *client, PRHelperRequest *req,
+                            PRHelperResponse *resp, Error **errp)
+{
+    uint32_t sz;
+
+    if (prh_read(client, req->cdb, sizeof(req->cdb), NULL) < 0) {
+        return -1;
+    }
+
+    if (client->fd == -1) {
+        error_setg(errp, "No file descriptor in request.");
+        return -1;
+    }
+
+    if (req->cdb[0] != PERSISTENT_RESERVE_OUT &&
+        req->cdb[0] != PERSISTENT_RESERVE_IN) {
+        error_setg(errp, "Invalid CDB, closing socket.");
+        goto out_close;
+    }
+
+    sz = scsi_cdb_xfer(req->cdb);
+    if (sz > sizeof(client->data)) {
+        goto out_close;
+    }
+
+    if (req->cdb[0] == PERSISTENT_RESERVE_OUT) {
+        if (qio_channel_read_all(QIO_CHANNEL(client->ioc),
+                                 (char *)client->data, sz,
+                                 errp) < 0) {
+            goto out_close;
+        }
+        if (sz < PR_OUT_FIXED_PARAM_SIZE) {
+            /* Illegal request, Parameter list length error.  Not a fatal
+             * error, so read the data and do not close the socket.
+            */
+            scsi_build_sense(resp->sense, SENSE_CODE(INVALID_PARAM_LEN));
+            resp->result = CHECK_CONDITION;
+            sz = 0;
+            close(client->fd);
+            client->fd = -1;
+        }
+    }
+
+    req->fd = client->fd;
+    req->sz = sz;
+    client->fd = -1;
+    return sz;
+
+out_close:
+    close(client->fd);
+    client->fd = -1;
+    return -1;
+}
+
+static int prh_write_response(PRHelperClient *client, PRHelperRequest *req,
+                              PRHelperResponse *resp, Error **errp)
+{
+    ssize_t r;
+
+    resp->result = cpu_to_be32(resp->result);
+    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
+                              (char *) resp, sizeof(*resp), errp);
+    if (r < 0) {
+        return r;
+    }
+
+    if (req->cdb[0] == PERSISTENT_RESERVE_IN && resp->result == GOOD) {
+        assert(req->sz <= sizeof(client->data));
+        r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
+                                  (char *) client->data,
+                                  req->sz, errp);
+    }
+    return r < 0 ? r : 0;
+}
+
+static void prh_co_entry(void *opaque)
+{
+    PRHelperClient *client = opaque;
+    Error *local_err = NULL;
+    uint32_t flags;
+    int r;
+
+    qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
+                             false, NULL);
+    qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc),
+                                   qemu_get_aio_context());
+
+    /* A very simple negotiation for future extensibility.  No features
+     * are defined so write 0.
+     */
+    flags = cpu_to_be32(0);
+    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
+                             (char *) &flags, sizeof(flags), NULL);
+    if (r < 0) {
+        goto out;
+    }
+
+    r = qio_channel_read_all(QIO_CHANNEL(client->ioc),
+                             (char *) &flags, sizeof(flags), NULL);
+    if (be32_to_cpu(flags) != 0 || r < 0) {
+        goto out;
+    }
+
+    while (atomic_read(&state) == RUNNING) {
+        PRHelperRequest req;
+        PRHelperResponse resp;
+        int sz;
+
+        sz = prh_read_request(client, &req, &resp, &local_err);
+        if (sz < 0) {
+            break;
+        }
+
+        if (sz > 0) {
+            num_active_sockets++;
+            if (req.cdb[0] == PERSISTENT_RESERVE_OUT) {
+                r = do_pr_out(req.fd, req.cdb, resp.sense, client->data, sz);
+            } else {
+                r = do_pr_in(req.fd, req.cdb, resp.sense, client->data, sz);
+            }
+            num_active_sockets--;
+            close(req.fd);
+            if (r == -1) {
+                break;
+            }
+            resp.result = r;
+        }
+
+        if (prh_write_response(client, &req, &resp, &local_err) < 0) {
+            break;
+        }
+    }
+
+    if (local_err) {
+        if (verbose == 0) {
+            error_free(local_err);
+        } else {
+            error_report_err(local_err);
+        }
+    }
+
+out:
+    qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc));
+    object_unref(OBJECT(client->ioc));
+    g_free(client);
+}
+
+static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
+{
+    QIOChannelSocket *cioc;
+    PRHelperClient *prh;
+
+    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
+                                     NULL);
+    if (!cioc) {
+        return TRUE;
+    }
+
+    prh = g_new(PRHelperClient, 1);
+    prh->ioc = cioc;
+    prh->fd = -1;
+    prh->co = qemu_coroutine_create(prh_co_entry, prh);
+    qemu_coroutine_enter(prh->co);
+
+    return TRUE;
+}
+
+
+/*
+ * Check socket parameters compatibility when socket activation is used.
+ */
+static const char *socket_activation_validate_opts(void)
+{
+    if (socket_path != NULL) {
+        return "Unix socket can't be set when using socket activation";
+    }
+
+    return NULL;
+}
+
+static void compute_default_paths(void)
+{
+    socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock");
+    pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid");
+}
+
+static void termsig_handler(int signum)
+{
+    atomic_cmpxchg(&state, RUNNING, TERMINATE);
+    qemu_notify_event();
+}
+
+static void close_server_socket(void)
+{
+    g_assert(server_ioc);
+
+    g_source_remove(server_watch);
+    server_watch = -1;
+    object_unref(OBJECT(server_ioc));
+    num_active_sockets--;
+}
+
+#ifdef CONFIG_LIBCAP
+static int drop_privileges(void)
+{
+    /* clear all capabilities */
+    capng_clear(CAPNG_SELECT_BOTH);
+
+    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+                     CAP_SYS_RAWIO) < 0) {
+        return -1;
+    }
+
+    /* Change user/group id, retaining the capabilities.  Because file descriptors
+     * are passed via SCM_RIGHTS, we don't need supplementary groups (and in
+     * fact the helper can run as "nobody").
+     */
+    if (capng_change_id(uid != -1 ? uid : getuid(),
+                        gid != -1 ? gid : getgid(),
+                        CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING)) {
+        return -1;
+    }
+
+    return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+    const char *sopt = "hVk:fdT:u:g:q";
+    struct option lopt[] = {
+        { "help", no_argument, NULL, 'h' },
+        { "version", no_argument, NULL, 'V' },
+        { "socket", required_argument, NULL, 'k' },
+        { "pidfile", no_argument, NULL, 'f' },
+        { "daemon", no_argument, NULL, 'd' },
+        { "trace", required_argument, NULL, 'T' },
+        { "user", required_argument, NULL, 'u' },
+        { "group", required_argument, NULL, 'g' },
+        { "quiet", no_argument, NULL, 'q' },
+        { NULL, 0, NULL, 0 }
+    };
+    int opt_ind = 0;
+    int quiet = 0;
+    char ch;
+    Error *local_err = NULL;
+    char *trace_file = NULL;
+    bool daemonize = false;
+    unsigned socket_activation;
+
+    struct sigaction sa_sigterm;
+    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
+    sa_sigterm.sa_handler = termsig_handler;
+    sigaction(SIGTERM, &sa_sigterm, NULL);
+    sigaction(SIGINT, &sa_sigterm, NULL);
+    sigaction(SIGHUP, &sa_sigterm, NULL);
+
+    signal(SIGPIPE, SIG_IGN);
+
+    compute_default_paths();
+
+    module_call_init(MODULE_INIT_TRACE);
+    module_call_init(MODULE_INIT_QOM);
+    qemu_add_opts(&qemu_trace_opts);
+    qemu_init_exec_dir(argv[0]);
+
+    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
+        switch (ch) {
+        case 'k':
+            socket_path = optarg;
+            if (socket_path[0] != '/') {
+                error_report("socket path must be absolute");
+                exit(EXIT_FAILURE);
+            }
+            break;
+        case 'f':
+            pidfile = optarg;
+            break;
+#ifdef CONFIG_LIBCAP
+        case 'u': {
+            unsigned long res;
+            struct passwd *userinfo = getpwnam(optarg);
+            if (userinfo) {
+                uid = userinfo->pw_uid;
+            } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
+                       (uid_t)res == res) {
+                uid = res;
+            } else {
+                error_report("invalid user '%s'", optarg);
+                exit(EXIT_FAILURE);
+            }
+            break;
+        }
+        case 'g': {
+            unsigned long res;
+            struct group *groupinfo = getgrnam(optarg);
+            if (groupinfo) {
+                gid = groupinfo->gr_gid;
+            } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
+                       (gid_t)res == res) {
+                gid = res;
+            } else {
+                error_report("invalid group '%s'", optarg);
+                exit(EXIT_FAILURE);
+            }
+            break;
+        }
+#else
+        case 'u':
+        case 'g':
+            error_report("-%c not supported by this %s", ch, argv[0]);
+            exit(1);
+#endif
+        case 'd':
+            daemonize = true;
+            break;
+        case 'q':
+            quiet = 1;
+            break;
+        case 'T':
+            g_free(trace_file);
+            trace_file = trace_opt_parse(optarg);
+            break;
+        case 'V':
+            version(argv[0]);
+            exit(0);
+            break;
+        case 'h':
+            usage(argv[0]);
+            exit(0);
+            break;
+        case '?':
+            error_report("Try `%s --help' for more information.", argv[0]);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    /* set verbosity */
+    verbose = !quiet;
+
+    if (!trace_init_backends()) {
+        exit(1);
+    }
+    trace_init_file(trace_file);
+    qemu_set_log(LOG_TRACE);
+
+#ifdef CONFIG_MPATH
+    dm_init();
+    multipath_pr_init();
+#endif
+
+    socket_activation = check_socket_activation();
+    if (socket_activation == 0) {
+        SocketAddress saddr = {
+            .type = SOCKET_ADDRESS_TYPE_UNIX,
+            .u.q_unix.path = g_strdup(socket_path)
+        };
+        server_ioc = qio_channel_socket_new();
+        if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) {
+            object_unref(OBJECT(server_ioc));
+            error_report_err(local_err);
+            return 1;
+        }
+        g_free(saddr.u.q_unix.path);
+    } else {
+        /* Using socket activation - check user didn't use -p etc. */
+        const char *err_msg = socket_activation_validate_opts();
+        if (err_msg != NULL) {
+            error_report("%s", err_msg);
+            exit(EXIT_FAILURE);
+        }
+
+        /* Can only listen on a single socket.  */
+        if (socket_activation > 1) {
+            error_report("%s does not support socket activation with LISTEN_FDS > 1",
+                         argv[0]);
+            exit(EXIT_FAILURE);
+        }
+        server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
+                                               &local_err);
+        if (server_ioc == NULL) {
+            error_report("Failed to use socket activation: %s",
+                         error_get_pretty(local_err));
+            exit(EXIT_FAILURE);
+        }
+        socket_path = NULL;
+    }
+
+    if (qemu_init_main_loop(&local_err)) {
+        error_report_err(local_err);
+        exit(EXIT_FAILURE);
+    }
+
+    server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
+                                         G_IO_IN,
+                                         accept_client,
+                                         NULL, NULL);
+
+#ifdef CONFIG_LIBCAP
+    if (drop_privileges() < 0) {
+        error_report("Failed to drop privileges: %s", strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+#endif
+
+    if (daemonize) {
+        if (daemon(0, 0) < 0) {
+            error_report("Failed to daemonize: %s", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    state = RUNNING;
+    do {
+        main_loop_wait(false);
+        if (state == TERMINATE) {
+            state = TERMINATING;
+            close_server_socket();
+        }
+    } while (num_active_sockets > 0);
+
+    exit(EXIT_SUCCESS);
+}
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (7 preceding siblings ...)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-23  5:01   ` Fam Zheng
                     ` (2 more replies)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper Paolo Bonzini
                   ` (4 subsequent siblings)
  13 siblings, 3 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

Proper support of persistent reservation for multipath devices requires
communication with the multipath daemon, so that the reservation is
registered and applied when a path comes up.  The device mapper
utilities provide a library to do so; this patch makes qemu-pr-helper.c
detect multipath devices and, when one is found, delegate the operation
to libmpathpersist.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile              |   3 +
 configure             |  57 ++++++++-
 docs/pr-manager.rst   |  27 +++++
 include/scsi/utils.h  |   6 +
 scsi/qemu-pr-helper.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++-
 scsi/utils.c          |  15 +++
 6 files changed, 414 insertions(+), 5 deletions(-)

diff --git a/Makefile b/Makefile
index bfd4f69ecd..f1acaad05b 100644
--- a/Makefile
+++ b/Makefile
@@ -388,6 +388,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal
 fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
 
 scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
+ifdef CONFIG_MPATH
+scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
+endif
 
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
diff --git a/configure b/configure
index 772aff18d6..d3c9371f7c 100755
--- a/configure
+++ b/configure
@@ -286,6 +286,7 @@ pixman=""
 sdl=""
 sdlabi=""
 virtfs=""
+mpath=""
 vnc="yes"
 sparse="no"
 vde=""
@@ -948,6 +949,10 @@ for opt do
   ;;
   --enable-virtfs) virtfs="yes"
   ;;
+  --disable-mpath) mpath="no"
+  ;;
+  --enable-mpath) mpath="yes"
+  ;;
   --disable-vnc) vnc="no"
   ;;
   --enable-vnc) vnc="yes"
@@ -1491,6 +1496,7 @@ disabled with --disable-FEATURE, default is enabled if available:
   vnc-png         PNG compression for VNC server
   cocoa           Cocoa UI (Mac OS X only)
   virtfs          VirtFS
+  mpath           Multipath persistent reservation passthrough
   xen             xen backend driver support
   xen-pci-passthrough
   brlapi          BrlAPI (Braile)
@@ -3336,6 +3342,29 @@ else
 fi
 
 ##########################################
+# libmpathpersist probe
+
+if test "$mpath" != "no" ; then
+  cat > $TMPC <<EOF
+#include <libudev.h>
+#include <mpath_persist.h>
+unsigned mpath_mx_alloc_len = 1024;
+int logsink;
+int main(void) {
+    struct udev *udev = udev_new();
+    mpath_lib_init(udev);
+}
+EOF
+  if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
+    mpathpersist=yes
+  else
+    mpathpersist=no
+  fi
+else
+  mpathpersist=no
+fi
+
+##########################################
 # libcap probe
 
 if test "$cap" != "no" ; then
@@ -5070,16 +5099,34 @@ if test "$want_tools" = "yes" ; then
   fi
 fi
 if test "$softmmu" = yes ; then
-  if test "$virtfs" != no ; then
-    if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
+  if test "$linux" = yes; then
+    if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then
       virtfs=yes
       tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
     else
       if test "$virtfs" = yes; then
-        error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
+        error_exit "VirtFS requires libcap devel and libattr devel"
       fi
       virtfs=no
     fi
+    if test "$mpath" != no && test "$mpathpersist" = yes ; then
+      mpath=yes
+      tools="$tools mpath/qemu-mpath-helper\$(EXESUF)"
+    else
+      if test "$mpath" = yes; then
+        error_exit "Multipath requires libmpathpersist devel"
+      fi
+      mpath=no
+    fi
+  else
+    if test "$virtfs" = yes; then
+      error_exit "VirtFS is supported only on Linux"
+    fi
+    virtfs=no
+    if test "$mpath" = yes; then
+      error_exit "Multipath is supported only on Linux"
+    fi
+    mpath=no
   fi
 fi
 
@@ -5326,6 +5373,7 @@ echo "Audio drivers     $audio_drv_list"
 echo "Block whitelist (rw) $block_drv_rw_whitelist"
 echo "Block whitelist (ro) $block_drv_ro_whitelist"
 echo "VirtFS support    $virtfs"
+echo "Multipath support $mpath"
 echo "VNC support       $vnc"
 if test "$vnc" = "yes" ; then
     echo "VNC SASL support  $vnc_sasl"
@@ -5773,6 +5821,9 @@ fi
 if test "$virtfs" = "yes" ; then
   echo "CONFIG_VIRTFS=y" >> $config_host_mak
 fi
+if test "$mpath" = "yes" ; then
+  echo "CONFIG_MPATH=y" >> $config_host_mak
+fi
 if test "$vhost_scsi" = "yes" ; then
   echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
 fi
diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
index 7107e59fb8..9b1de198b1 100644
--- a/docs/pr-manager.rst
+++ b/docs/pr-manager.rst
@@ -60,6 +60,7 @@ system service and supports the following option:
 
 -d, --daemon              run in the background
 -q, --quiet               decrease verbosity
+-v, --verbose             increase verbosity
 -f, --pidfile=path        PID file when running as a daemon
 -k, --socket=path         path to the socket
 -T, --trace=trace-opts    tracing options
@@ -82,3 +83,29 @@ its operation.  To do this, add the following options:
 
 -u, --user=user           user to drop privileges to
 -g, --group=group         group to drop privileges to
+
+---------------------------------------------
+Multipath devices and persistent reservations
+---------------------------------------------
+
+Proper support of persistent reservation for multipath devices requires
+communication with the multipath daemon, so that the reservation is
+registered and applied when a path is newly discovered or becomes online
+again.  :command:`qemu-pr-helper` can do this if the ``libmpathpersist``
+library was available on the system at build time.
+
+As of August 2017, a reservation key must be specified in ``multipath.conf``
+for ``multipathd`` to check for persistent reservation for newly
+discovered paths or reinstated paths.  The attribute can be added
+to the ``defaults`` section or the ``multipaths`` section; for example::
+
+    multipaths {
+        multipath {
+            wwid   XXXXXXXXXXXXXXXX
+            alias      yellow
+            reservation_key  0x123abc
+        }
+    }
+
+Linking :program:`qemu-pr-helper` to ``libmpathpersist`` does not impede
+its usage on regular SCSI devices.
diff --git a/include/scsi/utils.h b/include/scsi/utils.h
index c12b34f2e5..c626be2c78 100644
--- a/include/scsi/utils.h
+++ b/include/scsi/utils.h
@@ -44,6 +44,8 @@ extern const struct SCSISense sense_code_LUN_NOT_READY;
 extern const struct SCSISense sense_code_NO_MEDIUM;
 /* LUN not ready, medium removal prevented */
 extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
+/* Medium Error, Unrecoverable Read Error */
+extern const struct SCSISense sense_code_READ_ERROR;
 /* Hardware error, internal target failure */
 extern const struct SCSISense sense_code_TARGET_FAILURE;
 /* Illegal request, invalid command operation code */
@@ -80,6 +82,8 @@ extern const struct SCSISense sense_code_CAPACITY_CHANGED;
 extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
 /* Unit attention, Power on, reset or bus device reset occurred */
 extern const struct SCSISense sense_code_RESET;
+/* Unit attention, SCSI Bus Reset */
+extern const struct SCSISense sense_code_SCSI_BUS_RESET;
 /* Unit attention, Medium may have changed*/
 extern const struct SCSISense sense_code_MEDIUM_CHANGED;
 /* Unit attention, Reported LUNs data has changed */
@@ -90,6 +94,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
 extern const struct SCSISense sense_code_WRITE_PROTECTED;
 /* Data Protection, Space Allocation Failed Write Protect */
 extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
+/* Aborted Command, LUN Communication Failure */
+extern const struct SCSISense sense_code_LUN_COMM_FAILURE;
 
 #define SENSE_CODE(x) sense_code_ ## x
 
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
index d52234af0f..707bb6127b 100644
--- a/scsi/qemu-pr-helper.c
+++ b/scsi/qemu-pr-helper.c
@@ -51,6 +51,14 @@
 #include <pwd.h>
 #include <grp.h>
 
+#ifdef CONFIG_MPATH
+#define CONTROL_PATH "/dev/mapper/control"
+#include <libudev.h>
+#include "mpath_cmd.h"
+#include "mpath_persist.h"
+#endif
+
+QEMU_BUILD_BUG_ON(PR_HELPER_DATA_SIZE > MPATH_MAX_PARAM_LEN);
 
 #define PR_OUT_FIXED_PARAM_SIZE 24
 
@@ -60,6 +68,7 @@ static enum { RUNNING, TERMINATE, TERMINATING } state;
 static QIOChannelSocket *server_ioc;
 static int server_watch;
 static int num_active_sockets = 1;
+static int noisy;
 static int verbose;
 
 #ifdef CONFIG_LIBCAP
@@ -162,9 +171,290 @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
     return thread_pool_submit_co(pool, do_sgio_worker, &data);
 }
 
+/* Device mapper interface */
+
+#ifdef CONFIG_MPATH
+typedef struct DMData {
+    struct dm_ioctl dm;
+    uint8_t data[1024];
+} DMData;
+
+static int control_fd;
+
+static void *dm_ioctl(int ioc, struct dm_ioctl *dm)
+{
+    static DMData d;
+    memcpy(&d.dm, dm, sizeof(d.dm));
+    QEMU_BUILD_BUG_ON(sizeof(d.data) < sizeof(struct dm_target_spec));
+
+    d.dm.version[0] = DM_VERSION_MAJOR;
+    d.dm.version[1] = 0;
+    d.dm.version[2] = 0;
+    d.dm.data_size = 1024;
+    d.dm.data_start = offsetof(DMData, data);
+    if (ioctl(control_fd, ioc, &d) < 0) {
+        return NULL;
+    }
+    memcpy(dm, &d.dm, sizeof(d.dm));
+    return &d.data;
+}
+
+static void *dm_dev_ioctl(int fd, int ioc, struct dm_ioctl *dm)
+{
+    struct stat st;
+    int r;
+
+    r = fstat(fd, &st);
+    if (r < 0) {
+        perror("fstat");
+        exit(1);
+    }
+
+    dm->dev = st.st_rdev;
+    return dm_ioctl(ioc, dm);
+}
+
+static void dm_init(void)
+{
+    control_fd = open(CONTROL_PATH, O_RDWR);
+    if (control_fd < 0) {
+        perror("Cannot open " CONTROL_PATH);
+        exit(1);
+    }
+    struct dm_ioctl dm = { 0 };
+    if (!dm_ioctl(DM_VERSION, &dm)) {
+        perror("ioctl");
+        exit(1);
+    }
+    if (dm.version[0] != DM_VERSION_MAJOR) {
+        fprintf(stderr, "Unsupported device mapper interface");
+        exit(1);
+    }
+}
+
+/* Variables required by libmultipath and libmpathpersist.  */
+unsigned mpath_mx_alloc_len = PR_HELPER_DATA_SIZE;
+int logsink;
+
+static void multipath_pr_init(void)
+{
+    static struct udev *udev;
+
+    udev = udev_new();
+    mpath_lib_init(udev);
+}
+
+static int is_mpath(int fd)
+{
+    struct dm_ioctl dm = { .flags = DM_NOFLUSH_FLAG };
+    struct dm_target_spec *tgt;
+
+    tgt = dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm);
+    if (!tgt) {
+        if (errno == ENXIO) {
+            return 0;
+        }
+        perror("ioctl");
+        exit(EXIT_FAILURE);
+    }
+    return !strncmp(tgt->target_type, "multipath", DM_MAX_TYPE_NAME);
+}
+
+static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense)
+{
+    switch (r) {
+    case MPATH_PR_SUCCESS:
+        return GOOD;
+    case MPATH_PR_SENSE_NOT_READY:
+    case MPATH_PR_SENSE_MEDIUM_ERROR:
+    case MPATH_PR_SENSE_HARDWARE_ERROR:
+    case MPATH_PR_SENSE_ABORTED_COMMAND:
+        {
+            /* libmpathpersist ate the exact sense.  Try to find it by
+             * issuing TEST UNIT READY.
+             */
+            uint8_t cdb[6] = { TEST_UNIT_READY };
+            return do_sgio(fd, cdb, sense, NULL, 0, SG_DXFER_NONE);
+        }
+
+    case MPATH_PR_SENSE_UNIT_ATTENTION:
+        /* Congratulations libmpathpersist, you ruined the Unit Attention...
+         * Return a heavyweight one.
+         */
+        scsi_build_sense(sense, SENSE_CODE(SCSI_BUS_RESET));
+        return CHECK_CONDITION;
+    case MPATH_PR_SENSE_INVALID_OP:
+        /* Only one valid sense.  */
+        scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
+        return CHECK_CONDITION;
+    case MPATH_PR_ILLEGAL_REQ:
+        /* Guess.  */
+        scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
+        return CHECK_CONDITION;
+    case MPATH_PR_NO_SENSE:
+        scsi_build_sense(sense, SENSE_CODE(NO_SENSE));
+        return CHECK_CONDITION;
+
+    case MPATH_PR_RESERV_CONFLICT:
+        return RESERVATION_CONFLICT;
+
+    case MPATH_PR_OTHER:
+    default:
+        scsi_build_sense(sense, SENSE_CODE(LUN_COMM_FAILURE));
+        return CHECK_CONDITION;
+    }
+}
+
+static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
+                           uint8_t *data, int sz)
+{
+    int rq_servact = cdb[1];
+    struct prin_resp resp;
+    size_t written;
+    int r;
+
+    switch (rq_servact) {
+    case MPATH_PRIN_RKEY_SA:
+    case MPATH_PRIN_RRES_SA:
+    case MPATH_PRIN_RCAP_SA:
+        break;
+    case MPATH_PRIN_RFSTAT_SA:
+        /* Nobody implements it anyway, so bail out. */
+    default:
+        /* Cannot parse any other output.  */
+        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
+        return CHECK_CONDITION;
+    }
+
+    r = mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbose);
+    if (r == MPATH_PR_SUCCESS) {
+        switch (rq_servact) {
+        case MPATH_PRIN_RKEY_SA:
+        case MPATH_PRIN_RRES_SA: {
+            struct prin_readdescr *out = &resp.prin_descriptor.prin_readkeys;
+            stl_be_p(&data[0], out->prgeneration);
+            stl_be_p(&data[4], out->additional_length);
+            memcpy(&data[8], out->key_list, MIN(out->additional_length, sz - 8));
+            written = MIN(out->additional_length + 8, sz);
+            break;
+        }
+        case MPATH_PRIN_RCAP_SA: {
+            struct prin_capdescr *out = &resp.prin_descriptor.prin_readcap;
+            stw_be_p(&data[0], out->length);
+            data[2] = out->flags[0];
+            data[3] = out->flags[1];
+            stw_be_p(&data[4], out->pr_type_mask);
+            written = MIN(6, sz);
+            break;
+        }
+        default:
+            scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
+            return CHECK_CONDITION;
+        }
+        assert(written < sz);
+        memset(data + written, 0, sz - written);
+    }
+
+    return mpath_reconstruct_sense(fd, r, sense);
+}
+
+static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
+                            const uint8_t *param, int sz)
+{
+    int rq_servact = cdb[1];
+    int rq_scope = cdb[2] >> 4;
+    int rq_type = cdb[2] & 0xf;
+    struct prout_param_descriptor paramp;
+    char transportids[PR_HELPER_DATA_SIZE];
+    int r;
+    int i, j;
+
+    switch (rq_servact) {
+    case MPATH_PROUT_REG_SA:
+    case MPATH_PROUT_RES_SA:
+    case MPATH_PROUT_REL_SA:
+    case MPATH_PROUT_CLEAR_SA:
+    case MPATH_PROUT_PREE_SA:
+    case MPATH_PROUT_PREE_AB_SA:
+    case MPATH_PROUT_REG_IGN_SA:
+    case MPATH_PROUT_REG_MOV_SA:
+        break;
+    default:
+        /* Cannot parse any other input.  */
+        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
+        return CHECK_CONDITION;
+    }
+
+    /* Convert input data, especially transport IDs, to the structs
+     * used by libmpathpersist (which, of course, will immediately
+     * do the opposite).
+     */
+    memset(&paramp, 0, sizeof(paramp));
+    memcpy(&paramp.key, &param[0], 8);
+    memcpy(&paramp.sa_key, &param[8], 8);
+    paramp.sa_flags = param[10];
+    for (i = PR_OUT_FIXED_PARAM_SIZE, j = 0; i < sz; ) {
+        struct transportid *id = (struct transportid *) &transportids[j];
+        int len;
+
+        id->format_code = param[i] & 0xc0;
+        id->protocol_id = param[i] & 0x0f;
+        switch (param[i] & 0xcf) {
+        case 0:
+            /* FC transport.  */
+            memcpy(id->n_port_name, &param[i + 8], 8);
+            j += offsetof(struct transportid, n_port_name[8]);
+            i += 24;
+            break;
+        case 3:
+        case 0x43:
+            /* iSCSI transport.  */
+            len = lduw_be_p(&param[i + 2]);
+            if (len > 252 || (len & 3)) {
+                /* For format code 00, the standard says the maximum is 223,
+                 * plus the NUL terminator.  For format code 01 there is no
+                 * maximum length, but libmpathpersist ignores the first byte
+                 * of id->iscsi_name so our maximum is 252.
+                 */
+                goto illegal_req;
+            }
+            if (memchr(&param[i + 4], 0, len) == NULL) {
+                goto illegal_req;
+            }
+            memcpy(id->iscsi_name, &param[i + 2], len + 2);
+            j += offsetof(struct transportid, iscsi_name[len + 2]);
+            i += len + 4;
+            break;
+        case 6:
+            /* SAS transport.  */
+            memcpy(id->sas_address, &param[i + 4], 8);
+            j += offsetof(struct transportid, sas_address[8]);
+            i += 24;
+            break;
+        default:
+        illegal_req:
+            scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM));
+            return CHECK_CONDITION;
+        }
+
+        paramp.trnptid_list[paramp.num_transportid++] = id;
+    }
+
+    r = mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type,
+                                     &paramp, noisy, verbose);
+    return mpath_reconstruct_sense(fd, r, sense);
+}
+#endif
+
 static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
                     uint8_t *data, int sz)
 {
+#ifdef CONFIG_MPATH
+    if (is_mpath(fd)) {
+        return multipath_pr_in(fd, cdb, sense, data, sz);
+    }
+#endif
+
     return do_sgio(fd, cdb, sense, data, sz,
                    SG_DXFER_FROM_DEV);
 }
@@ -172,6 +462,12 @@ static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
 static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
                      const uint8_t *param, int sz)
 {
+#ifdef CONFIG_MPATH
+    if (is_mpath(fd)) {
+        return multipath_pr_out(fd, cdb, sense, param, sz);
+    }
+#endif
+
     return do_sgio(fd, cdb, sense, (uint8_t *)param, sz,
                    SG_DXFER_TO_DEV);
 }
@@ -444,6 +740,11 @@ static int drop_privileges(void)
                      CAP_SYS_RAWIO) < 0) {
         return -1;
     }
+    /* For /dev/mapper/control ioctls */
+    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+                     CAP_SYS_ADMIN) < 0) {
+        return -1;
+    }
 
     /* Change user/group id, retaining the capabilities.  Because file descriptors
      * are passed via SCM_RIGHTS, we don't need supplementary groups (and in
@@ -461,7 +762,7 @@ static int drop_privileges(void)
 
 int main(int argc, char **argv)
 {
-    const char *sopt = "hVk:fdT:u:g:q";
+    const char *sopt = "hVk:fdT:u:g:vq";
     struct option lopt[] = {
         { "help", no_argument, NULL, 'h' },
         { "version", no_argument, NULL, 'V' },
@@ -471,10 +772,12 @@ int main(int argc, char **argv)
         { "trace", required_argument, NULL, 'T' },
         { "user", required_argument, NULL, 'u' },
         { "group", required_argument, NULL, 'g' },
+        { "verbose", no_argument, NULL, 'v' },
         { "quiet", no_argument, NULL, 'q' },
         { NULL, 0, NULL, 0 }
     };
     int opt_ind = 0;
+    int loglevel = 1;
     int quiet = 0;
     char ch;
     Error *local_err = NULL;
@@ -551,6 +854,9 @@ int main(int argc, char **argv)
         case 'q':
             quiet = 1;
             break;
+        case 'v':
+            ++loglevel;
+            break;
         case 'T':
             g_free(trace_file);
             trace_file = trace_opt_parse(optarg);
@@ -570,7 +876,8 @@ int main(int argc, char **argv)
     }
 
     /* set verbosity */
-    verbose = !quiet;
+    noisy = !quiet && (loglevel >= 3);
+    verbose = quiet ? 0 : MIN(loglevel, 3);
 
     if (!trace_init_backends()) {
         exit(1);
diff --git a/scsi/utils.c b/scsi/utils.c
index eedd5f45b4..b5c0e05408 100644
--- a/scsi/utils.c
+++ b/scsi/utils.c
@@ -116,6 +116,11 @@ const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
     .key = NOT_READY, .asc = 0x53, .ascq = 0x02
 };
 
+/* Medium Error, Unrecoverable Read Error */
+const struct SCSISense sense_code_READ_ERROR = {
+    .key = MEDIUM_ERROR, .asc = 0x11, .ascq = 0x00
+};
+
 /* Hardware error, internal target failure */
 const struct SCSISense sense_code_TARGET_FAILURE = {
     .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
@@ -191,6 +196,11 @@ const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
     .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
 };
 
+/* Command aborted, LUN Communication Failure */
+const struct SCSISense sense_code_LUN_COMM_FAILURE = {
+    .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00
+};
+
 /* Unit attention, Capacity data has changed */
 const struct SCSISense sense_code_CAPACITY_CHANGED = {
     .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
@@ -201,6 +211,11 @@ const struct SCSISense sense_code_RESET = {
     .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
 };
 
+/* Unit attention, SCSI bus reset */
+const struct SCSISense sense_code_SCSI_BUS_RESET = {
+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x02
+};
+
 /* Unit attention, No medium */
 const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
     .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (8 preceding siblings ...)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper Paolo Bonzini
@ 2017-08-22 13:18 ` Paolo Bonzini
  2017-08-23  4:49   ` Fam Zheng
  2017-08-30 16:58   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
  2017-08-22 13:48 ` [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers no-reply
                   ` (3 subsequent siblings)
  13 siblings, 2 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, famz

This adds a concrete subclass of pr-manager that talks to qemu-pr-helper.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 scsi/Makefile.objs       |   2 +-
 scsi/pr-manager-helper.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 289 insertions(+), 1 deletion(-)
 create mode 100644 scsi/pr-manager-helper.c

diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
index 5496d2ae6a..4d25e476cf 100644
--- a/scsi/Makefile.objs
+++ b/scsi/Makefile.objs
@@ -1,3 +1,3 @@
 block-obj-y += utils.o
 
-block-obj-$(CONFIG_LINUX) += pr-manager.o
+block-obj-$(CONFIG_LINUX) += pr-manager.o pr-manager-helper.o
diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c
new file mode 100644
index 0000000000..c9d9606696
--- /dev/null
+++ b/scsi/pr-manager-helper.c
@@ -0,0 +1,288 @@
+/*
+ * Persistent reservation manager that talks to qemu-mpath-helper
+ *
+ * Copyright (c) 2017 Red Hat, Inc.
+ *
+ * Author: Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This code is licensed under the LGPL.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "scsi/constants.h"
+#include "scsi/pr-manager.h"
+#include "scsi/utils.h"
+#include "io/channel.h"
+#include "io/channel-socket.h"
+#include "pr-helper.h"
+
+#include <scsi/sg.h>
+
+#define PR_MAX_RECONNECT_ATTEMPTS 5
+
+#define TYPE_PR_MANAGER_HELPER "pr-manager-helper"
+
+#define PR_MANAGER_HELPER(obj) \
+     INTERFACE_CHECK(PRManagerHelper, (obj), \
+                     TYPE_PR_MANAGER_HELPER)
+
+typedef struct PRManagerHelper {
+    /* <private> */
+    PRManager parent;
+
+    char *path;
+
+    QemuMutex lock;
+    QIOChannel *ioc;
+} PRManagerHelper;
+
+/* Called with lock held.  */
+static int pr_manager_helper_read(PRManagerHelper *pr_mgr,
+                                  void *buf, int sz, Error **errp)
+{
+    ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp);
+
+    if (r < 0) {
+        object_unref(OBJECT(pr_mgr->ioc));
+        pr_mgr->ioc = NULL;
+        return r;
+    }
+
+    return r < 0 ? r : 0;
+}
+
+/* Called with lock held.  */
+static int pr_manager_helper_write(PRManagerHelper *pr_mgr,
+                                   int fd,
+                                   const void *buf, int sz, Error **errp)
+{
+    size_t nfds = (fd != -1);
+    while (sz > 0) {
+        struct iovec iov;
+        ssize_t n_written;
+
+        iov.iov_base = (void *)buf;
+        iov.iov_len = sz;
+        n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1,
+                                            nfds ? &fd : NULL, nfds, errp);
+
+        if (n_written <= 0) {
+            assert(n_written != QIO_CHANNEL_ERR_BLOCK);
+            object_unref(OBJECT(pr_mgr->ioc));
+            pr_mgr->ioc = NULL;
+            return n_written;
+        }
+
+        nfds = 0;
+        buf += n_written;
+        sz -= n_written;
+    }
+
+    return 0;
+}
+
+/* Called with lock held.  */
+static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr,
+                                        Error **errp)
+{
+    uint32_t flags;
+
+    SocketAddress saddr = {
+        .type = SOCKET_ADDRESS_TYPE_UNIX,
+        .u.q_unix.path = g_strdup(pr_mgr->path)
+    };
+    QIOChannelSocket *sioc = qio_channel_socket_new();
+    Error *local_err = NULL;
+
+    qio_channel_set_name(QIO_CHANNEL(sioc), "pr-manager-helper");
+    qio_channel_socket_connect_sync(sioc,
+                                    &saddr,
+                                    &local_err);
+    if (local_err) {
+        object_unref(OBJECT(sioc));
+        error_propagate(errp, local_err);
+        return -ENOTCONN;
+    }
+
+    qio_channel_set_delay(QIO_CHANNEL(sioc), false);
+    pr_mgr->ioc = QIO_CHANNEL(sioc);
+
+    /* A simple feature negotation protocol, even though there is
+     * no optional feature right now.
+     */
+    if (pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp) < 0) {
+        return -EINVAL;
+    }
+
+    flags = 0;
+    if (pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp) < 0) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int pr_manager_helper_run(PRManager *p,
+                                 int fd, struct sg_io_hdr *io_hdr)
+{
+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p);
+
+    uint32_t len;
+    PRHelperResponse resp;
+    int ret;
+    int expected_dir;
+    int attempts;
+    uint8_t cdb[PR_HELPER_CDB_SIZE] = { 0 };
+
+    if (!io_hdr->cmd_len || io_hdr->cmd_len > PR_HELPER_CDB_SIZE) {
+        return -EINVAL;
+    }
+
+    memcpy(cdb, io_hdr->cmdp, io_hdr->cmd_len);
+    assert(cdb[0] == PERSISTENT_RESERVE_OUT || cdb[0] == PERSISTENT_RESERVE_IN);
+    expected_dir =
+        (cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV);
+    if (io_hdr->dxfer_direction != expected_dir) {
+        return -EINVAL;
+    }
+
+    len = scsi_cdb_xfer(cdb);
+    if (io_hdr->dxfer_len < len || len > PR_HELPER_DATA_SIZE) {
+        return -EINVAL;
+    }
+
+    ret = 0;
+    qemu_mutex_lock(&pr_mgr->lock);
+
+    /* Try to reconnect while sending the CDB.  */
+    for (attempts = 0; attempts < PR_MAX_RECONNECT_ATTEMPTS; attempts++) {
+        if (!pr_mgr->ioc) {
+            if (pr_manager_helper_initialize(pr_mgr, NULL) < 0) {
+                qemu_mutex_unlock(&pr_mgr->lock);
+                g_usleep(G_USEC_PER_SEC);
+                qemu_mutex_lock(&pr_mgr->lock);
+            }
+        }
+
+        if (pr_mgr->ioc) {
+            if (pr_manager_helper_write(pr_mgr, fd, cdb,
+                                        ARRAY_SIZE(cdb), NULL) >= 0) {
+                break;
+            }
+        }
+    }
+    if (attempts == PR_MAX_RECONNECT_ATTEMPTS) {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    /* After sending the CDB, any communications failure causes the
+     * command to fail.  The failure is transient, retrying the command
+     * will invoke pr_manager_helper_initialize again.
+     */
+    if (expected_dir == SG_DXFER_TO_DEV) {
+        if (pr_manager_helper_write(pr_mgr, -1, io_hdr->dxferp,
+                                    len, NULL) < 0) {
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+    if (pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL) < 0) {
+        ret = -EINVAL;
+        goto out;
+    }
+    if (expected_dir == SG_DXFER_FROM_DEV && resp.result == 0) {
+        if (pr_manager_helper_read(pr_mgr, io_hdr->dxferp, len, NULL) < 0) {
+            ret = -EINVAL;
+            goto out;
+        }
+    }
+
+    io_hdr->status = resp.result;
+    if (resp.result == CHECK_CONDITION) {
+        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
+        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE);
+        memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr);
+    }
+
+out:
+    if (ret < 0) {
+        int sense_len = scsi_build_sense(io_hdr->sbp,
+                                         SENSE_CODE(LUN_COMM_FAILURE));
+        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
+        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len);
+        io_hdr->status = CHECK_CONDITION;
+    }
+    qemu_mutex_unlock(&pr_mgr->lock);
+    return ret;
+}
+
+static void pr_manager_helper_complete(UserCreatable *uc, Error **errp)
+{
+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(uc);
+
+    qemu_mutex_lock(&pr_mgr->lock);
+    pr_manager_helper_initialize(pr_mgr, errp);
+    qemu_mutex_unlock(&pr_mgr->lock);
+}
+
+static char *get_path(Object *obj, Error **errp)
+{
+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
+
+    return g_strdup(pr_mgr->path);
+}
+
+static void set_path(Object *obj, const char *str, Error **errp)
+{
+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
+
+    g_free(pr_mgr->path);
+    pr_mgr->path = g_strdup(str);
+}
+
+static void pr_manager_helper_instance_finalize(Object *obj)
+{
+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
+
+    g_free(pr_mgr->path);
+    object_unref(OBJECT(pr_mgr->ioc));
+    qemu_mutex_destroy(&pr_mgr->lock);
+}
+
+static void pr_manager_helper_instance_init(Object *obj)
+{
+    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
+
+    qemu_mutex_init(&pr_mgr->lock);
+}
+
+static void pr_manager_helper_class_init(ObjectClass *klass,
+                                         void *class_data G_GNUC_UNUSED)
+{
+    PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass);
+    UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass);
+
+    object_class_property_add_str(klass, "path", get_path, set_path,
+                                  &error_abort);
+    uc_klass->complete = pr_manager_helper_complete;
+    prmgr_klass->run = pr_manager_helper_run;
+}
+
+static const TypeInfo pr_manager_helper_info = {
+    .parent = TYPE_PR_MANAGER,
+    .name = TYPE_PR_MANAGER_HELPER,
+    .instance_size = sizeof(PRManagerHelper),
+    .instance_init = pr_manager_helper_instance_init,
+    .instance_finalize = pr_manager_helper_instance_finalize,
+    .class_init = pr_manager_helper_class_init,
+};
+
+static void pr_manager_helper_register_types(void)
+{
+    type_register_static(&pr_manager_helper_info);
+}
+
+type_init(pr_manager_helper_register_types);
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 02/10] scsi: move non-emulation specific code to scsi/
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 02/10] scsi: move non-emulation specific code to scsi/ Paolo Bonzini
@ 2017-08-22 13:34   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 48+ messages in thread
From: Philippe Mathieu-Daudé @ 2017-08-22 13:34 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: famz, qemu-block

On 08/22/2017 10:18 AM, Paolo Bonzini wrote:
> There is a bunch of SCSI code that is shared by block/iscsi.c and
> hw/scsi, and the introduction of the persistent reservation helper
> will add more instances of this.  There is also include/block/scsi.h,
> which actually is not part of the core block layer.
> 
> Create a directory for this kind of shared code.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>   MAINTAINERS            |   7 +
>   Makefile.objs          |   2 +-
>   hw/scsi/scsi-bus.c     | 397 ------------------------------------------------
>   hw/scsi/scsi-generic.c |   8 -
>   include/block/scsi.h   |   2 -
>   include/hw/scsi/scsi.h |  94 +-----------
>   include/scsi/utils.h   | 116 ++++++++++++++
>   scsi/Makefile.objs     |   1 +
>   scsi/utils.c           | 403 +++++++++++++++++++++++++++++++++++++++++++++++++
>   9 files changed, 529 insertions(+), 501 deletions(-)
>   create mode 100644 include/scsi/utils.h
>   create mode 100644 scsi/Makefile.objs
>   create mode 100644 scsi/utils.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ccee28b12d..fa6e21cd38 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1213,6 +1213,13 @@ F: migration/block*
>   F: include/block/aio.h
>   T: git git://github.com/stefanha/qemu.git block
>   
> +Block SCSI subsystem
> +M: Paolo Bonzini <pbonzini@redhat.com>
> +L: qemu-block@nongnu.org
> +S: Supported
> +F: include/scsi/*
> +F: scsi/*
> +
>   Block Jobs
>   M: Jeff Cody <jcody@redhat.com>
>   L: qemu-block@nongnu.org
> diff --git a/Makefile.objs b/Makefile.objs
> index 24a4ea08b8..f68aa3b60d 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -11,7 +11,7 @@ chardev-obj-y = chardev/
>   
>   block-obj-y += nbd/
>   block-obj-y += block.o blockjob.o
> -block-obj-y += block/
> +block-obj-y += block/ scsi/
>   block-obj-y += qemu-io-cmds.o
>   block-obj-$(CONFIG_REPLICATION) += replication.o
>   
> diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
> index 890f8fcc83..300912d213 100644
> --- a/hw/scsi/scsi-bus.c
> +++ b/hw/scsi/scsi-bus.c
> @@ -935,36 +935,6 @@ static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
>       return xfer * unit;
>   }
>   
> -uint32_t scsi_data_cdb_xfer(uint8_t *buf)
> -{
> -    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
> -        return 256;
> -    } else {
> -        return scsi_cdb_xfer(buf);
> -    }
> -}
> -
> -uint32_t scsi_cdb_xfer(uint8_t *buf)
> -{
> -    switch (buf[0] >> 5) {
> -    case 0:
> -        return buf[4];
> -        break;
> -    case 1:
> -    case 2:
> -        return lduw_be_p(&buf[7]);
> -        break;
> -    case 4:
> -        return ldl_be_p(&buf[10]) & 0xffffffffULL;
> -        break;
> -    case 5:
> -        return ldl_be_p(&buf[6]) & 0xffffffffULL;
> -        break;
> -    default:
> -        return -1;
> -    }
> -}
> -
>   static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
>   {
>       cmd->xfer = scsi_cdb_xfer(buf);
> @@ -1277,53 +1247,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
>       }
>   }
>   
> -static uint64_t scsi_cmd_lba(SCSICommand *cmd)
> -{
> -    uint8_t *buf = cmd->buf;
> -    uint64_t lba;
> -
> -    switch (buf[0] >> 5) {
> -    case 0:
> -        lba = ldl_be_p(&buf[0]) & 0x1fffff;
> -        break;
> -    case 1:
> -    case 2:
> -    case 5:
> -        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
> -        break;
> -    case 4:
> -        lba = ldq_be_p(&buf[2]);
> -        break;
> -    default:
> -        lba = -1;
> -
> -    }
> -    return lba;
> -}
> -
> -int scsi_cdb_length(uint8_t *buf) {
> -    int cdb_len;
> -
> -    switch (buf[0] >> 5) {
> -    case 0:
> -        cdb_len = 6;
> -        break;
> -    case 1:
> -    case 2:
> -        cdb_len = 10;
> -        break;
> -    case 4:
> -        cdb_len = 16;
> -        break;
> -    case 5:
> -        cdb_len = 12;
> -        break;
> -    default:
> -        cdb_len = -1;
> -    }
> -    return cdb_len;
> -}
> -
>   int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
>   {
>       int rc;
> @@ -1370,326 +1293,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
>       }
>   }
>   
> -/*
> - * Predefined sense codes
> - */
> -
> -/* No sense data available */
> -const struct SCSISense sense_code_NO_SENSE = {
> -    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
> -};
> -
> -/* LUN not ready, Manual intervention required */
> -const struct SCSISense sense_code_LUN_NOT_READY = {
> -    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
> -};
> -
> -/* LUN not ready, Medium not present */
> -const struct SCSISense sense_code_NO_MEDIUM = {
> -    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
> -};
> -
> -/* LUN not ready, medium removal prevented */
> -const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
> -    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
> -};
> -
> -/* Hardware error, internal target failure */
> -const struct SCSISense sense_code_TARGET_FAILURE = {
> -    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
> -};
> -
> -/* Illegal request, invalid command operation code */
> -const struct SCSISense sense_code_INVALID_OPCODE = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
> -};
> -
> -/* Illegal request, LBA out of range */
> -const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
> -};
> -
> -/* Illegal request, Invalid field in CDB */
> -const struct SCSISense sense_code_INVALID_FIELD = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
> -};
> -
> -/* Illegal request, Invalid field in parameter list */
> -const struct SCSISense sense_code_INVALID_PARAM = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
> -};
> -
> -/* Illegal request, Parameter list length error */
> -const struct SCSISense sense_code_INVALID_PARAM_LEN = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
> -};
> -
> -/* Illegal request, LUN not supported */
> -const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
> -};
> -
> -/* Illegal request, Saving parameters not supported */
> -const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
> -};
> -
> -/* Illegal request, Incompatible medium installed */
> -const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
> -};
> -
> -/* Illegal request, medium removal prevented */
> -const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
> -};
> -
> -/* Illegal request, Invalid Transfer Tag */
> -const struct SCSISense sense_code_INVALID_TAG = {
> -    .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
> -};
> -
> -/* Command aborted, I/O process terminated */
> -const struct SCSISense sense_code_IO_ERROR = {
> -    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
> -};
> -
> -/* Command aborted, I_T Nexus loss occurred */
> -const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
> -    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
> -};
> -
> -/* Command aborted, Logical Unit failure */
> -const struct SCSISense sense_code_LUN_FAILURE = {
> -    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
> -};
> -
> -/* Command aborted, Overlapped Commands Attempted */
> -const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
> -    .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
> -};
> -
> -/* Unit attention, Capacity data has changed */
> -const struct SCSISense sense_code_CAPACITY_CHANGED = {
> -    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
> -};
> -
> -/* Unit attention, Power on, reset or bus device reset occurred */
> -const struct SCSISense sense_code_RESET = {
> -    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
> -};
> -
> -/* Unit attention, No medium */
> -const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
> -    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
> -};
> -
> -/* Unit attention, Medium may have changed */
> -const struct SCSISense sense_code_MEDIUM_CHANGED = {
> -    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
> -};
> -
> -/* Unit attention, Reported LUNs data has changed */
> -const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
> -    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
> -};
> -
> -/* Unit attention, Device internal reset */
> -const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
> -    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
> -};
> -
> -/* Data Protection, Write Protected */
> -const struct SCSISense sense_code_WRITE_PROTECTED = {
> -    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
> -};
> -
> -/* Data Protection, Space Allocation Failed Write Protect */
> -const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
> -    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
> -};
> -
> -/*
> - * scsi_convert_sense
> - *
> - * Convert between fixed and descriptor sense buffers
> - */
> -int scsi_convert_sense(uint8_t *in_buf, int in_len,
> -                       uint8_t *buf, int len, bool fixed)
> -{
> -    bool fixed_in;
> -    SCSISense sense;
> -    if (!fixed && len < 8) {
> -        return 0;
> -    }
> -
> -    if (in_len == 0) {
> -        sense.key = NO_SENSE;
> -        sense.asc = 0;
> -        sense.ascq = 0;
> -    } else {
> -        fixed_in = (in_buf[0] & 2) == 0;
> -
> -        if (fixed == fixed_in) {
> -            memcpy(buf, in_buf, MIN(len, in_len));
> -            return MIN(len, in_len);
> -        }
> -
> -        if (fixed_in) {
> -            sense.key = in_buf[2];
> -            sense.asc = in_buf[12];
> -            sense.ascq = in_buf[13];
> -        } else {
> -            sense.key = in_buf[1];
> -            sense.asc = in_buf[2];
> -            sense.ascq = in_buf[3];
> -        }
> -    }
> -
> -    memset(buf, 0, len);
> -    if (fixed) {
> -        /* Return fixed format sense buffer */
> -        buf[0] = 0x70;
> -        buf[2] = sense.key;
> -        buf[7] = 10;
> -        buf[12] = sense.asc;
> -        buf[13] = sense.ascq;
> -        return MIN(len, SCSI_SENSE_LEN);
> -    } else {
> -        /* Return descriptor format sense buffer */
> -        buf[0] = 0x72;
> -        buf[1] = sense.key;
> -        buf[2] = sense.asc;
> -        buf[3] = sense.ascq;
> -        return 8;
> -    }
> -}
> -
> -const char *scsi_command_name(uint8_t cmd)
> -{
> -    static const char *names[] = {
> -        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
> -        [ REWIND                   ] = "REWIND",
> -        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
> -        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
> -        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
> -        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
> -        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
> -        [ READ_6                   ] = "READ_6",
> -        [ WRITE_6                  ] = "WRITE_6",
> -        [ SET_CAPACITY             ] = "SET_CAPACITY",
> -        [ READ_REVERSE             ] = "READ_REVERSE",
> -        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
> -        [ SPACE                    ] = "SPACE",
> -        [ INQUIRY                  ] = "INQUIRY",
> -        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
> -        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
> -        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
> -        [ MODE_SELECT              ] = "MODE_SELECT",
> -        [ RESERVE                  ] = "RESERVE",
> -        [ RELEASE                  ] = "RELEASE",
> -        [ COPY                     ] = "COPY",
> -        [ ERASE                    ] = "ERASE",
> -        [ MODE_SENSE               ] = "MODE_SENSE",
> -        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
> -        /* LOAD_UNLOAD and START_STOP use the same operation code */
> -        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
> -        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
> -        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
> -        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
> -        [ READ_10                  ] = "READ_10",
> -        [ WRITE_10                 ] = "WRITE_10",
> -        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
> -        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
> -        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
> -        [ VERIFY_10                ] = "VERIFY_10",
> -        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
> -        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
> -        [ SEARCH_LOW               ] = "SEARCH_LOW",
> -        [ SET_LIMITS               ] = "SET_LIMITS",
> -        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
> -        /* READ_POSITION and PRE_FETCH use the same operation code */
> -        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
> -        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
> -        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
> -        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
> -        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
> -        [ COMPARE                  ] = "COMPARE",
> -        [ COPY_VERIFY              ] = "COPY_VERIFY",
> -        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
> -        [ READ_BUFFER              ] = "READ_BUFFER",
> -        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
> -        [ READ_LONG_10             ] = "READ_LONG_10",
> -        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
> -        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
> -        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
> -        [ UNMAP                    ] = "UNMAP",
> -        [ READ_TOC                 ] = "READ_TOC",
> -        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
> -        [ SANITIZE                 ] = "SANITIZE",
> -        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
> -        [ LOG_SELECT               ] = "LOG_SELECT",
> -        [ LOG_SENSE                ] = "LOG_SENSE",
> -        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
> -        [ RESERVE_10               ] = "RESERVE_10",
> -        [ RELEASE_10               ] = "RELEASE_10",
> -        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
> -        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
> -        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
> -        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
> -        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
> -        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
> -        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
> -        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
> -        [ READ_16                  ] = "READ_16",
> -        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
> -        [ WRITE_16                 ] = "WRITE_16",
> -        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
> -        [ VERIFY_16                ] = "VERIFY_16",
> -        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
> -        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
> -        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
> -        [ LOCATE_16                ] = "LOCATE_16",
> -        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
> -        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
> -        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
> -        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
> -        [ REPORT_LUNS              ] = "REPORT_LUNS",
> -        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
> -        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
> -        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
> -        [ READ_12                  ] = "READ_12",
> -        [ WRITE_12                 ] = "WRITE_12",
> -        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
> -        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
> -        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
> -        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
> -        [ VERIFY_12                ] = "VERIFY_12",
> -        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
> -        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
> -        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
> -        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
> -        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
> -        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
> -        [ READ_CD                  ] = "READ_CD",
> -        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
> -        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
> -        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
> -        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
> -        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
> -        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
> -        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
> -        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
> -        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
> -        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
> -        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
> -    };
> -
> -    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
> -        return "*UNKNOWN*";
> -    return names[cmd];
> -}
> -
>   SCSIRequest *scsi_req_ref(SCSIRequest *req)
>   {
>       assert(req->refcount > 0);
> diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
> index 7e1cbab77e..7a8f500934 100644
> --- a/hw/scsi/scsi-generic.c
> +++ b/hw/scsi/scsi-generic.c
> @@ -36,14 +36,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
>   #include <scsi/sg.h>
>   #include "block/scsi.h"
>   
> -#define SG_ERR_DRIVER_TIMEOUT  0x06
> -#define SG_ERR_DRIVER_SENSE    0x08
> -
> -#define SG_ERR_DID_OK          0x00
> -#define SG_ERR_DID_NO_CONNECT  0x01
> -#define SG_ERR_DID_BUS_BUSY    0x02
> -#define SG_ERR_DID_TIME_OUT    0x03
> -
>   #ifndef MAX_UINT
>   #define MAX_UINT ((unsigned int)-1)
>   #endif
> diff --git a/include/block/scsi.h b/include/block/scsi.h
> index cdf0a58a07..a141dd71f8 100644
> --- a/include/block/scsi.h
> +++ b/include/block/scsi.h
> @@ -150,8 +150,6 @@
>   #define READ_CD               0xbe
>   #define SEND_DVD_STRUCTURE    0xbf
>   
> -const char *scsi_command_name(uint8_t cmd);
> -
>   /*
>    * SERVICE ACTION IN subcodes
>    */
> diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
> index 6ef67fb504..23a8ee6a7d 100644
> --- a/include/hw/scsi/scsi.h
> +++ b/include/hw/scsi/scsi.h
> @@ -4,45 +4,20 @@
>   #include "hw/qdev.h"
>   #include "hw/block/block.h"
>   #include "sysemu/sysemu.h"
> +#include "scsi/utils.h"
>   #include "qemu/notify.h"
>   
>   #define MAX_SCSI_DEVS	255
>   
> -#define SCSI_CMD_BUF_SIZE      16
> -#define SCSI_SENSE_LEN         18
> -#define SCSI_SENSE_LEN_SCANNER 32
> -#define SCSI_INQUIRY_LEN       36
> -
>   typedef struct SCSIBus SCSIBus;
>   typedef struct SCSIBusInfo SCSIBusInfo;
> -typedef struct SCSICommand SCSICommand;
>   typedef struct SCSIDevice SCSIDevice;
>   typedef struct SCSIRequest SCSIRequest;
>   typedef struct SCSIReqOps SCSIReqOps;
>   
> -enum SCSIXferMode {
> -    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
> -    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
> -    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
> -};
> -
> -typedef struct SCSISense {
> -    uint8_t key;
> -    uint8_t asc;
> -    uint8_t ascq;
> -} SCSISense;
> -
>   #define SCSI_SENSE_BUF_SIZE_OLD 96
>   #define SCSI_SENSE_BUF_SIZE 252
>   
> -struct SCSICommand {
> -    uint8_t buf[SCSI_CMD_BUF_SIZE];
> -    int len;
> -    size_t xfer;
> -    uint64_t lba;
> -    enum SCSIXferMode mode;
> -};
> -
>   struct SCSIRequest {
>       SCSIBus           *bus;
>       SCSIDevice        *dev;
> @@ -180,73 +155,6 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
>   void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, bool deprecated);
>   void scsi_legacy_handle_cmdline(void);
>   
> -/*
> - * Predefined sense codes
> - */
> -
> -/* No sense data available */
> -extern const struct SCSISense sense_code_NO_SENSE;
> -/* LUN not ready, Manual intervention required */
> -extern const struct SCSISense sense_code_LUN_NOT_READY;
> -/* LUN not ready, Medium not present */
> -extern const struct SCSISense sense_code_NO_MEDIUM;
> -/* LUN not ready, medium removal prevented */
> -extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
> -/* Hardware error, internal target failure */
> -extern const struct SCSISense sense_code_TARGET_FAILURE;
> -/* Illegal request, invalid command operation code */
> -extern const struct SCSISense sense_code_INVALID_OPCODE;
> -/* Illegal request, LBA out of range */
> -extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
> -/* Illegal request, Invalid field in CDB */
> -extern const struct SCSISense sense_code_INVALID_FIELD;
> -/* Illegal request, Invalid field in parameter list */
> -extern const struct SCSISense sense_code_INVALID_PARAM;
> -/* Illegal request, Parameter list length error */
> -extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
> -/* Illegal request, LUN not supported */
> -extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
> -/* Illegal request, Saving parameters not supported */
> -extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
> -/* Illegal request, Incompatible format */
> -extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
> -/* Illegal request, medium removal prevented */
> -extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
> -/* Illegal request, Invalid Transfer Tag */
> -extern const struct SCSISense sense_code_INVALID_TAG;
> -/* Command aborted, I/O process terminated */
> -extern const struct SCSISense sense_code_IO_ERROR;
> -/* Command aborted, I_T Nexus loss occurred */
> -extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
> -/* Command aborted, Logical Unit failure */
> -extern const struct SCSISense sense_code_LUN_FAILURE;
> -/* Command aborted, Overlapped Commands Attempted */
> -extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
> -/* LUN not ready, Capacity data has changed */
> -extern const struct SCSISense sense_code_CAPACITY_CHANGED;
> -/* LUN not ready, Medium not present */
> -extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
> -/* Unit attention, Power on, reset or bus device reset occurred */
> -extern const struct SCSISense sense_code_RESET;
> -/* Unit attention, Medium may have changed*/
> -extern const struct SCSISense sense_code_MEDIUM_CHANGED;
> -/* Unit attention, Reported LUNs data has changed */
> -extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
> -/* Unit attention, Device internal reset */
> -extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
> -/* Data Protection, Write Protected */
> -extern const struct SCSISense sense_code_WRITE_PROTECTED;
> -/* Data Protection, Space Allocation Failed Write Protect */
> -extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
> -
> -#define SENSE_CODE(x) sense_code_ ## x
> -
> -uint32_t scsi_data_cdb_xfer(uint8_t *buf);
> -uint32_t scsi_cdb_xfer(uint8_t *buf);
> -int scsi_cdb_length(uint8_t *buf);
> -int scsi_convert_sense(uint8_t *in_buf, int in_len,
> -                       uint8_t *buf, int len, bool fixed);
> -
>   SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
>                               uint32_t tag, uint32_t lun, void *hba_private);
>   SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
> diff --git a/include/scsi/utils.h b/include/scsi/utils.h
> new file mode 100644
> index 0000000000..35a74436bf
> --- /dev/null
> +++ b/include/scsi/utils.h
> @@ -0,0 +1,116 @@
> +#ifndef SCSI_UTILS_H
> +#define SCSI_UTILS_H 1
> +
> +#ifdef CONFIG_LINUX
> +#include <scsi/sg.h>
> +#endif
> +
> +#define SCSI_CMD_BUF_SIZE      16
> +#define SCSI_SENSE_LEN         18
> +#define SCSI_SENSE_LEN_SCANNER 32
> +#define SCSI_INQUIRY_LEN       36
> +
> +enum SCSIXferMode {
> +    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
> +    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
> +    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
> +};
> +
> +typedef struct SCSICommand {
> +    uint8_t buf[SCSI_CMD_BUF_SIZE];
> +    int len;
> +    size_t xfer;
> +    uint64_t lba;
> +    enum SCSIXferMode mode;
> +} SCSICommand;
> +
> +typedef struct SCSISense {
> +    uint8_t key;
> +    uint8_t asc;
> +    uint8_t ascq;
> +} SCSISense;
> +
> +/*
> + * Predefined sense codes
> + */
> +
> +/* No sense data available */
> +extern const struct SCSISense sense_code_NO_SENSE;
> +/* LUN not ready, Manual intervention required */
> +extern const struct SCSISense sense_code_LUN_NOT_READY;
> +/* LUN not ready, Medium not present */
> +extern const struct SCSISense sense_code_NO_MEDIUM;
> +/* LUN not ready, medium removal prevented */
> +extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
> +/* Hardware error, internal target failure */
> +extern const struct SCSISense sense_code_TARGET_FAILURE;
> +/* Illegal request, invalid command operation code */
> +extern const struct SCSISense sense_code_INVALID_OPCODE;
> +/* Illegal request, LBA out of range */
> +extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
> +/* Illegal request, Invalid field in CDB */
> +extern const struct SCSISense sense_code_INVALID_FIELD;
> +/* Illegal request, Invalid field in parameter list */
> +extern const struct SCSISense sense_code_INVALID_PARAM;
> +/* Illegal request, Parameter list length error */
> +extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
> +/* Illegal request, LUN not supported */
> +extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
> +/* Illegal request, Saving parameters not supported */
> +extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
> +/* Illegal request, Incompatible format */
> +extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
> +/* Illegal request, medium removal prevented */
> +extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
> +/* Illegal request, Invalid Transfer Tag */
> +extern const struct SCSISense sense_code_INVALID_TAG;
> +/* Command aborted, I/O process terminated */
> +extern const struct SCSISense sense_code_IO_ERROR;
> +/* Command aborted, I_T Nexus loss occurred */
> +extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
> +/* Command aborted, Logical Unit failure */
> +extern const struct SCSISense sense_code_LUN_FAILURE;
> +/* Command aborted, Overlapped Commands Attempted */
> +extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS;
> +/* LUN not ready, Capacity data has changed */
> +extern const struct SCSISense sense_code_CAPACITY_CHANGED;
> +/* LUN not ready, Medium not present */
> +extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
> +/* Unit attention, Power on, reset or bus device reset occurred */
> +extern const struct SCSISense sense_code_RESET;
> +/* Unit attention, Medium may have changed*/
> +extern const struct SCSISense sense_code_MEDIUM_CHANGED;
> +/* Unit attention, Reported LUNs data has changed */
> +extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
> +/* Unit attention, Device internal reset */
> +extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
> +/* Data Protection, Write Protected */
> +extern const struct SCSISense sense_code_WRITE_PROTECTED;
> +/* Data Protection, Space Allocation Failed Write Protect */
> +extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
> +
> +#define SENSE_CODE(x) sense_code_ ## x
> +
> +int scsi_convert_sense(uint8_t *in_buf, int in_len,
> +                       uint8_t *buf, int len, bool fixed);
> +const char *scsi_command_name(uint8_t cmd);
> +
> +uint64_t scsi_cmd_lba(SCSICommand *cmd);
> +uint32_t scsi_data_cdb_xfer(uint8_t *buf);
> +uint32_t scsi_cdb_xfer(uint8_t *buf);
> +int scsi_cdb_length(uint8_t *buf);
> +
> +/* Linux SG_IO interface.  */
> +#ifdef CONFIG_LINUX
> +#define SG_ERR_DRIVER_TIMEOUT  0x06
> +#define SG_ERR_DRIVER_SENSE    0x08
> +
> +#define SG_ERR_DID_OK          0x00
> +#define SG_ERR_DID_NO_CONNECT  0x01
> +#define SG_ERR_DID_BUS_BUSY    0x02
> +#define SG_ERR_DID_TIME_OUT    0x03
> +
> +#define SG_ERR_DRIVER_SENSE    0x08
> +#endif
> +
> +#endif
> diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
> new file mode 100644
> index 0000000000..31b82a5a36
> --- /dev/null
> +++ b/scsi/Makefile.objs
> @@ -0,0 +1 @@
> +block-obj-y += utils.o
> diff --git a/scsi/utils.c b/scsi/utils.c
> new file mode 100644
> index 0000000000..0db727591f
> --- /dev/null
> +++ b/scsi/utils.c
> @@ -0,0 +1,403 @@
> +#include "qemu/osdep.h"
> +#include "block/scsi.h"
> +#include "scsi/utils.h"
> +#include "qemu/bswap.h"
> +
> +uint32_t scsi_data_cdb_xfer(uint8_t *buf)
> +{
> +    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
> +        return 256;
> +    } else {
> +        return scsi_cdb_xfer(buf);
> +    }
> +}
> +
> +uint32_t scsi_cdb_xfer(uint8_t *buf)
> +{
> +    switch (buf[0] >> 5) {
> +    case 0:
> +        return buf[4];
> +        break;
> +    case 1:
> +    case 2:
> +        return lduw_be_p(&buf[7]);
> +        break;
> +    case 4:
> +        return ldl_be_p(&buf[10]) & 0xffffffffULL;
> +        break;
> +    case 5:
> +        return ldl_be_p(&buf[6]) & 0xffffffffULL;
> +        break;
> +    default:
> +        return -1;
> +    }
> +}
> +
> +uint64_t scsi_cmd_lba(SCSICommand *cmd)
> +{
> +    uint8_t *buf = cmd->buf;
> +    uint64_t lba;
> +
> +    switch (buf[0] >> 5) {
> +    case 0:
> +        lba = ldl_be_p(&buf[0]) & 0x1fffff;
> +        break;
> +    case 1:
> +    case 2:
> +    case 5:
> +        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
> +        break;
> +    case 4:
> +        lba = ldq_be_p(&buf[2]);
> +        break;
> +    default:
> +        lba = -1;
> +
> +    }
> +    return lba;
> +}
> +
> +int scsi_cdb_length(uint8_t *buf)
> +{
> +    int cdb_len;
> +
> +    switch (buf[0] >> 5) {
> +    case 0:
> +        cdb_len = 6;
> +        break;
> +    case 1:
> +    case 2:
> +        cdb_len = 10;
> +        break;
> +    case 4:
> +        cdb_len = 16;
> +        break;
> +    case 5:
> +        cdb_len = 12;
> +        break;
> +    default:
> +        cdb_len = -1;
> +    }
> +    return cdb_len;
> +}
> +
> +/*
> + * Predefined sense codes
> + */
> +
> +/* No sense data available */
> +const struct SCSISense sense_code_NO_SENSE = {
> +    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
> +};
> +
> +/* LUN not ready, Manual intervention required */
> +const struct SCSISense sense_code_LUN_NOT_READY = {
> +    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
> +};
> +
> +/* LUN not ready, Medium not present */
> +const struct SCSISense sense_code_NO_MEDIUM = {
> +    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
> +};
> +
> +/* LUN not ready, medium removal prevented */
> +const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
> +    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
> +};
> +
> +/* Hardware error, internal target failure */
> +const struct SCSISense sense_code_TARGET_FAILURE = {
> +    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
> +};
> +
> +/* Illegal request, invalid command operation code */
> +const struct SCSISense sense_code_INVALID_OPCODE = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
> +};
> +
> +/* Illegal request, LBA out of range */
> +const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
> +};
> +
> +/* Illegal request, Invalid field in CDB */
> +const struct SCSISense sense_code_INVALID_FIELD = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
> +};
> +
> +/* Illegal request, Invalid field in parameter list */
> +const struct SCSISense sense_code_INVALID_PARAM = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
> +};
> +
> +/* Illegal request, Parameter list length error */
> +const struct SCSISense sense_code_INVALID_PARAM_LEN = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
> +};
> +
> +/* Illegal request, LUN not supported */
> +const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
> +};
> +
> +/* Illegal request, Saving parameters not supported */
> +const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
> +};
> +
> +/* Illegal request, Incompatible medium installed */
> +const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
> +};
> +
> +/* Illegal request, medium removal prevented */
> +const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
> +};
> +
> +/* Illegal request, Invalid Transfer Tag */
> +const struct SCSISense sense_code_INVALID_TAG = {
> +    .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
> +};
> +
> +/* Command aborted, I/O process terminated */
> +const struct SCSISense sense_code_IO_ERROR = {
> +    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
> +};
> +
> +/* Command aborted, I_T Nexus loss occurred */
> +const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
> +    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
> +};
> +
> +/* Command aborted, Logical Unit failure */
> +const struct SCSISense sense_code_LUN_FAILURE = {
> +    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
> +};
> +
> +/* Command aborted, Overlapped Commands Attempted */
> +const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
> +    .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
> +};
> +
> +/* Unit attention, Capacity data has changed */
> +const struct SCSISense sense_code_CAPACITY_CHANGED = {
> +    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
> +};
> +
> +/* Unit attention, Power on, reset or bus device reset occurred */
> +const struct SCSISense sense_code_RESET = {
> +    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
> +};
> +
> +/* Unit attention, No medium */
> +const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
> +    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
> +};
> +
> +/* Unit attention, Medium may have changed */
> +const struct SCSISense sense_code_MEDIUM_CHANGED = {
> +    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
> +};
> +
> +/* Unit attention, Reported LUNs data has changed */
> +const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
> +    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
> +};
> +
> +/* Unit attention, Device internal reset */
> +const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
> +    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
> +};
> +
> +/* Data Protection, Write Protected */
> +const struct SCSISense sense_code_WRITE_PROTECTED = {
> +    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
> +};
> +
> +/* Data Protection, Space Allocation Failed Write Protect */
> +const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
> +    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
> +};
> +
> +/*
> + * scsi_convert_sense
> + *
> + * Convert between fixed and descriptor sense buffers
> + */
> +int scsi_convert_sense(uint8_t *in_buf, int in_len,
> +                       uint8_t *buf, int len, bool fixed)
> +{
> +    bool fixed_in;
> +    SCSISense sense;
> +    if (!fixed && len < 8) {
> +        return 0;
> +    }
> +
> +    if (in_len == 0) {
> +        sense.key = NO_SENSE;
> +        sense.asc = 0;
> +        sense.ascq = 0;
> +    } else {
> +        fixed_in = (in_buf[0] & 2) == 0;
> +
> +        if (fixed == fixed_in) {
> +            memcpy(buf, in_buf, MIN(len, in_len));
> +            return MIN(len, in_len);
> +        }
> +
> +        if (fixed_in) {
> +            sense.key = in_buf[2];
> +            sense.asc = in_buf[12];
> +            sense.ascq = in_buf[13];
> +        } else {
> +            sense.key = in_buf[1];
> +            sense.asc = in_buf[2];
> +            sense.ascq = in_buf[3];
> +        }
> +    }
> +
> +    memset(buf, 0, len);
> +    if (fixed) {
> +        /* Return fixed format sense buffer */
> +        buf[0] = 0x70;
> +        buf[2] = sense.key;
> +        buf[7] = 10;
> +        buf[12] = sense.asc;
> +        buf[13] = sense.ascq;
> +        return MIN(len, SCSI_SENSE_LEN);
> +    } else {
> +        /* Return descriptor format sense buffer */
> +        buf[0] = 0x72;
> +        buf[1] = sense.key;
> +        buf[2] = sense.asc;
> +        buf[3] = sense.ascq;
> +        return 8;
> +    }
> +}
> +
> +const char *scsi_command_name(uint8_t cmd)
> +{
> +    static const char *names[] = {
> +        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
> +        [ REWIND                   ] = "REWIND",
> +        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
> +        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
> +        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
> +        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
> +        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
> +        [ READ_6                   ] = "READ_6",
> +        [ WRITE_6                  ] = "WRITE_6",
> +        [ SET_CAPACITY             ] = "SET_CAPACITY",
> +        [ READ_REVERSE             ] = "READ_REVERSE",
> +        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
> +        [ SPACE                    ] = "SPACE",
> +        [ INQUIRY                  ] = "INQUIRY",
> +        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
> +        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
> +        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
> +        [ MODE_SELECT              ] = "MODE_SELECT",
> +        [ RESERVE                  ] = "RESERVE",
> +        [ RELEASE                  ] = "RELEASE",
> +        [ COPY                     ] = "COPY",
> +        [ ERASE                    ] = "ERASE",
> +        [ MODE_SENSE               ] = "MODE_SENSE",
> +        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
> +        /* LOAD_UNLOAD and START_STOP use the same operation code */
> +        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
> +        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
> +        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
> +        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
> +        [ READ_10                  ] = "READ_10",
> +        [ WRITE_10                 ] = "WRITE_10",
> +        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
> +        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
> +        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
> +        [ VERIFY_10                ] = "VERIFY_10",
> +        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
> +        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
> +        [ SEARCH_LOW               ] = "SEARCH_LOW",
> +        [ SET_LIMITS               ] = "SET_LIMITS",
> +        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
> +        /* READ_POSITION and PRE_FETCH use the same operation code */
> +        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
> +        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
> +        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
> +        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
> +        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
> +        [ COMPARE                  ] = "COMPARE",
> +        [ COPY_VERIFY              ] = "COPY_VERIFY",
> +        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
> +        [ READ_BUFFER              ] = "READ_BUFFER",
> +        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
> +        [ READ_LONG_10             ] = "READ_LONG_10",
> +        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
> +        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
> +        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
> +        [ UNMAP                    ] = "UNMAP",
> +        [ READ_TOC                 ] = "READ_TOC",
> +        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
> +        [ SANITIZE                 ] = "SANITIZE",
> +        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
> +        [ LOG_SELECT               ] = "LOG_SELECT",
> +        [ LOG_SENSE                ] = "LOG_SENSE",
> +        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
> +        [ RESERVE_10               ] = "RESERVE_10",
> +        [ RELEASE_10               ] = "RELEASE_10",
> +        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
> +        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
> +        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
> +        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
> +        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
> +        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
> +        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
> +        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
> +        [ READ_16                  ] = "READ_16",
> +        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
> +        [ WRITE_16                 ] = "WRITE_16",
> +        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
> +        [ VERIFY_16                ] = "VERIFY_16",
> +        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
> +        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
> +        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
> +        [ LOCATE_16                ] = "LOCATE_16",
> +        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
> +        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
> +        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
> +        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
> +        [ REPORT_LUNS              ] = "REPORT_LUNS",
> +        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
> +        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
> +        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
> +        [ READ_12                  ] = "READ_12",
> +        [ WRITE_12                 ] = "WRITE_12",
> +        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
> +        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
> +        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
> +        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
> +        [ VERIFY_12                ] = "VERIFY_12",
> +        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
> +        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
> +        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
> +        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
> +        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
> +        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
> +        [ READ_CD                  ] = "READ_CD",
> +        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
> +        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
> +        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
> +        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
> +        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
> +        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
> +        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
> +        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
> +        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
> +        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
> +        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",
> +    };
> +
> +    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) {
> +        return "*UNKNOWN*";
> +    }
> +    return names[cmd];
> +}
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 03/10] scsi: introduce scsi_build_sense
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 03/10] scsi: introduce scsi_build_sense Paolo Bonzini
@ 2017-08-22 13:35   ` Philippe Mathieu-Daudé
  2017-08-30 13:39   ` Stefan Hajnoczi
  1 sibling, 0 replies; 48+ messages in thread
From: Philippe Mathieu-Daudé @ 2017-08-22 13:35 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: famz, qemu-block

On 08/22/2017 10:18 AM, Paolo Bonzini wrote:
> Move more knowledge of sense data format out of hw/scsi/scsi-bus.c
> for reusability.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>   hw/scsi/scsi-bus.c   |  8 +-------
>   include/scsi/utils.h |  2 ++
>   scsi/utils.c         | 11 +++++++++++
>   3 files changed, 14 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
> index 300912d213..f71218f02a 100644
> --- a/hw/scsi/scsi-bus.c
> +++ b/hw/scsi/scsi-bus.c
> @@ -797,13 +797,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
>   {
>       trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
>                                  sense.key, sense.asc, sense.ascq);
> -    memset(req->sense, 0, 18);
> -    req->sense[0] = 0x70;
> -    req->sense[2] = sense.key;
> -    req->sense[7] = 10;
> -    req->sense[12] = sense.asc;
> -    req->sense[13] = sense.ascq;
> -    req->sense_len = 18;
> +    req->sense_len = scsi_build_sense(req->sense, sense);
>   }
>   
>   static void scsi_req_enqueue_internal(SCSIRequest *req)
> diff --git a/include/scsi/utils.h b/include/scsi/utils.h
> index 35a74436bf..76c3db98c0 100644
> --- a/include/scsi/utils.h
> +++ b/include/scsi/utils.h
> @@ -30,6 +30,8 @@ typedef struct SCSISense {
>       uint8_t ascq;
>   } SCSISense;
>   
> +int scsi_build_sense(uint8_t *buf, SCSISense sense);
> +
>   /*
>    * Predefined sense codes
>    */
> diff --git a/scsi/utils.c b/scsi/utils.c
> index 0db727591f..54d6d4486a 100644
> --- a/scsi/utils.c
> +++ b/scsi/utils.c
> @@ -81,6 +81,17 @@ int scsi_cdb_length(uint8_t *buf)
>       return cdb_len;
>   }
>   
> +int scsi_build_sense(uint8_t *buf, SCSISense sense)
> +{
> +    memset(buf, 0, 18);
> +    buf[0] = 0x70;
> +    buf[2] = sense.key;
> +    buf[7] = 10;
> +    buf[12] = sense.asc;
> +    buf[13] = sense.ascq;
> +    return 18;
> +}
> +
>   /*
>    * Predefined sense codes
>    */
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 05/10] scsi: move block/scsi.h to include/scsi/constants.h
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 05/10] scsi: move block/scsi.h to include/scsi/constants.h Paolo Bonzini
@ 2017-08-22 13:37   ` Philippe Mathieu-Daudé
  2017-08-30 13:41   ` Stefan Hajnoczi
  1 sibling, 0 replies; 48+ messages in thread
From: Philippe Mathieu-Daudé @ 2017-08-22 13:37 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: famz, qemu-block

On 08/22/2017 10:18 AM, Paolo Bonzini wrote:
> Complete the transition by renaming this header, which was
> shared by block/iscsi.c and the SCSI emulation code.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>   block/iscsi.c                              | 2 +-
>   hw/block/virtio-blk.c                      | 2 +-
>   hw/scsi/megasas.c                          | 2 +-
>   hw/scsi/mptendian.c                        | 2 +-
>   hw/scsi/mptsas.c                           | 2 +-
>   hw/scsi/scsi-bus.c                         | 2 +-
>   hw/scsi/scsi-disk.c                        | 2 +-
>   hw/scsi/scsi-generic.c                     | 2 +-
>   hw/scsi/spapr_vscsi.c                      | 2 +-
>   hw/scsi/virtio-scsi-dataplane.c            | 2 +-
>   hw/scsi/virtio-scsi.c                      | 2 +-
>   hw/scsi/vmw_pvscsi.c                       | 2 +-
>   hw/usb/dev-uas.c                           | 2 +-
>   include/hw/ide/internal.h                  | 2 +-
>   include/{block/scsi.h => scsi/constants.h} | 0
>   scsi/utils.c                               | 2 +-
>   tests/virtio-scsi-test.c                   | 2 +-
>   17 files changed, 16 insertions(+), 16 deletions(-)
>   rename include/{block/scsi.h => scsi/constants.h} (100%)
> 
> diff --git a/block/iscsi.c b/block/iscsi.c
> index d557c99668..c43c0953e1 100644
> --- a/block/iscsi.c
> +++ b/block/iscsi.c
> @@ -34,7 +34,7 @@
>   #include "qemu/bitops.h"
>   #include "qemu/bitmap.h"
>   #include "block/block_int.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "qemu/iov.h"
>   #include "qemu/uuid.h"
>   #include "qmp-commands.h"
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index a16ac75090..05d1440786 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -22,7 +22,7 @@
>   #include "sysemu/blockdev.h"
>   #include "hw/virtio/virtio-blk.h"
>   #include "dataplane/virtio-blk.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #ifdef __linux__
>   # include <scsi/sg.h>
>   #endif
> diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
> index 734fdaef90..0db68aacee 100644
> --- a/hw/scsi/megasas.c
> +++ b/hw/scsi/megasas.c
> @@ -27,7 +27,7 @@
>   #include "hw/pci/msix.h"
>   #include "qemu/iov.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "trace.h"
>   #include "qapi/error.h"
>   #include "mfi.h"
> diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c
> index b7fe2a2a36..3415229b5e 100644
> --- a/hw/scsi/mptendian.c
> +++ b/hw/scsi/mptendian.c
> @@ -28,7 +28,7 @@
>   #include "hw/pci/msi.h"
>   #include "qemu/iov.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "trace.h"
>   
>   #include "mptsas.h"
> diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
> index 765ab53c34..8bae8f543e 100644
> --- a/hw/scsi/mptsas.c
> +++ b/hw/scsi/mptsas.c
> @@ -30,7 +30,7 @@
>   #include "hw/pci/msi.h"
>   #include "qemu/iov.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "trace.h"
>   #include "qapi/error.h"
>   #include "mptsas.h"
> diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
> index f71218f02a..b9244606f8 100644
> --- a/hw/scsi/scsi-bus.c
> +++ b/hw/scsi/scsi-bus.c
> @@ -3,7 +3,7 @@
>   #include "qapi/error.h"
>   #include "qemu/error-report.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "hw/qdev.h"
>   #include "sysemu/block-backend.h"
>   #include "sysemu/blockdev.h"
> diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
> index 0a1f4ef0c7..5faf6682c5 100644
> --- a/hw/scsi/scsi-disk.c
> +++ b/hw/scsi/scsi-disk.c
> @@ -32,7 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
>   #include "qapi/error.h"
>   #include "qemu/error-report.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "sysemu/sysemu.h"
>   #include "sysemu/block-backend.h"
>   #include "sysemu/blockdev.h"
> diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
> index 04c687ee76..bd0d9ff355 100644
> --- a/hw/scsi/scsi-generic.c
> +++ b/hw/scsi/scsi-generic.c
> @@ -34,7 +34,7 @@ do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
>   do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
>   
>   #include <scsi/sg.h>
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   
>   #ifndef MAX_UINT
>   #define MAX_UINT ((unsigned int)-1)
> diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
> index 55ee48c4da..360db53ac8 100644
> --- a/hw/scsi/spapr_vscsi.c
> +++ b/hw/scsi/spapr_vscsi.c
> @@ -36,7 +36,7 @@
>   #include "cpu.h"
>   #include "hw/hw.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "srp.h"
>   #include "hw/qdev.h"
>   #include "hw/ppc/spapr.h"
> diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
> index 944ea4eb53..add4b3f4a4 100644
> --- a/hw/scsi/virtio-scsi-dataplane.c
> +++ b/hw/scsi/virtio-scsi-dataplane.c
> @@ -17,7 +17,7 @@
>   #include "qemu/error-report.h"
>   #include "sysemu/block-backend.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "hw/virtio/virtio-bus.h"
>   #include "hw/virtio/virtio-access.h"
>   
> diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
> index eb639442d1..823a1e9a42 100644
> --- a/hw/scsi/virtio-scsi.c
> +++ b/hw/scsi/virtio-scsi.c
> @@ -21,7 +21,7 @@
>   #include "qemu/iov.h"
>   #include "sysemu/block-backend.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "hw/virtio/virtio-bus.h"
>   #include "hw/virtio/virtio-access.h"
>   
> diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
> index 77d8b6f9e2..6d3f0bf11d 100644
> --- a/hw/scsi/vmw_pvscsi.c
> +++ b/hw/scsi/vmw_pvscsi.c
> @@ -28,7 +28,7 @@
>   #include "qemu/osdep.h"
>   #include "qapi/error.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "hw/pci/msi.h"
>   #include "vmw_pvscsi.h"
>   #include "trace.h"
> diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
> index fffc424396..c218b53f09 100644
> --- a/hw/usb/dev-uas.c
> +++ b/hw/usb/dev-uas.c
> @@ -19,7 +19,7 @@
>   #include "hw/usb.h"
>   #include "hw/usb/desc.h"
>   #include "hw/scsi/scsi.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   
>   /* --------------------------------------------------------------------- */
>   
> diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
> index 482a9512be..63a99e0366 100644
> --- a/include/hw/ide/internal.h
> +++ b/include/hw/ide/internal.h
> @@ -11,7 +11,7 @@
>   #include "sysemu/dma.h"
>   #include "sysemu/sysemu.h"
>   #include "hw/block/block.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   
>   /* debug IDE devices */
>   //#define DEBUG_IDE
> diff --git a/include/block/scsi.h b/include/scsi/constants.h
> similarity index 100%
> rename from include/block/scsi.h
> rename to include/scsi/constants.h
> diff --git a/scsi/utils.c b/scsi/utils.c
> index ca5b058a73..eedd5f45b4 100644
> --- a/scsi/utils.c
> +++ b/scsi/utils.c
> @@ -1,5 +1,5 @@
>   #include "qemu/osdep.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "scsi/utils.h"
>   #include "qemu/bswap.h"
>   
> diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
> index 87a3b6e81a..082d323541 100644
> --- a/tests/virtio-scsi-test.c
> +++ b/tests/virtio-scsi-test.c
> @@ -10,7 +10,7 @@
>   
>   #include "qemu/osdep.h"
>   #include "libqtest.h"
> -#include "block/scsi.h"
> +#include "scsi/constants.h"
>   #include "libqos/libqos-pc.h"
>   #include "libqos/libqos-spapr.h"
>   #include "libqos/virtio.h"
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 01/10] scsi: rename scsi_convert_sense
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 01/10] scsi: rename scsi_convert_sense Paolo Bonzini
@ 2017-08-22 13:38   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 48+ messages in thread
From: Philippe Mathieu-Daudé @ 2017-08-22 13:38 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: famz, qemu-block

On 08/22/2017 10:18 AM, Paolo Bonzini wrote:
> After introducing the scsi/ subdirectory, there will be a scsi_build_sense
> function that is the same as scsi_req_build_sense but without needing
> a SCSIRequest.  The existing scsi_build_sense function gets in the way,
> remove it.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>   hw/scsi/scsi-bus.c     | 10 +++++-----
>   hw/scsi/scsi-disk.c    |  4 ++--
>   include/hw/scsi/scsi.h |  4 ++--
>   3 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
> index e364410a23..890f8fcc83 100644
> --- a/hw/scsi/scsi-bus.c
> +++ b/hw/scsi/scsi-bus.c
> @@ -769,7 +769,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
>           return 0;
>       }
>   
> -    ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
> +    ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true);
>   
>       /*
>        * FIXME: clearing unit attention conditions upon autosense should be done
> @@ -790,7 +790,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
>   
>   int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
>   {
> -    return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
> +    return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed);
>   }
>   
>   void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
> @@ -1510,12 +1510,12 @@ const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
>   };
>   
>   /*
> - * scsi_build_sense
> + * scsi_convert_sense
>    *
>    * Convert between fixed and descriptor sense buffers
>    */
> -int scsi_build_sense(uint8_t *in_buf, int in_len,
> -                     uint8_t *buf, int len, bool fixed)
> +int scsi_convert_sense(uint8_t *in_buf, int in_len,
> +                       uint8_t *buf, int len, bool fixed)
>   {
>       bool fixed_in;
>       SCSISense sense;
> diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
> index 5f1e5e8070..0a1f4ef0c7 100644
> --- a/hw/scsi/scsi-disk.c
> +++ b/hw/scsi/scsi-disk.c
> @@ -1978,8 +1978,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
>           break;
>       case REQUEST_SENSE:
>           /* Just return "NO SENSE".  */
> -        buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
> -                                  (req->cmd.buf[1] & 1) == 0);
> +        buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
> +                                    (req->cmd.buf[1] & 1) == 0);
>           if (buflen < 0) {
>               goto illegal_request;
>           }
> diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
> index 6b85786dbf..6ef67fb504 100644
> --- a/include/hw/scsi/scsi.h
> +++ b/include/hw/scsi/scsi.h
> @@ -244,8 +244,8 @@ extern const struct SCSISense sense_code_SPACE_ALLOC_FAILED;
>   uint32_t scsi_data_cdb_xfer(uint8_t *buf);
>   uint32_t scsi_cdb_xfer(uint8_t *buf);
>   int scsi_cdb_length(uint8_t *buf);
> -int scsi_build_sense(uint8_t *in_buf, int in_len,
> -                     uint8_t *buf, int len, bool fixed);
> +int scsi_convert_sense(uint8_t *in_buf, int in_len,
> +                       uint8_t *buf, int len, bool fixed);
>   
>   SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
>                               uint32_t tag, uint32_t lun, void *hba_private);
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno Paolo Bonzini
@ 2017-08-22 13:45   ` Philippe Mathieu-Daudé
  2017-08-22 13:53     ` Paolo Bonzini
  2017-08-30 13:41   ` Stefan Hajnoczi
  1 sibling, 1 reply; 48+ messages in thread
From: Philippe Mathieu-Daudé @ 2017-08-22 13:45 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: famz, qemu-block

Hi Paolo,

On 08/22/2017 10:18 AM, Paolo Bonzini wrote:
> Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for
> reusability.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>   hw/scsi/scsi-generic.c | 40 +++++++---------------------------------
>   include/scsi/utils.h   |  3 +++
>   scsi/utils.c           | 35 +++++++++++++++++++++++++++++++++++
>   3 files changed, 45 insertions(+), 33 deletions(-)
> 
> diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
> index 7a8f500934..04c687ee76 100644
> --- a/hw/scsi/scsi-generic.c
> +++ b/hw/scsi/scsi-generic.c
> @@ -81,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
>   static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
>   {
>       int status;
> +    SCSISense sense;
>   
>       assert(r->req.aiocb == NULL);
>   
> @@ -88,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
>           scsi_req_cancel_complete(&r->req);
>           goto done;
>       }
> -    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
> -        r->req.sense_len = r->io_header.sb_len_wr;
> -    }
> -
> -    if (ret != 0) {
> -        switch (ret) {
> -        case -EDOM:
> -            status = TASK_SET_FULL;
> -            break;
> -        case -ENOMEM:
> -            status = CHECK_CONDITION;
> -            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
> -            break;
> -        default:
> -            status = CHECK_CONDITION;
> -            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
> -            break;
> -        }
> -    } else {
> -        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
> -            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
> -            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
> -            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
> -            status = BUSY;
> -            BADF("Driver Timeout\n");
> -        } else if (r->io_header.host_status) {
> -            status = CHECK_CONDITION;
> -            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
> -        } else if (r->io_header.status) {
> -            status = r->io_header.status;
> -        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
> -            status = CHECK_CONDITION;
> +    status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
> +    if (status == CHECK_CONDITION) {
> +        if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
> +            r->req.sense_len = r->io_header.sb_len_wr;
>           } else {
> -            status = GOOD;
> +            scsi_req_build_sense(&r->req, sense);
>           }
>       }
> +
>       DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
>               r, r->req.tag, status);
>   
> diff --git a/include/scsi/utils.h b/include/scsi/utils.h
> index 76c3db98c0..c12b34f2e5 100644
> --- a/include/scsi/utils.h
> +++ b/include/scsi/utils.h
> @@ -113,6 +113,9 @@ int scsi_cdb_length(uint8_t *buf);
>   #define SG_ERR_DID_TIME_OUT    0x03
>   
>   #define SG_ERR_DRIVER_SENSE    0x08
> +
> +int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
> +                           SCSISense *sense);
>   #endif
>   
>   #endif
> diff --git a/scsi/utils.c b/scsi/utils.c
> index 54d6d4486a..ca5b058a73 100644
> --- a/scsi/utils.c
> +++ b/scsi/utils.c
> @@ -412,3 +412,38 @@ const char *scsi_command_name(uint8_t cmd)
>       }
>       return names[cmd];
>   }
> +
> +#ifdef CONFIG_LINUX
> +int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
> +                           SCSISense *sense)
> +{
> +    if (errno_value != 0) {
> +        switch (errno_value) {
> +        case EDOM:
> +            return TASK_SET_FULL;
> +        case ENOMEM:
> +            *sense = SENSE_CODE(TARGET_FAILURE);
> +            return CHECK_CONDITION;
> +        default:
> +            *sense = SENSE_CODE(IO_ERROR);
> +            return CHECK_CONDITION;
> +        }
> +    } else {
> +        if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
> +            io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
> +            io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
> +            (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
> +            return BUSY;
> +        } else if (io_hdr->host_status) {
> +            *sense = SENSE_CODE(I_T_NEXUS_LOSS);
> +            return CHECK_CONDITION;
> +        } else if (io_hdr->status) {
> +            return io_hdr->status;
> +        } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
> +            return CHECK_CONDITION;
> +        }

> +    }
I find it easier to read with the return GOOD out of the if/else:

        return GOOD;

Either ways:
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> +}
> +#endif
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (9 preceding siblings ...)
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper Paolo Bonzini
@ 2017-08-22 13:48 ` no-reply
  2017-08-22 13:50 ` no-reply
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 48+ messages in thread
From: no-reply @ 2017-08-22 13:48 UTC (permalink / raw)
  To: pbonzini; +Cc: famz, qemu-devel

Hi,

This series failed build test on s390x host. Please find the details below.

Message-id: 20170822131832.20191-1-pbonzini@redhat.com
Type: series
Subject: [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers

=== TEST SCRIPT BEGIN ===
#!/bin/bash
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
set -e
echo "=== ENV ==="
env
echo "=== PACKAGES ==="
rpm -qa
echo "=== TEST BEGIN ==="
CC=$HOME/bin/cc
INSTALL=$PWD/install
BUILD=$PWD/build
echo -n "Using CC: "
realpath $CC
mkdir -p $BUILD $INSTALL
SRC=$PWD
cd $BUILD
$SRC/configure --cc=$CC --prefix=$INSTALL
make -j4
# XXX: we need reliable clean up
# make check -j4 V=1
make install
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag]         patchew/20170822131832.20191-1-pbonzini@redhat.com -> patchew/20170822131832.20191-1-pbonzini@redhat.com
Switched to a new branch 'test'
e72ec38 scsi: add persistent reservation manager using qemu-pr-helper
284895f scsi: add multipath support to qemu-pr-helper
a946f48 scsi: build qemu-pr-helper
05fe9d8 io: add qio_channel_read/write_all
773bd4b scsi, file-posix: add support for persistent reservation management
2dd394b scsi: move block/scsi.h to include/scsi/constants.h
216ab86 scsi: introduce sg_io_sense_from_errno
6a5a1d0 scsi: introduce scsi_build_sense
7fa7125 scsi: move non-emulation specific code to scsi/
4381f3f scsi: rename scsi_convert_sense

=== OUTPUT BEGIN ===
=== ENV ===
XDG_SESSION_ID=38768
SHELL=/bin/sh
USER=fam
PATCHEW=/home/fam/patchew/patchew-cli -s http://patchew.org --nodebug
PATH=/usr/bin:/bin
PWD=/var/tmp/patchew-tester-tmp-wgqekxxc/src
LANG=en_US.UTF-8
HOME=/home/fam
SHLVL=2
LOGNAME=fam
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1012/bus
XDG_RUNTIME_DIR=/run/user/1012
_=/usr/bin/env
=== PACKAGES ===
gpg-pubkey-873529b8-54e386ff
xz-libs-5.2.2-2.fc24.s390x
libxshmfence-1.2-3.fc24.s390x
giflib-4.1.6-15.fc24.s390x
trousers-lib-0.3.13-6.fc24.s390x
ncurses-base-6.0-6.20160709.fc25.noarch
gmp-6.1.1-1.fc25.s390x
libidn-1.33-1.fc25.s390x
slang-2.3.0-7.fc25.s390x
pkgconfig-0.29.1-1.fc25.s390x
alsa-lib-1.1.1-2.fc25.s390x
yum-metadata-parser-1.1.4-17.fc25.s390x
python3-slip-dbus-0.6.4-4.fc25.noarch
python2-cssselect-0.9.2-1.fc25.noarch
createrepo_c-libs-0.10.0-6.fc25.s390x
initscripts-9.69-1.fc25.s390x
parted-3.2-21.fc25.s390x
flex-2.6.0-3.fc25.s390x
colord-libs-1.3.4-1.fc25.s390x
python-osbs-client-0.33-3.fc25.noarch
perl-Pod-Simple-3.35-1.fc25.noarch
python2-simplejson-3.10.0-1.fc25.s390x
brltty-5.4-2.fc25.s390x
librados2-10.2.4-2.fc25.s390x
tcp_wrappers-7.6-83.fc25.s390x
libcephfs_jni1-10.2.4-2.fc25.s390x
nettle-devel-3.3-1.fc25.s390x
bzip2-devel-1.0.6-21.fc25.s390x
libuuid-2.28.2-2.fc25.s390x
python3-dnf-1.1.10-6.fc25.noarch
texlive-kpathsea-doc-svn41139-33.fc25.1.noarch
openssh-7.4p1-4.fc25.s390x
texlive-kpathsea-bin-svn40473-33.20160520.fc25.1.s390x
texlive-graphics-svn41015-33.fc25.1.noarch
texlive-dvipdfmx-def-svn40328-33.fc25.1.noarch
texlive-mfware-svn40768-33.fc25.1.noarch
texlive-texlive-scripts-svn41433-33.fc25.1.noarch
texlive-euro-svn22191.1.1-33.fc25.1.noarch
texlive-etex-svn37057.0-33.fc25.1.noarch
texlive-iftex-svn29654.0.2-33.fc25.1.noarch
texlive-palatino-svn31835.0-33.fc25.1.noarch
texlive-texlive-docindex-svn41430-33.fc25.1.noarch
texlive-xunicode-svn30466.0.981-33.fc25.1.noarch
texlive-koma-script-svn41508-33.fc25.1.noarch
texlive-pst-grad-svn15878.1.06-33.fc25.1.noarch
texlive-pst-blur-svn15878.2.0-33.fc25.1.noarch
texlive-jknapltx-svn19440.0-33.fc25.1.noarch
texinfo-6.1-4.fc25.s390x
openssl-devel-1.0.2k-1.fc25.s390x
gdk-pixbuf2-2.36.6-1.fc25.s390x
nspr-4.14.0-2.fc25.s390x
nss-softokn-freebl-3.30.2-1.0.fc25.s390x
jansson-2.10-2.fc25.s390x
fedora-repos-25-4.noarch
python3-libs-3.5.3-6.fc25.s390x
perl-Errno-1.25-387.fc25.s390x
acl-2.2.52-13.fc25.s390x
pcre2-utf16-10.23-8.fc25.s390x
pango-1.40.5-1.fc25.s390x
systemd-pam-231-17.fc25.s390x
python2-gluster-3.10.4-1.fc25.s390x
NetworkManager-libnm-1.4.4-5.fc25.s390x
selinux-policy-3.13.1-225.18.fc25.noarch
poppler-0.45.0-5.fc25.s390x
ccache-3.3.4-1.fc25.s390x
valgrind-3.12.0-9.fc25.s390x
perl-open-1.10-387.fc25.noarch
libaio-0.3.110-6.fc24.s390x
libfontenc-1.1.3-3.fc24.s390x
lzo-2.08-8.fc24.s390x
isl-0.14-5.fc24.s390x
libXau-1.0.8-6.fc24.s390x
linux-atm-libs-2.5.1-14.fc24.s390x
libXext-1.3.3-4.fc24.s390x
libXxf86vm-1.1.4-3.fc24.s390x
bison-3.0.4-4.fc24.s390x
perl-srpm-macros-1-20.fc25.noarch
gawk-4.1.3-8.fc25.s390x
libwayland-client-1.12.0-1.fc25.s390x
perl-Exporter-5.72-366.fc25.noarch
perl-version-0.99.17-1.fc25.s390x
fftw-libs-double-3.3.5-3.fc25.s390x
libssh2-1.8.0-1.fc25.s390x
ModemManager-glib-1.6.4-1.fc25.s390x
newt-python3-0.52.19-2.fc25.s390x
python-munch-2.0.4-3.fc25.noarch
python-bugzilla-1.2.2-4.fc25.noarch
libedit-3.1-16.20160618cvs.fc25.s390x
createrepo_c-0.10.0-6.fc25.s390x
device-mapper-multipath-libs-0.4.9-83.fc25.s390x
yum-3.4.3-510.fc25.noarch
dracut-config-rescue-044-78.fc25.s390x
mozjs17-17.0.0-16.fc25.s390x
libselinux-2.5-13.fc25.s390x
libgo-devel-6.3.1-1.fc25.s390x
python2-pyparsing-2.1.10-1.fc25.noarch
cairo-gobject-1.14.8-1.fc25.s390x
ethtool-4.8-1.fc25.s390x
xorg-x11-proto-devel-7.7-20.fc25.noarch
brlapi-0.6.5-2.fc25.s390x
librados-devel-10.2.4-2.fc25.s390x
libXinerama-devel-1.1.3-6.fc24.s390x
lua-posix-33.3.1-3.fc25.s390x
usbredir-devel-0.7.1-2.fc24.s390x
libepoxy-1.4.1-1.fc25.s390x
python3-dnf-plugins-core-0.1.21-5.fc25.noarch
texlive-pdftex-doc-svn41149-33.fc25.1.noarch
openssh-clients-7.4p1-4.fc25.s390x
iptables-1.6.0-3.fc25.s390x
texlive-texlive.infra-svn41280-33.fc25.1.noarch
texlive-graphics-cfg-svn40269-33.fc25.1.noarch
texlive-bibtex-svn40768-33.fc25.1.noarch
texlive-mfware-bin-svn40473-33.20160520.fc25.1.s390x
texlive-texlive-scripts-bin-svn29741.0-33.20160520.fc25.1.noarch
texlive-sauerj-svn15878.0-33.fc25.1.noarch
texlive-enctex-svn34957.0-33.fc25.1.noarch
texlive-ifetex-svn24853.1.2-33.fc25.1.noarch
texlive-ntgclass-svn15878.2.1a-33.fc25.1.noarch
texlive-tex-gyre-math-svn41264-33.fc25.1.noarch
texlive-bera-svn20031.0-33.fc25.1.noarch
texlive-ms-svn29849.0-33.fc25.1.noarch
texlive-pst-fill-svn15878.1.01-33.fc25.1.noarch
texlive-ctable-svn38672-33.fc25.1.noarch
texlive-extsizes-svn17263.1.4a-33.fc25.1.noarch
texlive-collection-latexrecommended-svn35765.0-33.20160520.fc25.1.noarch
perl-Filter-1.57-1.fc25.s390x
krb5-workstation-1.14.4-7.fc25.s390x
python2-rpm-macros-3-12.fc25.noarch
libglvnd-egl-0.2.999-14.20170308git8e6e102.fc25.s390x
libglvnd-opengl-0.2.999-14.20170308git8e6e102.fc25.s390x
gdbm-1.13-1.fc25.s390x
nss-util-3.30.2-1.0.fc25.s390x
libcrypt-nss-2.24-9.fc25.s390x
libtasn1-4.12-1.fc25.s390x
fedora-release-25-2.noarch
gdb-headless-7.12.1-48.fc25.s390x
perl-macros-5.24.2-387.fc25.s390x
sqlite-devel-3.14.2-2.fc25.s390x
pcre-devel-8.41-1.fc25.s390x
libX11-1.6.5-1.fc25.s390x
coreutils-8.25-17.fc25.s390x
python2-openidc-client-0-3.20170523git77cb3ee.fc25.noarch
nss-sysinit-3.30.2-1.1.fc25.s390x
systemtap-client-3.1-5.fc25.s390x
nss-devel-3.30.2-1.1.fc25.s390x
firewalld-0.4.4.5-1.fc25.noarch
rpmlint-1.9-9.fc25.noarch
system-python-3.5.3-6.fc25.s390x
gpg-pubkey-efe550f5-5220ba41
gpg-pubkey-81b46521-55b3ca9a
filesystem-3.2-37.fc24.s390x
libffi-3.1-9.fc24.s390x
keyutils-libs-1.5.9-8.fc24.s390x
libnfnetlink-1.0.1-8.fc24.s390x
libtheora-1.1.1-14.fc24.s390x
xml-common-0.6.3-44.fc24.noarch
autoconf-2.69-22.fc24.noarch
libXt-1.1.5-3.fc24.s390x
kbd-legacy-2.0.3-3.fc24.noarch
ghostscript-fonts-5.50-35.fc24.noarch
libXevie-1.0.3-11.fc24.s390x
libcap-2.25-2.fc25.s390x
mpfr-3.1.5-1.fc25.s390x
perl-Carp-1.40-365.fc25.noarch
libmnl-1.0.4-1.fc25.s390x
perl-Unicode-EastAsianWidth-1.33-8.fc25.noarch
libwayland-cursor-1.12.0-1.fc25.s390x
python-krbV-1.0.90-12.fc25.s390x
python2-urllib3-1.15.1-3.fc25.noarch
fipscheck-1.4.1-11.fc25.s390x
libndp-1.6-1.fc25.s390x
gnupg2-2.1.13-2.fc25.s390x
libXfixes-5.0.3-1.fc25.s390x
adwaita-icon-theme-3.22.0-1.fc25.noarch
dconf-0.26.0-1.fc25.s390x
ncurses-devel-6.0-6.20160709.fc25.s390x
dejagnu-1.6-1.fc25.noarch
libstdc++-devel-6.3.1-1.fc25.s390x
device-mapper-1.02.136-3.fc25.s390x
subversion-1.9.5-1.fc25.s390x
libtool-ltdl-2.4.6-13.fc25.s390x
libevent-2.0.22-1.fc25.s390x
atk-devel-2.22.0-1.fc25.s390x
libev-4.24-1.fc25.s390x
xorg-x11-fonts-Type1-7.5-16.fc24.noarch
brlapi-devel-0.6.5-2.fc25.s390x
pulseaudio-libs-10.0-2.fc25.s390x
glib2-2.50.3-1.fc25.s390x
python2-rpm-4.13.0.1-1.fc25.s390x
dnf-1.1.10-6.fc25.noarch
texlive-metafont-bin-svn40987-33.20160520.fc25.1.s390x
texlive-xkeyval-svn35741.2.7a-33.fc25.1.noarch
texlive-euler-svn17261.2.5-33.fc25.1.noarch
texlive-mptopdf-svn41282-33.fc25.1.noarch
texlive-wasy-svn35831.0-33.fc25.1.noarch
texlive-avantgar-svn31835.0-33.fc25.1.noarch
texlive-eurosym-svn17265.1.4_subrfix-33.fc25.1.noarch
texlive-knuth-lib-svn35820.0-33.fc25.1.noarch
texlive-parallel-svn15878.0-33.fc25.1.noarch
texlive-texlive-msg-translations-svn41431-33.fc25.1.noarch
texlive-latex-svn40218-33.fc25.1.noarch
texlive-lualatex-math-svn40621-33.fc25.1.noarch
texlive-auto-pst-pdf-svn23723.0.6-33.fc25.1.noarch
texlive-powerdot-svn38984-33.fc25.1.noarch
texlive-wasysym-svn15878.2.0-33.fc25.1.noarch
ImageMagick-libs-6.9.3.0-6.fc25.s390x
geoclue2-2.4.5-1.fc25.s390x
perl-IO-Socket-IP-0.39-1.fc25.noarch
python2-pyasn1-0.2.3-1.fc25.noarch
libglvnd-0.2.999-14.20170308git8e6e102.fc25.s390x
libglvnd-gles-0.2.999-14.20170308git8e6e102.fc25.s390x
gdk-pixbuf2-devel-2.36.6-1.fc25.s390x
at-spi2-core-devel-2.22.1-1.fc25.s390x
libacl-2.2.52-13.fc25.s390x
perl-libs-5.24.2-387.fc25.s390x
mesa-libglapi-17.0.5-3.fc25.s390x
kernel-headers-4.11.10-200.fc25.s390x
p11-kit-devel-0.23.2-4.fc25.s390x
python3-rpmconf-1.0.19-1.fc25.noarch
sqlite-3.14.2-2.fc25.s390x
pcre-utf32-8.41-1.fc25.s390x
libX11-common-1.6.5-1.fc25.noarch
coreutils-common-8.25-17.fc25.s390x
mesa-libEGL-17.0.5-3.fc25.s390x
nss-3.30.2-1.1.fc25.s390x
systemtap-runtime-3.1-5.fc25.s390x
NetworkManager-glib-1.4.4-5.fc25.s390x
audit-2.7.7-1.fc25.s390x
perl-Time-HiRes-1.9742-1.fc25.s390x
libsolv-0.6.28-1.fc25.s390x
gpg-pubkey-34ec9cba-54e38751
gpg-pubkey-030d5aed-55b577f0
basesystem-11-2.fc24.noarch
libmpc-1.0.2-5.fc24.s390x
libunistring-0.9.4-3.fc24.s390x
libmodman-2.0.1-12.fc24.s390x
lsscsi-0.28-3.fc24.s390x
kbd-misc-2.0.3-3.fc24.noarch
kmod-23-1.fc25.s390x
newt-0.52.19-2.fc25.s390x
perl-Text-Unidecode-1.27-3.fc25.noarch
plymouth-core-libs-0.9.3-0.6.20160620git0e65b86c.fc25.s390x
which-2.21-1.fc25.s390x
python3-slip-0.6.4-4.fc25.noarch
python3-systemd-232-1.fc25.s390x
python-lockfile-0.11.0-4.fc25.noarch
python2-requests-2.10.0-4.fc25.noarch
libnghttp2-1.13.0-2.fc25.s390x
python-urlgrabber-3.10.1-9.fc25.noarch
iputils-20161105-1.fc25.s390x
rest-0.8.0-1.fc25.s390x
adwaita-cursor-theme-3.22.0-1.fc25.noarch
authconfig-6.2.10-14.fc25.s390x
automake-1.15-7.fc25.noarch
shared-mime-info-1.8-1.fc25.s390x
pigz-2.3.4-1.fc25.s390x
device-mapper-libs-1.02.136-3.fc25.s390x
dnsmasq-2.76-2.fc25.s390x
fedora-packager-0.6.0.1-1.fc25.noarch
gcc-c++-6.3.1-1.fc25.s390x
libwebp-0.5.2-1.fc25.s390x
boost-system-1.60.0-10.fc25.s390x
libasyncns-0.8-10.fc24.s390x
libXau-devel-1.0.8-6.fc24.s390x
libverto-libev-0.2.6-6.fc24.s390x
python3-html5lib-0.999-9.fc25.noarch
ttmkfdir-3.0.9-48.fc24.s390x
pulseaudio-libs-glib2-10.0-2.fc25.s390x
wpa_supplicant-2.6-1.fc25.s390x
texlive-lib-2016-33.20160520.fc25.s390x
libXi-devel-1.7.9-1.fc25.s390x
python3-distro-1.0.3-1.fc25.noarch
rpm-plugin-systemd-inhibit-4.13.0.1-1.fc25.s390x
texlive-texlive-common-doc-svn40682-33.fc25.1.noarch
packagedb-cli-2.14.1-1.fc25.noarch
texlive-metafont-svn40793-33.fc25.1.noarch
texlive-tools-svn40934-33.fc25.1.noarch
texlive-enumitem-svn24146.3.5.2-33.fc25.1.noarch
texlive-mptopdf-bin-svn18674.0-33.20160520.fc25.1.noarch
texlive-underscore-svn18261.0-33.fc25.1.noarch
texlive-anysize-svn15878.0-33.fc25.1.noarch
texlive-euenc-svn19795.0.1h-33.fc25.1.noarch
texlive-kastrup-svn15878.0-33.fc25.1.noarch
texlive-paralist-svn39247-33.fc25.1.noarch
texlive-texlive-en-svn41185-33.fc25.1.noarch
texlive-tipa-svn29349.1.3-33.fc25.1.noarch
texlive-currfile-svn40725-33.fc25.1.noarch
texlive-pst-node-svn40743-33.fc25.1.noarch
texlive-pst-slpe-svn24391.1.31-33.fc25.1.noarch
texlive-typehtml-svn17134.0-33.fc25.1.noarch
SDL2-devel-2.0.5-3.fc25.s390x
libcroco-0.6.11-3.fc25.s390x
bluez-libs-devel-5.44-1.fc25.s390x
kernel-4.10.8-200.fc25.s390x
expat-2.2.1-1.fc25.s390x
system-python-libs-3.5.3-6.fc25.s390x
pcre2-10.23-8.fc25.s390x
firewalld-filesystem-0.4.4.5-1.fc25.noarch
pcre-cpp-8.41-1.fc25.s390x
python3-firewall-0.4.4.5-1.fc25.noarch
freetype-devel-2.6.5-9.fc25.s390x
pcre-utf16-8.41-1.fc25.s390x
linux-firmware-20170605-74.git37857004.fc25.noarch
distribution-gpg-keys-1.12-1.fc25.noarch
kernel-modules-4.11.10-200.fc25.s390x
gnutls-devel-3.5.14-1.fc25.s390x
systemtap-devel-3.1-5.fc25.s390x
java-1.8.0-openjdk-1.8.0.131-1.b12.fc25.s390x
polkit-0.113-8.fc25.s390x
perl-SelfLoader-1.23-387.fc25.noarch
libdb-utils-5.3.28-24.fc25.s390x
fontpackages-filesystem-1.44-17.fc24.noarch
groff-base-1.22.3-8.fc24.s390x
ilmbase-2.2.0-5.fc24.s390x
OpenEXR-libs-2.2.0-5.fc24.s390x
hesiod-3.2.1-6.fc24.s390x
sysfsutils-2.1.0-19.fc24.s390x
ocaml-srpm-macros-2-4.fc24.noarch
mailx-12.5-19.fc24.s390x
ncurses-libs-6.0-6.20160709.fc25.s390x
ipset-libs-6.29-1.fc25.s390x
gmp-devel-6.1.1-1.fc25.s390x
python-pip-8.1.2-2.fc25.noarch
harfbuzz-1.3.2-1.fc25.s390x
python2-iniparse-0.4-20.fc25.noarch
python3-iniparse-0.4-20.fc25.noarch
python3-kickstart-2.32-1.fc25.noarch
perl-Net-SSLeay-1.78-1.fc25.s390x
drpm-0.3.0-3.fc25.s390x
glib-networking-2.50.0-1.fc25.s390x
webkitgtk3-2.4.11-3.fc25.s390x
libXaw-1.0.13-4.fc25.s390x
xorg-x11-font-utils-7.5-32.fc25.s390x
hardlink-1.1-1.fc25.s390x
libcom_err-1.43.3-1.fc25.s390x
python2-dateutil-2.6.0-1.fc25.noarch
libXpm-3.5.12-1.fc25.s390x
python2-smmap-2.0.1-1.fc25.noarch
poppler-data-0.4.7-6.fc25.noarch
librbd1-10.2.4-2.fc25.s390x
perl-Digest-MD5-2.55-2.fc25.s390x
wayland-protocols-devel-1.7-1.fc25.noarch
texi2html-5.0-4.fc24.noarch
libxkbcommon-0.7.1-1.fc25.s390x
libuuid-devel-2.28.2-2.fc25.s390x
libcacard-2.5.3-1.fc25.s390x
libwmf-lite-0.2.8.4-50.fc25.s390x
texlive-tetex-svn41059-33.fc25.1.noarch
texlive-thumbpdf-svn34621.3.16-33.fc25.1.noarch
texlive-carlisle-svn18258.0-33.fc25.1.noarch
texlive-makeindex-bin-svn40473-33.20160520.fc25.1.s390x
texlive-pdftex-svn41149-33.fc25.1.noarch
texlive-csquotes-svn39538-33.fc25.1.noarch
texlive-courier-svn35058.0-33.fc25.1.noarch
texlive-helvetic-svn31835.0-33.fc25.1.noarch
texlive-mfnfss-svn19410.0-33.fc25.1.noarch
texlive-sepnum-svn20186.2.0-33.fc25.1.noarch
texlive-utopia-svn15878.0-33.fc25.1.noarch
texlive-luatexbase-svn38550-33.fc25.1.noarch
texlive-pst-3d-svn17257.1.10-33.fc25.1.noarch
texlive-latex-bin-bin-svn14050.0-33.20160520.fc25.1.noarch
texlive-l3experimental-svn41163-33.fc25.1.noarch
net-tools-2.0-0.40.20160329git.fc25.s390x
perl-Pod-Perldoc-3.28-1.fc25.noarch
openssl-1.0.2k-1.fc25.s390x
man-pages-4.06-4.fc25.noarch
python3-magic-5.29-4.fc25.noarch
libxml2-2.9.4-2.fc25.s390x
nss-softokn-3.30.2-1.0.fc25.s390x
p11-kit-trust-0.23.2-4.fc25.s390x
emacs-filesystem-25.2-2.fc25.noarch
python3-dateutil-2.6.0-1.fc25.noarch
perl-threads-shared-1.57-1.fc25.s390x
libnotify-0.7.7-1.fc25.s390x
unzip-6.0-32.fc25.s390x
pango-devel-1.40.5-1.fc25.s390x
libdrm-2.4.81-1.fc25.s390x
python-beautifulsoup4-4.6.0-1.fc25.noarch
libcurl-7.51.0-7.fc25.s390x
dhcp-client-4.3.5-3.fc25.s390x
python2-fedora-0.9.0-6.fc25.noarch
emacs-25.2-2.fc25.s390x
gdb-7.12.1-48.fc25.s390x
expat-devel-2.2.1-1.fc25.s390x
gpg-pubkey-95a43f54-5284415a
dejavu-fonts-common-2.35-3.fc24.noarch
libSM-1.2.2-4.fc24.s390x
diffutils-3.3-13.fc24.s390x
libogg-1.3.2-5.fc24.s390x
hunspell-en-US-0.20140811.1-5.fc24.noarch
libdaemon-0.14-10.fc24.s390x
patch-2.7.5-3.fc24.s390x
libsysfs-2.1.0-19.fc24.s390x
procmail-3.22-39.fc24.s390x
libXdamage-1.1.4-8.fc24.s390x
libotf-0.9.13-7.fc24.s390x
urw-fonts-2.4-22.fc24.noarch
crontabs-1.11-12.20150630git.fc24.noarch
ppp-2.4.7-9.fc24.s390x
cyrus-sasl-2.1.26-26.2.fc24.s390x
zlib-devel-1.2.8-10.fc24.s390x
time-1.7-49.fc24.s390x
gpg-pubkey-fdb19c98-56fd6333
libcap-ng-0.7.8-1.fc25.s390x
binutils-2.26.1-1.fc25.s390x
lcms2-2.8-2.fc25.s390x
libcomps-0.1.7-5.fc25.s390x
apr-1.5.2-4.fc25.s390x
perl-constant-1.33-367.fc25.noarch
perl-Data-Dumper-2.161-1.fc25.s390x
ipcalc-0.1.8-1.fc25.s390x
gmp-c++-6.1.1-1.fc25.s390x
fontconfig-2.12.1-1.fc25.s390x
enchant-1.6.0-14.fc25.s390x
pyliblzma-0.5.3-16.fc25.s390x
libsepol-devel-2.5-10.fc25.s390x
python3-ordered-set-2.0.0-4.fc25.noarch
python-ipaddress-1.0.16-3.fc25.noarch
python2-kerberos-1.2.5-1.fc25.s390x
python2-pysocks-1.5.6-5.fc25.noarch
fipscheck-lib-1.4.1-11.fc25.s390x
libatomic_ops-7.4.4-1.fc25.s390x
net-snmp-agent-libs-5.7.3-13.fc25.s390x
dracut-044-78.fc25.s390x
python2-pygpgme-0.3-18.fc25.s390x
orc-0.4.26-1.fc25.s390x
yum-utils-1.1.31-511.fc25.noarch
libXrender-0.9.10-1.fc25.s390x
libXrandr-1.5.1-1.fc25.s390x
go-srpm-macros-2-7.fc25.noarch
gnupg2-smime-2.1.13-2.fc25.s390x
guile-devel-2.0.13-1.fc25.s390x
uboot-tools-2016.09.01-2.fc25.s390x
pykickstart-2.32-1.fc25.noarch
python-bunch-1.0.1-9.fc25.noarch
perl-generators-1.10-1.fc25.noarch
perl-Mozilla-CA-20160104-3.fc25.noarch
bzip2-libs-1.0.6-21.fc25.s390x
libpng-1.6.27-1.fc25.s390x
desktop-file-utils-0.23-2.fc25.s390x
python2-cccolutils-1.4-1.fc25.s390x
python2-lxml-3.7.2-1.fc25.s390x
redhat-rpm-config-45-1.fc25.noarch
device-mapper-event-libs-1.02.136-3.fc25.s390x
lvm2-libs-2.02.167-3.fc25.s390x
python2-gitdb-2.0.0-1.fc25.noarch
gcc-gfortran-6.3.1-1.fc25.s390x
libselinux-python-2.5-13.fc25.s390x
openjpeg2-2.1.2-3.fc25.s390x
boost-thread-1.60.0-10.fc25.s390x
librbd-devel-10.2.4-2.fc25.s390x
libXcursor-devel-1.1.14-6.fc24.s390x
latex2html-2012-7.fc24.noarch
lksctp-tools-1.0.16-5.fc24.s390x
libfdt-1.4.2-1.fc25.s390x
libXft-devel-2.3.2-4.fc24.s390x
libattr-devel-2.4.47-16.fc24.s390x
libiscsi-devel-1.15.0-2.fc24.s390x
gettext-0.19.8.1-3.fc25.s390x
libjpeg-turbo-devel-1.5.1-0.fc25.s390x
pulseaudio-libs-devel-10.0-2.fc25.s390x
libepoxy-devel-1.4.1-1.fc25.s390x
krb5-libs-1.14.4-7.fc25.s390x
libmount-2.28.2-2.fc25.s390x
python3-decorator-4.0.11-1.fc25.noarch
rpm-plugin-selinux-4.13.0.1-1.fc25.s390x
tzdata-java-2017b-1.fc25.noarch
python-srpm-macros-3-12.fc25.noarch
libsmartcols-2.28.2-2.fc25.s390x
kernel-core-4.10.5-200.fc25.s390x
kernel-modules-4.10.5-200.fc25.s390x
texlive-kpathsea-svn41139-33.fc25.1.noarch
texlive-amsmath-svn41561-33.fc25.1.noarch
texlive-thumbpdf-bin-svn6898.0-33.20160520.fc25.1.noarch
texlive-psnfss-svn33946.9.2a-33.fc25.1.noarch
texlive-subfig-svn15878.1.3-33.fc25.1.noarch
texlive-fancybox-svn18304.1.4-33.fc25.1.noarch
texlive-lua-alt-getopt-svn29349.0.7.0-33.fc25.1.noarch
texlive-natbib-svn20668.8.31b-33.fc25.1.noarch
texlive-pdftex-bin-svn40987-33.20160520.fc25.1.s390x
texlive-xdvi-svn40768-33.fc25.1.noarch
texlive-crop-svn15878.1.5-33.fc25.1.noarch
texlive-babel-english-svn30264.3.3p-33.fc25.1.noarch
texlive-cmextra-svn32831.0-33.fc25.1.noarch
texlive-fancyhdr-svn15878.3.1-33.fc25.1.noarch
texlive-luatex-svn40963-33.fc25.1.noarch
texlive-knuth-local-svn38627-33.fc25.1.noarch
texlive-mflogo-font-svn36898.1.002-33.fc25.1.noarch
texlive-parskip-svn19963.2.0-33.fc25.1.noarch
texlive-section-svn20180.0-33.fc25.1.noarch
texlive-textcase-svn15878.0-33.fc25.1.noarch
texlive-updmap-map-svn41159-33.fc25.1.noarch
texlive-attachfile-svn38830-33.fc25.1.noarch
libglvnd-glx-0.2.999-14.20170308git8e6e102.fc25.s390x
libglvnd-core-devel-0.2.999-14.20170308git8e6e102.fc25.s390x
python-magic-5.29-4.fc25.noarch
glibc-common-2.24-9.fc25.s390x
sqlite-libs-3.14.2-2.fc25.s390x
libtiff-4.0.8-1.fc25.s390x
libdb-5.3.28-24.fc25.s390x
glusterfs-client-xlators-3.10.4-1.fc25.s390x
nss-util-devel-3.30.2-1.0.fc25.s390x
gnutls-3.5.14-1.fc25.s390x
bind-license-9.10.5-2.P2.fc25.noarch
mesa-libGLES-17.0.5-3.fc25.s390x
python3-requests-kerberos-0.10.0-2.fc25.noarch
python3-pyOpenSSL-16.2.0-1.fc25.noarch
perl-threads-2.16-1.fc25.s390x
cryptsetup-libs-1.7.5-1.fc25.s390x
vim-minimal-8.0.705-1.fc25.s390x
netpbm-10.79.00-1.fc25.s390x
qrencode-libs-3.4.4-1.fc25.s390x
mariadb-config-10.1.24-3.fc25.s390x
gstreamer1-plugins-base-1.10.5-1.fc25.s390x
elfutils-default-yama-scope-0.169-1.fc25.noarch
glusterfs-3.10.4-1.fc25.s390x
systemd-udev-231-17.fc25.s390x
python2-koji-1.13.0-2.fc25.noarch
unbound-libs-1.6.3-1.fc25.s390x
openldap-2.4.44-11.fc25.s390x
koji-1.13.0-2.fc25.noarch
bind99-libs-9.9.10-2.P3.fc25.s390x
libcurl-devel-7.51.0-7.fc25.s390x
mesa-libGL-devel-17.0.5-3.fc25.s390x
python2-sssdconfig-1.15.2-5.fc25.noarch
webkitgtk4-plugin-process-gtk2-2.16.5-1.fc25.s390x
graphite2-devel-1.3.10-1.fc25.s390x
systemtap-sdt-devel-3.1-5.fc25.s390x
iproute-tc-4.11.0-1.fc25.s390x
libarchive-3.2.2-2.fc25.s390x
publicsuffix-list-dafsa-20170424-1.fc25.noarch
texlive-luaotfload-svn40902-33.fc25.1.noarch
texlive-unicode-math-svn38462-33.fc25.1.noarch
texlive-fancyvrb-svn18492.2.8-33.fc25.1.noarch
texlive-pst-pdf-bin-svn7838.0-33.20160520.fc25.1.noarch
texlive-amscls-svn36804.0-33.fc25.1.noarch
texlive-ltxmisc-svn21927.0-33.fc25.1.noarch
texlive-breqn-svn38099.0.98d-33.fc25.1.noarch
texlive-xetex-def-svn40327-33.fc25.1.noarch
openssh-server-7.4p1-4.fc25.s390x
sendmail-8.15.2-8.fc25.s390x
tzdata-2017b-1.fc25.noarch
hunspell-1.4.1-2.fc25.s390x
gpg-pubkey-8e1431d5-53bcbac7
zlib-1.2.8-10.fc24.s390x
sed-4.2.2-15.fc24.s390x
psmisc-22.21-8.fc24.s390x
gpm-libs-1.20.7-9.fc24.s390x
zip-3.0-16.fc24.s390x
libyubikey-1.13-2.fc24.s390x
sg3_utils-libs-1.41-3.fc24.s390x
polkit-pkla-compat-0.1-7.fc24.s390x
passwd-0.79-8.fc24.s390x
trousers-0.3.13-6.fc24.s390x
grubby-8.40-3.fc24.s390x
rootfiles-8.1-19.fc24.noarch
nettle-3.3-1.fc25.s390x
libksba-1.3.5-1.fc25.s390x
perl-Text-ParseWords-3.30-365.fc25.noarch
perl-PathTools-3.63-366.fc25.s390x
perl-File-Temp-0.23.04-365.fc25.noarch
fuse-libs-2.9.7-1.fc25.s390x
perl-Pod-Escapes-1.07-365.fc25.noarch
perl-Term-ANSIColor-4.05-2.fc25.noarch
perl-URI-1.71-5.fc25.noarch
libXfont-1.5.2-1.fc25.s390x
python-six-1.10.0-3.fc25.noarch
dbus-glib-0.108-1.fc25.s390x
gobject-introspection-1.50.0-1.fc25.s390x
libpwquality-1.3.0-6.fc25.s390x
python-gobject-base-3.22.0-1.fc25.s390x
python-html5lib-0.999-9.fc25.noarch
python3-dbus-1.2.4-2.fc25.s390x
python3-chardet-2.3.0-1.fc25.noarch
python3-urllib3-1.15.1-3.fc25.noarch
python-offtrac-0.1.0-7.fc25.noarch
python2-cryptography-1.5.3-3.fc25.s390x
python2-requests-kerberos-0.10.0-2.fc25.noarch
libserf-1.3.9-1.fc25.s390x
libdatrie-0.2.9-3.fc25.s390x
s390utils-base-1.36.0-1.fc25.s390x
kpartx-0.4.9-83.fc25.s390x
s390utils-cpuplugd-1.36.0-1.fc25.s390x
s390utils-osasnmpd-1.36.0-1.fc25.s390x
python-dnf-plugins-extras-common-0.0.12-4.fc25.noarch
fpc-srpm-macros-1.0-1.fc25.noarch
libuser-0.62-4.fc25.s390x
man-db-2.7.5-3.fc25.s390x
python-systemd-doc-232-1.fc25.s390x
lz4-1.7.5-1.fc25.s390x
tar-1.29-3.fc25.s390x
bodhi-client-0.9.12.2-6.fc25.noarch
cairo-1.14.8-1.fc25.s390x
gcc-go-6.3.1-1.fc25.s390x
cracklib-dicts-2.9.6-4.fc25.s390x
libselinux-python3-2.5-13.fc25.s390x
python2-enchant-1.6.8-1.fc25.noarch
boost-iostreams-1.60.0-10.fc25.s390x
userspace-rcu-0.9.2-2.fc25.s390x
libXext-devel-1.3.3-4.fc24.s390x
libXrandr-devel-1.5.1-1.fc25.s390x
perl-XML-XPath-1.39-1.fc25.noarch
python3-lxml-3.7.2-1.fc25.s390x
libiscsi-1.15.0-2.fc24.s390x
fontconfig-devel-2.12.1-1.fc25.s390x
libfdt-devel-1.4.2-1.fc25.s390x
ceph-devel-compat-10.2.4-2.fc25.s390x
zlib-static-1.2.8-10.fc24.s390x
chrpath-0.16-3.fc24.s390x
info-6.1-4.fc25.s390x
iptables-libs-1.6.0-3.fc25.s390x
libfdisk-2.28.2-2.fc25.s390x
dnf-plugins-core-0.1.21-5.fc25.noarch
perl-Storable-2.56-368.fc25.s390x
python2-decorator-4.0.11-1.fc25.noarch
libnetfilter_conntrack-1.0.6-2.fc25.s390x
texlive-texlive.infra-bin-svn40312-33.20160520.fc25.1.s390x
texlive-ifluatex-svn41346-33.fc25.1.noarch
texlive-fp-svn15878.0-33.fc25.1.noarch
texlive-latex-fonts-svn28888.0-33.fc25.1.noarch
texlive-bibtex-bin-svn40473-33.20160520.fc25.1.s390x
texlive-glyphlist-svn28576.0-33.fc25.1.noarch
texlive-marvosym-svn29349.2.2a-33.fc25.1.noarch
texlive-tex-bin-svn40987-33.20160520.fc25.1.s390x
texlive-texconfig-svn40768-33.fc25.1.noarch
texlive-wasy2-ps-svn35830.0-33.fc25.1.noarch
texlive-psfrag-svn15878.3.04-33.fc25.1.noarch
texlive-charter-svn15878.0-33.fc25.1.noarch
texlive-ec-svn25033.1.0-33.fc25.1.noarch
texlive-lineno-svn21442.4.41-33.fc25.1.noarch
texlive-hyphen-base-svn41138-33.fc25.1.noarch
texlive-manfnt-font-svn35799.0-33.fc25.1.noarch
texlive-ncntrsbk-svn31835.0-33.fc25.1.noarch
texlive-pst-math-svn34786.0.63-33.fc25.1.noarch
texlive-symbol-svn31835.0-33.fc25.1.noarch
texlive-environ-svn33821.0.3-33.fc25.1.noarch
texlive-algorithms-svn38085.0.1-33.fc25.1.noarch
kernel-core-4.10.8-200.fc25.s390x
libglvnd-devel-0.2.999-14.20170308git8e6e102.fc25.s390x
python3-hawkey-0.6.4-3.fc25.s390x
glibc-all-langpacks-2.24-9.fc25.s390x
freetype-2.6.5-9.fc25.s390x
mesa-libwayland-egl-17.0.5-3.fc25.s390x
libicu-57.1-5.fc25.s390x
nspr-devel-4.14.0-2.fc25.s390x
libnl3-cli-3.2.29-3.fc25.s390x
cups-libs-2.2.0-9.fc25.s390x
bind-libs-lite-9.10.5-2.P2.fc25.s390x
ca-certificates-2017.2.14-1.0.fc25.noarch
python3-kerberos-1.2.5-1.fc25.s390x
python3-cryptography-1.5.3-3.fc25.s390x
perl-IO-1.36-387.fc25.s390x
dhcp-libs-4.3.5-3.fc25.s390x
rsync-3.1.2-4.fc25.s390x
make-4.1-6.fc25.s390x
pcre2-devel-10.23-8.fc25.s390x
quota-4.03-8.fc25.s390x
libX11-devel-1.6.5-1.fc25.s390x
ghostscript-9.20-9.fc25.s390x
dbus-1.11.14-1.fc25.s390x
rpcbind-0.2.4-6.rc2.fc25.s390x
pyOpenSSL-16.2.0-1.fc25.noarch
glusterfs-devel-3.10.4-1.fc25.s390x
nss-tools-3.30.2-1.1.fc25.s390x
python3-pycurl-7.43.0-6.fc25.s390x
bind99-license-9.9.10-2.P3.fc25.noarch
curl-7.51.0-7.fc25.s390x
glusterfs-api-devel-3.10.4-1.fc25.s390x
python-firewall-0.4.4.5-1.fc25.noarch
netpbm-progs-10.79.00-1.fc25.s390x
libsndfile-1.0.28-3.fc25.s390x
python3-sssdconfig-1.15.2-5.fc25.noarch
wget-1.18-3.fc25.s390x
libsemanage-2.5-9.fc25.s390x
telnet-0.17-68.fc25.s390x
texlive-ifplatform-svn21156.0.4-33.fc25.1.noarch
texlive-eso-pic-svn37925.2.0g-33.fc25.1.noarch
texlive-xcolor-svn41044-33.fc25.1.noarch
texlive-pst-eps-svn15878.1.0-33.fc25.1.noarch
texlive-pst-text-svn15878.1.00-33.fc25.1.noarch
texlive-rotating-svn16832.2.16b-33.fc25.1.noarch
texlive-pdfpages-svn40638-33.fc25.1.noarch
texlive-cm-super-svn15878.0-33.fc25.1.noarch
texlive-xetex-svn41438-33.fc25.1.noarch
dnf-yum-1.1.10-6.fc25.noarch
libseccomp-devel-2.3.2-1.fc25.s390x
gpgme-1.8.0-10.fc25.s390x
apr-util-1.5.4-3.fc24.s390x
jbigkit-libs-2.1-5.fc24.s390x
pixman-0.34.0-2.fc24.s390x
dwz-0.12-2.fc24.s390x
expect-5.45-22.fc24.s390x
libsigsegv-2.10-10.fc24.s390x
fakeroot-libs-1.20.2-4.fc24.s390x
m17n-lib-1.7.0-5.fc24.s390x
libverto-0.2.6-6.fc24.s390x
libXmu-1.1.2-4.fc24.s390x
libXcursor-1.1.14-6.fc24.s390x
python-kitchen-1.2.4-2.fc24.noarch
fakeroot-1.20.2-4.fc24.s390x
blktrace-1.1.0-3.fc24.s390x
usermode-1.111-8.fc24.s390x
kbd-2.0.3-3.fc24.s390x
libaio-devel-0.3.110-6.fc24.s390x
web-assets-filesystem-5-4.fc24.noarch
libgpg-error-1.24-1.fc25.s390x
findutils-4.6.0-8.fc25.s390x
libassuan-2.4.3-1.fc25.s390x
libusbx-1.0.21-1.fc25.s390x
libxslt-1.1.28-13.fc25.s390x
libmetalink-0.1.3-1.fc25.s390x
perl-MIME-Base64-3.15-365.fc25.s390x
ncurses-6.0-6.20160709.fc25.s390x
libwayland-server-1.12.0-1.fc25.s390x
perl-Fedora-VSP-0.001-4.fc25.noarch
perl-libintl-perl-1.26-1.fc25.s390x
shadow-utils-4.2.1-11.fc25.s390x
atk-2.22.0-1.fc25.s390x
pam-1.3.0-1.fc25.s390x
harfbuzz-icu-1.3.2-1.fc25.s390x
libsecret-0.18.5-2.fc25.s390x
s390utils-iucvterm-1.36.0-1.fc25.s390x
python3-requests-2.10.0-4.fc25.noarch
pyusb-1.0.0-2.fc25.noarch
python-enum34-1.0.4-6.fc25.noarch
pyxattr-0.5.3-8.fc25.s390x
libbabeltrace-1.4.0-3.fc25.s390x
libthai-0.1.25-1.fc25.s390x
deltarpm-3.6-17.fc25.s390x
s390utils-mon_statd-1.36.0-1.fc25.s390x
device-mapper-multipath-0.4.9-83.fc25.s390x
python3-pygpgme-0.3-18.fc25.s390x
libreport-filesystem-2.8.0-1.fc25.s390x
ghc-srpm-macros-1.4.2-4.fc25.noarch
rpmdevtools-8.9-1.fc25.noarch
python-dnf-plugins-extras-migrate-0.0.12-4.fc25.noarch
perl-IO-Socket-SSL-2.038-1.fc25.noarch
perl-File-ShareDir-1.102-7.fc25.noarch
tcl-8.6.6-1.fc25.s390x
bzip2-1.0.6-21.fc25.s390x
libss-1.43.3-1.fc25.s390x
libselinux-utils-2.5-13.fc25.s390x
python3-enchant-1.6.8-1.fc25.noarch
python2-dockerfile-parse-0.0.5-7.fc25.noarch
systemd-bootchart-231-2.fc25.s390x
gcc-objc-6.3.1-1.fc25.s390x
e2fsprogs-1.43.3-1.fc25.s390x
libstdc++-static-6.3.1-1.fc25.s390x
libpng-devel-1.6.27-1.fc25.s390x
perl-XML-Parser-2.44-5.fc25.s390x
lttng-ust-2.8.1-2.fc25.s390x
libXfixes-devel-5.0.3-1.fc25.s390x
libXcomposite-devel-0.4.4-8.fc24.s390x
python3-javapackages-4.7.0-6.1.fc25.noarch
libcephfs_jni-devel-10.2.4-2.fc25.s390x
keyutils-libs-devel-1.5.9-8.fc24.s390x
harfbuzz-devel-1.3.2-1.fc25.s390x
libidn-devel-1.33-1.fc25.s390x
libnfs-1.9.8-2.fc24.s390x
libssh2-devel-1.8.0-1.fc25.s390x
qemu-sanity-check-nodeps-1.1.5-5.fc24.s390x
alsa-lib-devel-1.1.1-2.fc25.s390x
libpsl-0.17.0-1.fc25.s390x
libseccomp-2.3.2-1.fc25.s390x
copy-jdk-configs-2.2-2.fc25.noarch
json-glib-1.2.6-1.fc25.s390x
python2-dnf-1.1.10-6.fc25.noarch
python2-GitPython-2.1.3-1.fc25.noarch
texlive-tetex-bin-svn36770.0-33.20160520.fc25.1.noarch
texlive-amsfonts-svn29208.3.04-33.fc25.1.noarch
texlive-babel-svn40706-33.fc25.1.noarch
texlive-colortbl-svn29803.v1.0a-33.fc25.1.noarch
texlive-babelbib-svn25245.1.31-33.fc25.1.noarch
texlive-footmisc-svn23330.5.5b-33.fc25.1.noarch
texlive-makeindex-svn40768-33.fc25.1.noarch
texlive-plain-svn40274-33.fc25.1.noarch
texlive-texconfig-bin-svn29741.0-33.20160520.fc25.1.noarch
texlive-zapfding-svn31835.0-33.fc25.1.noarch
texlive-microtype-svn41127-33.fc25.1.noarch
texlive-bookman-svn31835.0-33.fc25.1.noarch
texlive-dvisvgm-def-svn41011-33.fc25.1.noarch
texlive-finstrut-svn21719.0.5-33.fc25.1.noarch
texlive-hyph-utf8-svn41189-33.fc25.1.noarch
texlive-lualibs-svn40370-33.fc25.1.noarch
kernel-modules-4.10.8-200.fc25.s390x
python2-hawkey-0.6.4-3.fc25.s390x
glibc-2.24-9.fc25.s390x
elfutils-libelf-0.169-1.fc25.s390x
libsoup-2.56.0-3.fc25.s390x
libnl3-3.2.29-3.fc25.s390x
gstreamer1-1.10.5-1.fc25.s390x
polkit-libs-0.113-8.fc25.s390x
libtirpc-1.0.2-0.fc25.s390x
emacs-common-25.2-2.fc25.s390x
libteam-1.27-1.fc25.s390x
python3-3.5.3-6.fc25.s390x
python3-pyasn1-0.2.3-1.fc25.noarch
perl-File-Path-2.12-366.fc25.noarch
mesa-libwayland-egl-devel-17.0.5-3.fc25.s390x
libacl-devel-2.2.52-13.fc25.s390x
lua-libs-5.3.4-3.fc25.s390x
pcre2-utf32-10.23-8.fc25.s390x
quota-nls-4.03-8.fc25.noarch
gtk3-3.22.16-1.fc25.s390x
ghostscript-x11-9.20-9.fc25.s390x
systemd-231-17.fc25.s390x
glusterfs-api-3.10.4-1.fc25.s390x
glusterfs-extra-xlators-3.10.4-1.fc25.s390x
glusterfs-server-3.10.4-1.fc25.s390x
java-1.8.0-openjdk-headless-1.8.0.131-1.b12.fc25.s390x
git-2.9.4-1.fc25.s390x
dhcp-common-4.3.5-3.fc25.noarch
python2-rpkg-1.49-5.fc25.noarch
vte291-devel-0.46.2-1.fc25.s390x
python-devel-2.7.13-2.fc25.s390x
elfutils-0.169-1.fc25.s390x
lua-5.3.4-3.fc25.s390x
python3-beautifulsoup4-4.6.0-1.fc25.noarch
libmicrohttpd-0.9.55-1.fc25.s390x
screen-4.6.1-1.fc25.s390x
strace-4.18-1.fc25.s390x
texlive-mparhack-svn15878.1.4-33.fc25.1.noarch
texlive-pspicture-svn15878.0-33.fc25.1.noarch
texlive-soul-svn15878.2.4-33.fc25.1.noarch
texlive-trimspaces-svn15878.1.1-33.fc25.1.noarch
texlive-varwidth-svn24104.0.92-33.fc25.1.noarch
texlive-geometry-svn19716.5.6-33.fc25.1.noarch
texlive-memoir-svn41203-33.fc25.1.noarch
texlive-pgf-svn40966-33.fc25.1.noarch
texlive-pst-coil-svn37377.1.07-33.fc25.1.noarch
texlive-pst-plot-svn41242-33.fc25.1.noarch
texlive-latex-bin-svn41438-33.fc25.1.noarch
texlive-ucs-svn35853.2.2-33.fc25.1.noarch
texlive-ae-svn15878.1.4-33.fc25.1.noarch
texlive-xetex-bin-svn41091-33.20160520.fc25.1.s390x
fedora-upgrade-26.1-1.fc25.noarch
fedpkg-1.28-1.fc25.noarch
perl-Thread-Queue-3.12-1.fc25.noarch
cdparanoia-libs-10.2-21.fc24.s390x
ustr-1.0.4-21.fc24.s390x
libusb-0.1.5-7.fc24.s390x
readline-devel-6.3-8.fc24.s390x
chkconfig-1.8-1.fc25.s390x
avahi-libs-0.6.32-4.fc25.s390x
perl-Unicode-Normalize-1.25-365.fc25.s390x
perl-libnet-3.10-1.fc25.noarch
perl-podlators-4.09-1.fc25.noarch
dbus-python-1.2.4-2.fc25.s390x
libgnome-keyring-3.12.0-7.fc25.s390x
python-backports-1.0-8.fc25.s390x
python-pycparser-2.14-7.fc25.noarch
plymouth-scripts-0.9.3-0.6.20160620git0e65b86c.fc25.s390x
cronie-1.5.1-2.fc25.s390x
python2-librepo-1.7.18-3.fc25.s390x
libXv-1.0.11-1.fc25.s390x
python2-ndg_httpsclient-0.4.0-4.fc25.noarch
btrfs-progs-4.6.1-1.fc25.s390x
libgcc-6.3.1-1.fc25.s390x
libgomp-6.3.1-1.fc25.s390x
perl-Encode-2.88-5.fc25.s390x
cracklib-2.9.6-4.fc25.s390x
libobjc-6.3.1-1.fc25.s390x
gcc-6.3.1-1.fc25.s390x
python3-dnf-plugin-system-upgrade-0.7.1-4.fc25.noarch
boost-random-1.60.0-10.fc25.s390x
libref_array-0.1.5-29.fc25.s390x
libXrender-devel-0.9.10-1.fc25.s390x
javapackages-tools-4.7.0-6.1.fc25.noarch
keyutils-1.5.9-8.fc24.s390x
libcom_err-devel-1.43.3-1.fc25.s390x
lzo-minilzo-2.08-8.fc24.s390x
libusbx-devel-1.0.21-1.fc25.s390x
virglrenderer-devel-0.5.0-1.20160411git61846f92f.fc25.s390x
acpica-tools-20160831-1.fc25.s390x
grep-2.27-2.fc25.s390x
dnf-conf-1.1.10-6.fc25.noarch
crypto-policies-20160921-4.gitf3018dd.fc25.noarch
rpm-build-libs-4.13.0.1-1.fc25.s390x
libnfsidmap-0.27-1.fc25.s390x
SDL2-2.0.5-3.fc25.s390x
texlive-etex-pkg-svn39355-33.fc25.1.noarch
texlive-multido-svn18302.1.42-33.fc25.1.noarch
texlive-gsftopk-svn40768-33.fc25.1.noarch
texlive-pst-ovl-svn40873-33.fc25.1.noarch
texlive-ltabptch-svn17533.1.74d-33.fc25.1.noarch
texlive-cite-svn36428.5.5-33.fc25.1.noarch
texlive-fpl-svn15878.1.002-33.fc25.1.noarch
texlive-mathpazo-svn15878.1.003-33.fc25.1.noarch
texlive-rcs-svn15878.0-33.fc25.1.noarch
texlive-type1cm-svn21820.0-33.fc25.1.noarch
texlive-l3kernel-svn41246-33.fc25.1.noarch
texlive-hyperref-svn41396-33.fc25.1.noarch
texlive-pst-tree-svn24142.1.12-33.fc25.1.noarch
texlive-sansmathaccent-svn30187.0-33.fc25.1.noarch
texlive-dvipdfmx-bin-svn40273-33.20160520.fc25.1.s390x
texlive-zapfchan-svn31835.0-33.fc25.1.noarch
glib2-static-2.50.3-1.fc25.s390x
bash-completion-2.5-1.fc25.noarch
glusterfs-libs-3.10.4-1.fc25.s390x
p11-kit-0.23.2-4.fc25.s390x
hyphen-2.8.8-4.fc24.s390x
gnutls-c++-3.5.14-1.fc25.s390x
python3-idna-2.5-1.fc25.noarch
nss-softokn-devel-3.30.2-1.0.fc25.s390x
less-481-7.fc25.s390x
rpmconf-base-1.0.19-1.fc25.noarch
gtk2-2.24.31-2.fc25.s390x
mesa-libgbm-17.0.5-3.fc25.s390x
nfs-utils-2.1.1-5.rc4.fc25.s390x
perl-Git-2.9.4-1.fc25.noarch
mock-1.4.2-1.fc25.noarch
mc-4.8.19-5.fc25.s390x
pcre-static-8.41-1.fc25.s390x
bind-libs-9.10.5-2.P2.fc25.s390x
libproxy-0.4.15-2.fc25.s390x
gpg-pubkey-a29cb19c-53bcbba6
m4-1.4.17-9.fc24.s390x
liblockfile-1.09-4.fc24.s390x
sg3_utils-1.41-3.fc24.s390x
libXinerama-1.1.3-6.fc24.s390x
libXft-2.3.2-4.fc24.s390x
tcp_wrappers-libs-7.6-83.fc25.s390x
perl-Text-Tabs+Wrap-2013.0523-365.fc25.noarch
perl-Error-0.17024-7.fc25.noarch
perl-Term-Cap-1.17-365.fc25.noarch
perl-Pod-Usage-1.69-1.fc25.noarch
device-mapper-persistent-data-0.6.3-1.fc25.s390x
net-snmp-libs-5.7.3-13.fc25.s390x
python3-six-1.10.0-3.fc25.noarch
python3-pysocks-1.5.6-5.fc25.noarch
python-chardet-2.3.0-1.fc25.noarch
python2-cffi-1.7.0-2.fc25.s390x
gc-devel-7.4.4-1.fc25.s390x
plymouth-0.9.3-0.6.20160620git0e65b86c.fc25.s390x
ebtables-2.0.10-21.fc25.s390x
python3-librepo-1.7.18-3.fc25.s390x
net-snmp-5.7.3-13.fc25.s390x
at-spi2-atk-2.22.0-1.fc25.s390x
avahi-autoipd-0.6.32-4.fc25.s390x
libgo-6.3.1-1.fc25.s390x
cpp-6.3.1-1.fc25.s390x
pyparsing-2.1.10-1.fc25.noarch
python3-pyparsing-2.1.10-1.fc25.noarch
libcollection-0.7.0-29.fc25.s390x
libcephfs-devel-10.2.4-2.fc25.s390x
libXdamage-devel-1.1.4-8.fc24.s390x
libverto-devel-0.2.6-6.fc24.s390x
snappy-1.1.3-2.fc24.s390x
cairo-gobject-devel-1.14.8-1.fc25.s390x
cyrus-sasl-devel-2.1.26-26.2.fc24.s390x
libXi-1.7.9-1.fc25.s390x
texlive-base-2016-33.20160520.fc25.noarch
python3-rpm-4.13.0.1-1.fc25.s390x
texlive-booktabs-svn40846-33.fc25.1.noarch
texlive-lm-svn28119.2.004-33.fc25.1.noarch
texlive-gsftopk-bin-svn40473-33.20160520.fc25.1.s390x
texlive-tex-svn40793-33.fc25.1.noarch
texlive-fancyref-svn15878.0.9c-33.fc25.1.noarch
texlive-chngcntr-svn17157.1.0a-33.fc25.1.noarch
texlive-fix2col-svn38770-33.fc25.1.noarch
texlive-marginnote-svn41382-33.fc25.1.noarch
texlive-pxfonts-svn15878.0-33.fc25.1.noarch
texlive-txfonts-svn15878.0-33.fc25.1.noarch
texlive-l3packages-svn41246-33.fc25.1.noarch
texlive-oberdiek-svn41346-33.fc25.1.noarch
texlive-pst-tools-svn34067.0.05-33.fc25.1.noarch
texlive-tex-gyre-svn18651.2.004-33.fc25.1.noarch
texlive-dvipdfmx-svn41149-33.fc25.1.noarch
texlive-collection-fontsrecommended-svn35830.0-33.20160520.fc25.1.noarch
libcacard-devel-2.5.3-1.fc25.s390x
ykpers-1.18.0-2.fc25.s390x
python2-idna-2.5-1.fc25.noarch
file-libs-5.29-4.fc25.s390x
policycoreutils-2.5-20.fc25.s390x
libgcrypt-1.7.8-1.fc25.s390x
pcre-8.41-1.fc25.s390x
GeoIP-1.6.11-1.fc25.s390x
ghostscript-core-9.20-9.fc25.s390x
python3-cffi-1.7.0-2.fc25.s390x
nss-softokn-freebl-devel-3.30.2-1.0.fc25.s390x
json-c-0.12.1-2.fc25.s390x
vim-common-8.0.705-1.fc25.s390x
vte291-0.46.2-1.fc25.s390x
libdrm-devel-2.4.81-1.fc25.s390x
gssproxy-0.7.0-9.fc25.s390x
git-core-doc-2.9.4-1.fc25.s390x
systemtap-3.1-5.fc25.s390x
mesa-libgbm-devel-17.0.5-3.fc25.s390x
vim-enhanced-8.0.705-1.fc25.s390x
glibc-static-2.24-9.fc25.s390x
libgusb-0.2.10-1.fc25.s390x
python-async-0.6.1-9.fc22.s390x
dejavu-sans-mono-fonts-2.35-3.fc24.noarch
popt-1.16-7.fc24.s390x
cyrus-sasl-lib-2.1.26-26.2.fc24.s390x
xz-5.2.2-2.fc24.s390x
libpipeline-1.4.1-2.fc24.s390x
pinentry-0.9.7-2.fc24.s390x
pth-2.0.7-27.fc24.s390x
libsepol-2.5-10.fc25.s390x
libxcb-1.12-1.fc25.s390x
perl-Getopt-Long-2.49.1-1.fc25.noarch
avahi-glib-0.6.32-4.fc25.s390x
python3-pip-8.1.2-2.fc25.noarch
python3-libcomps-0.1.7-5.fc25.s390x
python-slip-0.6.4-4.fc25.noarch
python2-libcomps-0.1.7-5.fc25.s390x
gc-7.4.4-1.fc25.s390x
s390utils-cmsfs-1.36.0-1.fc25.s390x
newt-python-0.52.19-2.fc25.s390x
qt5-srpm-macros-5.7.1-1.fc25.noarch
device-mapper-event-1.02.136-3.fc25.s390x
perl-Class-Inspector-1.31-2.fc25.noarch
libbasicobjects-0.1.1-29.fc25.s390x
libradosstriper1-10.2.4-2.fc25.s390x
libXxf86vm-devel-1.1.4-3.fc24.s390x
zziplib-0.13.62-7.fc24.s390x
libpaper-1.1.24-12.fc24.s390x
libini_config-1.3.0-29.fc25.s390x
snappy-devel-1.1.3-2.fc24.s390x
libcap-ng-devel-0.7.8-1.fc25.s390x
libxkbcommon-devel-0.7.1-1.fc25.s390x
openssl-libs-1.0.2k-1.fc25.s390x
libkadm5-1.14.4-7.fc25.s390x
rpm-libs-4.13.0.1-1.fc25.s390x
util-linux-2.28.2-2.fc25.s390x
texlive-etoolbox-svn38031.2.2a-33.fc25.1.noarch
texlive-dvips-svn41149-33.fc25.1.noarch
texlive-latexconfig-svn40274-33.fc25.1.noarch
texlive-tex-ini-files-svn40533-33.fc25.1.noarch
texlive-qstest-svn15878.0-33.fc25.1.noarch
texlive-cmap-svn41168-33.fc25.1.noarch
texlive-luatex-bin-svn41091-33.20160520.fc25.1.s390x
texlive-mflogo-svn38628-33.fc25.1.noarch
texlive-sansmath-svn17997.1.1-33.fc25.1.noarch
texlive-unicode-data-svn39808-33.fc25.1.noarch
texlive-luaotfload-bin-svn34647.0-33.20160520.fc25.1.noarch
texlive-listings-svn37534.1.6-33.fc25.1.noarch
texlive-pstricks-svn41321-33.fc25.1.noarch
texlive-metalogo-svn18611.0.12-33.fc25.1.noarch
texlive-collection-latex-svn41011-33.20160520.fc25.1.noarch
kernel-4.10.5-200.fc25.s390x
python2-dnf-plugins-core-0.1.21-5.fc25.noarch
xkeyboard-config-2.20-2.fc25.noarch
file-5.29-4.fc25.s390x
perl-Test-Harness-3.39-1.fc25.noarch
systemd-libs-231-17.fc25.s390x
webkitgtk4-jsc-2.16.5-1.fc25.s390x
gtk-update-icon-cache-3.22.16-1.fc25.s390x
glibc-devel-2.24-9.fc25.s390x
python3-pycparser-2.14-7.fc25.noarch
kernel-devel-4.11.10-200.fc25.s390x
gsm-1.0.17-1.fc25.s390x
vim-filesystem-8.0.705-1.fc25.s390x
webkitgtk4-2.16.5-1.fc25.s390x
python-2.7.13-2.fc25.s390x
glusterfs-fuse-3.10.4-1.fc25.s390x
git-core-2.9.4-1.fc25.s390x
selinux-policy-targeted-3.13.1-225.18.fc25.noarch
kernel-4.11.10-200.fc25.s390x
rpmconf-1.0.19-1.fc25.noarch
teamd-1.27-1.fc25.s390x
jasper-libs-1.900.13-4.fc25.s390x
libattr-2.4.47-16.fc24.s390x
libvisual-0.4.0-20.fc24.s390x
libpcap-1.7.4-2.fc24.s390x
libutempter-1.1.6-8.fc24.s390x
libgudev-230-3.fc24.s390x
popt-devel-1.16-7.fc24.s390x
hicolor-icon-theme-0.15-3.fc24.noarch
setup-2.10.4-1.fc25.noarch
bash-4.3.43-4.fc25.s390x
libjpeg-turbo-1.5.1-0.fc25.s390x
perl-Socket-2.024-1.fc25.s390x
perl-HTTP-Tiny-0.070-1.fc25.noarch
ipset-6.29-1.fc25.s390x
python2-setuptools-25.1.1-1.fc25.noarch
gsettings-desktop-schemas-3.22.0-1.fc25.s390x
python3-setuptools-25.1.1-1.fc25.noarch
python-slip-dbus-0.6.4-4.fc25.noarch
python2-ply-3.8-2.fc25.noarch
dtc-1.4.2-1.fc25.s390x
guile-2.0.13-1.fc25.s390x
cronie-anacron-1.5.1-2.fc25.s390x
libXtst-1.2.3-1.fc25.s390x
iso-codes-3.70-1.fc25.noarch
s390utils-1.36.0-1.fc25.s390x
python-backports-ssl_match_hostname-3.5.0.1-3.fc25.noarch
fedora-cert-0.6.0.1-1.fc25.noarch
libstdc++-6.3.1-1.fc25.s390x
subversion-libs-1.9.5-1.fc25.s390x
libgfortran-6.3.1-1.fc25.s390x
dnf-plugin-system-upgrade-0.7.1-4.fc25.noarch
lvm2-2.02.167-3.fc25.s390x
libselinux-devel-2.5-13.fc25.s390x
perl-Time-Local-1.250-1.fc25.noarch
libradosstriper-devel-10.2.4-2.fc25.s390x
flac-libs-1.3.2-1.fc25.s390x
perl-Digest-1.17-366.fc25.noarch
teckit-2.5.1-15.fc24.s390x
libpath_utils-0.2.1-29.fc25.s390x
attr-2.4.47-16.fc24.s390x
usbredir-0.7.1-2.fc24.s390x
cairo-devel-1.14.8-1.fc25.s390x
lzo-devel-2.08-8.fc24.s390x
libcap-devel-2.25-2.fc25.s390x
krb5-devel-1.14.4-7.fc25.s390x
rpm-4.13.0.1-1.fc25.s390x
kernel-devel-4.10.5-200.fc25.s390x
libbsd-0.8.3-1.fc25.s390x
texlive-url-svn32528.3.4-33.fc25.1.noarch
texlive-dvips-bin-svn40987-33.20160520.fc25.1.s390x
texlive-index-svn24099.4.1beta-33.fc25.1.noarch
texlive-setspace-svn24881.6.7a-33.fc25.1.noarch
texlive-mathtools-svn38833-33.fc25.1.noarch
texlive-cm-svn32865.0-33.fc25.1.noarch
texlive-graphics-def-svn41879-33.fc25.1.noarch
texlive-mdwtools-svn15878.1.05.4-33.fc25.1.noarch
texlive-rsfs-svn15878.0-33.fc25.1.noarch
texlive-ucharcat-svn38907-33.fc25.1.noarch
texlive-fontspec-svn41262-33.fc25.1.noarch
texlive-showexpl-svn32737.v0.3l-33.fc25.1.noarch
texlive-pstricks-add-svn40744-33.fc25.1.noarch
texlive-beamer-svn36461.3.36-33.fc25.1.noarch
texlive-collection-basic-svn41149-33.20160520.fc25.1.noarch
rpm-build-4.13.0.1-1.fc25.s390x
xemacs-filesystem-21.5.34-20.20170124hgf412e9f093d4.fc25.noarch
hawkey-0.6.4-3.fc25.s390x
gdk-pixbuf2-modules-2.36.6-1.fc25.s390x
bluez-libs-5.44-1.fc25.s390x
audit-libs-2.7.7-1.fc25.s390x
iproute-4.11.0-1.fc25.s390x
libICE-1.0.9-9.fc25.s390x
glibc-headers-2.24-9.fc25.s390x
python3-ply-3.8-2.fc25.noarch
perl-5.24.2-387.fc25.s390x
graphite2-1.3.10-1.fc25.s390x
vte-profile-0.46.2-1.fc25.s390x
gtk3-devel-3.22.16-1.fc25.s390x
python-libs-2.7.13-2.fc25.s390x
mesa-libGL-17.0.5-3.fc25.s390x
python2-pycurl-7.43.0-6.fc25.s390x
NetworkManager-1.4.4-5.fc25.s390x
mesa-libEGL-devel-17.0.5-3.fc25.s390x
mariadb-libs-10.1.24-3.fc25.s390x
mesa-libGLES-devel-17.0.5-3.fc25.s390x
hostname-3.15-8.fc25.s390x
gpg-pubkey-a0a7badb-52844296
readline-6.3-8.fc24.s390x
cpio-2.12-3.fc24.s390x
libXcomposite-0.4.4-8.fc24.s390x
procps-ng-3.3.10-11.fc24.s390x
GConf2-3.2.6-16.fc24.s390x
xz-devel-5.2.2-2.fc24.s390x
fedora-logos-22.0.0-3.fc24.s390x
gpg-pubkey-e372e838-56fd7943
kmod-libs-23-1.fc25.s390x
perl-parent-0.236-1.fc25.noarch
perl-TermReadKey-2.37-1.fc25.s390x
ncurses-c++-libs-6.0-6.20160709.fc25.s390x
gzip-1.8-1.fc25.s390x
python3-gobject-base-3.22.0-1.fc25.s390x
python2-yubico-1.3.2-3.fc25.noarch
s390utils-ziomon-1.36.0-1.fc25.s390x
librepo-1.7.18-3.fc25.s390x
librsvg2-2.40.16-2.fc25.s390x
gnat-srpm-macros-4-1.fc25.noarch
python-decoratortools-1.8-12.fc25.noarch
m17n-db-1.7.0-7.fc25.noarch
e2fsprogs-libs-1.43.3-1.fc25.s390x
libvorbis-1.3.5-1.fc25.s390x
gcc-gdb-plugin-6.3.1-1.fc25.s390x
npth-1.3-1.fc25.s390x
libcephfs1-10.2.4-2.fc25.s390x
wayland-devel-1.12.0-1.fc25.s390x
libxcb-devel-1.12-1.fc25.s390x
perl-encoding-2.19-5.fc25.s390x
python3-cssselect-0.9.2-1.fc25.noarch
gettext-libs-0.19.8.1-3.fc25.s390x
at-spi2-atk-devel-2.22.0-1.fc25.s390x
virglrenderer-0.5.0-1.20160411git61846f92f.fc25.s390x
pixman-devel-0.34.0-2.fc24.s390x
libnfs-devel-1.9.8-2.fc24.s390x
libblkid-2.28.2-2.fc25.s390x
glib2-devel-2.50.3-1.fc25.s390x
texlive-ifxetex-svn19685.0.5-33.fc25.1.noarch
texlive-caption-svn41409-33.fc25.1.noarch
texlive-float-svn15878.1.3d-33.fc25.1.noarch
texlive-pdftex-def-svn22653.0.06d-33.fc25.1.noarch
texlive-xdvi-bin-svn40750-33.20160520.fc25.1.s390x
texlive-beton-svn15878.0-33.fc25.1.noarch
texlive-filecontents-svn24250.1.3-33.fc25.1.noarch
texlive-lm-math-svn36915.1.959-33.fc25.1.noarch
texlive-pslatex-svn16416.0-33.fc25.1.noarch
texlive-times-svn35058.0-33.fc25.1.noarch
texlive-breakurl-svn29901.1.40-33.fc25.1.noarch
texlive-filehook-svn24280.0.5d-33.fc25.1.noarch
texlive-pst-pdf-svn31660.1.1v-33.fc25.1.noarch
texlive-seminar-svn34011.1.62-33.fc25.1.noarch
texlive-xetexconfig-svn41133-33.fc25.1.noarch
python-rpm-macros-3-12.fc25.noarch
rpm-devel-4.13.0.1-1.fc25.s390x
nss-pem-1.0.3-3.fc25.s390x
at-spi2-core-2.22.1-1.fc25.s390x
GeoIP-GeoLite-data-2017.04-1.fc25.noarch
kernel-devel-4.10.8-200.fc25.s390x
dbus-libs-1.11.14-1.fc25.s390x
perl-Scalar-List-Utils-1.48-1.fc25.s390x
libidn2-2.0.2-1.fc25.s390x
libtasn1-devel-4.12-1.fc25.s390x
python3-koji-1.13.0-2.fc25.noarch
glusterfs-cli-3.10.4-1.fc25.s390x
opus-1.1.5-1.fc25.s390x
mariadb-common-10.1.24-3.fc25.s390x
elfutils-libs-0.169-1.fc25.s390x
kernel-core-4.11.10-200.fc25.s390x
gnutls-dane-3.5.14-1.fc25.s390x
systemd-container-231-17.fc25.s390x
sudo-1.8.20p2-1.fc25.s390x
dbus-devel-1.11.14-1.fc25.s390x
perl-Module-CoreList-5.20170621-1.fc25.noarch
libicu-devel-57.1-5.fc25.s390x
js-jquery-2.2.4-3.fc25.noarch
=== TEST BEGIN ===
Using CC: /home/fam/bin/cc
Install prefix    /var/tmp/patchew-tester-tmp-wgqekxxc/src/install
BIOS directory    /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/share/qemu
binary directory  /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/bin
library directory /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/lib
module directory  /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/lib/qemu
libexec directory /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/libexec
include directory /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/include
config directory  /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/etc
local state directory   /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/var
Manual directory  /var/tmp/patchew-tester-tmp-wgqekxxc/src/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path       /var/tmp/patchew-tester-tmp-wgqekxxc/src
C compiler        /home/fam/bin/cc
Host C compiler   cc
C++ compiler      c++
Objective-C compiler /home/fam/bin/cc
ARFLAGS           rv
CFLAGS            -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g 
QEMU_CFLAGS       -I/usr/include/pixman-1  -Werror -DHAS_LIBSSH2_SFTP_FSYNC -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -DNCURSES_WIDECHAR -D_GNU_SOURCE -m64 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv  -Wendif-labels -Wno-shift-negative-value -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-strong -I/usr/include/p11-kit-1    -I/usr/include/libpng16 -I/usr/include/libdrm  -I/usr/include/cacard -I/usr/include/nss3 -I/usr/include/nspr4 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/libusb-1.0 
LDFLAGS           -Wl,--warn-common -m64 -g 
make              make
install           install
python            python -B
smbd              /usr/sbin/smbd
module support    no
host CPU          s390x
host big endian   yes
target list       aarch64-softmmu alpha-softmmu arm-softmmu cris-softmmu i386-softmmu lm32-softmmu m68k-softmmu microblazeel-softmmu microblaze-softmmu mips64el-softmmu mips64-softmmu mipsel-softmmu mips-softmmu moxie-softmmu nios2-softmmu or1k-softmmu ppc64-softmmu ppcemb-softmmu ppc-softmmu s390x-softmmu sh4eb-softmmu sh4-softmmu sparc64-softmmu sparc-softmmu tricore-softmmu unicore32-softmmu x86_64-softmmu xtensaeb-softmmu xtensa-softmmu aarch64-linux-user alpha-linux-user armeb-linux-user arm-linux-user cris-linux-user hppa-linux-user i386-linux-user m68k-linux-user microblazeel-linux-user microblaze-linux-user mips64el-linux-user mips64-linux-user mipsel-linux-user mips-linux-user mipsn32el-linux-user mipsn32-linux-user nios2-linux-user or1k-linux-user ppc64abi32-linux-user ppc64le-linux-user ppc64-linux-user ppc-linux-user s390x-linux-user sh4eb-linux-user sh4-linux-user sparc32plus-linux-user sparc64-linux-user sparc-linux-user tilegx-linux-user x86_64-linux-user
gprof enabled     no
sparse enabled    no
strip binaries    yes
profiler          no
static build      no
pixman            system
SDL support       yes (2.0.5)
GTK support       yes (3.22.16)
GTK GL support    yes
VTE support       yes (0.46.2)
TLS priority      NORMAL
GNUTLS support    yes
GNUTLS rnd        yes
libgcrypt         no
libgcrypt kdf     no
nettle            yes (3.3)
nettle kdf        yes
libtasn1          yes
curses support    yes
virgl support     yes
curl support      yes
mingw32 support   no
Audio drivers     oss
Block whitelist (rw) 
Block whitelist (ro) 
VirtFS support    yes
Multipath support no
VNC support       yes
VNC SASL support  yes
VNC JPEG support  yes
VNC PNG support   yes
xen support       no
brlapi support    yes
bluez  support    yes
Documentation     yes
PIE               no
vde support       no
netmap support    no
Linux AIO support yes
ATTR/XATTR support yes
Install blobs     yes
KVM support       yes
HAX support       no
TCG support       yes
TCG debug enabled no
TCG interpreter   no
RDMA support      no
fdt support       yes
preadv support    yes
fdatasync         yes
madvise           yes
posix_madvise     yes
libcap-ng support yes
vhost-net support yes
vhost-scsi support yes
vhost-vsock support yes
vhost-user support yes
Trace backends    log
spice support     no 
rbd support       yes
xfsctl support    no
smartcard support yes
libusb            yes
usb net redir     yes
OpenGL support    yes
OpenGL dmabufs    yes
libiscsi support  yes
libnfs support    yes
build guest agent yes
QGA VSS support   no
QGA w32 disk info no
QGA MSI support   no
seccomp support   no
coroutine backend ucontext
coroutine pool    yes
debug stack usage no
crypto afalg      no
GlusterFS support yes
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   yes
TPM passthrough   no
QOM debugging     yes
Live block migration yes
lzo support       yes
snappy support    yes
bzip2 support     yes
NUMA host support no
tcmalloc support  no
jemalloc support  no
avx2 optimization no
replication support yes
VxHS block device no
  GEN     aarch64-softmmu/config-devices.mak.tmp
  GEN     cris-softmmu/config-devices.mak.tmp
  GEN     arm-softmmu/config-devices.mak.tmp
  GEN     alpha-softmmu/config-devices.mak.tmp
  GEN     aarch64-softmmu/config-devices.mak
  GEN     cris-softmmu/config-devices.mak
  GEN     alpha-softmmu/config-devices.mak
  GEN     i386-softmmu/config-devices.mak.tmp
  GEN     lm32-softmmu/config-devices.mak.tmp
  GEN     i386-softmmu/config-devices.mak
  GEN     m68k-softmmu/config-devices.mak.tmp
  GEN     m68k-softmmu/config-devices.mak
  GEN     lm32-softmmu/config-devices.mak
  GEN     microblazeel-softmmu/config-devices.mak.tmp
  GEN     microblaze-softmmu/config-devices.mak.tmp
  GEN     mips64el-softmmu/config-devices.mak.tmp
  GEN     microblaze-softmmu/config-devices.mak
  GEN     microblazeel-softmmu/config-devices.mak
  GEN     mips64-softmmu/config-devices.mak.tmp
  GEN     mips64el-softmmu/config-devices.mak
  GEN     mipsel-softmmu/config-devices.mak.tmp
  GEN     mips-softmmu/config-devices.mak.tmp
  GEN     arm-softmmu/config-devices.mak
  GEN     mipsel-softmmu/config-devices.mak
  GEN     moxie-softmmu/config-devices.mak.tmp
  GEN     mips-softmmu/config-devices.mak
  GEN     nios2-softmmu/config-devices.mak.tmp
  GEN     moxie-softmmu/config-devices.mak
  GEN     or1k-softmmu/config-devices.mak.tmp
  GEN     nios2-softmmu/config-devices.mak
  GEN     ppcemb-softmmu/config-devices.mak.tmp
  GEN     or1k-softmmu/config-devices.mak
  GEN     ppc-softmmu/config-devices.mak.tmp
  GEN     ppc64-softmmu/config-devices.mak.tmp
  GEN     ppcemb-softmmu/config-devices.mak
  GEN     s390x-softmmu/config-devices.mak.tmp
  GEN     ppc-softmmu/config-devices.mak
  GEN     sh4eb-softmmu/config-devices.mak.tmp
  GEN     sh4eb-softmmu/config-devices.mak
  GEN     sh4-softmmu/config-devices.mak.tmp
  GEN     mips64-softmmu/config-devices.mak
  GEN     sparc64-softmmu/config-devices.mak.tmp
  GEN     ppc64-softmmu/config-devices.mak
  GEN     s390x-softmmu/config-devices.mak
  GEN     sparc64-softmmu/config-devices.mak
  GEN     tricore-softmmu/config-devices.mak.tmp
  GEN     sparc-softmmu/config-devices.mak.tmp
  GEN     unicore32-softmmu/config-devices.mak.tmp
  GEN     tricore-softmmu/config-devices.mak
  GEN     x86_64-softmmu/config-devices.mak.tmp
  GEN     sh4-softmmu/config-devices.mak
  GEN     xtensaeb-softmmu/config-devices.mak.tmp
  GEN     x86_64-softmmu/config-devices.mak
  GEN     sparc-softmmu/config-devices.mak
  GEN     xtensa-softmmu/config-devices.mak.tmp
  GEN     aarch64-linux-user/config-devices.mak.tmp
  GEN     unicore32-softmmu/config-devices.mak
  GEN     xtensaeb-softmmu/config-devices.mak
  GEN     alpha-linux-user/config-devices.mak.tmp
  GEN     alpha-linux-user/config-devices.mak
  GEN     armeb-linux-user/config-devices.mak.tmp
  GEN     aarch64-linux-user/config-devices.mak
  GEN     arm-linux-user/config-devices.mak.tmp
  GEN     cris-linux-user/config-devices.mak.tmp
  GEN     xtensa-softmmu/config-devices.mak
  GEN     arm-linux-user/config-devices.mak
  GEN     hppa-linux-user/config-devices.mak.tmp
  GEN     hppa-linux-user/config-devices.mak
  GEN     i386-linux-user/config-devices.mak.tmp
  GEN     i386-linux-user/config-devices.mak
  GEN     m68k-linux-user/config-devices.mak.tmp
  GEN     microblazeel-linux-user/config-devices.mak.tmp
  GEN     m68k-linux-user/config-devices.mak
  GEN     microblazeel-linux-user/config-devices.mak
  GEN     microblaze-linux-user/config-devices.mak.tmp
  GEN     mips64el-linux-user/config-devices.mak.tmp
  GEN     cris-linux-user/config-devices.mak
  GEN     mips64-linux-user/config-devices.mak.tmp
  GEN     armeb-linux-user/config-devices.mak
  GEN     mips64-linux-user/config-devices.mak
  GEN     mipsel-linux-user/config-devices.mak.tmp
  GEN     microblaze-linux-user/config-devices.mak
  GEN     mips-linux-user/config-devices.mak.tmp
  GEN     mips64el-linux-user/config-devices.mak
  GEN     mipsn32el-linux-user/config-devices.mak.tmp
  GEN     mipsn32-linux-user/config-devices.mak.tmp
  GEN     mipsel-linux-user/config-devices.mak
  GEN     nios2-linux-user/config-devices.mak.tmp
  GEN     mips-linux-user/config-devices.mak
  GEN     or1k-linux-user/config-devices.mak.tmp
  GEN     mipsn32el-linux-user/config-devices.mak
  GEN     nios2-linux-user/config-devices.mak
  GEN     mipsn32-linux-user/config-devices.mak
  GEN     ppc64le-linux-user/config-devices.mak.tmp
  GEN     ppc64le-linux-user/config-devices.mak
  GEN     ppc64-linux-user/config-devices.mak.tmp
  GEN     ppc64abi32-linux-user/config-devices.mak.tmp
  GEN     ppc-linux-user/config-devices.mak.tmp
  GEN     ppc64-linux-user/config-devices.mak
  GEN     or1k-linux-user/config-devices.mak
  GEN     sh4eb-linux-user/config-devices.mak.tmp
  GEN     sh4eb-linux-user/config-devices.mak
  GEN     sh4-linux-user/config-devices.mak.tmp
  GEN     s390x-linux-user/config-devices.mak.tmp
  GEN     s390x-linux-user/config-devices.mak
  GEN     sparc32plus-linux-user/config-devices.mak.tmp
  GEN     sparc32plus-linux-user/config-devices.mak
  GEN     ppc-linux-user/config-devices.mak
  GEN     sparc64-linux-user/config-devices.mak.tmp
  GEN     sparc-linux-user/config-devices.mak.tmp
  GEN     sparc64-linux-user/config-devices.mak
  GEN     sparc-linux-user/config-devices.mak
  GEN     ppc64abi32-linux-user/config-devices.mak
  GEN     tilegx-linux-user/config-devices.mak.tmp
  GEN     x86_64-linux-user/config-devices.mak.tmp
  GEN     sh4-linux-user/config-devices.mak
  GEN     x86_64-linux-user/config-devices.mak
  GEN     config-host.h
  GEN     qemu-options.def
  GEN     tilegx-linux-user/config-devices.mak
  GEN     qmp-commands.h
  GEN     qapi-types.h
  GEN     qapi-visit.h
  GEN     qapi-event.h
  GEN     qmp-marshal.c
  GEN     qapi-types.c
  GEN     qapi-visit.c
  GEN     qapi-event.c
  GEN     qmp-introspect.h
  GEN     qmp-introspect.c
  GEN     trace/generated-tcg-tracers.h
  GEN     trace/generated-helpers-wrappers.h
  GEN     trace/generated-helpers.h
make: *** No rule to make target '/var/tmp/patchew-tester-tmp-wgqekxxc/src/scsi/trace-events', needed by 'scsi/trace.h-timestamp'.  Stop.
make: *** Waiting for unfinished jobs....
  GEN     module_block.h
  GEN     trace/generated-helpers.c
=== OUTPUT END ===

Test command exited with code: 2


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (10 preceding siblings ...)
  2017-08-22 13:48 ` [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers no-reply
@ 2017-08-22 13:50 ` no-reply
  2017-08-22 13:50 ` no-reply
  2017-08-22 13:51 ` no-reply
  13 siblings, 0 replies; 48+ messages in thread
From: no-reply @ 2017-08-22 13:50 UTC (permalink / raw)
  To: pbonzini; +Cc: famz, qemu-devel

Hi,

This series failed build test on FreeBSD host. Please find the details below.

Message-id: 20170822131832.20191-1-pbonzini@redhat.com
Type: series
Subject: [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers

=== TEST SCRIPT BEGIN ===
#!/bin/sh
# Testing script will be invoked under the git checkout with
# HEAD pointing to a commit that has the patches applied on top of "base"
# branch
set -e
echo "=== ENV ==="
env
echo "=== PACKAGES ==="
pkg info
echo "=== TEST BEGIN ==="
CC=/usr/local/libexec/ccache/cc
INSTALL=$PWD/install
BUILD=$PWD/build
echo -n "Using CC: "
realpath $CC
mkdir -p $BUILD $INSTALL
SRC=$PWD
cd $BUILD
$SRC/configure --cc=$CC --prefix=$INSTALL --target-list=x86_64-softmmu
gmake -j4
# XXX: we need reliable clean up
# make check -j4 V=1
gmake install
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 t [tag update]            patchew/1503387936-3483-1-git-send-email-douly.fnst@cn.fujitsu.com -> patchew/1503387936-3483-1-git-send-email-douly.fnst@cn.fujitsu.com
 * [new tag]               patchew/20170822131832.20191-1-pbonzini@redhat.com -> patchew/20170822131832.20191-1-pbonzini@redhat.com
Switched to a new branch 'test'
e72ec38399 scsi: add persistent reservation manager using qemu-pr-helper
284895f2ab scsi: add multipath support to qemu-pr-helper
a946f484ca scsi: build qemu-pr-helper
05fe9d89ec io: add qio_channel_read/write_all
773bd4b8d7 scsi, file-posix: add support for persistent reservation management
2dd394b769 scsi: move block/scsi.h to include/scsi/constants.h
216ab8692e scsi: introduce sg_io_sense_from_errno
6a5a1d0624 scsi: introduce scsi_build_sense
7fa71258fa scsi: move non-emulation specific code to scsi/
4381f3f50d scsi: rename scsi_convert_sense

=== OUTPUT BEGIN ===
=== ENV ===
LOGNAME=patchew-tester
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
PWD=/var/tmp/patchew-tester-tmp-tarewg4x/src
HOME=/home/patchew-tester
USER=patchew-tester
SHELL=/bin/sh
PATCHEW=/home/patchew-tester/patchew/patchew-cli -s http://patchew.org --nodebug
=== PACKAGES ===
bash-4.4.12_2                  GNU Project's Bourne Again SHell
binutils-2.28,1                GNU binary tools
bison-3.0.4,1                  Parser generator from FSF, (mostly) compatible with Yacc
ca_root_nss-3.30.2             Root certificate bundle from the Mozilla Project
ccache-3.3.4_3                 Tool to minimize the compile time of C/C++ programs
curl-7.54.0                    Non-interactive tool to get files from FTP, GOPHER, HTTP(S) servers
cvsps-2.1_2                    Create patchset information from CVS
dtc-1.4.2_1                    Device Tree Compiler
expat-2.2.0_1                  XML 1.0 parser written in C
gcc-5.4.0                      GNU Compiler Collection 5
gcc-ecj-4.5                    Eclipse Java Compiler used to build GCC Java
gettext-runtime-0.19.8.1_1     GNU gettext runtime libraries and programs
git-2.13.0                     Distributed source code management tool
glib-2.46.2_5                  Some useful routines of C programming (current stable version)
gmake-4.2.1_1                  GNU version of 'make' utility
gmp-6.1.2                      Free library for arbitrary precision arithmetic
indexinfo-0.2.6                Utility to regenerate the GNU info page index
libffi-3.2.1                   Foreign Function Interface
libiconv-1.14_10               Character set conversion library
libnghttp2-1.21.0              HTTP/2.0 C Library
m4-1.4.18,1                    GNU M4
mpc-1.0.3                      Library of complex numbers with arbitrarily high precision
mpfr-3.1.5_1                   Library for multiple-precision floating-point computations
p5-Authen-SASL-2.16_1          Perl5 module for SASL authentication
p5-Digest-HMAC-1.03_1          Perl5 interface to HMAC Message-Digest Algorithms
p5-Error-0.17024               Error/exception handling in object-oriented programming style
p5-GSSAPI-0.28_1               Perl extension providing access to the GSSAPIv2 library
pcre-8.40                      Perl Compatible Regular Expressions library
perl5-5.24.1                   Practical Extraction and Report Language
pixman-0.34.0                  Low-level pixel manipulation library
pkg-1.10.1                     Package manager
pkgconf-1.3.0,1                Utility to help to configure compiler and linker flags
python-2.7_3,2                 "meta-port" for the default version of Python interpreter
python2-2_3                    The "meta-port" for version 2 of the Python interpreter
python27-2.7.13_3              Interpreted object-oriented programming language
python3-3_3                    The "meta-port" for version 3 of the Python interpreter
python35-3.5.3_1               Interpreted object-oriented programming language
readline-6.3.8                 Library for editing command lines as they are typed
sudo-1.8.20p1                  Allow others to run commands as root
=== TEST BEGIN ===
Using CC: /usr/local/bin/ccache
Install prefix    /var/tmp/patchew-tester-tmp-tarewg4x/src/install
BIOS directory    /var/tmp/patchew-tester-tmp-tarewg4x/src/install/share/qemu
binary directory  /var/tmp/patchew-tester-tmp-tarewg4x/src/install/bin
library directory /var/tmp/patchew-tester-tmp-tarewg4x/src/install/lib
module directory  /var/tmp/patchew-tester-tmp-tarewg4x/src/install/lib/qemu
libexec directory /var/tmp/patchew-tester-tmp-tarewg4x/src/install/libexec
include directory /var/tmp/patchew-tester-tmp-tarewg4x/src/install/include
config directory  /var/tmp/patchew-tester-tmp-tarewg4x/src/install/etc
local state directory   /var/tmp/patchew-tester-tmp-tarewg4x/src/install/var
Manual directory  /var/tmp/patchew-tester-tmp-tarewg4x/src/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path       /var/tmp/patchew-tester-tmp-tarewg4x/src
C compiler        /usr/local/libexec/ccache/cc
Host C compiler   cc
C++ compiler      c++
Objective-C compiler clang
ARFLAGS           rv
CFLAGS            -O2 -g 
QEMU_CFLAGS       -I/usr/local/include/pixman-1   -pthread -I/usr/local/include/glib-2.0 -I/usr/local/lib/glib-2.0/include -I/usr/local/include  -DNCURSES_WIDECHAR  -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv  -Wno-string-plus-int -Wno-initializer-overrides -Wendif-labels -Wno-shift-negative-value -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-definition -Wtype-limits -fstack-protector-strong 
LDFLAGS           -Wl,--warn-common -m64 -g 
make              gmake
install           install
python            python -B
smbd              /usr/sbin/smbd
module support    no
host CPU          x86_64
host big endian   no
target list       x86_64-softmmu
gprof enabled     no
sparse enabled    no
strip binaries    yes
profiler          no
static build      no
pixman            system
SDL support       no 
GTK support       no 
GTK GL support    no
VTE support       no 
TLS priority      NORMAL
GNUTLS support    no
GNUTLS rnd        no
libgcrypt         no
libgcrypt kdf     no
nettle            no 
nettle kdf        no
libtasn1          no
curses support    yes
virgl support     no
curl support      yes
mingw32 support   no
Audio drivers     oss
Block whitelist (rw) 
Block whitelist (ro) 
VirtFS support    no
Multipath support no
VNC support       yes
VNC SASL support  no
VNC JPEG support  no
VNC PNG support   no
xen support       no
brlapi support    no
bluez  support    no
Documentation     no
PIE               no
vde support       no
netmap support    yes
Linux AIO support no
ATTR/XATTR support no
Install blobs     yes
KVM support       no
HAX support       no
TCG support       yes
TCG debug enabled no
TCG interpreter   no
RDMA support      no
fdt support       no
preadv support    yes
fdatasync         no
madvise           yes
posix_madvise     yes
libcap-ng support no
vhost-net support no
vhost-scsi support no
vhost-vsock support no
vhost-user support yes
Trace backends    log
spice support     no 
rbd support       no
xfsctl support    no
smartcard support no
libusb            yes
usb net redir     no
OpenGL support    no
OpenGL dmabufs    no
libiscsi support  no
libnfs support    no
build guest agent yes
QGA VSS support   no
QGA w32 disk info no
QGA MSI support   no
seccomp support   no
coroutine backend ucontext
coroutine pool    yes
debug stack usage no
crypto afalg      no
GlusterFS support no
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   no
TPM passthrough   no
QOM debugging     yes
Live block migration yes
lzo support       no
snappy support    no
bzip2 support     yes
NUMA host support no
tcmalloc support  no
jemalloc support  no
avx2 optimization no
replication support yes
VxHS block device no
  GEN     x86_64-softmmu/config-devices.mak.tmp
  GEN     config-host.h
  GEN     qemu-options.def
  GEN     qmp-commands.h
  GEN     x86_64-softmmu/config-devices.mak
  GEN     qapi-types.h
  GEN     qapi-visit.h
  GEN     qapi-event.h
  GEN     qmp-marshal.c
  GEN     qapi-types.c
  GEN     qapi-visit.c
  GEN     qapi-event.c
  GEN     qmp-introspect.h
  GEN     qmp-introspect.c
  GEN     trace/generated-tcg-tracers.h
  GEN     trace/generated-helpers-wrappers.h
  GEN     trace/generated-helpers.h
  GEN     trace/generated-helpers.c
  GEN     module_block.h
gmake: *** No rule to make target '/var/tmp/patchew-tester-tmp-tarewg4x/src/scsi/trace-events', needed by 'scsi/trace.h-timestamp'.  Stop.
gmake: *** Waiting for unfinished jobs....
=== OUTPUT END ===

Test command exited with code: 2


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (11 preceding siblings ...)
  2017-08-22 13:50 ` no-reply
@ 2017-08-22 13:50 ` no-reply
  2017-08-22 13:51 ` no-reply
  13 siblings, 0 replies; 48+ messages in thread
From: no-reply @ 2017-08-22 13:50 UTC (permalink / raw)
  To: pbonzini; +Cc: famz, qemu-devel

Hi,

This series failed automatic build test. Please find the testing commands and
their output below. If you have docker installed, you can probably reproduce it
locally.

Type: series
Message-id: 20170822131832.20191-1-pbonzini@redhat.com
Subject: [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers

=== TEST SCRIPT BEGIN ===
#!/bin/bash
set -e
git submodule update --init dtc
# Let docker tests dump environment info
export SHOW_ENV=1
export J=8
time make docker-test-quick@centos6
time make docker-test-build@min-glib
time make docker-test-mingw@fedora
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
 * [new tag]               patchew/20170822131832.20191-1-pbonzini@redhat.com -> patchew/20170822131832.20191-1-pbonzini@redhat.com
Switched to a new branch 'test'
e72ec38399 scsi: add persistent reservation manager using qemu-pr-helper
284895f2ab scsi: add multipath support to qemu-pr-helper
a946f484ca scsi: build qemu-pr-helper
05fe9d89ec io: add qio_channel_read/write_all
773bd4b8d7 scsi, file-posix: add support for persistent reservation management
2dd394b769 scsi: move block/scsi.h to include/scsi/constants.h
216ab8692e scsi: introduce sg_io_sense_from_errno
6a5a1d0624 scsi: introduce scsi_build_sense
7fa71258fa scsi: move non-emulation specific code to scsi/
4381f3f50d scsi: rename scsi_convert_sense

=== OUTPUT BEGIN ===
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into '/var/tmp/patchew-tester-tmp-ilb8t7pz/src/dtc'...
Submodule path 'dtc': checked out '558cd81bdd432769b59bff01240c44f82cfb1a9d'
  BUILD   centos6
make[1]: Entering directory '/var/tmp/patchew-tester-tmp-ilb8t7pz/src'
  ARCHIVE qemu.tgz
  ARCHIVE dtc.tgz
  COPY    RUNNER
    RUN test-quick in qemu:centos6 
Packages installed:
SDL-devel-1.2.14-7.el6_7.1.x86_64
bison-2.4.1-5.el6.x86_64
bzip2-devel-1.0.5-7.el6_0.x86_64
ccache-3.1.6-2.el6.x86_64
csnappy-devel-0-6.20150729gitd7bc683.el6.x86_64
flex-2.5.35-9.el6.x86_64
gcc-4.4.7-18.el6.x86_64
git-1.7.1-8.el6.x86_64
glib2-devel-2.28.8-9.el6.x86_64
libepoxy-devel-1.2-3.el6.x86_64
libfdt-devel-1.4.0-1.el6.x86_64
librdmacm-devel-1.0.21-0.el6.x86_64
lzo-devel-2.03-3.1.el6_5.1.x86_64
make-3.81-23.el6.x86_64
mesa-libEGL-devel-11.0.7-4.el6.x86_64
mesa-libgbm-devel-11.0.7-4.el6.x86_64
package g++ is not installed
pixman-devel-0.32.8-1.el6.x86_64
spice-glib-devel-0.26-8.el6.x86_64
spice-server-devel-0.12.4-16.el6.x86_64
tar-1.23-15.el6_8.x86_64
vte-devel-0.25.1-9.el6.x86_64
xen-devel-4.6.3-15.el6.x86_64
zlib-devel-1.2.3-29.el6.x86_64

Environment variables:
PACKAGES=bison     bzip2-devel     ccache     csnappy-devel     flex     g++     gcc     git     glib2-devel     libepoxy-devel     libfdt-devel     librdmacm-devel     lzo-devel     make     mesa-libEGL-devel     mesa-libgbm-devel     pixman-devel     SDL-devel     spice-glib-devel     spice-server-devel     tar     vte-devel     xen-devel     zlib-devel
HOSTNAME=e2df32bf6f5a
TERM=xterm
MAKEFLAGS= -j8
HISTSIZE=1000
J=8
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
MAIL=/var/spool/mail/root
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
LANG=en_US.UTF-8
TARGET_LIST=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
FEATURES= dtc
DEBUG=
G_BROKEN_FILENAMES=1
CCACHE_HASHDIR=
_=/usr/bin/env

Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/var/tmp/qemu-build/install
No C++ compiler available; disabling C++ specific optional code
Install prefix    /var/tmp/qemu-build/install
BIOS directory    /var/tmp/qemu-build/install/share/qemu
binary directory  /var/tmp/qemu-build/install/bin
library directory /var/tmp/qemu-build/install/lib
module directory  /var/tmp/qemu-build/install/lib/qemu
libexec directory /var/tmp/qemu-build/install/libexec
include directory /var/tmp/qemu-build/install/include
config directory  /var/tmp/qemu-build/install/etc
local state directory   /var/tmp/qemu-build/install/var
Manual directory  /var/tmp/qemu-build/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path       /tmp/qemu-test/src
C compiler        cc
Host C compiler   cc
C++ compiler      
Objective-C compiler cc
ARFLAGS           rv
CFLAGS            -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g 
QEMU_CFLAGS       -I/usr/include/pixman-1   -I$(SRC_PATH)/dtc/libfdt -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include   -DNCURSES_WIDECHAR   -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv  -Wendif-labels -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-all  -I/usr/include/libpng12   -I/usr/include/libdrm     -I/usr/include/spice-server -I/usr/include/cacard -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/nss3 -I/usr/include/nspr4 -I/usr/include/spice-1   -I/usr/include/cacard -I/usr/include/nss3 -I/usr/include/nspr4  
LDFLAGS           -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g 
make              make
install           install
python            python -B
smbd              /usr/sbin/smbd
module support    no
host CPU          x86_64
host big endian   no
target list       x86_64-softmmu aarch64-softmmu
gprof enabled     no
sparse enabled    no
strip binaries    yes
profiler          no
static build      no
pixman            system
SDL support       yes (1.2.14)
GTK support       yes (2.24.23)
GTK GL support    no
VTE support       yes (0.25.1)
TLS priority      NORMAL
GNUTLS support    no
GNUTLS rnd        no
libgcrypt         no
libgcrypt kdf     no
nettle            no 
nettle kdf        no
libtasn1          no
curses support    yes
virgl support     no
curl support      no
mingw32 support   no
Audio drivers     oss
Block whitelist (rw) 
Block whitelist (ro) 
VirtFS support    no
Multipath support no
VNC support       yes
VNC SASL support  no
VNC JPEG support  yes
VNC PNG support   yes
xen support       yes
xen ctrl version  40600
pv dom build      no
brlapi support    no
bluez  support    no
Documentation     no
PIE               yes
vde support       no
netmap support    no
Linux AIO support no
ATTR/XATTR support yes
Install blobs     yes
KVM support       yes
HAX support       no
TCG support       yes
TCG debug enabled no
TCG interpreter   no
RDMA support      yes
fdt support       yes
preadv support    yes
fdatasync         yes
madvise           yes
posix_madvise     yes
libcap-ng support no
vhost-net support yes
vhost-scsi support yes
vhost-vsock support yes
vhost-user support yes
Trace backends    log
spice support     yes (0.12.6/0.12.4)
rbd support       no
xfsctl support    no
smartcard support yes
libusb            no
usb net redir     no
OpenGL support    yes
OpenGL dmabufs    no
libiscsi support  no
libnfs support    no
build guest agent yes
QGA VSS support   no
QGA w32 disk info no
QGA MSI support   no
seccomp support   no
coroutine backend ucontext
coroutine pool    yes
debug stack usage no
crypto afalg      no
GlusterFS support no
gcov              gcov
gcov enabled      no
TPM support       yes
libssh2 support   no
TPM passthrough   yes
QOM debugging     yes
Live block migration yes
lzo support       yes
snappy support    no
bzip2 support     yes
NUMA host support no
tcmalloc support  no
jemalloc support  no
avx2 optimization no
replication support yes
VxHS block device no
mkdir -p dtc/libfdt
mkdir -p dtc/tests
  GEN     aarch64-softmmu/config-devices.mak.tmp
  GEN     x86_64-softmmu/config-devices.mak.tmp
  GEN     qemu-options.def
  GEN     qmp-commands.h
  GEN     config-host.h
  GEN     qapi-types.h
  GEN     qapi-visit.h
  GEN     qapi-event.h
  GEN     x86_64-softmmu/config-devices.mak
  GEN     aarch64-softmmu/config-devices.mak
  GEN     qmp-marshal.c
  GEN     qapi-types.c
  GEN     qapi-visit.c
  GEN     qapi-event.c
  GEN     qmp-introspect.h
  GEN     qmp-introspect.c
  GEN     trace/generated-tcg-tracers.h
  GEN     trace/generated-helpers-wrappers.h
  GEN     trace/generated-helpers.h
  GEN     trace/generated-helpers.c
  GEN     module_block.h
make: *** No rule to make target `/tmp/qemu-test/src/scsi/trace-events', needed by `/var/tmp/qemu-build/trace-events-all'.  Stop.
make: *** Waiting for unfinished jobs....
Traceback (most recent call last):
  File "./tests/docker/docker.py", line 382, in <module>
    sys.exit(main())
  File "./tests/docker/docker.py", line 379, in main
    return args.cmdobj.run(args, argv)
  File "./tests/docker/docker.py", line 237, in run
    return Docker().run(argv, args.keep, quiet=args.quiet)
  File "./tests/docker/docker.py", line 205, in run
    quiet=quiet)
  File "./tests/docker/docker.py", line 123, in _do_check
    return subprocess.check_call(self._command + cmd, **kwargs)
  File "/usr/lib64/python2.7/subprocess.py", line 186, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['docker', 'run', '--label', 'com.qemu.instance.uuid=bf5e7926874011e789ed52540069c830', '-u', '0', '-t', '--rm', '--net=none', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=8', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/var/tmp/patchew-tester-tmp-ilb8t7pz/src/docker-src.2017-08-22-09.49.37.9883:/var/tmp/qemu:z,ro', '-v', '/root/.cache/qemu-docker-ccache:/var/tmp/ccache:z', 'qemu:centos6', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit status 2
make[1]: *** [tests/docker/Makefile.include:139: docker-run] Error 1
make[1]: Leaving directory '/var/tmp/patchew-tester-tmp-ilb8t7pz/src'
make: *** [tests/docker/Makefile.include:168: docker-run-test-quick@centos6] Error 2

real	1m20.250s
user	0m5.140s
sys	0m1.571s
=== OUTPUT END ===

Test command exited with code: 2


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers
  2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
                   ` (12 preceding siblings ...)
  2017-08-22 13:50 ` no-reply
@ 2017-08-22 13:51 ` no-reply
  13 siblings, 0 replies; 48+ messages in thread
From: no-reply @ 2017-08-22 13:51 UTC (permalink / raw)
  To: pbonzini; +Cc: famz, qemu-devel

Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20170822131832.20191-1-pbonzini@redhat.com
Subject: [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

git config --local diff.renamelimit 0
git config --local diff.renames True

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
e72ec38399 scsi: add persistent reservation manager using qemu-pr-helper
284895f2ab scsi: add multipath support to qemu-pr-helper
a946f484ca scsi: build qemu-pr-helper
05fe9d89ec io: add qio_channel_read/write_all
773bd4b8d7 scsi, file-posix: add support for persistent reservation management
2dd394b769 scsi: move block/scsi.h to include/scsi/constants.h
216ab8692e scsi: introduce sg_io_sense_from_errno
6a5a1d0624 scsi: introduce scsi_build_sense
7fa71258fa scsi: move non-emulation specific code to scsi/
4381f3f50d scsi: rename scsi_convert_sense

=== OUTPUT BEGIN ===
Checking PATCH 1/10: scsi: rename scsi_convert_sense...
Checking PATCH 2/10: scsi: move non-emulation specific code to scsi/...
ERROR: space prohibited after that open square bracket '['
#1042: FILE: scsi/utils.c:282:
+        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",

ERROR: space prohibited before that close square bracket ']'
#1042: FILE: scsi/utils.c:282:
+        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",

ERROR: space prohibited after that open square bracket '['
#1043: FILE: scsi/utils.c:283:
+        [ REWIND                   ] = "REWIND",

ERROR: space prohibited before that close square bracket ']'
#1043: FILE: scsi/utils.c:283:
+        [ REWIND                   ] = "REWIND",

ERROR: space prohibited after that open square bracket '['
#1044: FILE: scsi/utils.c:284:
+        [ REQUEST_SENSE            ] = "REQUEST_SENSE",

ERROR: space prohibited before that close square bracket ']'
#1044: FILE: scsi/utils.c:284:
+        [ REQUEST_SENSE            ] = "REQUEST_SENSE",

ERROR: space prohibited after that open square bracket '['
#1045: FILE: scsi/utils.c:285:
+        [ FORMAT_UNIT              ] = "FORMAT_UNIT",

ERROR: space prohibited before that close square bracket ']'
#1045: FILE: scsi/utils.c:285:
+        [ FORMAT_UNIT              ] = "FORMAT_UNIT",

ERROR: space prohibited after that open square bracket '['
#1046: FILE: scsi/utils.c:286:
+        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",

ERROR: space prohibited before that close square bracket ']'
#1046: FILE: scsi/utils.c:286:
+        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",

WARNING: line over 80 characters
#1047: FILE: scsi/utils.c:287:
+        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",

ERROR: space prohibited after that open square bracket '['
#1047: FILE: scsi/utils.c:287:
+        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",

ERROR: space prohibited before that close square bracket ']'
#1047: FILE: scsi/utils.c:287:
+        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",

WARNING: line over 80 characters
#1048: FILE: scsi/utils.c:288:
+        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */

ERROR: space prohibited after that open square bracket '['
#1049: FILE: scsi/utils.c:289:
+        [ READ_6                   ] = "READ_6",

ERROR: space prohibited before that close square bracket ']'
#1049: FILE: scsi/utils.c:289:
+        [ READ_6                   ] = "READ_6",

ERROR: space prohibited after that open square bracket '['
#1050: FILE: scsi/utils.c:290:
+        [ WRITE_6                  ] = "WRITE_6",

ERROR: space prohibited before that close square bracket ']'
#1050: FILE: scsi/utils.c:290:
+        [ WRITE_6                  ] = "WRITE_6",

ERROR: space prohibited after that open square bracket '['
#1051: FILE: scsi/utils.c:291:
+        [ SET_CAPACITY             ] = "SET_CAPACITY",

ERROR: space prohibited before that close square bracket ']'
#1051: FILE: scsi/utils.c:291:
+        [ SET_CAPACITY             ] = "SET_CAPACITY",

ERROR: space prohibited after that open square bracket '['
#1052: FILE: scsi/utils.c:292:
+        [ READ_REVERSE             ] = "READ_REVERSE",

ERROR: space prohibited before that close square bracket ']'
#1052: FILE: scsi/utils.c:292:
+        [ READ_REVERSE             ] = "READ_REVERSE",

ERROR: space prohibited after that open square bracket '['
#1053: FILE: scsi/utils.c:293:
+        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",

ERROR: space prohibited before that close square bracket ']'
#1053: FILE: scsi/utils.c:293:
+        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",

ERROR: space prohibited after that open square bracket '['
#1054: FILE: scsi/utils.c:294:
+        [ SPACE                    ] = "SPACE",

ERROR: space prohibited before that close square bracket ']'
#1054: FILE: scsi/utils.c:294:
+        [ SPACE                    ] = "SPACE",

ERROR: space prohibited after that open square bracket '['
#1055: FILE: scsi/utils.c:295:
+        [ INQUIRY                  ] = "INQUIRY",

ERROR: space prohibited before that close square bracket ']'
#1055: FILE: scsi/utils.c:295:
+        [ INQUIRY                  ] = "INQUIRY",

ERROR: space prohibited after that open square bracket '['
#1056: FILE: scsi/utils.c:296:
+        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",

ERROR: space prohibited before that close square bracket ']'
#1056: FILE: scsi/utils.c:296:
+        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",

ERROR: space prohibited after that open square bracket '['
#1057: FILE: scsi/utils.c:297:
+        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",

ERROR: space prohibited before that close square bracket ']'
#1057: FILE: scsi/utils.c:297:
+        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",

ERROR: space prohibited after that open square bracket '['
#1058: FILE: scsi/utils.c:298:
+        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",

ERROR: space prohibited before that close square bracket ']'
#1058: FILE: scsi/utils.c:298:
+        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",

ERROR: space prohibited after that open square bracket '['
#1059: FILE: scsi/utils.c:299:
+        [ MODE_SELECT              ] = "MODE_SELECT",

ERROR: space prohibited before that close square bracket ']'
#1059: FILE: scsi/utils.c:299:
+        [ MODE_SELECT              ] = "MODE_SELECT",

ERROR: space prohibited after that open square bracket '['
#1060: FILE: scsi/utils.c:300:
+        [ RESERVE                  ] = "RESERVE",

ERROR: space prohibited before that close square bracket ']'
#1060: FILE: scsi/utils.c:300:
+        [ RESERVE                  ] = "RESERVE",

ERROR: space prohibited after that open square bracket '['
#1061: FILE: scsi/utils.c:301:
+        [ RELEASE                  ] = "RELEASE",

ERROR: space prohibited before that close square bracket ']'
#1061: FILE: scsi/utils.c:301:
+        [ RELEASE                  ] = "RELEASE",

ERROR: space prohibited after that open square bracket '['
#1062: FILE: scsi/utils.c:302:
+        [ COPY                     ] = "COPY",

ERROR: space prohibited before that close square bracket ']'
#1062: FILE: scsi/utils.c:302:
+        [ COPY                     ] = "COPY",

ERROR: space prohibited after that open square bracket '['
#1063: FILE: scsi/utils.c:303:
+        [ ERASE                    ] = "ERASE",

ERROR: space prohibited before that close square bracket ']'
#1063: FILE: scsi/utils.c:303:
+        [ ERASE                    ] = "ERASE",

ERROR: space prohibited after that open square bracket '['
#1064: FILE: scsi/utils.c:304:
+        [ MODE_SENSE               ] = "MODE_SENSE",

ERROR: space prohibited before that close square bracket ']'
#1064: FILE: scsi/utils.c:304:
+        [ MODE_SENSE               ] = "MODE_SENSE",

ERROR: space prohibited after that open square bracket '['
#1065: FILE: scsi/utils.c:305:
+        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",

ERROR: space prohibited before that close square bracket ']'
#1065: FILE: scsi/utils.c:305:
+        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",

ERROR: space prohibited after that open square bracket '['
#1067: FILE: scsi/utils.c:307:
+        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",

ERROR: space prohibited before that close square bracket ']'
#1067: FILE: scsi/utils.c:307:
+        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",

ERROR: space prohibited after that open square bracket '['
#1068: FILE: scsi/utils.c:308:
+        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",

ERROR: space prohibited before that close square bracket ']'
#1068: FILE: scsi/utils.c:308:
+        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",

ERROR: space prohibited after that open square bracket '['
#1069: FILE: scsi/utils.c:309:
+        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",

ERROR: space prohibited before that close square bracket ']'
#1069: FILE: scsi/utils.c:309:
+        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",

ERROR: space prohibited after that open square bracket '['
#1070: FILE: scsi/utils.c:310:
+        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",

ERROR: space prohibited before that close square bracket ']'
#1070: FILE: scsi/utils.c:310:
+        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",

ERROR: space prohibited after that open square bracket '['
#1071: FILE: scsi/utils.c:311:
+        [ READ_10                  ] = "READ_10",

ERROR: space prohibited before that close square bracket ']'
#1071: FILE: scsi/utils.c:311:
+        [ READ_10                  ] = "READ_10",

ERROR: space prohibited after that open square bracket '['
#1072: FILE: scsi/utils.c:312:
+        [ WRITE_10                 ] = "WRITE_10",

ERROR: space prohibited before that close square bracket ']'
#1072: FILE: scsi/utils.c:312:
+        [ WRITE_10                 ] = "WRITE_10",

ERROR: space prohibited after that open square bracket '['
#1073: FILE: scsi/utils.c:313:
+        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",

ERROR: space prohibited before that close square bracket ']'
#1073: FILE: scsi/utils.c:313:
+        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",

ERROR: space prohibited after that open square bracket '['
#1075: FILE: scsi/utils.c:315:
+        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",

ERROR: space prohibited before that close square bracket ']'
#1075: FILE: scsi/utils.c:315:
+        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",

ERROR: space prohibited after that open square bracket '['
#1076: FILE: scsi/utils.c:316:
+        [ VERIFY_10                ] = "VERIFY_10",

ERROR: space prohibited before that close square bracket ']'
#1076: FILE: scsi/utils.c:316:
+        [ VERIFY_10                ] = "VERIFY_10",

ERROR: space prohibited after that open square bracket '['
#1077: FILE: scsi/utils.c:317:
+        [ SEARCH_HIGH              ] = "SEARCH_HIGH",

ERROR: space prohibited before that close square bracket ']'
#1077: FILE: scsi/utils.c:317:
+        [ SEARCH_HIGH              ] = "SEARCH_HIGH",

ERROR: space prohibited after that open square bracket '['
#1078: FILE: scsi/utils.c:318:
+        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",

ERROR: space prohibited before that close square bracket ']'
#1078: FILE: scsi/utils.c:318:
+        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",

ERROR: space prohibited after that open square bracket '['
#1079: FILE: scsi/utils.c:319:
+        [ SEARCH_LOW               ] = "SEARCH_LOW",

ERROR: space prohibited before that close square bracket ']'
#1079: FILE: scsi/utils.c:319:
+        [ SEARCH_LOW               ] = "SEARCH_LOW",

ERROR: space prohibited after that open square bracket '['
#1080: FILE: scsi/utils.c:320:
+        [ SET_LIMITS               ] = "SET_LIMITS",

ERROR: space prohibited before that close square bracket ']'
#1080: FILE: scsi/utils.c:320:
+        [ SET_LIMITS               ] = "SET_LIMITS",

ERROR: space prohibited after that open square bracket '['
#1081: FILE: scsi/utils.c:321:
+        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",

ERROR: space prohibited before that close square bracket ']'
#1081: FILE: scsi/utils.c:321:
+        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",

ERROR: space prohibited after that open square bracket '['
#1083: FILE: scsi/utils.c:323:
+        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",

ERROR: space prohibited before that close square bracket ']'
#1083: FILE: scsi/utils.c:323:
+        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",

ERROR: space prohibited after that open square bracket '['
#1084: FILE: scsi/utils.c:324:
+        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",

ERROR: space prohibited before that close square bracket ']'
#1084: FILE: scsi/utils.c:324:
+        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",

ERROR: line over 90 characters
#1085: FILE: scsi/utils.c:325:
+        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",

ERROR: space prohibited after that open square bracket '['
#1085: FILE: scsi/utils.c:325:
+        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",

ERROR: space prohibited before that close square bracket ']'
#1085: FILE: scsi/utils.c:325:
+        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",

ERROR: line over 90 characters
#1086: FILE: scsi/utils.c:326:
+        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */

ERROR: space prohibited after that open square bracket '['
#1087: FILE: scsi/utils.c:327:
+        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",

ERROR: space prohibited before that close square bracket ']'
#1087: FILE: scsi/utils.c:327:
+        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",

ERROR: space prohibited after that open square bracket '['
#1088: FILE: scsi/utils.c:328:
+        [ COMPARE                  ] = "COMPARE",

ERROR: space prohibited before that close square bracket ']'
#1088: FILE: scsi/utils.c:328:
+        [ COMPARE                  ] = "COMPARE",

ERROR: space prohibited after that open square bracket '['
#1089: FILE: scsi/utils.c:329:
+        [ COPY_VERIFY              ] = "COPY_VERIFY",

ERROR: space prohibited before that close square bracket ']'
#1089: FILE: scsi/utils.c:329:
+        [ COPY_VERIFY              ] = "COPY_VERIFY",

ERROR: space prohibited after that open square bracket '['
#1090: FILE: scsi/utils.c:330:
+        [ WRITE_BUFFER             ] = "WRITE_BUFFER",

ERROR: space prohibited before that close square bracket ']'
#1090: FILE: scsi/utils.c:330:
+        [ WRITE_BUFFER             ] = "WRITE_BUFFER",

ERROR: space prohibited after that open square bracket '['
#1091: FILE: scsi/utils.c:331:
+        [ READ_BUFFER              ] = "READ_BUFFER",

ERROR: space prohibited before that close square bracket ']'
#1091: FILE: scsi/utils.c:331:
+        [ READ_BUFFER              ] = "READ_BUFFER",

ERROR: space prohibited after that open square bracket '['
#1092: FILE: scsi/utils.c:332:
+        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",

ERROR: space prohibited before that close square bracket ']'
#1092: FILE: scsi/utils.c:332:
+        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",

ERROR: space prohibited after that open square bracket '['
#1093: FILE: scsi/utils.c:333:
+        [ READ_LONG_10             ] = "READ_LONG_10",

ERROR: space prohibited before that close square bracket ']'
#1093: FILE: scsi/utils.c:333:
+        [ READ_LONG_10             ] = "READ_LONG_10",

ERROR: space prohibited after that open square bracket '['
#1094: FILE: scsi/utils.c:334:
+        [ WRITE_LONG_10            ] = "WRITE_LONG_10",

ERROR: space prohibited before that close square bracket ']'
#1094: FILE: scsi/utils.c:334:
+        [ WRITE_LONG_10            ] = "WRITE_LONG_10",

ERROR: space prohibited after that open square bracket '['
#1095: FILE: scsi/utils.c:335:
+        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",

ERROR: space prohibited before that close square bracket ']'
#1095: FILE: scsi/utils.c:335:
+        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",

ERROR: space prohibited after that open square bracket '['
#1096: FILE: scsi/utils.c:336:
+        [ WRITE_SAME_10            ] = "WRITE_SAME_10",

ERROR: space prohibited before that close square bracket ']'
#1096: FILE: scsi/utils.c:336:
+        [ WRITE_SAME_10            ] = "WRITE_SAME_10",

ERROR: space prohibited after that open square bracket '['
#1097: FILE: scsi/utils.c:337:
+        [ UNMAP                    ] = "UNMAP",

ERROR: space prohibited before that close square bracket ']'
#1097: FILE: scsi/utils.c:337:
+        [ UNMAP                    ] = "UNMAP",

ERROR: space prohibited after that open square bracket '['
#1098: FILE: scsi/utils.c:338:
+        [ READ_TOC                 ] = "READ_TOC",

ERROR: space prohibited before that close square bracket ']'
#1098: FILE: scsi/utils.c:338:
+        [ READ_TOC                 ] = "READ_TOC",

ERROR: space prohibited after that open square bracket '['
#1099: FILE: scsi/utils.c:339:
+        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",

ERROR: space prohibited before that close square bracket ']'
#1099: FILE: scsi/utils.c:339:
+        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",

ERROR: space prohibited after that open square bracket '['
#1100: FILE: scsi/utils.c:340:
+        [ SANITIZE                 ] = "SANITIZE",

ERROR: space prohibited before that close square bracket ']'
#1100: FILE: scsi/utils.c:340:
+        [ SANITIZE                 ] = "SANITIZE",

ERROR: space prohibited after that open square bracket '['
#1101: FILE: scsi/utils.c:341:
+        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",

ERROR: space prohibited before that close square bracket ']'
#1101: FILE: scsi/utils.c:341:
+        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",

ERROR: space prohibited after that open square bracket '['
#1102: FILE: scsi/utils.c:342:
+        [ LOG_SELECT               ] = "LOG_SELECT",

ERROR: space prohibited before that close square bracket ']'
#1102: FILE: scsi/utils.c:342:
+        [ LOG_SELECT               ] = "LOG_SELECT",

ERROR: space prohibited after that open square bracket '['
#1103: FILE: scsi/utils.c:343:
+        [ LOG_SENSE                ] = "LOG_SENSE",

ERROR: space prohibited before that close square bracket ']'
#1103: FILE: scsi/utils.c:343:
+        [ LOG_SENSE                ] = "LOG_SENSE",

ERROR: space prohibited after that open square bracket '['
#1104: FILE: scsi/utils.c:344:
+        [ MODE_SELECT_10           ] = "MODE_SELECT_10",

ERROR: space prohibited before that close square bracket ']'
#1104: FILE: scsi/utils.c:344:
+        [ MODE_SELECT_10           ] = "MODE_SELECT_10",

ERROR: space prohibited after that open square bracket '['
#1105: FILE: scsi/utils.c:345:
+        [ RESERVE_10               ] = "RESERVE_10",

ERROR: space prohibited before that close square bracket ']'
#1105: FILE: scsi/utils.c:345:
+        [ RESERVE_10               ] = "RESERVE_10",

ERROR: space prohibited after that open square bracket '['
#1106: FILE: scsi/utils.c:346:
+        [ RELEASE_10               ] = "RELEASE_10",

ERROR: space prohibited before that close square bracket ']'
#1106: FILE: scsi/utils.c:346:
+        [ RELEASE_10               ] = "RELEASE_10",

ERROR: space prohibited after that open square bracket '['
#1107: FILE: scsi/utils.c:347:
+        [ MODE_SENSE_10            ] = "MODE_SENSE_10",

ERROR: space prohibited before that close square bracket ']'
#1107: FILE: scsi/utils.c:347:
+        [ MODE_SENSE_10            ] = "MODE_SENSE_10",

ERROR: space prohibited after that open square bracket '['
#1108: FILE: scsi/utils.c:348:
+        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",

ERROR: space prohibited before that close square bracket ']'
#1108: FILE: scsi/utils.c:348:
+        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",

ERROR: space prohibited after that open square bracket '['
#1109: FILE: scsi/utils.c:349:
+        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",

ERROR: space prohibited before that close square bracket ']'
#1109: FILE: scsi/utils.c:349:
+        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",

ERROR: space prohibited after that open square bracket '['
#1110: FILE: scsi/utils.c:350:
+        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",

ERROR: space prohibited before that close square bracket ']'
#1110: FILE: scsi/utils.c:350:
+        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",

ERROR: space prohibited after that open square bracket '['
#1111: FILE: scsi/utils.c:351:
+        [ EXTENDED_COPY            ] = "EXTENDED_COPY",

ERROR: space prohibited before that close square bracket ']'
#1111: FILE: scsi/utils.c:351:
+        [ EXTENDED_COPY            ] = "EXTENDED_COPY",

ERROR: space prohibited after that open square bracket '['
#1112: FILE: scsi/utils.c:352:
+        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",

ERROR: space prohibited before that close square bracket ']'
#1112: FILE: scsi/utils.c:352:
+        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",

ERROR: space prohibited after that open square bracket '['
#1113: FILE: scsi/utils.c:353:
+        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",

ERROR: space prohibited before that close square bracket ']'
#1113: FILE: scsi/utils.c:353:
+        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",

ERROR: space prohibited after that open square bracket '['
#1114: FILE: scsi/utils.c:354:
+        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",

ERROR: space prohibited before that close square bracket ']'
#1114: FILE: scsi/utils.c:354:
+        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",

ERROR: space prohibited after that open square bracket '['
#1115: FILE: scsi/utils.c:355:
+        [ READ_16                  ] = "READ_16",

ERROR: space prohibited before that close square bracket ']'
#1115: FILE: scsi/utils.c:355:
+        [ READ_16                  ] = "READ_16",

ERROR: space prohibited after that open square bracket '['
#1116: FILE: scsi/utils.c:356:
+        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",

ERROR: space prohibited before that close square bracket ']'
#1116: FILE: scsi/utils.c:356:
+        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",

ERROR: space prohibited after that open square bracket '['
#1117: FILE: scsi/utils.c:357:
+        [ WRITE_16                 ] = "WRITE_16",

ERROR: space prohibited before that close square bracket ']'
#1117: FILE: scsi/utils.c:357:
+        [ WRITE_16                 ] = "WRITE_16",

ERROR: space prohibited after that open square bracket '['
#1118: FILE: scsi/utils.c:358:
+        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",

ERROR: space prohibited before that close square bracket ']'
#1118: FILE: scsi/utils.c:358:
+        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",

ERROR: space prohibited after that open square bracket '['
#1119: FILE: scsi/utils.c:359:
+        [ VERIFY_16                ] = "VERIFY_16",

ERROR: space prohibited before that close square bracket ']'
#1119: FILE: scsi/utils.c:359:
+        [ VERIFY_16                ] = "VERIFY_16",

ERROR: space prohibited after that open square bracket '['
#1120: FILE: scsi/utils.c:360:
+        [ PRE_FETCH_16             ] = "PRE_FETCH_16",

ERROR: space prohibited before that close square bracket ']'
#1120: FILE: scsi/utils.c:360:
+        [ PRE_FETCH_16             ] = "PRE_FETCH_16",

ERROR: space prohibited after that open square bracket '['
#1121: FILE: scsi/utils.c:361:
+        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",

ERROR: space prohibited before that close square bracket ']'
#1121: FILE: scsi/utils.c:361:
+        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",

ERROR: space prohibited after that open square bracket '['
#1123: FILE: scsi/utils.c:363:
+        [ LOCATE_16                ] = "LOCATE_16",

ERROR: space prohibited before that close square bracket ']'
#1123: FILE: scsi/utils.c:363:
+        [ LOCATE_16                ] = "LOCATE_16",

ERROR: space prohibited after that open square bracket '['
#1124: FILE: scsi/utils.c:364:
+        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",

ERROR: space prohibited before that close square bracket ']'
#1124: FILE: scsi/utils.c:364:
+        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",

ERROR: space prohibited after that open square bracket '['
#1126: FILE: scsi/utils.c:366:
+        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",

ERROR: space prohibited before that close square bracket ']'
#1126: FILE: scsi/utils.c:366:
+        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",

ERROR: space prohibited after that open square bracket '['
#1127: FILE: scsi/utils.c:367:
+        [ WRITE_LONG_16            ] = "WRITE_LONG_16",

ERROR: space prohibited before that close square bracket ']'
#1127: FILE: scsi/utils.c:367:
+        [ WRITE_LONG_16            ] = "WRITE_LONG_16",

ERROR: space prohibited after that open square bracket '['
#1128: FILE: scsi/utils.c:368:
+        [ REPORT_LUNS              ] = "REPORT_LUNS",

ERROR: space prohibited before that close square bracket ']'
#1128: FILE: scsi/utils.c:368:
+        [ REPORT_LUNS              ] = "REPORT_LUNS",

ERROR: space prohibited after that open square bracket '['
#1129: FILE: scsi/utils.c:369:
+        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",

ERROR: space prohibited before that close square bracket ']'
#1129: FILE: scsi/utils.c:369:
+        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",

ERROR: space prohibited after that open square bracket '['
#1130: FILE: scsi/utils.c:370:
+        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",

ERROR: space prohibited before that close square bracket ']'
#1130: FILE: scsi/utils.c:370:
+        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",

ERROR: space prohibited after that open square bracket '['
#1131: FILE: scsi/utils.c:371:
+        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",

ERROR: space prohibited before that close square bracket ']'
#1131: FILE: scsi/utils.c:371:
+        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",

ERROR: space prohibited after that open square bracket '['
#1132: FILE: scsi/utils.c:372:
+        [ READ_12                  ] = "READ_12",

ERROR: space prohibited before that close square bracket ']'
#1132: FILE: scsi/utils.c:372:
+        [ READ_12                  ] = "READ_12",

ERROR: space prohibited after that open square bracket '['
#1133: FILE: scsi/utils.c:373:
+        [ WRITE_12                 ] = "WRITE_12",

ERROR: space prohibited before that close square bracket ']'
#1133: FILE: scsi/utils.c:373:
+        [ WRITE_12                 ] = "WRITE_12",

ERROR: space prohibited after that open square bracket '['
#1134: FILE: scsi/utils.c:374:
+        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",

ERROR: space prohibited before that close square bracket ']'
#1134: FILE: scsi/utils.c:374:
+        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",

ERROR: space prohibited after that open square bracket '['
#1136: FILE: scsi/utils.c:376:
+        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",

ERROR: space prohibited before that close square bracket ']'
#1136: FILE: scsi/utils.c:376:
+        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",

ERROR: space prohibited after that open square bracket '['
#1137: FILE: scsi/utils.c:377:
+        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",

ERROR: space prohibited before that close square bracket ']'
#1137: FILE: scsi/utils.c:377:
+        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",

ERROR: space prohibited after that open square bracket '['
#1138: FILE: scsi/utils.c:378:
+        [ VERIFY_12                ] = "VERIFY_12",

ERROR: space prohibited before that close square bracket ']'
#1138: FILE: scsi/utils.c:378:
+        [ VERIFY_12                ] = "VERIFY_12",

ERROR: space prohibited after that open square bracket '['
#1139: FILE: scsi/utils.c:379:
+        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",

ERROR: space prohibited before that close square bracket ']'
#1139: FILE: scsi/utils.c:379:
+        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",

ERROR: space prohibited after that open square bracket '['
#1140: FILE: scsi/utils.c:380:
+        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",

ERROR: space prohibited before that close square bracket ']'
#1140: FILE: scsi/utils.c:380:
+        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",

ERROR: space prohibited after that open square bracket '['
#1141: FILE: scsi/utils.c:381:
+        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",

ERROR: space prohibited before that close square bracket ']'
#1141: FILE: scsi/utils.c:381:
+        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",

ERROR: space prohibited after that open square bracket '['
#1142: FILE: scsi/utils.c:382:
+        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",

ERROR: space prohibited before that close square bracket ']'
#1142: FILE: scsi/utils.c:382:
+        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",

ERROR: space prohibited after that open square bracket '['
#1143: FILE: scsi/utils.c:383:
+        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",

ERROR: space prohibited before that close square bracket ']'
#1143: FILE: scsi/utils.c:383:
+        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",

ERROR: space prohibited after that open square bracket '['
#1145: FILE: scsi/utils.c:385:
+        [ READ_CD                  ] = "READ_CD",

ERROR: space prohibited before that close square bracket ']'
#1145: FILE: scsi/utils.c:385:
+        [ READ_CD                  ] = "READ_CD",

ERROR: space prohibited after that open square bracket '['
#1146: FILE: scsi/utils.c:386:
+        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",

ERROR: space prohibited before that close square bracket ']'
#1146: FILE: scsi/utils.c:386:
+        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",

ERROR: space prohibited after that open square bracket '['
#1147: FILE: scsi/utils.c:387:
+        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",

ERROR: space prohibited before that close square bracket ']'
#1147: FILE: scsi/utils.c:387:
+        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",

ERROR: space prohibited after that open square bracket '['
#1148: FILE: scsi/utils.c:388:
+        [ RESERVE_TRACK            ] = "RESERVE_TRACK",

ERROR: space prohibited before that close square bracket ']'
#1148: FILE: scsi/utils.c:388:
+        [ RESERVE_TRACK            ] = "RESERVE_TRACK",

ERROR: space prohibited after that open square bracket '['
#1149: FILE: scsi/utils.c:389:
+        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",

ERROR: space prohibited before that close square bracket ']'
#1149: FILE: scsi/utils.c:389:
+        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",

ERROR: space prohibited after that open square bracket '['
#1150: FILE: scsi/utils.c:390:
+        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",

ERROR: space prohibited before that close square bracket ']'
#1150: FILE: scsi/utils.c:390:
+        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",

ERROR: space prohibited after that open square bracket '['
#1151: FILE: scsi/utils.c:391:
+        [ SET_CD_SPEED             ] = "SET_CD_SPEED",

ERROR: space prohibited before that close square bracket ']'
#1151: FILE: scsi/utils.c:391:
+        [ SET_CD_SPEED             ] = "SET_CD_SPEED",

ERROR: space prohibited after that open square bracket '['
#1152: FILE: scsi/utils.c:392:
+        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",

ERROR: space prohibited before that close square bracket ']'
#1152: FILE: scsi/utils.c:392:
+        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",

ERROR: space prohibited after that open square bracket '['
#1153: FILE: scsi/utils.c:393:
+        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",

ERROR: space prohibited before that close square bracket ']'
#1153: FILE: scsi/utils.c:393:
+        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",

ERROR: space prohibited after that open square bracket '['
#1154: FILE: scsi/utils.c:394:
+        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",

ERROR: space prohibited before that close square bracket ']'
#1154: FILE: scsi/utils.c:394:
+        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",

ERROR: space prohibited after that open square bracket '['
#1155: FILE: scsi/utils.c:395:
+        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",

ERROR: space prohibited before that close square bracket ']'
#1155: FILE: scsi/utils.c:395:
+        [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",

ERROR: space prohibited after that open square bracket '['
#1156: FILE: scsi/utils.c:396:
+        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",

ERROR: space prohibited before that close square bracket ']'
#1156: FILE: scsi/utils.c:396:
+        [ READ_DISC_INFORMATION    ] = "READ_DISC_INFORMATION",

total: 214 errors, 2 warnings, 1097 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 3/10: scsi: introduce scsi_build_sense...
Checking PATCH 4/10: scsi: introduce sg_io_sense_from_errno...
Checking PATCH 5/10: scsi: move block/scsi.h to include/scsi/constants.h...
Checking PATCH 6/10: scsi, file-posix: add support for persistent reservation management...
WARNING: line over 80 characters
#91: FILE: block/file-posix.c:414:
+            .help = "id of persistent reservation manager object (default: none)",

total: 0 errors, 1 warnings, 318 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 7/10: io: add qio_channel_read/write_all...
Checking PATCH 8/10: scsi: build qemu-pr-helper...
WARNING: line over 80 characters
#614: FILE: scsi/qemu-pr-helper.c:382:
+static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaque)

WARNING: line over 80 characters
#680: FILE: scsi/qemu-pr-helper.c:448:
+    /* Change user/group id, retaining the capabilities.  Because file descriptors

WARNING: line over 80 characters
#825: FILE: scsi/qemu-pr-helper.c:593:
+        if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) {

WARNING: line over 80 characters
#841: FILE: scsi/qemu-pr-helper.c:609:
+            error_report("%s does not support socket activation with LISTEN_FDS > 1",

total: 0 errors, 4 warnings, 831 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 9/10: scsi: add multipath support to qemu-pr-helper...
WARNING: line over 80 characters
#414: FILE: scsi/qemu-pr-helper.c:337:
+            memcpy(&data[8], out->key_list, MIN(out->additional_length, sz - 8));

total: 0 errors, 1 warnings, 580 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
Checking PATCH 10/10: scsi: add persistent reservation manager using qemu-pr-helper...
WARNING: line over 80 characters
#171: FILE: scsi/pr-manager-helper.c:146:
+        (cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV);

total: 0 errors, 1 warnings, 292 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno
  2017-08-22 13:45   ` Philippe Mathieu-Daudé
@ 2017-08-22 13:53     ` Paolo Bonzini
  0 siblings, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 13:53 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel; +Cc: famz, qemu-block

On 22/08/2017 15:45, Philippe Mathieu-Daudé wrote:
> Hi Paolo,
> 
> On 08/22/2017 10:18 AM, Paolo Bonzini wrote:
>> Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for
>> reusability.
>>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>   hw/scsi/scsi-generic.c | 40 +++++++---------------------------------
>>   include/scsi/utils.h   |  3 +++
>>   scsi/utils.c           | 35 +++++++++++++++++++++++++++++++++++
>>   3 files changed, 45 insertions(+), 33 deletions(-)
>>
>> diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
>> index 7a8f500934..04c687ee76 100644
>> --- a/hw/scsi/scsi-generic.c
>> +++ b/hw/scsi/scsi-generic.c
>> @@ -81,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
>>   static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
>>   {
>>       int status;
>> +    SCSISense sense;
>>         assert(r->req.aiocb == NULL);
>>   @@ -88,42 +89,15 @@ static void
>> scsi_command_complete_noio(SCSIGenericReq *r, int ret)
>>           scsi_req_cancel_complete(&r->req);
>>           goto done;
>>       }
>> -    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
>> -        r->req.sense_len = r->io_header.sb_len_wr;
>> -    }
>> -
>> -    if (ret != 0) {
>> -        switch (ret) {
>> -        case -EDOM:
>> -            status = TASK_SET_FULL;
>> -            break;
>> -        case -ENOMEM:
>> -            status = CHECK_CONDITION;
>> -            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
>> -            break;
>> -        default:
>> -            status = CHECK_CONDITION;
>> -            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
>> -            break;
>> -        }
>> -    } else {
>> -        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
>> -            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
>> -            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
>> -            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
>> -            status = BUSY;
>> -            BADF("Driver Timeout\n");
>> -        } else if (r->io_header.host_status) {
>> -            status = CHECK_CONDITION;
>> -            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
>> -        } else if (r->io_header.status) {
>> -            status = r->io_header.status;
>> -        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
>> -            status = CHECK_CONDITION;
>> +    status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
>> +    if (status == CHECK_CONDITION) {
>> +        if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
>> +            r->req.sense_len = r->io_header.sb_len_wr;
>>           } else {
>> -            status = GOOD;
>> +            scsi_req_build_sense(&r->req, sense);
>>           }
>>       }
>> +
>>       DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
>>               r, r->req.tag, status);
>>   diff --git a/include/scsi/utils.h b/include/scsi/utils.h
>> index 76c3db98c0..c12b34f2e5 100644
>> --- a/include/scsi/utils.h
>> +++ b/include/scsi/utils.h
>> @@ -113,6 +113,9 @@ int scsi_cdb_length(uint8_t *buf);
>>   #define SG_ERR_DID_TIME_OUT    0x03
>>     #define SG_ERR_DRIVER_SENSE    0x08
>> +
>> +int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
>> +                           SCSISense *sense);
>>   #endif
>>     #endif
>> diff --git a/scsi/utils.c b/scsi/utils.c
>> index 54d6d4486a..ca5b058a73 100644
>> --- a/scsi/utils.c
>> +++ b/scsi/utils.c
>> @@ -412,3 +412,38 @@ const char *scsi_command_name(uint8_t cmd)
>>       }
>>       return names[cmd];
>>   }
>> +
>> +#ifdef CONFIG_LINUX
>> +int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
>> +                           SCSISense *sense)
>> +{
>> +    if (errno_value != 0) {
>> +        switch (errno_value) {
>> +        case EDOM:
>> +            return TASK_SET_FULL;
>> +        case ENOMEM:
>> +            *sense = SENSE_CODE(TARGET_FAILURE);
>> +            return CHECK_CONDITION;
>> +        default:
>> +            *sense = SENSE_CODE(IO_ERROR);
>> +            return CHECK_CONDITION;
>> +        }
>> +    } else {
>> +        if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
>> +            io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
>> +            io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
>> +            (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
>> +            return BUSY;
>> +        } else if (io_hdr->host_status) {
>> +            *sense = SENSE_CODE(I_T_NEXUS_LOSS);
>> +            return CHECK_CONDITION;
>> +        } else if (io_hdr->status) {
>> +            return io_hdr->status;
>> +        } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
>> +            return CHECK_CONDITION;
>> +        }
> 
>> +    }
> I find it easier to read with the return GOOD out of the if/else:
> 
>        return GOOD;

Yes, you're right.

Paolo

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper Paolo Bonzini
@ 2017-08-22 14:34   ` Marc-André Lureau
  2017-08-22 16:04     ` Paolo Bonzini
  2017-08-24 15:45   ` Eric Blake
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 48+ messages in thread
From: Marc-André Lureau @ 2017-08-22 14:34 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: QEMU, Fam Zheng, open list:Block layer core

Hi

On Tue, Aug 22, 2017 at 3:18 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Introduce a privileged helper to run persistent reservation commands.
> This lets virtual machines send persistent reservations without using
> CAP_SYS_RAWIO or out-of-tree patches.  The helper uses Unix permissions
> and SCM_RIGHTS to restrict access to processes that can access its socket
> and prove that they have an open file descriptor for a raw SCSI device.
>

Could this be handled by udisk? It seems at first the problem is not
specific to qemu.

(I was also wondering if there was any overlap with the stratis
daemon, https://stratis-storage.github.io/, but after 5 minutes
research, probably not, stratis is higher level)

> The next patch will also correct the usage of persistent reservations
> with multipath devices.
>
> It would also be possible to support for Linux's IOC_PR_* ioctls in
> the future, to support NVMe devices.  For now, however, only SCSI is
> supported.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  Makefile                   |   9 +-
>  configure                  |   2 +-
>  docs/interop/pr-helper.rst |  78 ++++++
>  docs/pr-manager.rst        |  33 +++
>  scsi/pr-helper.h           |  13 +
>  scsi/qemu-pr-helper.c      | 657 +++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 790 insertions(+), 2 deletions(-)
>  create mode 100644 docs/interop/pr-helper.rst
>  create mode 100644 scsi/pr-helper.h
>  create mode 100644 scsi/qemu-pr-helper.c
>
> diff --git a/Makefile b/Makefile
> index 97a58a0f4e..bfd4f69ecd 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -209,6 +209,9 @@ ifdef BUILD_DOCS
>  DOCS=qemu-doc.html qemu-doc.txt qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
>  DOCS+=docs/interop/qemu-qmp-ref.html docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7
>  DOCS+=docs/interop/qemu-ga-ref.html docs/interop/qemu-ga-ref.txt docs/interop/qemu-ga-ref.7
> +ifdef CONFIG_LINUX
> +DOCS+=scsi/qemu-pr-helper.8
> +endif
>  ifdef CONFIG_VIRTFS
>  DOCS+=fsdev/virtfs-proxy-helper.1
>  endif
> @@ -384,6 +387,8 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
>  fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
>  fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
>
> +scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
> +
>  qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
>         $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
>
> @@ -491,7 +496,7 @@ clean:
>         rm -f *.msi
>         find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
>         rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
> -       rm -f fsdev/*.pod
> +       rm -f fsdev/*.pod scsi/*.pod
>         rm -f qemu-img-cmds.h
>         rm -f ui/shader/*-vert.h ui/shader/*-frag.h
>         @# May not be present in GENERATED_FILES
> @@ -590,6 +595,7 @@ endif
>  ifdef CONFIG_VIRTFS
>         $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
>         $(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
> +       $(INSTALL_DATA) scsi/qemu-pr-helper.8 "$(DESTDIR)$(mandir)/man8"

ifdef CONFIG_LINUX?

>  endif
>
>  install-datadir:
> @@ -718,6 +724,7 @@ qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
>  qemu.1: qemu-option-trace.texi
>  qemu-img.1: qemu-img.texi qemu-option-trace.texi qemu-img-cmds.texi
>  fsdev/virtfs-proxy-helper.1: fsdev/virtfs-proxy-helper.texi
> +scsi/qemu-pr-helper.8: scsi/qemu-pr-helper.texi
>  qemu-nbd.8: qemu-nbd.texi qemu-option-trace.texi
>  qemu-ga.8: qemu-ga.texi
>
> diff --git a/configure b/configure
> index dd73cce62f..772aff18d6 100755
> --- a/configure
> +++ b/configure
> @@ -6545,7 +6545,7 @@ fi
>
>  # build tree in object directory in case the source is not in the current directory
>  DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
> -DIRS="$DIRS docs docs/interop fsdev"
> +DIRS="$DIRS docs docs/interop fsdev scsi"
>  DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
>  DIRS="$DIRS roms/seabios roms/vgabios"
>  DIRS="$DIRS qapi-generated"
> diff --git a/docs/interop/pr-helper.rst b/docs/interop/pr-helper.rst
> new file mode 100644
> index 0000000000..765174c31f
> --- /dev/null
> +++ b/docs/interop/pr-helper.rst
> @@ -0,0 +1,78 @@
> +..
> +
> +======================================
> +Persistent reservation helper protocol
> +======================================
> +
> +QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
> +can delegate implementation of persistent reservations to an external
> +(and typically privilege) program.  Persistent Reservations allow
> +restricting access to block devices to specific initiators in a shared
> +storage setup.
> +
> +For a more detailed reference please refer the the SCSI Primary
> +Commands standard, specifically the section on Reservations and the
> +"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.
> +
> +This document describes the socket protocol used between QEMU's
> +``pr-manager-helper`` object and the external program.
> +
> +.. contents::
> +
> +Connection and initialization
> +-----------------------------
> +
> +After connecting to the helper program's socket, the helper starts a simple
> +feature negotiation process by writing four bytes corresponding to
> +the features it exposes (``supported_features``).  QEMU also writes
> +four bytes corresponding to the desired features of the helper program
> +(``requested_features``).

They do so without waiting each other? probably best to be explicit about it.

> +
> +If a bit is 1 in ``requested_features`` and 0 in ``supported_features``,
> +the corresponding feature is not supported by the helper and the connection
> +is closed.  On the other hand, it is acceptable for a bit to be 0 in
> +``requested_features`` and 1 in ``supported_features``; in this case,
> +he helper will not enable the feature.

he/the

> +
> +Right now no feature is defined, so the two parts always write four
> +zero bytes.
> +
> +All data transmitted on the socket is big-endian.

I would write that on top.

> +
> +Command format
> +--------------
> +
> +A command consists of a request and a response.  A request consists
> +of a 16-byte SCSI CDB.  A file descriptor must be passed to the helper
> +together with the SCSI CDB using ancillary data.
> +
> +The CDB has the following limitations:
> +
> +- the command (stored in the first byte) must be one of 0x5E
> +  (PERSISTENT RESERVE IN) or 0x5F (PERSISTENT RESERVE OUT).
> +
> +- the allocation length (stored in bytes 7-8 of the CDB for PERSISTENT
> +  RESERVE IN) or parameter list length (stored in bytes 5-8 of the CDB
> +  for PERSISTENT RESERVE OUT) is limited to 8 KiB.
> +
> +For PERSISTENT RESERVE OUT, the parameter list is sent right after the
> +CDB.
> +
> +The helper's reply has the following fixed structure:
> +
> +- 4 bytes for the SCSI status
> +
> +- 96 bytes for the SCSI sense data
> +
> +The sense data is always sent to keep the protocol simple, even though
> +it is only valid if the SCSI status is CHECK CONDITION (0x02).
> +
> +For PERSISTENT RESERVE IN, the data is sent right after the sense
> +data if the SCSI status is GOOD (0x00).
> +
> +It is invalid to send multiple commands concurrently on the same
> +socket.  It is however possible to connect multiple sockets to the
> +helper and send multiple commands to the helper for one or more
> +file descriptors.

I suggest to make it a seperate section if this is true for all commands.

> +
> +If the protocol is violated, the helper closes the socket.
> diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
> index b6089fb57c..7107e59fb8 100644
> --- a/docs/pr-manager.rst
> +++ b/docs/pr-manager.rst
> @@ -49,3 +49,36 @@ Alternatively, using ``-blockdev``::
>            -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
>            -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
>            -device scsi-block,drive=hd
> +
> +----------------------------------
> +Invoking :program:`qemu-pr-helper`
> +----------------------------------
> +
> +QEMU provides an implementation of the persistent reservation helper,
> +called :program:`qemu-pr-helper`.  The helper should be started as a
> +system service and supports the following option:
> +
> +-d, --daemon              run in the background
> +-q, --quiet               decrease verbosity
> +-f, --pidfile=path        PID file when running as a daemon
> +-k, --socket=path         path to the socket
> +-T, --trace=trace-opts    tracing options
> +
> +By default, the socket and PID file are placed in the runtime state
> +directory, for example :file:`/var/run/qemu-pr-helper.sock` and
> +:file:`/var/run/qemu-pr-helper.pid`.  The PID file is not created
> +unless :option:`-d` is passed too.
> +
> +:program:`qemu-pr-helper` can also use the systemd socket activation
> +protocol.  In this case, the systemd socket unit should specify a
> +Unix stream socket, like this::
> +
> +    [Socket]
> +    ListenStream=/var/run/qemu-pr-helper.sock
> +
> +After connecting to the socket, :program:`qemu-pr-helper`` can optionally drop
> +root privileges, except for those capabilities that are needed for
> +its operation.  To do this, add the following options:
> +
> +-u, --user=user           user to drop privileges to
> +-g, --group=group         group to drop privileges to
> diff --git a/scsi/pr-helper.h b/scsi/pr-helper.h
> new file mode 100644
> index 0000000000..2c7ccc9928
> --- /dev/null
> +++ b/scsi/pr-helper.h
> @@ -0,0 +1,13 @@
> +#ifndef QEMU_PR_HELPER_H
> +#define QEMU_PR_HELPER_H 1
> +
> +#define PR_HELPER_CDB_SIZE     16
> +#define PR_HELPER_SENSE_SIZE   96
> +#define PR_HELPER_DATA_SIZE    8192
> +
> +typedef struct PRHelperResponse {
> +    int32_t result;
> +    uint8_t sense[PR_HELPER_SENSE_SIZE];
> +} PRHelperResponse;
> +
> +#endif
> diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
> new file mode 100644
> index 0000000000..d52234af0f
> --- /dev/null
> +++ b/scsi/qemu-pr-helper.c
> @@ -0,0 +1,657 @@
> +/*
> + * Helper to forward persistent reservation commands to libmpathpersist
> + *
> + * Copyright (C) 2017 Red Hat, Inc. <pbonzini@redhat.com>
> + *
> + * Author: Paolo Bonzini <pbonzini@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; under version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include <getopt.h>
> +#include "qapi/error.h"
> +#include "qemu-common.h"
> +#include "qemu/cutils.h"
> +#include "qemu/main-loop.h"
> +#include "qemu/error-report.h"
> +#include "qemu/config-file.h"
> +#include "qemu/bswap.h"
> +#include "qemu/log.h"
> +#include "qemu/systemd.h"
> +#include "qapi/util.h"
> +#include "qapi/qmp/qstring.h"
> +#include "io/channel-socket.h"
> +#include "trace/control.h"
> +#include "qemu-version.h"
> +
> +#include "block/aio.h"
> +#include "block/thread-pool.h"
> +
> +#include "scsi/constants.h"
> +#include "scsi/utils.h"
> +#include "pr-helper.h"
> +#include <sys/ioctl.h>
> +#include <linux/dm-ioctl.h>
> +#include <scsi/sg.h>
> +
> +#ifdef CONFIG_LIBCAP
> +#include <cap-ng.h>
> +#endif
> +#include <pwd.h>
> +#include <grp.h>
> +
> +
> +#define PR_OUT_FIXED_PARAM_SIZE 24
> +
> +static char *socket_path;
> +static char *pidfile;
> +static enum { RUNNING, TERMINATE, TERMINATING } state;
> +static QIOChannelSocket *server_ioc;
> +static int server_watch;
> +static int num_active_sockets = 1;
> +static int verbose;
> +
> +#ifdef CONFIG_LIBCAP
> +static int uid = -1;
> +static int gid = -1;
> +#endif
> +
> +static void usage(const char *name)
> +{
> +    (printf) (

Why '(printf)' ? I noticed qemu-nbd use this too.

> +"Usage: %s [OPTIONS] FILE\n"
> +"Persistent Reservation helper program for QEMU\n"
> +"\n"
> +"  -h, --help                display this help and exit\n"
> +"  -V, --version             output version information and exit\n"
> +"\n"
> +"  -d, --daemon              run in the background\n"
> +"  -f, --pidfile=PATH        PID file when running as a daemon\n"
> +"                            (default '%s')\n"
> +"  -k, --socket=PATH         path to the unix socket\n"
> +"                            (default '%s')\n"
> +"  -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
> +"                            specify tracing options\n"
> +#ifdef CONFIG_LIBCAP
> +"  -u, --user=USER           user to drop privileges to\n"
> +"  -g, --group=GROUP         group to drop privileges to\n"
> +#endif
> +"\n"
> +QEMU_HELP_BOTTOM "\n"
> +    , name, pidfile, socket_path);
> +}
> +
> +static void version(const char *name)
> +{
> +    printf(
> +"%s " QEMU_VERSION QEMU_PKGVERSION "\n"
> +"Written by Paolo Bonzini.\n"
> +"\n"
> +QEMU_COPYRIGHT "\n"
> +"This is free software; see the source for copying conditions.  There is NO\n"
> +"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
> +    , name);
> +}
> +
> +/* SG_IO support */
> +
> +typedef struct PRHelperSGIOData {
> +    int fd;
> +    const uint8_t *cdb;
> +    uint8_t *sense;
> +    uint8_t *buf;
> +    int sz;
> +    int dir;
> +} PRHelperSGIOData;
> +
> +static int do_sgio_worker(void *opaque)
> +{
> +    PRHelperSGIOData *data = opaque;
> +    struct sg_io_hdr io_hdr;
> +    int ret;
> +    int status;
> +    SCSISense sense_code;
> +
> +    memset(data->sense, 0, PR_HELPER_SENSE_SIZE);
> +    memset(&io_hdr, 0, sizeof(io_hdr));
> +    io_hdr.interface_id = 'S';
> +    io_hdr.cmd_len = PR_HELPER_CDB_SIZE;
> +    io_hdr.cmdp = (uint8_t *)data->cdb;
> +    io_hdr.sbp = data->sense;
> +    io_hdr.mx_sb_len = PR_HELPER_SENSE_SIZE;
> +    io_hdr.timeout = 1;
> +    io_hdr.dxfer_direction = data->dir;
> +    io_hdr.dxferp = (char *)data->buf;
> +    io_hdr.dxfer_len = data->sz;
> +    ret = ioctl(data->fd, SG_IO, &io_hdr);
> +    status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr,
> +                                    &sense_code);
> +    if (status == CHECK_CONDITION &&
> +        !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) {
> +        scsi_build_sense(data->sense, sense_code);
> +    }
> +
> +    return status;
> +}
> +
> +static int do_sgio(int fd, const uint8_t *cdb, uint8_t *sense,
> +                    uint8_t *buf, int sz, int dir)
> +{
> +    ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context());
> +
> +    PRHelperSGIOData data = {
> +        .fd = fd,
> +        .cdb = cdb,
> +        .sense = sense,
> +        .buf = buf,
> +        .sz = sz,
> +        .dir = dir,
> +    };
> +
> +    return thread_pool_submit_co(pool, do_sgio_worker, &data);
> +}
> +
> +static int do_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
> +                    uint8_t *data, int sz)
> +{
> +    return do_sgio(fd, cdb, sense, data, sz,
> +                   SG_DXFER_FROM_DEV);
> +}
> +
> +static int do_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
> +                     const uint8_t *param, int sz)
> +{
> +    return do_sgio(fd, cdb, sense, (uint8_t *)param, sz,
> +                   SG_DXFER_TO_DEV);
> +}
> +
> +/* Client */
> +
> +typedef struct PRHelperClient {
> +    QIOChannelSocket *ioc;
> +    Coroutine *co;
> +    int fd;
> +    uint8_t data[PR_HELPER_DATA_SIZE];
> +} PRHelperClient;
> +
> +typedef struct PRHelperRequest {
> +    int fd;
> +    size_t sz;
> +    uint8_t cdb[PR_HELPER_CDB_SIZE];
> +} PRHelperRequest;
> +
> +static int prh_read(PRHelperClient *client, void *buf, int sz, Error **errp)
> +{
> +    while (sz > 0) {
> +        int *fds = NULL;
> +        size_t nfds = 0;
> +        int i;
> +        struct iovec iov;
> +        ssize_t n_read;
> +
> +        iov.iov_base = buf;
> +        iov.iov_len = sz;
> +        n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1,
> +                                        &fds, &nfds, errp);
> +
> +        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
> +            qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN);
> +            continue;
> +        }
> +        if (n_read <= 0) {
> +            return n_read ? n_read : -1;
> +        }
> +
> +        /* Stash one file descriptor per request.  */
> +        if (nfds) {
> +            for (i = 0; i < nfds; i++) {
> +                if (client->fd == -1) {
> +                    client->fd = fds[i++];
> +                } else {
> +                    close(fds[i]);

Isn't this a condition to close the client?

> +                }
> +            }
> +            g_free(fds);
> +        }
> +
> +        buf += n_read;
> +        sz -= n_read;
> +    }
> +
> +    return 0;
> +}
> +
> +static int prh_read_request(PRHelperClient *client, PRHelperRequest *req,
> +                            PRHelperResponse *resp, Error **errp)
> +{
> +    uint32_t sz;
> +
> +    if (prh_read(client, req->cdb, sizeof(req->cdb), NULL) < 0) {
> +        return -1;
> +    }
> +
> +    if (client->fd == -1) {
> +        error_setg(errp, "No file descriptor in request.");
> +        return -1;
> +    }
> +
> +    if (req->cdb[0] != PERSISTENT_RESERVE_OUT &&
> +        req->cdb[0] != PERSISTENT_RESERVE_IN) {
> +        error_setg(errp, "Invalid CDB, closing socket.");
> +        goto out_close;
> +    }
> +
> +    sz = scsi_cdb_xfer(req->cdb);
> +    if (sz > sizeof(client->data)) {
> +        goto out_close;
> +    }
> +
> +    if (req->cdb[0] == PERSISTENT_RESERVE_OUT) {
> +        if (qio_channel_read_all(QIO_CHANNEL(client->ioc),
> +                                 (char *)client->data, sz,
> +                                 errp) < 0) {
> +            goto out_close;
> +        }
> +        if (sz < PR_OUT_FIXED_PARAM_SIZE) {
> +            /* Illegal request, Parameter list length error.  Not a fatal
> +             * error, so read the data and do not close the socket.
> +            */
> +            scsi_build_sense(resp->sense, SENSE_CODE(INVALID_PARAM_LEN));
> +            resp->result = CHECK_CONDITION;
> +            sz = 0;
> +            close(client->fd);
> +            client->fd = -1;
> +        }
> +    }
> +
> +    req->fd = client->fd;
> +    req->sz = sz;
> +    client->fd = -1;
> +    return sz;
> +
> +out_close:
> +    close(client->fd);
> +    client->fd = -1;
> +    return -1;
> +}
> +
> +static int prh_write_response(PRHelperClient *client, PRHelperRequest *req,
> +                              PRHelperResponse *resp, Error **errp)
> +{
> +    ssize_t r;
> +
> +    resp->result = cpu_to_be32(resp->result);
> +    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
> +                              (char *) resp, sizeof(*resp), errp);
> +    if (r < 0) {
> +        return r;
> +    }
> +
> +    if (req->cdb[0] == PERSISTENT_RESERVE_IN && resp->result == GOOD) {
> +        assert(req->sz <= sizeof(client->data));
> +        r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
> +                                  (char *) client->data,
> +                                  req->sz, errp);
> +    }
> +    return r < 0 ? r : 0;
> +}
> +
> +static void prh_co_entry(void *opaque)
> +{
> +    PRHelperClient *client = opaque;
> +    Error *local_err = NULL;
> +    uint32_t flags;
> +    int r;
> +
> +    qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
> +                             false, NULL);
> +    qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc),
> +                                   qemu_get_aio_context());
> +
> +    /* A very simple negotiation for future extensibility.  No features
> +     * are defined so write 0.
> +     */
> +    flags = cpu_to_be32(0);
> +    r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
> +                             (char *) &flags, sizeof(flags), NULL);
> +    if (r < 0) {
> +        goto out;
> +    }
> +
> +    r = qio_channel_read_all(QIO_CHANNEL(client->ioc),
> +                             (char *) &flags, sizeof(flags), NULL);
> +    if (be32_to_cpu(flags) != 0 || r < 0) {
> +        goto out;
> +    }
> +
> +    while (atomic_read(&state) == RUNNING) {
> +        PRHelperRequest req;
> +        PRHelperResponse resp;
> +        int sz;
> +
> +        sz = prh_read_request(client, &req, &resp, &local_err);
> +        if (sz < 0) {
> +            break;
> +        }
> +
> +        if (sz > 0) {
> +            num_active_sockets++;
> +            if (req.cdb[0] == PERSISTENT_RESERVE_OUT) {
> +                r = do_pr_out(req.fd, req.cdb, resp.sense, client->data, sz);
> +            } else {
> +                r = do_pr_in(req.fd, req.cdb, resp.sense, client->data, sz);
> +            }
> +            num_active_sockets--;
> +            close(req.fd);
> +            if (r == -1) {
> +                break;
> +            }
> +            resp.result = r;
> +        }
> +
> +        if (prh_write_response(client, &req, &resp, &local_err) < 0) {
> +            break;
> +        }
> +    }
> +
> +    if (local_err) {
> +        if (verbose == 0) {
> +            error_free(local_err);
> +        } else {
> +            error_report_err(local_err);
> +        }
> +    }
> +
> +out:
> +    qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc));
> +    object_unref(OBJECT(client->ioc));
> +    g_free(client);
> +}
> +
> +static gboolean accept_client(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
> +{
> +    QIOChannelSocket *cioc;
> +    PRHelperClient *prh;
> +
> +    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
> +                                     NULL);
> +    if (!cioc) {
> +        return TRUE;
> +    }
> +
> +    prh = g_new(PRHelperClient, 1);
> +    prh->ioc = cioc;
> +    prh->fd = -1;
> +    prh->co = qemu_coroutine_create(prh_co_entry, prh);
> +    qemu_coroutine_enter(prh->co);
> +
> +    return TRUE;
> +}
> +
> +
> +/*
> + * Check socket parameters compatibility when socket activation is used.
> + */
> +static const char *socket_activation_validate_opts(void)
> +{
> +    if (socket_path != NULL) {
> +        return "Unix socket can't be set when using socket activation";
> +    }
> +
> +    return NULL;
> +}
> +
> +static void compute_default_paths(void)
> +{
> +    socket_path = qemu_get_local_state_pathname("run/qemu-pr-helper.sock");
> +    pidfile = qemu_get_local_state_pathname("run/qemu-pr-helper.pid");
> +}
> +
> +static void termsig_handler(int signum)
> +{
> +    atomic_cmpxchg(&state, RUNNING, TERMINATE);
> +    qemu_notify_event();
> +}
> +
> +static void close_server_socket(void)
> +{
> +    g_assert(server_ioc);

you mix assert() and g_assert(), pick one! :)

> +
> +    g_source_remove(server_watch);
> +    server_watch = -1;
> +    object_unref(OBJECT(server_ioc));
> +    num_active_sockets--;
> +}
> +
> +#ifdef CONFIG_LIBCAP
> +static int drop_privileges(void)
> +{
> +    /* clear all capabilities */
> +    capng_clear(CAPNG_SELECT_BOTH);
> +
> +    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
> +                     CAP_SYS_RAWIO) < 0) {
> +        return -1;
> +    }
> +
> +    /* Change user/group id, retaining the capabilities.  Because file descriptors
> +     * are passed via SCM_RIGHTS, we don't need supplementary groups (and in
> +     * fact the helper can run as "nobody").
> +     */
> +    if (capng_change_id(uid != -1 ? uid : getuid(),
> +                        gid != -1 ? gid : getgid(),
> +                        CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING)) {
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +#endif
> +
> +int main(int argc, char **argv)
> +{
> +    const char *sopt = "hVk:fdT:u:g:q";
> +    struct option lopt[] = {
> +        { "help", no_argument, NULL, 'h' },
> +        { "version", no_argument, NULL, 'V' },
> +        { "socket", required_argument, NULL, 'k' },
> +        { "pidfile", no_argument, NULL, 'f' },
> +        { "daemon", no_argument, NULL, 'd' },
> +        { "trace", required_argument, NULL, 'T' },
> +        { "user", required_argument, NULL, 'u' },
> +        { "group", required_argument, NULL, 'g' },
> +        { "quiet", no_argument, NULL, 'q' },
> +        { NULL, 0, NULL, 0 }
> +    };
> +    int opt_ind = 0;
> +    int quiet = 0;
> +    char ch;
> +    Error *local_err = NULL;
> +    char *trace_file = NULL;
> +    bool daemonize = false;
> +    unsigned socket_activation;
> +
> +    struct sigaction sa_sigterm;
> +    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
> +    sa_sigterm.sa_handler = termsig_handler;
> +    sigaction(SIGTERM, &sa_sigterm, NULL);
> +    sigaction(SIGINT, &sa_sigterm, NULL);
> +    sigaction(SIGHUP, &sa_sigterm, NULL);
> +
> +    signal(SIGPIPE, SIG_IGN);
> +
> +    compute_default_paths();
> +
> +    module_call_init(MODULE_INIT_TRACE);
> +    module_call_init(MODULE_INIT_QOM);
> +    qemu_add_opts(&qemu_trace_opts);
> +    qemu_init_exec_dir(argv[0]);
> +
> +    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
> +        switch (ch) {
> +        case 'k':
> +            socket_path = optarg;
> +            if (socket_path[0] != '/') {
> +                error_report("socket path must be absolute");
> +                exit(EXIT_FAILURE);
> +            }
> +            break;
> +        case 'f':
> +            pidfile = optarg;
> +            break;
> +#ifdef CONFIG_LIBCAP
> +        case 'u': {
> +            unsigned long res;
> +            struct passwd *userinfo = getpwnam(optarg);
> +            if (userinfo) {
> +                uid = userinfo->pw_uid;
> +            } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
> +                       (uid_t)res == res) {
> +                uid = res;
> +            } else {
> +                error_report("invalid user '%s'", optarg);
> +                exit(EXIT_FAILURE);
> +            }
> +            break;
> +        }
> +        case 'g': {
> +            unsigned long res;
> +            struct group *groupinfo = getgrnam(optarg);
> +            if (groupinfo) {
> +                gid = groupinfo->gr_gid;
> +            } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
> +                       (gid_t)res == res) {
> +                gid = res;
> +            } else {
> +                error_report("invalid group '%s'", optarg);
> +                exit(EXIT_FAILURE);
> +            }
> +            break;
> +        }
> +#else
> +        case 'u':
> +        case 'g':
> +            error_report("-%c not supported by this %s", ch, argv[0]);
> +            exit(1);
> +#endif
> +        case 'd':
> +            daemonize = true;
> +            break;
> +        case 'q':
> +            quiet = 1;
> +            break;
> +        case 'T':
> +            g_free(trace_file);
> +            trace_file = trace_opt_parse(optarg);
> +            break;
> +        case 'V':
> +            version(argv[0]);
> +            exit(0);

EXIT_SUCCESS for consistency

> +            break;
> +        case 'h':
> +            usage(argv[0]);
> +            exit(0);

same here

> +            break;
> +        case '?':
> +            error_report("Try `%s --help' for more information.", argv[0]);
> +            exit(EXIT_FAILURE);
> +        }
> +    }
> +
> +    /* set verbosity */
> +    verbose = !quiet;
> +
> +    if (!trace_init_backends()) {
> +        exit(1);

EXIT_FAILURE

> +    }
> +    trace_init_file(trace_file);
> +    qemu_set_log(LOG_TRACE);
> +
> +#ifdef CONFIG_MPATH
> +    dm_init();
> +    multipath_pr_init();
> +#endif
> +
> +    socket_activation = check_socket_activation();
> +    if (socket_activation == 0) {
> +        SocketAddress saddr = {
> +            .type = SOCKET_ADDRESS_TYPE_UNIX,
> +            .u.q_unix.path = g_strdup(socket_path)
> +        };
> +        server_ioc = qio_channel_socket_new();
> +        if (qio_channel_socket_listen_sync(server_ioc, &saddr, &local_err) < 0) {
> +            object_unref(OBJECT(server_ioc));
> +            error_report_err(local_err);
> +            return 1;
> +        }
> +        g_free(saddr.u.q_unix.path);
> +    } else {
> +        /* Using socket activation - check user didn't use -p etc. */
> +        const char *err_msg = socket_activation_validate_opts();
> +        if (err_msg != NULL) {
> +            error_report("%s", err_msg);
> +            exit(EXIT_FAILURE);
> +        }
> +
> +        /* Can only listen on a single socket.  */
> +        if (socket_activation > 1) {
> +            error_report("%s does not support socket activation with LISTEN_FDS > 1",
> +                         argv[0]);
> +            exit(EXIT_FAILURE);
> +        }
> +        server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
> +                                               &local_err);
> +        if (server_ioc == NULL) {
> +            error_report("Failed to use socket activation: %s",
> +                         error_get_pretty(local_err));
> +            exit(EXIT_FAILURE);
> +        }
> +        socket_path = NULL;
> +    }
> +
> +    if (qemu_init_main_loop(&local_err)) {
> +        error_report_err(local_err);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
> +                                         G_IO_IN,
> +                                         accept_client,
> +                                         NULL, NULL);
> +
> +#ifdef CONFIG_LIBCAP
> +    if (drop_privileges() < 0) {
> +        error_report("Failed to drop privileges: %s", strerror(errno));
> +        exit(EXIT_FAILURE);
> +    }
> +#endif
> +
> +    if (daemonize) {
> +        if (daemon(0, 0) < 0) {
> +            error_report("Failed to daemonize: %s", strerror(errno));
> +            exit(EXIT_FAILURE);
> +        }
> +    }
> +
> +    state = RUNNING;
> +    do {
> +        main_loop_wait(false);
> +        if (state == TERMINATE) {
> +            state = TERMINATING;
> +            close_server_socket();
> +        }
> +    } while (num_active_sockets > 0);
> +
> +    exit(EXIT_SUCCESS);
> +}
> --
> 2.13.5
>
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper
  2017-08-22 14:34   ` Marc-André Lureau
@ 2017-08-22 16:04     ` Paolo Bonzini
  0 siblings, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-22 16:04 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU, Fam Zheng, open list:Block layer core

On 22/08/2017 16:34, Marc-André Lureau wrote:
> Could this be handled by udisk? It seems at first the problem is not
> specific to qemu.

Yes, possibly.  In practice, everybody else who uses persistent
reservations seems to run as root. :)

>> +static void usage(const char *name)
>> +{
>> +    (printf) (
> Why '(printf)' ? I noticed qemu-nbd use this too.
> 

It lets you use #ifdef inside the argument list.

>>
>> +        /* Stash one file descriptor per request.  */
>> +        if (nfds) {
>> +            for (i = 0; i < nfds; i++) {
>> +                if (client->fd == -1) {
>> +                    client->fd = fds[i++];
>> +                } else {
>> +                    close(fds[i]);
> 
> Isn't this a condition to close the client?

Yes, though I still have to go through the descriptors and close them.

Paolo

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management Paolo Bonzini
@ 2017-08-23  4:13   ` Fam Zheng
  2017-08-23  6:56     ` Paolo Bonzini
  2017-08-24 15:37   ` Eric Blake
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 48+ messages in thread
From: Fam Zheng @ 2017-08-23  4:13 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, qemu-block

On Tue, 08/22 15:18, Paolo Bonzini wrote:
> diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst

Is docs/interop/persistent-reservation-manager.rst better? (Move to interop/ and
de-abbreviate) ...

> new file mode 100644
> index 0000000000..b6089fb57c
> --- /dev/null
> +++ b/docs/pr-manager.rst
> @@ -0,0 +1,51 @@
> +======================================
> +Persistent reservation managers
> +======================================
> +
> +SCSI persistent Reservations allow restricting access to block devices
> +to specific initiators in a shared storage setup.  When implementing
> +clustering of virtual machines, it is a common requirement for virtual
> +machines to send persistent reservation SCSI commands.  However,
> +the operating system restricts sending these commands to unprivileged
> +programs because incorrect usage can disrupt regular operation of the
> +storage fabric.
> +
> +For this reason, QEMU's SCSI passthrough devices, ``scsi-block``
> +and ``scsi-generic`` (both are only available on Linux) can delegate
> +implementation of persistent reservations to a separate object,
> +the "persistent reservation manager".  Only PERSISTENT RESERVE OUT and
> +PERSISTENT RESERVE IN commands are passed to the persistent reservation
> +manager object; other commands are processed by QEMU as usual.
> +
> +-----------------------------------------
> +Defining a persistent reservation manager
> +-----------------------------------------
> +
> +A persistent reservation manager is an instance of a subclass of the
> +"pr-manager" QOM class.

Or is this abstraction class the reason it is not under interop? Why not just
define the protocol?

> +
> +Right now only one subclass is defined, ``pr-manager-helper``, which
> +forwards the commands to an external privileged helper program
> +over Unix sockets.  The helper program only allows sending persistent
> +reservation commands to devices for which QEMU has a file descriptor,
> +so that QEMU will not be able to effect persistent reservations
> +unless it has access to both the socket and the device.
> +
> +``pr-manager-helper`` has a single string property, ``path``, which
> +accepts the path to the helper program's Unix socket.  For example,
> +the following command line defines a ``pr-manager-helper`` object and
> +attaches it to a SCSI passthrough device::
> +
> +      $ qemu-system-x86_64
> +          -device virtio-scsi \
> +          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
> +          -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
> +          -device scsi-block,drive=hd
> +
> +Alternatively, using ``-blockdev``::
> +
> +      $ qemu-system-x86_64
> +          -device virtio-scsi \
> +          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
> +          -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
> +          -device scsi-block,drive=hd

Fam

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper Paolo Bonzini
@ 2017-08-23  4:49   ` Fam Zheng
  2017-08-23  6:55     ` Paolo Bonzini
  2017-08-23  7:48     ` Paolo Bonzini
  2017-08-30 16:58   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
  1 sibling, 2 replies; 48+ messages in thread
From: Fam Zheng @ 2017-08-23  4:49 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, qemu-block

On Tue, 08/22 15:18, Paolo Bonzini wrote:
> This adds a concrete subclass of pr-manager that talks to qemu-pr-helper.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  scsi/Makefile.objs       |   2 +-
>  scsi/pr-manager-helper.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 289 insertions(+), 1 deletion(-)
>  create mode 100644 scsi/pr-manager-helper.c
> 
> diff --git a/scsi/Makefile.objs b/scsi/Makefile.objs
> index 5496d2ae6a..4d25e476cf 100644
> --- a/scsi/Makefile.objs
> +++ b/scsi/Makefile.objs
> @@ -1,3 +1,3 @@
>  block-obj-y += utils.o
>  
> -block-obj-$(CONFIG_LINUX) += pr-manager.o
> +block-obj-$(CONFIG_LINUX) += pr-manager.o pr-manager-helper.o
> diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c
> new file mode 100644
> index 0000000000..c9d9606696
> --- /dev/null
> +++ b/scsi/pr-manager-helper.c
> @@ -0,0 +1,288 @@
> +/*
> + * Persistent reservation manager that talks to qemu-mpath-helper

s/qemu-mpath-helper/qemu-pr-helper/

> + *
> + * Copyright (c) 2017 Red Hat, Inc.

Since I'm commenting on a header, just BTW I was educated that (c) stands for
"copyright" so this is actually a ubiquitous redundancy. :)

> + *
> + * Author: Paolo Bonzini <pbonzini@redhat.com>
> + *
> + * This code is licensed under the LGPL.

Interesting, I think the version of the license is required?

> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "scsi/constants.h"
> +#include "scsi/pr-manager.h"
> +#include "scsi/utils.h"
> +#include "io/channel.h"
> +#include "io/channel-socket.h"
> +#include "pr-helper.h"
> +
> +#include <scsi/sg.h>
> +
> +#define PR_MAX_RECONNECT_ATTEMPTS 5
> +
> +#define TYPE_PR_MANAGER_HELPER "pr-manager-helper"
> +
> +#define PR_MANAGER_HELPER(obj) \
> +     INTERFACE_CHECK(PRManagerHelper, (obj), \
> +                     TYPE_PR_MANAGER_HELPER)
> +
> +typedef struct PRManagerHelper {
> +    /* <private> */
> +    PRManager parent;
> +
> +    char *path;
> +
> +    QemuMutex lock;
> +    QIOChannel *ioc;
> +} PRManagerHelper;
> +
> +/* Called with lock held.  */
> +static int pr_manager_helper_read(PRManagerHelper *pr_mgr,
> +                                  void *buf, int sz, Error **errp)
> +{
> +    ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp);
> +
> +    if (r < 0) {
> +        object_unref(OBJECT(pr_mgr->ioc));
> +        pr_mgr->ioc = NULL;
> +        return r;
> +    }
> +
> +    return r < 0 ? r : 0;
> +}
> +
> +/* Called with lock held.  */
> +static int pr_manager_helper_write(PRManagerHelper *pr_mgr,
> +                                   int fd,
> +                                   const void *buf, int sz, Error **errp)
> +{
> +    size_t nfds = (fd != -1);
> +    while (sz > 0) {
> +        struct iovec iov;
> +        ssize_t n_written;
> +
> +        iov.iov_base = (void *)buf;
> +        iov.iov_len = sz;
> +        n_written = qio_channel_writev_full(QIO_CHANNEL(pr_mgr->ioc), &iov, 1,
> +                                            nfds ? &fd : NULL, nfds, errp);
> +
> +        if (n_written <= 0) {
> +            assert(n_written != QIO_CHANNEL_ERR_BLOCK);
> +            object_unref(OBJECT(pr_mgr->ioc));
> +            pr_mgr->ioc = NULL;
> +            return n_written;
> +        }
> +
> +        nfds = 0;
> +        buf += n_written;
> +        sz -= n_written;
> +    }
> +
> +    return 0;
> +}
> +
> +/* Called with lock held.  */
> +static int pr_manager_helper_initialize(PRManagerHelper *pr_mgr,
> +                                        Error **errp)
> +{
> +    uint32_t flags;
> +
> +    SocketAddress saddr = {
> +        .type = SOCKET_ADDRESS_TYPE_UNIX,
> +        .u.q_unix.path = g_strdup(pr_mgr->path)

Missing g_free()?

> +    };
> +    QIOChannelSocket *sioc = qio_channel_socket_new();
> +    Error *local_err = NULL;
> +
> +    qio_channel_set_name(QIO_CHANNEL(sioc), "pr-manager-helper");
> +    qio_channel_socket_connect_sync(sioc,
> +                                    &saddr,
> +                                    &local_err);
> +    if (local_err) {
> +        object_unref(OBJECT(sioc));
> +        error_propagate(errp, local_err);
> +        return -ENOTCONN;
> +    }
> +
> +    qio_channel_set_delay(QIO_CHANNEL(sioc), false);
> +    pr_mgr->ioc = QIO_CHANNEL(sioc);
> +
> +    /* A simple feature negotation protocol, even though there is
> +     * no optional feature right now.
> +     */
> +    if (pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp) < 0) {

Not returning the return value of pr_manager_helper_read()?.

> +        return -EINVAL;
> +    }
> +
> +    flags = 0;
> +    if (pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp) < 0) {
> +        return -EINVAL;

Same here.

> +    }
> +
> +    return 0;
> +}
> +
> +static int pr_manager_helper_run(PRManager *p,
> +                                 int fd, struct sg_io_hdr *io_hdr)
> +{
> +    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(p);
> +
> +    uint32_t len;
> +    PRHelperResponse resp;
> +    int ret;
> +    int expected_dir;
> +    int attempts;
> +    uint8_t cdb[PR_HELPER_CDB_SIZE] = { 0 };
> +
> +    if (!io_hdr->cmd_len || io_hdr->cmd_len > PR_HELPER_CDB_SIZE) {
> +        return -EINVAL;
> +    }
> +
> +    memcpy(cdb, io_hdr->cmdp, io_hdr->cmd_len);
> +    assert(cdb[0] == PERSISTENT_RESERVE_OUT || cdb[0] == PERSISTENT_RESERVE_IN);
> +    expected_dir =
> +        (cdb[0] == PERSISTENT_RESERVE_OUT ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV);
> +    if (io_hdr->dxfer_direction != expected_dir) {
> +        return -EINVAL;
> +    }
> +
> +    len = scsi_cdb_xfer(cdb);
> +    if (io_hdr->dxfer_len < len || len > PR_HELPER_DATA_SIZE) {
> +        return -EINVAL;
> +    }
> +
> +    ret = 0;
> +    qemu_mutex_lock(&pr_mgr->lock);
> +
> +    /* Try to reconnect while sending the CDB.  */
> +    for (attempts = 0; attempts < PR_MAX_RECONNECT_ATTEMPTS; attempts++) {
> +        if (!pr_mgr->ioc) {
> +            if (pr_manager_helper_initialize(pr_mgr, NULL) < 0) {
> +                qemu_mutex_unlock(&pr_mgr->lock);
> +                g_usleep(G_USEC_PER_SEC);
> +                qemu_mutex_lock(&pr_mgr->lock);
> +            }
> +        }
> +
> +        if (pr_mgr->ioc) {
> +            if (pr_manager_helper_write(pr_mgr, fd, cdb,
> +                                        ARRAY_SIZE(cdb), NULL) >= 0) {
> +                break;
> +            }
> +        }
> +    }
> +    if (attempts == PR_MAX_RECONNECT_ATTEMPTS) {
> +        ret = -EINVAL;
> +        goto out;
> +    }
> +
> +    /* After sending the CDB, any communications failure causes the
> +     * command to fail.  The failure is transient, retrying the command
> +     * will invoke pr_manager_helper_initialize again.
> +     */
> +    if (expected_dir == SG_DXFER_TO_DEV) {
> +        if (pr_manager_helper_write(pr_mgr, -1, io_hdr->dxferp,
> +                                    len, NULL) < 0) {
> +            ret = -EINVAL;
> +            goto out;
> +        }
> +    }
> +    if (pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL) < 0) {
> +        ret = -EINVAL;
> +        goto out;
> +    }
> +    if (expected_dir == SG_DXFER_FROM_DEV && resp.result == 0) {
> +        if (pr_manager_helper_read(pr_mgr, io_hdr->dxferp, len, NULL) < 0) {
> +            ret = -EINVAL;
> +            goto out;
> +        }
> +    }

Same for these three errors, too.

> +
> +    io_hdr->status = resp.result;
> +    if (resp.result == CHECK_CONDITION) {
> +        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
> +        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE);
> +        memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr);
> +    }
> +
> +out:
> +    if (ret < 0) {
> +        int sense_len = scsi_build_sense(io_hdr->sbp,
> +                                         SENSE_CODE(LUN_COMM_FAILURE));
> +        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
> +        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len);
> +        io_hdr->status = CHECK_CONDITION;
> +    }
> +    qemu_mutex_unlock(&pr_mgr->lock);
> +    return ret;
> +}

Fam

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper Paolo Bonzini
@ 2017-08-23  5:01   ` Fam Zheng
  2017-08-23  6:50     ` Paolo Bonzini
  2017-08-30 16:06   ` Stefan Hajnoczi
  2017-08-30 16:37   ` Stefan Hajnoczi
  2 siblings, 1 reply; 48+ messages in thread
From: Fam Zheng @ 2017-08-23  5:01 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, qemu-block

On Tue, 08/22 15:18, Paolo Bonzini wrote:
> Proper support of persistent reservation for multipath devices requires
> communication with the multipath daemon, so that the reservation is
> registered and applied when a path comes up.  The device mapper
> utilities provide a library to do so; this patch makes qemu-pr-helper.c
> detect multipath devices and, when one is found, delegate the operation
> to libmpathpersist.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  Makefile              |   3 +
>  configure             |  57 ++++++++-
>  docs/pr-manager.rst   |  27 +++++
>  include/scsi/utils.h  |   6 +
>  scsi/qemu-pr-helper.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  scsi/utils.c          |  15 +++
>  6 files changed, 414 insertions(+), 5 deletions(-)
> 
> diff --git a/Makefile b/Makefile
> index bfd4f69ecd..f1acaad05b 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -388,6 +388,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal
>  fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
>  
>  scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
> +ifdef CONFIG_MPATH
> +scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
> +endif
>  
>  qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
>  	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
> diff --git a/configure b/configure
> index 772aff18d6..d3c9371f7c 100755
> --- a/configure
> +++ b/configure
> @@ -286,6 +286,7 @@ pixman=""
>  sdl=""
>  sdlabi=""
>  virtfs=""
> +mpath=""

Whole patch: s/\<mpath\>/pr-helper/ ?

>  vnc="yes"
>  sparse="no"
>  vde=""
> @@ -948,6 +949,10 @@ for opt do
>    ;;
>    --enable-virtfs) virtfs="yes"
>    ;;
> +  --disable-mpath) mpath="no"
> +  ;;
> +  --enable-mpath) mpath="yes"
> +  ;;
>    --disable-vnc) vnc="no"
>    ;;
>    --enable-vnc) vnc="yes"
> @@ -1491,6 +1496,7 @@ disabled with --disable-FEATURE, default is enabled if available:
>    vnc-png         PNG compression for VNC server
>    cocoa           Cocoa UI (Mac OS X only)
>    virtfs          VirtFS
> +  mpath           Multipath persistent reservation passthrough
>    xen             xen backend driver support
>    xen-pci-passthrough
>    brlapi          BrlAPI (Braile)
> @@ -3336,6 +3342,29 @@ else
>  fi
>  
>  ##########################################
> +# libmpathpersist probe
> +
> +if test "$mpath" != "no" ; then
> +  cat > $TMPC <<EOF
> +#include <libudev.h>
> +#include <mpath_persist.h>
> +unsigned mpath_mx_alloc_len = 1024;
> +int logsink;
> +int main(void) {
> +    struct udev *udev = udev_new();
> +    mpath_lib_init(udev);
> +}
> +EOF
> +  if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
> +    mpathpersist=yes
> +  else
> +    mpathpersist=no
> +  fi
> +else
> +  mpathpersist=no
> +fi
> +
> +##########################################
>  # libcap probe
>  
>  if test "$cap" != "no" ; then
> @@ -5070,16 +5099,34 @@ if test "$want_tools" = "yes" ; then
>    fi
>  fi
>  if test "$softmmu" = yes ; then
> -  if test "$virtfs" != no ; then
> -    if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
> +  if test "$linux" = yes; then
> +    if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then
>        virtfs=yes
>        tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
>      else
>        if test "$virtfs" = yes; then
> -        error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
> +        error_exit "VirtFS requires libcap devel and libattr devel"
>        fi
>        virtfs=no
>      fi
> +    if test "$mpath" != no && test "$mpathpersist" = yes ; then
> +      mpath=yes
> +      tools="$tools mpath/qemu-mpath-helper\$(EXESUF)"

scsi/qemu-pr-helper?

> +    else
> +      if test "$mpath" = yes; then
> +        error_exit "Multipath requires libmpathpersist devel"
> +      fi
> +      mpath=no
> +    fi
> +  else
> +    if test "$virtfs" = yes; then
> +      error_exit "VirtFS is supported only on Linux"
> +    fi
> +    virtfs=no
> +    if test "$mpath" = yes; then
> +      error_exit "Multipath is supported only on Linux"
> +    fi
> +    mpath=no
>    fi
>  fi
>  
> @@ -5326,6 +5373,7 @@ echo "Audio drivers     $audio_drv_list"
>  echo "Block whitelist (rw) $block_drv_rw_whitelist"
>  echo "Block whitelist (ro) $block_drv_ro_whitelist"
>  echo "VirtFS support    $virtfs"
> +echo "Multipath support $mpath"
>  echo "VNC support       $vnc"
>  if test "$vnc" = "yes" ; then
>      echo "VNC SASL support  $vnc_sasl"
> @@ -5773,6 +5821,9 @@ fi
>  if test "$virtfs" = "yes" ; then
>    echo "CONFIG_VIRTFS=y" >> $config_host_mak
>  fi
> +if test "$mpath" = "yes" ; then
> +  echo "CONFIG_MPATH=y" >> $config_host_mak
> +fi
>  if test "$vhost_scsi" = "yes" ; then
>    echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
>  fi

Fam

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all Paolo Bonzini
@ 2017-08-23  5:08   ` Fam Zheng
  2017-08-23  6:54     ` Paolo Bonzini
  2017-08-30 12:52   ` Daniel P. Berrange
  2017-08-30 14:33   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
  2 siblings, 1 reply; 48+ messages in thread
From: Fam Zheng @ 2017-08-23  5:08 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, qemu-block, Daniel P . Berrange

On Tue, 08/22 15:18, Paolo Bonzini wrote:
> It is pretty common to read a fixed-size buffer from a socket.  Add a
> function that does this, either with multiple reads (on blocking sockets)
> or by yielding if called from a coroutine.
> 
> Cc: Daniel P. Berrange <berrange@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  include/io/channel.h | 36 ++++++++++++++++++++++++++++++++++-
>  io/channel.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 89 insertions(+), 1 deletion(-)
> 
> diff --git a/include/io/channel.h b/include/io/channel.h
> index db9bb022a1..9cfb4d081f 100644
> --- a/include/io/channel.h
> +++ b/include/io/channel.h
> @@ -299,7 +299,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc,
>                             Error **errp);
>  
>  /**
> - * qio_channel_readv:
> + * qio_channel_read:
>   * @ioc: the channel object
>   * @buf: the memory region to read data into
>   * @buflen: the length of @buf
> @@ -315,6 +315,23 @@ ssize_t qio_channel_read(QIOChannel *ioc,
>                           Error **errp);
>  
>  /**
> + * qio_channel_read_all:
> + * @ioc: the channel object
> + * @buf: the memory region to read data into
> + * @buflen: the number of bytes to @buf
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Reads @buflen bytes into @buf, possibly blocking or (if the
> + * channel is non-blocking) yielding from the current coroutine
> + * multiple times until the entire content is read.  Otherwise
> + * behaves as qio_channel_read().
> + */
> +ssize_t coroutine_fn qio_channel_read_all(QIOChannel *ioc,
> +                                          char *buf,
> +                                          size_t buflen,
> +                                          Error **errp);
> +
> +/**
>   * qio_channel_write:
>   * @ioc: the channel object
>   * @buf: the memory regions to send data from
> @@ -331,6 +348,23 @@ ssize_t qio_channel_write(QIOChannel *ioc,
>                            Error **errp);
>  
>  /**
> + * qio_channel_write_all:
> + * @ioc: the channel object
> + * @buf: the memory region to write data into
> + * @buflen: the number of bytes to @buf
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Writes @buflen bytes from @buf, possibly blocking or (if the
> + * channel is non-blocking) yielding from the current coroutine
> + * multiple times until the entire content is written.  Otherwise
> + * behaves as qio_channel_write().
> + */
> +ssize_t coroutine_fn qio_channel_write_all(QIOChannel *ioc,
> +                                           const char *buf,
> +                                           size_t buflen,
> +                                           Error **errp);
> +
> +/**
>   * qio_channel_set_blocking:
>   * @ioc: the channel object
>   * @enabled: the blocking flag state
> diff --git a/io/channel.c b/io/channel.c
> index 1cfb8b33a2..7ab3f4eede 100644
> --- a/io/channel.c
> +++ b/io/channel.c
> @@ -113,6 +113,60 @@ ssize_t qio_channel_read(QIOChannel *ioc,
>  }
>  
>  
> +ssize_t qio_channel_read_all(QIOChannel *ioc,
> +                             char *buf,
> +                             size_t buflen,
> +                             Error **errp)
> +{
> +    ssize_t total = 0;
> +    while (buflen > 0) {
> +        ssize_t n_read = qio_channel_read(ioc, buf, buflen, errp);
> +
> +        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
> +            assert(ioc->ctx);
> +            qio_channel_yield(ioc, G_IO_IN);
> +            continue;
> +        }
> +        if (n_read < 0) {
> +            return n_read;
> +        }
> +
> +        buf += n_read;
> +        total += n_read;
> +        buflen -= n_read;
> +    }
> +
> +    return total;
> +}
> +
> +
> +ssize_t qio_channel_write_all(QIOChannel *ioc,
> +                              const char *buf,
> +                              size_t buflen,
> +                              Error **errp)
> +{
> +    ssize_t total = 0;
> +    while (buflen > 0) {
> +        ssize_t n_written = qio_channel_write(ioc, buf, buflen, errp);
> +
> +        if (n_written == QIO_CHANNEL_ERR_BLOCK) {
> +            assert(ioc->ctx);
> +            qio_channel_yield(ioc, G_IO_OUT);
> +            continue;
> +        }
> +        if (n_written < 0) {
> +            return n_written;
> +        }
> +
> +        buf += n_written;
> +        total += n_written;
> +        buflen -= n_written;
> +    }
> +
> +    return total;
> +}
> +
> +
>  ssize_t qio_channel_write(QIOChannel *ioc,
>                            const char *buf,
>                            size_t buflen,
> -- 
> 2.13.5
> 
> 

Are there any caller depending on short read/write? Is it okay to change all (or
most) qio_channel_{read,write}* functions to this "full read/write" behavior?

Fam

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper
  2017-08-23  5:01   ` Fam Zheng
@ 2017-08-23  6:50     ` Paolo Bonzini
  0 siblings, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-23  6:50 UTC (permalink / raw)
  To: Fam Zheng; +Cc: qemu-devel, qemu-block

On 23/08/2017 07:01, Fam Zheng wrote:
> On Tue, 08/22 15:18, Paolo Bonzini wrote:
>> Proper support of persistent reservation for multipath devices requires
>> communication with the multipath daemon, so that the reservation is
>> registered and applied when a path comes up.  The device mapper
>> utilities provide a library to do so; this patch makes qemu-pr-helper.c
>> detect multipath devices and, when one is found, delegate the operation
>> to libmpathpersist.
>>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>  Makefile              |   3 +
>>  configure             |  57 ++++++++-
>>  docs/pr-manager.rst   |  27 +++++
>>  include/scsi/utils.h  |   6 +
>>  scsi/qemu-pr-helper.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++-
>>  scsi/utils.c          |  15 +++
>>  6 files changed, 414 insertions(+), 5 deletions(-)
>>
>> diff --git a/Makefile b/Makefile
>> index bfd4f69ecd..f1acaad05b 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -388,6 +388,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal
>>  fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
>>  
>>  scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
>> +ifdef CONFIG_MPATH
>> +scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
>> +endif
>>  
>>  qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
>>  	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")
>> diff --git a/configure b/configure
>> index 772aff18d6..d3c9371f7c 100755
>> --- a/configure
>> +++ b/configure
>> @@ -286,6 +286,7 @@ pixman=""
>>  sdl=""
>>  sdlabi=""
>>  virtfs=""
>> +mpath=""
> 
> Whole patch: s/\<mpath\>/pr-helper/ ?

No, the helper can work without multipath support.  The mpath variable
is about supporting multipath in the helper.

Paolo

>>  vnc="yes"
>>  sparse="no"
>>  vde=""
>> @@ -948,6 +949,10 @@ for opt do
>>    ;;
>>    --enable-virtfs) virtfs="yes"
>>    ;;
>> +  --disable-mpath) mpath="no"
>> +  ;;
>> +  --enable-mpath) mpath="yes"
>> +  ;;
>>    --disable-vnc) vnc="no"
>>    ;;
>>    --enable-vnc) vnc="yes"
>> @@ -1491,6 +1496,7 @@ disabled with --disable-FEATURE, default is enabled if available:
>>    vnc-png         PNG compression for VNC server
>>    cocoa           Cocoa UI (Mac OS X only)
>>    virtfs          VirtFS
>> +  mpath           Multipath persistent reservation passthrough
>>    xen             xen backend driver support
>>    xen-pci-passthrough
>>    brlapi          BrlAPI (Braile)
>> @@ -3336,6 +3342,29 @@ else
>>  fi
>>  
>>  ##########################################
>> +# libmpathpersist probe
>> +
>> +if test "$mpath" != "no" ; then
>> +  cat > $TMPC <<EOF
>> +#include <libudev.h>
>> +#include <mpath_persist.h>
>> +unsigned mpath_mx_alloc_len = 1024;
>> +int logsink;
>> +int main(void) {
>> +    struct udev *udev = udev_new();
>> +    mpath_lib_init(udev);
>> +}
>> +EOF
>> +  if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
>> +    mpathpersist=yes
>> +  else
>> +    mpathpersist=no
>> +  fi
>> +else
>> +  mpathpersist=no
>> +fi
>> +
>> +##########################################
>>  # libcap probe
>>  
>>  if test "$cap" != "no" ; then
>> @@ -5070,16 +5099,34 @@ if test "$want_tools" = "yes" ; then
>>    fi
>>  fi
>>  if test "$softmmu" = yes ; then
>> -  if test "$virtfs" != no ; then
>> -    if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
>> +  if test "$linux" = yes; then
>> +    if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then
>>        virtfs=yes
>>        tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
>>      else
>>        if test "$virtfs" = yes; then
>> -        error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
>> +        error_exit "VirtFS requires libcap devel and libattr devel"
>>        fi
>>        virtfs=no
>>      fi
>> +    if test "$mpath" != no && test "$mpathpersist" = yes ; then
>> +      mpath=yes
>> +      tools="$tools mpath/qemu-mpath-helper\$(EXESUF)"
> 
> scsi/qemu-pr-helper?
> 
>> +    else
>> +      if test "$mpath" = yes; then
>> +        error_exit "Multipath requires libmpathpersist devel"
>> +      fi
>> +      mpath=no
>> +    fi
>> +  else
>> +    if test "$virtfs" = yes; then
>> +      error_exit "VirtFS is supported only on Linux"
>> +    fi
>> +    virtfs=no
>> +    if test "$mpath" = yes; then
>> +      error_exit "Multipath is supported only on Linux"
>> +    fi
>> +    mpath=no
>>    fi
>>  fi
>>  
>> @@ -5326,6 +5373,7 @@ echo "Audio drivers     $audio_drv_list"
>>  echo "Block whitelist (rw) $block_drv_rw_whitelist"
>>  echo "Block whitelist (ro) $block_drv_ro_whitelist"
>>  echo "VirtFS support    $virtfs"
>> +echo "Multipath support $mpath"
>>  echo "VNC support       $vnc"
>>  if test "$vnc" = "yes" ; then
>>      echo "VNC SASL support  $vnc_sasl"
>> @@ -5773,6 +5821,9 @@ fi
>>  if test "$virtfs" = "yes" ; then
>>    echo "CONFIG_VIRTFS=y" >> $config_host_mak
>>  fi
>> +if test "$mpath" = "yes" ; then
>> +  echo "CONFIG_MPATH=y" >> $config_host_mak
>> +fi
>>  if test "$vhost_scsi" = "yes" ; then
>>    echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
>>  fi
> 
> Fam
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all
  2017-08-23  5:08   ` Fam Zheng
@ 2017-08-23  6:54     ` Paolo Bonzini
  0 siblings, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-23  6:54 UTC (permalink / raw)
  To: Fam Zheng; +Cc: qemu-devel, qemu-block, Daniel P . Berrange

On 23/08/2017 07:08, Fam Zheng wrote:
> On Tue, 08/22 15:18, Paolo Bonzini wrote:
>> It is pretty common to read a fixed-size buffer from a socket.  Add a
>> function that does this, either with multiple reads (on blocking sockets)
>> or by yielding if called from a coroutine.
>>
>> Cc: Daniel P. Berrange <berrange@redhat.com>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>  include/io/channel.h | 36 ++++++++++++++++++++++++++++++++++-
>>  io/channel.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 89 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/io/channel.h b/include/io/channel.h
>> index db9bb022a1..9cfb4d081f 100644
>> --- a/include/io/channel.h
>> +++ b/include/io/channel.h
>> @@ -299,7 +299,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc,
>>                             Error **errp);
>>  
>>  /**
>> - * qio_channel_readv:
>> + * qio_channel_read:
>>   * @ioc: the channel object
>>   * @buf: the memory region to read data into
>>   * @buflen: the length of @buf
>> @@ -315,6 +315,23 @@ ssize_t qio_channel_read(QIOChannel *ioc,
>>                           Error **errp);
>>  
>>  /**
>> + * qio_channel_read_all:
>> + * @ioc: the channel object
>> + * @buf: the memory region to read data into
>> + * @buflen: the number of bytes to @buf
>> + * @errp: pointer to a NULL-initialized error object
>> + *
>> + * Reads @buflen bytes into @buf, possibly blocking or (if the
>> + * channel is non-blocking) yielding from the current coroutine
>> + * multiple times until the entire content is read.  Otherwise
>> + * behaves as qio_channel_read().
>> + */
>> +ssize_t coroutine_fn qio_channel_read_all(QIOChannel *ioc,
>> +                                          char *buf,
>> +                                          size_t buflen,
>> +                                          Error **errp);
>> +
>> +/**
>>   * qio_channel_write:
>>   * @ioc: the channel object
>>   * @buf: the memory regions to send data from
>> @@ -331,6 +348,23 @@ ssize_t qio_channel_write(QIOChannel *ioc,
>>                            Error **errp);
>>  
>>  /**
>> + * qio_channel_write_all:
>> + * @ioc: the channel object
>> + * @buf: the memory region to write data into
>> + * @buflen: the number of bytes to @buf
>> + * @errp: pointer to a NULL-initialized error object
>> + *
>> + * Writes @buflen bytes from @buf, possibly blocking or (if the
>> + * channel is non-blocking) yielding from the current coroutine
>> + * multiple times until the entire content is written.  Otherwise
>> + * behaves as qio_channel_write().
>> + */
>> +ssize_t coroutine_fn qio_channel_write_all(QIOChannel *ioc,
>> +                                           const char *buf,
>> +                                           size_t buflen,
>> +                                           Error **errp);
>> +
>> +/**
>>   * qio_channel_set_blocking:
>>   * @ioc: the channel object
>>   * @enabled: the blocking flag state
>> diff --git a/io/channel.c b/io/channel.c
>> index 1cfb8b33a2..7ab3f4eede 100644
>> --- a/io/channel.c
>> +++ b/io/channel.c
>> @@ -113,6 +113,60 @@ ssize_t qio_channel_read(QIOChannel *ioc,
>>  }
>>  
>>  
>> +ssize_t qio_channel_read_all(QIOChannel *ioc,
>> +                             char *buf,
>> +                             size_t buflen,
>> +                             Error **errp)
>> +{
>> +    ssize_t total = 0;
>> +    while (buflen > 0) {
>> +        ssize_t n_read = qio_channel_read(ioc, buf, buflen, errp);
>> +
>> +        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
>> +            assert(ioc->ctx);
>> +            qio_channel_yield(ioc, G_IO_IN);
>> +            continue;
>> +        }
>> +        if (n_read < 0) {
>> +            return n_read;
>> +        }
>> +
>> +        buf += n_read;
>> +        total += n_read;
>> +        buflen -= n_read;
>> +    }
>> +
>> +    return total;
>> +}
>> +
>> +
>> +ssize_t qio_channel_write_all(QIOChannel *ioc,
>> +                              const char *buf,
>> +                              size_t buflen,
>> +                              Error **errp)
>> +{
>> +    ssize_t total = 0;
>> +    while (buflen > 0) {
>> +        ssize_t n_written = qio_channel_write(ioc, buf, buflen, errp);
>> +
>> +        if (n_written == QIO_CHANNEL_ERR_BLOCK) {
>> +            assert(ioc->ctx);
>> +            qio_channel_yield(ioc, G_IO_OUT);
>> +            continue;
>> +        }
>> +        if (n_written < 0) {
>> +            return n_written;
>> +        }
>> +
>> +        buf += n_written;
>> +        total += n_written;
>> +        buflen -= n_written;
>> +    }
>> +
>> +    return total;
>> +}
>> +
>> +
>>  ssize_t qio_channel_write(QIOChannel *ioc,
>>                            const char *buf,
>>                            size_t buflen,
>> -- 
>> 2.13.5
> 
> Are there any caller depending on short read/write? Is it okay to change all (or
> most) qio_channel_{read,write}* functions to this "full read/write" behavior?

No, it looks like I'm the first. :)  NBD also implements something
similar to this patch, but it uses qio_channel_{read,write}v.

Paolo

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper
  2017-08-23  4:49   ` Fam Zheng
@ 2017-08-23  6:55     ` Paolo Bonzini
  2017-08-23  7:48     ` Paolo Bonzini
  1 sibling, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-23  6:55 UTC (permalink / raw)
  To: Fam Zheng; +Cc: qemu-devel, qemu-block

On 23/08/2017 06:49, Fam Zheng wrote:
>> + * Persistent reservation manager that talks to qemu-mpath-helper
> s/qemu-mpath-helper/qemu-pr-helper/

Oops, you got a glimpse into the history of the patches. :)  (it was
first designed for multipath only, then decided that generic PR support
would be both useful and easier to debug and test).

>> + *
>> + * Author: Paolo Bonzini <pbonzini@redhat.com>
>> + *
>> + * This code is licensed under the LGPL.
> 
> Interesting, I think the version of the license is required?

Cut and paste, will fix.

Paolo

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management
  2017-08-23  4:13   ` Fam Zheng
@ 2017-08-23  6:56     ` Paolo Bonzini
  0 siblings, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-23  6:56 UTC (permalink / raw)
  To: Fam Zheng; +Cc: qemu-devel, qemu-block

On 23/08/2017 06:13, Fam Zheng wrote:
> On Tue, 08/22 15:18, Paolo Bonzini wrote:
>> diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst
> 
> Is docs/interop/persistent-reservation-manager.rst better? (Move to interop/ and
> de-abbreviate) ...
> 
>> new file mode 100644
>> index 0000000000..b6089fb57c
>> --- /dev/null
>> +++ b/docs/pr-manager.rst
>> @@ -0,0 +1,51 @@
>> +======================================
>> +Persistent reservation managers
>> +======================================
>> +
>> +SCSI persistent Reservations allow restricting access to block devices
>> +to specific initiators in a shared storage setup.  When implementing
>> +clustering of virtual machines, it is a common requirement for virtual
>> +machines to send persistent reservation SCSI commands.  However,
>> +the operating system restricts sending these commands to unprivileged
>> +programs because incorrect usage can disrupt regular operation of the
>> +storage fabric.
>> +
>> +For this reason, QEMU's SCSI passthrough devices, ``scsi-block``
>> +and ``scsi-generic`` (both are only available on Linux) can delegate
>> +implementation of persistent reservations to a separate object,
>> +the "persistent reservation manager".  Only PERSISTENT RESERVE OUT and
>> +PERSISTENT RESERVE IN commands are passed to the persistent reservation
>> +manager object; other commands are processed by QEMU as usual.
>> +
>> +-----------------------------------------
>> +Defining a persistent reservation manager
>> +-----------------------------------------
>> +
>> +A persistent reservation manager is an instance of a subclass of the
>> +"pr-manager" QOM class.
> 
> Or is this abstraction class the reason it is not under interop? Why not just
> define the protocol?

It is not under interop because this is user documentation.  The
protocol documentation is under interop because the protocol is public,
and if someone else wants to talk to qemu-pr-helper they can.

(If the protocol was private, the protocol documentation would have been
under docs/devel).

Paolo

>> +
>> +Right now only one subclass is defined, ``pr-manager-helper``, which
>> +forwards the commands to an external privileged helper program
>> +over Unix sockets.  The helper program only allows sending persistent
>> +reservation commands to devices for which QEMU has a file descriptor,
>> +so that QEMU will not be able to effect persistent reservations
>> +unless it has access to both the socket and the device.
>> +
>> +``pr-manager-helper`` has a single string property, ``path``, which
>> +accepts the path to the helper program's Unix socket.  For example,
>> +the following command line defines a ``pr-manager-helper`` object and
>> +attaches it to a SCSI passthrough device::
>> +
>> +      $ qemu-system-x86_64
>> +          -device virtio-scsi \
>> +          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
>> +          -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
>> +          -device scsi-block,drive=hd
>> +
>> +Alternatively, using ``-blockdev``::
>> +
>> +      $ qemu-system-x86_64
>> +          -device virtio-scsi \
>> +          -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
>> +          -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
>> +          -device scsi-block,drive=hd
> 
> Fam
> 

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper
  2017-08-23  4:49   ` Fam Zheng
  2017-08-23  6:55     ` Paolo Bonzini
@ 2017-08-23  7:48     ` Paolo Bonzini
  1 sibling, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-23  7:48 UTC (permalink / raw)
  To: Fam Zheng; +Cc: qemu-devel, qemu-block

On 23/08/2017 06:49, Fam Zheng wrote:
>> +
>> +    /* A simple feature negotation protocol, even though there is
>> +     * no optional feature right now.
>> +     */
>> +    if (pr_manager_helper_read(pr_mgr, &flags, sizeof(flags), errp) < 0) {
> Not returning the return value of pr_manager_helper_read()?.
> 
>> +        return -EINVAL;
>> +    }
>> +
>> +    flags = 0;
>> +    if (pr_manager_helper_write(pr_mgr, -1, &flags, sizeof(flags), errp) < 0) {
>> +        return -EINVAL;
> Same here.
> 

Sorry, I forgot to answer these.  The QIOChannel functions (and thus
pr_manager_helper_read/write) only answer -1 or QIO_CHANNEL_ERROR_BLOCK.
 I'll change read/write to return -EINVAL instead.

Paolo

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management Paolo Bonzini
  2017-08-23  4:13   ` Fam Zheng
@ 2017-08-24 15:37   ` Eric Blake
  2017-08-24 15:47     ` Paolo Bonzini
  2017-08-30 12:59   ` Daniel P. Berrange
  2017-08-30 14:26   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
  3 siblings, 1 reply; 48+ messages in thread
From: Eric Blake @ 2017-08-24 15:37 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: famz, qemu-block

[-- Attachment #1: Type: text/plain, Size: 1454 bytes --]

On 08/22/2017 08:18 AM, Paolo Bonzini wrote:
> It is a common requirement for virtual machine to send persistent
> reservations, but this currently requires either running QEMU with
> CAP_SYS_RAWIO, or using out-of-tree patches that let an unprivileged
> QEMU bypass Linux's filter on SG_IO commands.
> 
> As an alternative mechanism, the next patches will introduce a
> privileged helper to run persistent reservation commands without
> expanding QEMU's attack surface unnecessarily.

> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---

> +++ b/qapi/block-core.json
> @@ -2191,6 +2191,9 @@
>  # Driver specific block device options for the file backend.
>  #
>  # @filename:    path to the image file
> +# @pr-manager:  the if for the object that will handle persistent reservations

s/if/interface/ for legibility

> +#               for this device (default: forward the commands via SG_IO,
> +#               since 2.11)
>  # @aio:         AIO backend (default: threads) (since: 2.8)
>  # @locking:     whether to enable file locking. If set to 'auto', only enable
>  #               when Open File Descriptor (OFD) locking API is available
> @@ -2200,6 +2203,7 @@
>  ##
>  { 'struct': 'BlockdevOptionsFile',
>    'data': { 'filename': 'str',
> +            '*pr-manager': 'str',
-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper Paolo Bonzini
  2017-08-22 14:34   ` Marc-André Lureau
@ 2017-08-24 15:45   ` Eric Blake
  2017-08-30 15:44   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
  2017-08-30 16:06   ` Stefan Hajnoczi
  3 siblings, 0 replies; 48+ messages in thread
From: Eric Blake @ 2017-08-24 15:45 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: famz, qemu-block

[-- Attachment #1: Type: text/plain, Size: 1700 bytes --]

On 08/22/2017 08:18 AM, Paolo Bonzini wrote:
> Introduce a privileged helper to run persistent reservation commands.
> This lets virtual machines send persistent reservations without using
> CAP_SYS_RAWIO or out-of-tree patches.  The helper uses Unix permissions
> and SCM_RIGHTS to restrict access to processes that can access its socket
> and prove that they have an open file descriptor for a raw SCSI device.
> 
> The next patch will also correct the usage of persistent reservations
> with multipath devices.
> 
> It would also be possible to support for Linux's IOC_PR_* ioctls in
> the future, to support NVMe devices.  For now, however, only SCSI is
> supported.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---

> +++ b/docs/interop/pr-helper.rst
> @@ -0,0 +1,78 @@
> +..
> +
> +======================================
> +Persistent reservation helper protocol
> +======================================
> +
> +QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
> +can delegate implementation of persistent reservations to an external
> +(and typically privilege) program.  Persistent Reservations allow

s/privilege/privileged/


> +
> +If a bit is 1 in ``requested_features`` and 0 in ``supported_features``,
> +the corresponding feature is not supported by the helper and the connection
> +is closed.  On the other hand, it is acceptable for a bit to be 0 in
> +``requested_features`` and 1 in ``supported_features``; in this case,
> +he helper will not enable the feature.

s/^he/the/

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management
  2017-08-24 15:37   ` Eric Blake
@ 2017-08-24 15:47     ` Paolo Bonzini
  0 siblings, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-08-24 15:47 UTC (permalink / raw)
  To: Eric Blake, qemu-devel; +Cc: famz, qemu-block

[-- Attachment #1: Type: text/plain, Size: 242 bytes --]

On 24/08/2017 17:37, Eric Blake wrote:
>>  #
>>  # @filename:    path to the image file
>> +# @pr-manager:  the if for the object that will handle persistent reservations
> s/if/interface/ for legibility
> 

"id" actually.

Paolo


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all Paolo Bonzini
  2017-08-23  5:08   ` Fam Zheng
@ 2017-08-30 12:52   ` Daniel P. Berrange
  2017-08-30 14:33   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
  2 siblings, 0 replies; 48+ messages in thread
From: Daniel P. Berrange @ 2017-08-30 12:52 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, qemu-block, famz

On Tue, Aug 22, 2017 at 03:18:29PM +0200, Paolo Bonzini wrote:
> It is pretty common to read a fixed-size buffer from a socket.  Add a
> function that does this, either with multiple reads (on blocking sockets)
> or by yielding if called from a coroutine.
> 
> Cc: Daniel P. Berrange <berrange@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  include/io/channel.h | 36 ++++++++++++++++++++++++++++++++++-
>  io/channel.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 89 insertions(+), 1 deletion(-)

This lacks test suite coverage.

Also this is more or less the same as code Juan has proposed too:

https://lists.gnu.org/archive/html/qemu-devel/2017-08/msg01536.html

Rather than have dualing patch series, I'll post an update that
addresses my concerns with both patches, so we can merge these
new APIs independantly of your / Juan's patch series.

> 
> diff --git a/include/io/channel.h b/include/io/channel.h
> index db9bb022a1..9cfb4d081f 100644
> --- a/include/io/channel.h
> +++ b/include/io/channel.h
> @@ -299,7 +299,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc,
>                             Error **errp);
>  
>  /**
> - * qio_channel_readv:
> + * qio_channel_read:
>   * @ioc: the channel object
>   * @buf: the memory region to read data into
>   * @buflen: the length of @buf
> @@ -315,6 +315,23 @@ ssize_t qio_channel_read(QIOChannel *ioc,
>                           Error **errp);
>  
>  /**
> + * qio_channel_read_all:
> + * @ioc: the channel object
> + * @buf: the memory region to read data into
> + * @buflen: the number of bytes to @buf
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Reads @buflen bytes into @buf, possibly blocking or (if the
> + * channel is non-blocking) yielding from the current coroutine
> + * multiple times until the entire content is read.  Otherwise
> + * behaves as qio_channel_read().
> + */
> +ssize_t coroutine_fn qio_channel_read_all(QIOChannel *ioc,
> +                                          char *buf,
> +                                          size_t buflen,
> +                                          Error **errp);
> +
> +/**
>   * qio_channel_write:
>   * @ioc: the channel object
>   * @buf: the memory regions to send data from
> @@ -331,6 +348,23 @@ ssize_t qio_channel_write(QIOChannel *ioc,
>                            Error **errp);
>  
>  /**
> + * qio_channel_write_all:
> + * @ioc: the channel object
> + * @buf: the memory region to write data into
> + * @buflen: the number of bytes to @buf
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Writes @buflen bytes from @buf, possibly blocking or (if the
> + * channel is non-blocking) yielding from the current coroutine
> + * multiple times until the entire content is written.  Otherwise
> + * behaves as qio_channel_write().
> + */
> +ssize_t coroutine_fn qio_channel_write_all(QIOChannel *ioc,
> +                                           const char *buf,
> +                                           size_t buflen,
> +                                           Error **errp);
> +
> +/**
>   * qio_channel_set_blocking:
>   * @ioc: the channel object
>   * @enabled: the blocking flag state
> diff --git a/io/channel.c b/io/channel.c
> index 1cfb8b33a2..7ab3f4eede 100644
> --- a/io/channel.c
> +++ b/io/channel.c
> @@ -113,6 +113,60 @@ ssize_t qio_channel_read(QIOChannel *ioc,
>  }
>  
>  
> +ssize_t qio_channel_read_all(QIOChannel *ioc,
> +                             char *buf,
> +                             size_t buflen,
> +                             Error **errp)
> +{
> +    ssize_t total = 0;
> +    while (buflen > 0) {
> +        ssize_t n_read = qio_channel_read(ioc, buf, buflen, errp);
> +
> +        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
> +            assert(ioc->ctx);
> +            qio_channel_yield(ioc, G_IO_IN);
> +            continue;
> +        }
> +        if (n_read < 0) {
> +            return n_read;
> +        }
> +
> +        buf += n_read;
> +        total += n_read;
> +        buflen -= n_read;
> +    }

This busy-loops on EOF ie when n_read == 0.

> +
> +    return total;
> +}
> +
> +
> +ssize_t qio_channel_write_all(QIOChannel *ioc,
> +                              const char *buf,
> +                              size_t buflen,
> +                              Error **errp)
> +{
> +    ssize_t total = 0;
> +    while (buflen > 0) {
> +        ssize_t n_written = qio_channel_write(ioc, buf, buflen, errp);
> +
> +        if (n_written == QIO_CHANNEL_ERR_BLOCK) {
> +            assert(ioc->ctx);
> +            qio_channel_yield(ioc, G_IO_OUT);
> +            continue;
> +        }
> +        if (n_written < 0) {
> +            return n_written;
> +        }
> +
> +        buf += n_written;
> +        total += n_written;
> +        buflen -= n_written;
> +    }
> +
> +    return total;
> +}
> +
> +
>  ssize_t qio_channel_write(QIOChannel *ioc,
>                            const char *buf,
>                            size_t buflen,
> -- 
> 2.13.5
> 
> 

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management Paolo Bonzini
  2017-08-23  4:13   ` Fam Zheng
  2017-08-24 15:37   ` Eric Blake
@ 2017-08-30 12:59   ` Daniel P. Berrange
  2017-08-30 14:26   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
  3 siblings, 0 replies; 48+ messages in thread
From: Daniel P. Berrange @ 2017-08-30 12:59 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:28PM +0200, Paolo Bonzini wrote:
> It is a common requirement for virtual machine to send persistent
> reservations, but this currently requires either running QEMU with
> CAP_SYS_RAWIO, or using out-of-tree patches that let an unprivileged
> QEMU bypass Linux's filter on SG_IO commands.
> 
> As an alternative mechanism, the next patches will introduce a
> privileged helper to run persistent reservation commands without
> expanding QEMU's attack surface unnecessarily.

FYI, libvirt should block this helper program as it sets up capabilities
in such a way that prevent QEMU evalating privileges via setuid binaries.

We would have to figure out a way for libvirt to run the daemon I guess.

> 
> The helper is invoked through a "pr-manager" QOM object, to which
> file-posix.c passes SG_IO requests for PERSISTENT RESERVE OUT and
> PERSISTENT RESERVE IN commands.  For example:
> 
>   $ qemu-system-x86_64
>       -device virtio-scsi \
>       -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
>       -drive if=none,id=hd,driver=raw,file.filename=/dev/sdb,file.pr-manager=helper0
>       -device scsi-block,drive=hd
> 
> or:
> 
>   $ qemu-system-x86_64
>       -device virtio-scsi \
>       -object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
>       -blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
>       -device scsi-block,drive=hd
> 
> Multiple pr-manager implementations are conceivable and possible, though
> only one is implemented right now.  For example, a pr-manager could:
> 
> - talk directly to the multipath daemon from a privileged QEMU
>   (i.e. QEMU links to libmpathpersist); this makes reservation work
>   properly with multipath, but still requires CAP_SYS_RAWIO
> 
> - use the Linux IOC_PR_* ioctls (they require CAP_SYS_ADMIN though)
> 
> - more interestingly, implement reservations directly in QEMU
>   through file system locks or a shared database (e.g. sqlite)

IIUC This last thing is essentially what libvirt already provided via
its virtlockd daemon. For SCSI disks, we have a configuration option that
tells it to run the '/lib/udev/scsi_id' program, and then acquires a
fcntl() lock on a file  in /var/lib/libvirt/lockd/scsivolumes/ whose
name is based on the value reported by scsi_id.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 03/10] scsi: introduce scsi_build_sense
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 03/10] scsi: introduce scsi_build_sense Paolo Bonzini
  2017-08-22 13:35   ` Philippe Mathieu-Daudé
@ 2017-08-30 13:39   ` Stefan Hajnoczi
  1 sibling, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 13:39 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:25PM +0200, Paolo Bonzini wrote:
> Move more knowledge of sense data format out of hw/scsi/scsi-bus.c
> for reusability.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  hw/scsi/scsi-bus.c   |  8 +-------
>  include/scsi/utils.h |  2 ++
>  scsi/utils.c         | 11 +++++++++++
>  3 files changed, 14 insertions(+), 7 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno Paolo Bonzini
  2017-08-22 13:45   ` Philippe Mathieu-Daudé
@ 2017-08-30 13:41   ` Stefan Hajnoczi
  1 sibling, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 13:41 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:26PM +0200, Paolo Bonzini wrote:
> Move more knowledge of SG_IO out of hw/scsi/scsi-generic.c, for
> reusability.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  hw/scsi/scsi-generic.c | 40 +++++++---------------------------------
>  include/scsi/utils.h   |  3 +++
>  scsi/utils.c           | 35 +++++++++++++++++++++++++++++++++++
>  3 files changed, 45 insertions(+), 33 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 05/10] scsi: move block/scsi.h to include/scsi/constants.h
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 05/10] scsi: move block/scsi.h to include/scsi/constants.h Paolo Bonzini
  2017-08-22 13:37   ` Philippe Mathieu-Daudé
@ 2017-08-30 13:41   ` Stefan Hajnoczi
  1 sibling, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 13:41 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:27PM +0200, Paolo Bonzini wrote:
> Complete the transition by renaming this header, which was
> shared by block/iscsi.c and the SCSI emulation code.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  block/iscsi.c                              | 2 +-
>  hw/block/virtio-blk.c                      | 2 +-
>  hw/scsi/megasas.c                          | 2 +-
>  hw/scsi/mptendian.c                        | 2 +-
>  hw/scsi/mptsas.c                           | 2 +-
>  hw/scsi/scsi-bus.c                         | 2 +-
>  hw/scsi/scsi-disk.c                        | 2 +-
>  hw/scsi/scsi-generic.c                     | 2 +-
>  hw/scsi/spapr_vscsi.c                      | 2 +-
>  hw/scsi/virtio-scsi-dataplane.c            | 2 +-
>  hw/scsi/virtio-scsi.c                      | 2 +-
>  hw/scsi/vmw_pvscsi.c                       | 2 +-
>  hw/usb/dev-uas.c                           | 2 +-
>  include/hw/ide/internal.h                  | 2 +-
>  include/{block/scsi.h => scsi/constants.h} | 0
>  scsi/utils.c                               | 2 +-
>  tests/virtio-scsi-test.c                   | 2 +-
>  17 files changed, 16 insertions(+), 16 deletions(-)
>  rename include/{block/scsi.h => scsi/constants.h} (100%)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management Paolo Bonzini
                     ` (2 preceding siblings ...)
  2017-08-30 12:59   ` Daniel P. Berrange
@ 2017-08-30 14:26   ` Stefan Hajnoczi
  3 siblings, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 14:26 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:28PM +0200, Paolo Bonzini wrote:
> +#ifdef CONFIG_LINUX
> +PRManager *pr_manager_lookup(const char *id, Error **errp);
> +#else
> +static inline PRManager *pr_manager_lookup(const char *id,
> +                                                              Error **errp)

Indentation

> diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c
> new file mode 100644
> index 0000000000..e80f8d9b31
> --- /dev/null
> +++ b/scsi/pr-manager.c
> @@ -0,0 +1,109 @@
> +/*
> + * Persistent reservation manager abstract class
> + *
> + * Copyright (c) 2017 Red Hat, Inc.
> + *
> + * Author: Paolo Bonzini <pbonzini@redhat.com>
> + *
> + * This code is licensed under the LGPL.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "block/aio.h"
> +#include "block/thread-pool.h"
> +#include "scsi/pr-manager.h"
> +#include "scsi/trace.h"
> +
> +#include <scsi/sg.h>

HACKING "1.2. Include directives" defines the order of #includes.  It
should be "qemu/osdep.h", <scsi/sg.h>, followed by all other QEMU
headers.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 07/10] io: add qio_channel_read/write_all
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all Paolo Bonzini
  2017-08-23  5:08   ` Fam Zheng
  2017-08-30 12:52   ` Daniel P. Berrange
@ 2017-08-30 14:33   ` Stefan Hajnoczi
  2 siblings, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 14:33 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, Daniel P . Berrange, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:29PM +0200, Paolo Bonzini wrote:
> @@ -315,6 +315,23 @@ ssize_t qio_channel_read(QIOChannel *ioc,
>                           Error **errp);
>  
>  /**
> + * qio_channel_read_all:
> + * @ioc: the channel object
> + * @buf: the memory region to read data into
> + * @buflen: the number of bytes to @buf
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Reads @buflen bytes into @buf, possibly blocking or (if the
> + * channel is non-blocking) yielding from the current coroutine
> + * multiple times until the entire content is read.  Otherwise
> + * behaves as qio_channel_read().
> + */
> +ssize_t coroutine_fn qio_channel_read_all(QIOChannel *ioc,

This function is not coroutine_fn.  It only assumes coroutine context
when called on a non-blocking socket.

> +                                          char *buf,
> +                                          size_t buflen,
> +                                          Error **errp);
> +
> +/**
>   * qio_channel_write:
>   * @ioc: the channel object
>   * @buf: the memory regions to send data from
> @@ -331,6 +348,23 @@ ssize_t qio_channel_write(QIOChannel *ioc,
>                            Error **errp);
>  
>  /**
> + * qio_channel_write_all:
> + * @ioc: the channel object
> + * @buf: the memory region to write data into
> + * @buflen: the number of bytes to @buf
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Writes @buflen bytes from @buf, possibly blocking or (if the
> + * channel is non-blocking) yielding from the current coroutine
> + * multiple times until the entire content is written.  Otherwise
> + * behaves as qio_channel_write().
> + */
> +ssize_t coroutine_fn qio_channel_write_all(QIOChannel *ioc,

This function is not coroutine_fn.  It only assumes coroutine context
when called on a non-blocking socket.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 08/10] scsi: build qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper Paolo Bonzini
  2017-08-22 14:34   ` Marc-André Lureau
  2017-08-24 15:45   ` Eric Blake
@ 2017-08-30 15:44   ` Stefan Hajnoczi
  2017-08-30 16:06   ` Stefan Hajnoczi
  3 siblings, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 15:44 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:30PM +0200, Paolo Bonzini wrote:
> diff --git a/docs/interop/pr-helper.rst b/docs/interop/pr-helper.rst
> new file mode 100644
> index 0000000000..765174c31f
> --- /dev/null
> +++ b/docs/interop/pr-helper.rst
> @@ -0,0 +1,78 @@
> +..
> +
> +======================================
> +Persistent reservation helper protocol
> +======================================
> +
> +QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
> +can delegate implementation of persistent reservations to an external
> +(and typically privilege) program.  Persistent Reservations allow

privileged

> diff --git a/scsi/pr-helper.h b/scsi/pr-helper.h
> new file mode 100644
> index 0000000000..2c7ccc9928
> --- /dev/null
> +++ b/scsi/pr-helper.h
> @@ -0,0 +1,13 @@

Do you want to license this file under the BSD license just in case
someone wants to copy it into an external helper implementation?  The
file is trivial but still.

> +#ifndef QEMU_PR_HELPER_H
> +#define QEMU_PR_HELPER_H 1
> +

Missing #include <stdint.h> for in32_t and uint8_t.

> +#include "qemu/osdep.h"
> +#include <getopt.h>
> +#include "qapi/error.h"
> +#include "qemu-common.h"
> +#include "qemu/cutils.h"
> +#include "qemu/main-loop.h"
> +#include "qemu/error-report.h"
> +#include "qemu/config-file.h"
> +#include "qemu/bswap.h"
> +#include "qemu/log.h"
> +#include "qemu/systemd.h"
> +#include "qapi/util.h"
> +#include "qapi/qmp/qstring.h"
> +#include "io/channel-socket.h"
> +#include "trace/control.h"
> +#include "qemu-version.h"
> +
> +#include "block/aio.h"
> +#include "block/thread-pool.h"
> +
> +#include "scsi/constants.h"
> +#include "scsi/utils.h"
> +#include "pr-helper.h"
> +#include <sys/ioctl.h>
> +#include <linux/dm-ioctl.h>
> +#include <scsi/sg.h>
> +
> +#ifdef CONFIG_LIBCAP
> +#include <cap-ng.h>
> +#endif
> +#include <pwd.h>
> +#include <grp.h>

#include ordering

> +static int prh_read(PRHelperClient *client, void *buf, int sz, Error **errp)
> +{
> +    while (sz > 0) {
> +        int *fds = NULL;
> +        size_t nfds = 0;
> +        int i;
> +        struct iovec iov;
> +        ssize_t n_read;
> +
> +        iov.iov_base = buf;
> +        iov.iov_len = sz;
> +        n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1,
> +                                        &fds, &nfds, errp);
> +
> +        if (n_read == QIO_CHANNEL_ERR_BLOCK) {
> +            qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN);
> +            continue;
> +        }
> +        if (n_read <= 0) {
> +            return n_read ? n_read : -1;

This assumes that client->fd == -1.  It's probably true on Linux but I'm
not sure.  What happens if the client sends an fd with a write that is
smaller than sz, and then follows up by closing the socket?  In the
worst case this would leak client->fd (the caller assumes it's -1 on
failure).

> +        }
> +
> +        /* Stash one file descriptor per request.  */
> +        if (nfds) {
> +            for (i = 0; i < nfds; i++) {
> +                if (client->fd == -1) {
> +                    client->fd = fds[i++];

i++ looks like a bug.  The loop is already iterating fds[i] so we don't
need to increment it.  This would leak the following file descriptor.

> +static void prh_co_entry(void *opaque)

coroutine_fn

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper Paolo Bonzini
  2017-08-23  5:01   ` Fam Zheng
@ 2017-08-30 16:06   ` Stefan Hajnoczi
  2017-08-30 16:37   ` Stefan Hajnoczi
  2 siblings, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 16:06 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:31PM +0200, Paolo Bonzini wrote:
> @@ -444,6 +740,11 @@ static int drop_privileges(void)
>                       CAP_SYS_RAWIO) < 0) {
>          return -1;
>      }
> +    /* For /dev/mapper/control ioctls */
> +    if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
> +                     CAP_SYS_ADMIN) < 0) {
> +        return -1;
> +    }

Only if mpath is being used?  This capability isn't necessary with
ordinary sg_io so it would be nice to avoid keeping it in that case.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 08/10] scsi: build qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper Paolo Bonzini
                     ` (2 preceding siblings ...)
  2017-08-30 15:44   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
@ 2017-08-30 16:06   ` Stefan Hajnoczi
  3 siblings, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 16:06 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:30PM +0200, Paolo Bonzini wrote:
> +#ifdef CONFIG_MPATH
> +    dm_init();
> +    multipath_pr_init();
> +#endif

This should be in the next patch.

Stefan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper Paolo Bonzini
  2017-08-23  5:01   ` Fam Zheng
  2017-08-30 16:06   ` Stefan Hajnoczi
@ 2017-08-30 16:37   ` Stefan Hajnoczi
  2017-09-11  9:14     ` [Qemu-devel] [Qemu-block] " Paolo Bonzini
  2 siblings, 1 reply; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 16:37 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:31PM +0200, Paolo Bonzini wrote:
> +static int multipath_pr_in(int fd, const uint8_t *cdb, uint8_t *sense,
> +                           uint8_t *data, int sz)
> +{
> +    int rq_servact = cdb[1];
> +    struct prin_resp resp;
> +    size_t written;
> +    int r;
> +
> +    switch (rq_servact) {
> +    case MPATH_PRIN_RKEY_SA:
> +    case MPATH_PRIN_RRES_SA:
> +    case MPATH_PRIN_RCAP_SA:
> +        break;
> +    case MPATH_PRIN_RFSTAT_SA:
> +        /* Nobody implements it anyway, so bail out. */
> +    default:
> +        /* Cannot parse any other output.  */
> +        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
> +        return CHECK_CONDITION;
> +    }
> +
> +    r = mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbose);
> +    if (r == MPATH_PR_SUCCESS) {
> +        switch (rq_servact) {

The case statements asssume sz has a certain minimum value.  I didn't
see a check anywhere that guarantees this.  It may be easier to hide the
client's sz value and instead use sizeof(client->data).  The caller can
worry about sz.

> +        case MPATH_PRIN_RKEY_SA:
> +        case MPATH_PRIN_RRES_SA: {
> +            struct prin_readdescr *out = &resp.prin_descriptor.prin_readkeys;
> +            stl_be_p(&data[0], out->prgeneration);
> +            stl_be_p(&data[4], out->additional_length);
> +            memcpy(&data[8], out->key_list, MIN(out->additional_length, sz - 8));

sz < 8 is possible, please handle this case.

> +            written = MIN(out->additional_length + 8, sz);
> +            break;
> +        }
> +        case MPATH_PRIN_RCAP_SA: {
> +            struct prin_capdescr *out = &resp.prin_descriptor.prin_readcap;
> +            stw_be_p(&data[0], out->length);
> +            data[2] = out->flags[0];
> +            data[3] = out->flags[1];
> +            stw_be_p(&data[4], out->pr_type_mask);
> +            written = MIN(6, sz);
> +            break;
> +        }
> +        default:
> +            scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE));
> +            return CHECK_CONDITION;
> +        }
> +        assert(written < sz);

Why is written == sz not allowed?

> +        memset(data + written, 0, sz - written);
> +    }
> +
> +    return mpath_reconstruct_sense(fd, r, sense);
> +}
> +
> +static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense,
> +                            const uint8_t *param, int sz)
> +{
> +    int rq_servact = cdb[1];
> +    int rq_scope = cdb[2] >> 4;
> +    int rq_type = cdb[2] & 0xf;
> +    struct prout_param_descriptor paramp;
> +    char transportids[PR_HELPER_DATA_SIZE];
> +    int r;
> +    int i, j;
> +
> +    switch (rq_servact) {
> +    case MPATH_PROUT_REG_SA:
> +    case MPATH_PROUT_RES_SA:
> +    case MPATH_PROUT_REL_SA:
> +    case MPATH_PROUT_CLEAR_SA:
> +    case MPATH_PROUT_PREE_SA:
> +    case MPATH_PROUT_PREE_AB_SA:
> +    case MPATH_PROUT_REG_IGN_SA:
> +    case MPATH_PROUT_REG_MOV_SA:
> +        break;
> +    default:
> +        /* Cannot parse any other input.  */
> +        scsi_build_sense(sense, SENSE_CODE(INVALID_FIELD));
> +        return CHECK_CONDITION;
> +    }
> +
> +    /* Convert input data, especially transport IDs, to the structs
> +     * used by libmpathpersist (which, of course, will immediately
> +     * do the opposite).
> +     */
> +    memset(&paramp, 0, sizeof(paramp));
> +    memcpy(&paramp.key, &param[0], 8);
> +    memcpy(&paramp.sa_key, &param[8], 8);
> +    paramp.sa_flags = param[10];
> +    for (i = PR_OUT_FIXED_PARAM_SIZE, j = 0; i < sz; ) {
> +        struct transportid *id = (struct transportid *) &transportids[j];
> +        int len;
> +
> +        id->format_code = param[i] & 0xc0;
> +        id->protocol_id = param[i] & 0x0f;
> +        switch (param[i] & 0xcf) {

At this point we know sz > PR_OUT_FIXED_PARAM_SIZE && i < sz.  I think
the following case statements can read beyond the end of client->data[]
because nothing checks sz before accessing param[].

Missing sz checks?

> +        case 0:
> +            /* FC transport.  */
> +            memcpy(id->n_port_name, &param[i + 8], 8);
> +            j += offsetof(struct transportid, n_port_name[8]);
> +            i += 24;
> +            break;
> +        case 3:
> +        case 0x43:
> +            /* iSCSI transport.  */
> +            len = lduw_be_p(&param[i + 2]);
> +            if (len > 252 || (len & 3)) {

int len can be negative here :(.  Please use the size_t type - it's
unsigned and used by memchr(3)/memcpy(3).

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper
  2017-08-22 13:18 ` [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper Paolo Bonzini
  2017-08-23  4:49   ` Fam Zheng
@ 2017-08-30 16:58   ` Stefan Hajnoczi
  1 sibling, 0 replies; 48+ messages in thread
From: Stefan Hajnoczi @ 2017-08-30 16:58 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, famz, qemu-block

On Tue, Aug 22, 2017 at 03:18:32PM +0200, Paolo Bonzini wrote:
> +/* Called with lock held.  */
> +static int pr_manager_helper_read(PRManagerHelper *pr_mgr,
> +                                  void *buf, int sz, Error **errp)
> +{
> +    ssize_t r = qio_channel_read_all(pr_mgr->ioc, buf, sz, errp);
> +
> +    if (r < 0) {
> +        object_unref(OBJECT(pr_mgr->ioc));
> +        pr_mgr->ioc = NULL;
> +        return r;
> +    }
> +
> +    return r < 0 ? r : 0;

At this point we know r >= 0:

  return r;

> +    if (pr_manager_helper_read(pr_mgr, &resp, sizeof(resp), NULL) < 0) {
> +        ret = -EINVAL;
> +        goto out;
> +    }

resp.result is big-endian and accessed without byteswaps below.  We
need:

  resp.result = be32_to_host(resp.result);

> +    if (expected_dir == SG_DXFER_FROM_DEV && resp.result == 0) {
> +        if (pr_manager_helper_read(pr_mgr, io_hdr->dxferp, len, NULL) < 0) {
> +            ret = -EINVAL;
> +            goto out;
> +        }
> +    }
> +
> +    io_hdr->status = resp.result;
> +    if (resp.result == CHECK_CONDITION) {
> +        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
> +        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, PR_HELPER_SENSE_SIZE);
> +        memcpy(io_hdr->sbp, resp.sense, io_hdr->sb_len_wr);
> +    }
> +
> +out:
> +    if (ret < 0) {
> +        int sense_len = scsi_build_sense(io_hdr->sbp,
> +                                         SENSE_CODE(LUN_COMM_FAILURE));
> +        io_hdr->driver_status = SG_ERR_DRIVER_SENSE;
> +        io_hdr->sb_len_wr = MIN(io_hdr->mx_sb_len, sense_len);
> +        io_hdr->status = CHECK_CONDITION;
> +    }
> +    qemu_mutex_unlock(&pr_mgr->lock);
> +    return ret;
> +}
> +static void pr_manager_helper_instance_finalize(Object *obj)
> +{
> +    PRManagerHelper *pr_mgr = PR_MANAGER_HELPER(obj);
> +
> +    g_free(pr_mgr->path);

Double free, the "path" property already has a release function that
frees the string.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper
  2017-08-30 16:37   ` Stefan Hajnoczi
@ 2017-09-11  9:14     ` Paolo Bonzini
  0 siblings, 0 replies; 48+ messages in thread
From: Paolo Bonzini @ 2017-09-11  9:14 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: famz, qemu-devel, qemu-block

On 30/08/2017 18:37, Stefan Hajnoczi wrote:
> 
> The case statements asssume sz has a certain minimum value.  I didn't
> see a check anywhere that guarantees this.  It may be easier to hide the
> client's sz value and instead use sizeof(client->data).  The caller can
> worry about sz.

Makes sense.  OUT needs the client sz, but IN doesn't and it gets in the
way.  This lets me just assert in multipath_pr_in that sz is large enough.

>> +    /* Convert input data, especially transport IDs, to the structs
>> +     * used by libmpathpersist (which, of course, will immediately
>> +     * do the opposite).
>> +     */
>> +    memset(&paramp, 0, sizeof(paramp));
>> +    memcpy(&paramp.key, &param[0], 8);
>> +    memcpy(&paramp.sa_key, &param[8], 8);
>> +    paramp.sa_flags = param[10];
>> +    for (i = PR_OUT_FIXED_PARAM_SIZE, j = 0; i < sz; ) {
>> +        struct transportid *id = (struct transportid *) &transportids[j];
>> +        int len;
>> +
>> +        id->format_code = param[i] & 0xc0;
>> +        id->protocol_id = param[i] & 0x0f;
>> +        switch (param[i] & 0xcf) {
> At this point we know sz > PR_OUT_FIXED_PARAM_SIZE && i < sz.  I think
> the following case statements can read beyond the end of client->data[]
> because nothing checks sz before accessing param[].
> 
> Missing sz checks?

There is a transport id length field that has to be checked against sz,
indeed.  After doing that, the for loop is fine (though the initial
index is wrong, because PR_OUT_FIXED_PARAM_SIZE points to the length
field and the transport ids are at PR_OUT_FIXED_PARAM_SIZE + 4).

>> +            /* iSCSI transport.  */
>> +            len = lduw_be_p(&param[i + 2]);
>> +            if (len > 252 || (len & 3)) {
> 
> int len can be negative here .  Please use the size_t type - it's
> unsigned and used by memchr(3)/memcpy(3).

Can it? lduw_be_p reads 16 bits (and it's unsigned as the name says).

Paolo

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2017-09-11  9:14 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-22 13:18 [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers Paolo Bonzini
2017-08-22 13:18 ` [Qemu-devel] [PATCH 01/10] scsi: rename scsi_convert_sense Paolo Bonzini
2017-08-22 13:38   ` Philippe Mathieu-Daudé
2017-08-22 13:18 ` [Qemu-devel] [PATCH 02/10] scsi: move non-emulation specific code to scsi/ Paolo Bonzini
2017-08-22 13:34   ` Philippe Mathieu-Daudé
2017-08-22 13:18 ` [Qemu-devel] [PATCH 03/10] scsi: introduce scsi_build_sense Paolo Bonzini
2017-08-22 13:35   ` Philippe Mathieu-Daudé
2017-08-30 13:39   ` Stefan Hajnoczi
2017-08-22 13:18 ` [Qemu-devel] [PATCH 04/10] scsi: introduce sg_io_sense_from_errno Paolo Bonzini
2017-08-22 13:45   ` Philippe Mathieu-Daudé
2017-08-22 13:53     ` Paolo Bonzini
2017-08-30 13:41   ` Stefan Hajnoczi
2017-08-22 13:18 ` [Qemu-devel] [PATCH 05/10] scsi: move block/scsi.h to include/scsi/constants.h Paolo Bonzini
2017-08-22 13:37   ` Philippe Mathieu-Daudé
2017-08-30 13:41   ` Stefan Hajnoczi
2017-08-22 13:18 ` [Qemu-devel] [PATCH 06/10] scsi, file-posix: add support for persistent reservation management Paolo Bonzini
2017-08-23  4:13   ` Fam Zheng
2017-08-23  6:56     ` Paolo Bonzini
2017-08-24 15:37   ` Eric Blake
2017-08-24 15:47     ` Paolo Bonzini
2017-08-30 12:59   ` Daniel P. Berrange
2017-08-30 14:26   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2017-08-22 13:18 ` [Qemu-devel] [PATCH 07/10] io: add qio_channel_read/write_all Paolo Bonzini
2017-08-23  5:08   ` Fam Zheng
2017-08-23  6:54     ` Paolo Bonzini
2017-08-30 12:52   ` Daniel P. Berrange
2017-08-30 14:33   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2017-08-22 13:18 ` [Qemu-devel] [PATCH 08/10] scsi: build qemu-pr-helper Paolo Bonzini
2017-08-22 14:34   ` Marc-André Lureau
2017-08-22 16:04     ` Paolo Bonzini
2017-08-24 15:45   ` Eric Blake
2017-08-30 15:44   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2017-08-30 16:06   ` Stefan Hajnoczi
2017-08-22 13:18 ` [Qemu-devel] [PATCH 09/10] scsi: add multipath support to qemu-pr-helper Paolo Bonzini
2017-08-23  5:01   ` Fam Zheng
2017-08-23  6:50     ` Paolo Bonzini
2017-08-30 16:06   ` Stefan Hajnoczi
2017-08-30 16:37   ` Stefan Hajnoczi
2017-09-11  9:14     ` [Qemu-devel] [Qemu-block] " Paolo Bonzini
2017-08-22 13:18 ` [Qemu-devel] [PATCH 10/10] scsi: add persistent reservation manager using qemu-pr-helper Paolo Bonzini
2017-08-23  4:49   ` Fam Zheng
2017-08-23  6:55     ` Paolo Bonzini
2017-08-23  7:48     ` Paolo Bonzini
2017-08-30 16:58   ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2017-08-22 13:48 ` [Qemu-devel] [RFC PATCH 00/10] scsi, block: introduce persistent reservation managers no-reply
2017-08-22 13:50 ` no-reply
2017-08-22 13:50 ` no-reply
2017-08-22 13:51 ` no-reply

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.