From nobody Wed Feb 11 02:33:28 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1506037118681167.98767977511568; Thu, 21 Sep 2017 16:38:38 -0700 (PDT) Received: from localhost ([::1]:55953 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dvB3F-0006Q0-T1 for importer@patchew.org; Thu, 21 Sep 2017 19:38:37 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37550) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dvAie-00056O-HH for qemu-devel@nongnu.org; Thu, 21 Sep 2017 19:17:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dvAib-0004bZ-S0 for qemu-devel@nongnu.org; Thu, 21 Sep 2017 19:17:20 -0400 Received: from mail-wr0-x234.google.com ([2a00:1450:400c:c0c::234]:43250) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dvAib-0004aC-HR for qemu-devel@nongnu.org; Thu, 21 Sep 2017 19:17:17 -0400 Received: by mail-wr0-x234.google.com with SMTP id a43so5653948wrc.0 for ; Thu, 21 Sep 2017 16:17:17 -0700 (PDT) Received: from 640k.lan (dynamic-adsl-78-12-246-117.clienti.tiscali.it. [78.12.246.117]) by smtp.gmail.com with ESMTPSA id u186sm2596278wmd.19.2017.09.21.16.17.14 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 21 Sep 2017 16:17:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:subject:date:message-id:in-reply-to:references; bh=FL8GUsBukO18xdzZWRurnP/uhIY+PATxb0V9Bq4ptLQ=; b=efZwsG1clLNc+YCXyMvhwQB0rVJSZW8eqkNIJypcc8yr8Fv9/7+RcYgNjev3RZwgsj mE5ODEl/vZtdGgiFu03HMVkLK4YeMN7IqDXxSHE0zqi1i9Q08KNVkJRSm+g3rk1PAjmB 8Ek8HC8C2G9fPZpFxemecyGyR55ckR0B6PMLcBKBX4XqSqsvx+Zp+lG1pu2ULE0wMBvf GWWXWfrCXXykvc58chPJPEZOMXHa/cv0sK8G9UH+TZDguXBcxVPmC7rjpgULMIp+/EdN AAwIPh8+gDcaw4BB0H/APUVrSSj3Nqt/Wz4CKbrmNsHvK2T4MH39lgoTf00yQGrMQPuq oj0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:subject:date:message-id :in-reply-to:references; bh=FL8GUsBukO18xdzZWRurnP/uhIY+PATxb0V9Bq4ptLQ=; b=MXvJfDkuTC7EB/70IYgJ6AVzwG2vZrjSxrcJ/im/zGMaHgQcvvjLLuo7utpWI4d1k5 g45JwShvXUWwCIw0tO0Px/jjvHQR9dKOBP1xiPQalh+Ua9tksT4D/5nwYRcfQHnQLLth XXWFvMnhD0hrZ7l2IinJVUAsfCt+Uvmg5NkMOPFuu1nsI5SqZvy+b8oQqHeaidET7Rxn 8D2h3MSqIsZrHmlq6+fY8k9+vdBW/sZxabBct7RZ22Ffw45gHFUaG18VJrqwcKkQTff9 TOettz1y/b4AB2NG13LGgEr9zdwU9SSj+Qork/d1WwE1mQO4tj299MmrEcuVb049zXh4 vitQ== X-Gm-Message-State: AHPjjUi1QWe8KltjVgIV19H7L40/B+0OpBVXZprW/Tu/KZqSnHbUW6lo mhiDz0z29JjnnSUzYTtcWzIHwIsh X-Google-Smtp-Source: AOwi7QCAUZmeUvHOiY42TFQl5gYGhlS+mztXsQMpExFMl5Pl0uL/h5oRFBN9n9fMq2rfnDsRaz1SxQ== X-Received: by 10.223.133.164 with SMTP id 33mr3156135wrt.179.1506035835800; Thu, 21 Sep 2017 16:17:15 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Fri, 22 Sep 2017 01:16:35 +0200 Message-Id: <1506035800-30509-28-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1506035800-30509-1-git-send-email-pbonzini@redhat.com> References: <1506035800-30509-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c0c::234 Subject: [Qemu-devel] [PULL 27/32] scsi: add multipath support to qemu-pr-helper X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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 --- Makefile | 3 + configure | 58 ++++++++- docs/pr-manager.rst | 27 ++++ include/scsi/utils.h | 4 + scsi/qemu-pr-helper.c | 346 ++++++++++++++++++++++++++++++++++++++++++++++= +++- scsi/utils.c | 10 ++ 6 files changed, 442 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 8406aeb..4eb4037 100644 --- a/Makefile +++ b/Makefile @@ -373,6 +373,9 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-= helper.o fsdev/9p-marshal fsdev/virtfs-proxy-helper$(EXESUF): LIBS +=3D -lcap =20 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 +=3D -ludev -lmultipath -lmpathpersist +endif =20 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 c76ce3c..4ca32f5 100755 --- a/configure +++ b/configure @@ -290,6 +290,7 @@ netmap=3D"no" sdl=3D"" sdlabi=3D"" virtfs=3D"" +mpath=3D"" vnc=3D"yes" sparse=3D"no" vde=3D"" @@ -936,6 +937,10 @@ for opt do ;; --enable-virtfs) virtfs=3D"yes" ;; + --disable-mpath) mpath=3D"no" + ;; + --enable-mpath) mpath=3D"yes" + ;; --disable-vnc) vnc=3D"no" ;; --enable-vnc) vnc=3D"yes" @@ -1479,6 +1484,7 @@ disabled with --disable-FEATURE, default is enabled i= f 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) @@ -3300,6 +3306,30 @@ else fi =20 ########################################## +# libmpathpersist probe + +if test "$mpath" !=3D "no" ; then + cat > $TMPC < +#include +unsigned mpath_mx_alloc_len =3D 1024; +int logsink; +int main(void) { + struct udev *udev =3D udev_new(); + mpath_lib_init(udev); + return 0; +} +EOF + if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then + mpathpersist=3Dyes + else + mpathpersist=3Dno + fi +else + mpathpersist=3Dno +fi + +########################################## # libcap probe =20 if test "$cap" !=3D "no" ; then @@ -5034,16 +5064,34 @@ if test "$want_tools" =3D "yes" ; then fi fi if test "$softmmu" =3D yes ; then - if test "$virtfs" !=3D no ; then - if test "$cap" =3D yes && test "$linux" =3D yes && test "$attr" =3D ye= s ; then + if test "$linux" =3D yes; then + if test "$virtfs" !=3D no && test "$cap" =3D yes && test "$attr" =3D y= es ; then virtfs=3Dyes tools=3D"$tools fsdev/virtfs-proxy-helper\$(EXESUF)" else if test "$virtfs" =3D 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=3Dno fi + if test "$mpath" !=3D no && test "$mpathpersist" =3D yes ; then + mpath=3Dyes + tools=3D"$tools mpath/qemu-mpath-helper\$(EXESUF)" + else + if test "$mpath" =3D yes; then + error_exit "Multipath requires libmpathpersist devel" + fi + mpath=3Dno + fi + else + if test "$virtfs" =3D yes; then + error_exit "VirtFS is supported only on Linux" + fi + virtfs=3Dno + if test "$mpath" =3D yes; then + error_exit "Multipath is supported only on Linux" + fi + mpath=3Dno fi fi =20 @@ -5289,6 +5337,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" =3D "yes" ; then echo "VNC SASL support $vnc_sasl" @@ -5732,6 +5781,9 @@ fi if test "$virtfs" =3D "yes" ; then echo "CONFIG_VIRTFS=3Dy" >> $config_host_mak fi +if test "$mpath" =3D "yes" ; then + echo "CONFIG_MPATH=3Dy" >> $config_host_mak +fi if test "$vhost_scsi" =3D "yes" ; then echo "CONFIG_VHOST_SCSI=3Dy" >> $config_host_mak fi diff --git a/docs/pr-manager.rst b/docs/pr-manager.rst index 7107e59..9b1de19 100644 --- a/docs/pr-manager.rst +++ b/docs/pr-manager.rst @@ -60,6 +60,7 @@ system service and supports the following option: =20 -d, --daemon run in the background -q, --quiet decrease verbosity +-v, --verbose increase verbosity -f, --pidfile=3Dpath PID file when running as a daemon -k, --socket=3Dpath path to the socket -T, --trace=3Dtrace-opts tracing options @@ -82,3 +83,29 @@ its operation. To do this, add the following options: =20 -u, --user=3Duser user to drop privileges to -g, --group=3Dgroup 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 d301b31..00a4bdb 100644 --- a/include/scsi/utils.h +++ b/include/scsi/utils.h @@ -72,10 +72,14 @@ extern const struct SCSISense sense_code_IO_ERROR; 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, LUN Communication failure */ +extern const struct SCSISense sense_code_LUN_COMM_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; +/* Unit attention, SCSI bus reset */ +extern const struct SCSISense sense_code_SCSI_BUS_RESET; /* 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 */ diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index 9662ede..3f08ab1 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -30,6 +30,12 @@ #include #include =20 +#ifdef CONFIG_MPATH +#include +#include +#include +#endif + #include "qapi/error.h" #include "qemu-common.h" #include "qemu/cutils.h" @@ -60,6 +66,7 @@ static enum { RUNNING, TERMINATE, TERMINATING } state; static QIOChannelSocket *server_ioc; static int server_watch; static int num_active_sockets =3D 1; +static int noisy; static int verbose; =20 #ifdef CONFIG_LIBCAP @@ -171,9 +178,316 @@ static int do_sgio(int fd, const uint8_t *cdb, uint8_= t *sense, return r; } =20 +/* Device mapper interface */ + +#ifdef CONFIG_MPATH +#define CONTROL_PATH "/dev/mapper/control" + +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] =3D DM_VERSION_MAJOR; + d.dm.version[1] =3D 0; + d.dm.version[2] =3D 0; + d.dm.data_size =3D 1024; + d.dm.data_start =3D 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 =3D fstat(fd, &st); + if (r < 0) { + perror("fstat"); + exit(1); + } + + dm->dev =3D st.st_rdev; + return dm_ioctl(ioc, dm); +} + +static void dm_init(void) +{ + control_fd =3D open(CONTROL_PATH, O_RDWR); + if (control_fd < 0) { + perror("Cannot open " CONTROL_PATH); + exit(1); + } + struct dm_ioctl dm =3D { 0 }; + if (!dm_ioctl(DM_VERSION, &dm)) { + perror("ioctl"); + exit(1); + } + if (dm.version[0] !=3D DM_VERSION_MAJOR) { + fprintf(stderr, "Unsupported device mapper interface"); + exit(1); + } +} + +/* Variables required by libmultipath and libmpathpersist. */ +QEMU_BUILD_BUG_ON(PR_HELPER_DATA_SIZE > MPATH_MAX_PARAM_LEN); +unsigned mpath_mx_alloc_len =3D PR_HELPER_DATA_SIZE; +int logsink; + +static void multipath_pr_init(void) +{ + static struct udev *udev; + + udev =3D udev_new(); + mpath_lib_init(udev); +} + +static int is_mpath(int fd) +{ + struct dm_ioctl dm =3D { .flags =3D DM_NOFLUSH_FLAG }; + struct dm_target_spec *tgt; + + tgt =3D dm_dev_ioctl(fd, DM_TABLE_STATUS, &dm); + if (!tgt) { + if (errno =3D=3D 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] =3D { TEST_UNIT_READY }; + int sz =3D 0; + return do_sgio(fd, cdb, sense, NULL, &sz, 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 =3D 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 =3D mpath_persistent_reserve_in(fd, rq_servact, &resp, noisy, verbos= e); + if (r =3D=3D MPATH_PR_SUCCESS) { + switch (rq_servact) { + case MPATH_PRIN_RKEY_SA: + case MPATH_PRIN_RRES_SA: { + struct prin_readdescr *out =3D &resp.prin_descriptor.prin_read= keys; + assert(sz >=3D 8); + written =3D MIN(out->additional_length + 8, sz); + stl_be_p(&data[0], out->prgeneration); + stl_be_p(&data[4], out->additional_length); + memcpy(&data[8], out->key_list, written - 8); + break; + } + case MPATH_PRIN_RCAP_SA: { + struct prin_capdescr *out =3D &resp.prin_descriptor.prin_readc= ap; + assert(sz >=3D 6); + written =3D 6; + stw_be_p(&data[0], out->length); + data[2] =3D out->flags[0]; + data[3] =3D out->flags[1]; + stw_be_p(&data[4], out->pr_type_mask); + break; + } + default: + scsi_build_sense(sense, SENSE_CODE(INVALID_OPCODE)); + return CHECK_CONDITION; + } + assert(written <=3D 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 =3D cdb[1]; + int rq_scope =3D cdb[2] >> 4; + int rq_type =3D cdb[2] & 0xf; + struct prout_param_descriptor paramp; + char transportids[PR_HELPER_DATA_SIZE]; + int r; + + 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: + break; + case MPATH_PROUT_REG_MOV_SA: + /* Not supported by struct prout_param_descriptor. */ + 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(¶mp, 0, sizeof(paramp)); + memcpy(¶mp.key, ¶m[0], 8); + memcpy(¶mp.sa_key, ¶m[8], 8); + paramp.sa_flags =3D param[10]; + if (sz > PR_OUT_FIXED_PARAM_SIZE) { + size_t transportid_len; + int i, j; + if (sz < PR_OUT_FIXED_PARAM_SIZE + 4) { + scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM_LEN)); + return CHECK_CONDITION; + } + transportid_len =3D ldl_be_p(¶m[24]) + PR_OUT_FIXED_PARAM_SIZE= + 4; + if (transportid_len > sz) { + scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); + return CHECK_CONDITION; + } + for (i =3D PR_OUT_FIXED_PARAM_SIZE + 4, j =3D 0; i < transportid_l= en; ) { + struct transportid *id =3D (struct transportid *) &transportid= s[j]; + int len; + + id->format_code =3D param[i] & 0xc0; + id->protocol_id =3D param[i] & 0x0f; + switch (param[i] & 0xcf) { + case 0: + /* FC transport. */ + if (i + 24 > transportid_len) { + goto illegal_req; + } + memcpy(id->n_port_name, ¶m[i + 8], 8); + j +=3D offsetof(struct transportid, n_port_name[8]); + i +=3D 24; + break; + case 3: + case 0x43: + /* iSCSI transport. */ + len =3D lduw_be_p(¶m[i + 2]); + if (len > 252 || (len & 3) || i + len + 4 > transportid_le= n) { + /* For format code 00, the standard says the maximum i= s 223 + * plus the NUL terminator. For format code 01 there = is no + * maximum length, but libmpathpersist ignores the fir= st + * byte of id->iscsi_name so our maximum is 252. + */ + goto illegal_req; + } + if (memchr(¶m[i + 4], 0, len) =3D=3D NULL) { + goto illegal_req; + } + memcpy(id->iscsi_name, ¶m[i + 2], len + 2); + j +=3D offsetof(struct transportid, iscsi_name[len + 2]); + i +=3D len + 4; + break; + case 6: + /* SAS transport. */ + if (i + 24 > transportid_len) { + goto illegal_req; + } + memcpy(id->sas_address, ¶m[i + 4], 8); + j +=3D offsetof(struct transportid, sas_address[8]); + i +=3D 24; + break; + default: + illegal_req: + scsi_build_sense(sense, SENSE_CODE(INVALID_PARAM)); + return CHECK_CONDITION; + } + + paramp.trnptid_list[paramp.num_transportid++] =3D id; + } + } + + r =3D mpath_persistent_reserve_out(fd, rq_servact, rq_scope, rq_type, + ¶mp, 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 *resp_sz) { +#ifdef CONFIG_MPATH + if (is_mpath(fd)) { + /* multipath_pr_in fills the whole input buffer. */ + return multipath_pr_in(fd, cdb, sense, data, *resp_sz); + } +#endif + return do_sgio(fd, cdb, sense, data, resp_sz, SG_DXFER_FROM_DEV); } @@ -181,7 +495,14 @@ 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) { - int resp_sz =3D sz; + int resp_sz; +#ifdef CONFIG_MPATH + if (is_mpath(fd)) { + return multipath_pr_out(fd, cdb, sense, param, sz); + } +#endif + + resp_sz =3D sz; return do_sgio(fd, cdb, sense, (uint8_t *)param, &resp_sz, SG_DXFER_TO_DEV); } @@ -491,6 +812,14 @@ static int drop_privileges(void) return -1; } =20 +#ifdef CONFIG_MPATH + /* For /dev/mapper/control ioctls */ + if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, + CAP_SYS_ADMIN) < 0) { + return -1; + } +#endif + /* Change user/group id, retaining the capabilities. Because file des= criptors * are passed via SCM_RIGHTS, we don't need supplementary groups (and = in * fact the helper can run as "nobody"). @@ -507,7 +836,7 @@ static int drop_privileges(void) =20 int main(int argc, char **argv) { - const char *sopt =3D "hVk:fdT:u:g:q"; + const char *sopt =3D "hVk:fdT:u:g:vq"; struct option lopt[] =3D { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, @@ -517,10 +846,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 =3D 0; + int loglevel =3D 1; int quiet =3D 0; char ch; Error *local_err =3D NULL; @@ -597,6 +928,9 @@ int main(int argc, char **argv) case 'q': quiet =3D 1; break; + case 'v': + ++loglevel; + break; case 'T': g_free(trace_file); trace_file =3D trace_opt_parse(optarg); @@ -616,7 +950,8 @@ int main(int argc, char **argv) } =20 /* set verbosity */ - verbose =3D !quiet; + noisy =3D !quiet && (loglevel >=3D 3); + verbose =3D quiet ? 0 : MIN(loglevel, 3); =20 if (!trace_init_backends()) { exit(EXIT_FAILURE); @@ -624,6 +959,11 @@ int main(int argc, char **argv) trace_init_file(trace_file); qemu_set_log(LOG_TRACE); =20 +#ifdef CONFIG_MPATH + dm_init(); + multipath_pr_init(); +#endif + socket_activation =3D check_socket_activation(); if (socket_activation =3D=3D 0) { SocketAddress saddr =3D { diff --git a/scsi/utils.c b/scsi/utils.c index fab60bd..5684951 100644 --- a/scsi/utils.c +++ b/scsi/utils.c @@ -206,6 +206,11 @@ const struct SCSISense sense_code_OVERLAPPED_COMMANDS = =3D { .key =3D ABORTED_COMMAND, .asc =3D 0x4e, .ascq =3D 0x00 }; =20 +/* Command aborted, LUN Communication Failure */ +const struct SCSISense sense_code_LUN_COMM_FAILURE =3D { + .key =3D ABORTED_COMMAND, .asc =3D 0x08, .ascq =3D 0x00 +}; + /* Unit attention, Capacity data has changed */ const struct SCSISense sense_code_CAPACITY_CHANGED =3D { .key =3D UNIT_ATTENTION, .asc =3D 0x2a, .ascq =3D 0x09 @@ -216,6 +221,11 @@ const struct SCSISense sense_code_RESET =3D { .key =3D UNIT_ATTENTION, .asc =3D 0x29, .ascq =3D 0x00 }; =20 +/* Unit attention, SCSI bus reset */ +const struct SCSISense sense_code_SCSI_BUS_RESET =3D { + .key =3D UNIT_ATTENTION, .asc =3D 0x29, .ascq =3D 0x02 +}; + /* Unit attention, No medium */ const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM =3D { .key =3D UNIT_ATTENTION, .asc =3D 0x3a, .ascq =3D 0x00 --=20 1.8.3.1