[libvirt] [RFC] proposal for libiscsi storage pool

Hi everybody! I am starting this thread to discuss a new storage pool backend for iSCSI using libiSCSI. There already is an iSCSI backend, however, it uses iscsiadm binary to execute the desired operation. The binary can be spawned multiple times during single execution of an API. This is suboptimal. Moreover the iscsi storage pool is mapped by the kernel into a block device in /dev/. Iscsiadm makes operations directly on that block device. Libiscsi on the other hand is sending the commands directly to a remote iscsi portal. According to that, to be able to use a storage pool using libiscsi we have to implement the storage pool backend entirely. What we would have: Pool XML using iscsiadm: <pool type="iscsi" mode="host"> <name>virtimages</name> <source> <host name="iscsi.example.com"/> <device path="iqn.2013-06.com.example:iscsi-pool"/> <auth type='chap' username='myuser'> <secret usage='libvirtiscsi'/> </auth> </source> <target> <path>/dev/disk/by-path</path> </target> </pool> Pool XML using libiscsi: <pool type="iscsi" mode="direct"> <name>virtimages</name> <source> <host name="iscsi.example.com"/> <device path="iqn.2013-06.com.example:iscsi-pool"/> <auth type='chap' username='myuser'> <secret usage='libvirtiscsi'/> </auth> </source> </pool> The change that occurs is having a direct mode that will lead to the libiscsi backend and the host mode that will lead to the actual backend using iscsiadm. To tie the backend to the front was thinking about adding something like VIR_STORAGE_POOL_LIBISCSI to storage_conf. About the domain XML only accept: <disk type='volume' device='disk'> <driver name='qemu' type='raw'/> <source pool='iscsi-pool' volume='unit:0:0:2' mode='direct'/> <target dev='vdc' bus='virtio'/> </disk> would be great using a switch case on VIR_STORAGE_POOL_LIBISCSI inside domain_conf. Best regards, -- Clementine Hayat

On 06/04/2018 05:54 PM, Clementine Hayat wrote:
Hi everybody!
I am starting this thread to discuss a new storage pool backend for iSCSI using libiSCSI.
There already is an iSCSI backend, however, it uses iscsiadm binary to execute the desired operation. The binary can be spawned multiple times during single execution of an API. This is suboptimal.
Moreover the iscsi storage pool is mapped by the kernel into a block device in /dev/. Iscsiadm makes operations directly on that block device. Libiscsi on the other hand is sending the commands directly to a remote iscsi portal. According to that, to be able to use a storage pool using libiscsi we have to implement the storage pool backend entirely.
What we would have:
Pool XML using iscsiadm:
<pool type="iscsi" mode="host">
This sounds reasonable. However, I think for backwards compatibility we need to treat <pool type="iscsi"/> as mode="host". That is, if we don't parse any @mode, we must assume "host" and then we can format it into the XML back.
<name>virtimages</name> <source> <host name="iscsi.example.com"/> <device path="iqn.2013-06.com.example:iscsi-pool"/> <auth type='chap' username='myuser'> <secret usage='libvirtiscsi'/> </auth> </source> <target> <path>/dev/disk/by-path</path> </target> </pool>
Pool XML using libiscsi:
<pool type="iscsi" mode="direct"> <name>virtimages</name> <source> <host name="iscsi.example.com"/> <device path="iqn.2013-06.com.example:iscsi-pool"/> <auth type='chap' username='myuser'> <secret usage='libvirtiscsi'/> </auth> </source> </pool>
The change that occurs is having a direct mode that will lead to the libiscsi backend and the host mode that will lead to the actual backend using iscsiadm.
To tie the backend to the front was thinking about adding something like VIR_STORAGE_POOL_LIBISCSI to storage_conf.
Yes, that is one of the changes needed. Sounds right.
About the domain XML only accept:
<disk type='volume' device='disk'> <driver name='qemu' type='raw'/> <source pool='iscsi-pool' volume='unit:0:0:2' mode='direct'/> <target dev='vdc' bus='virtio'/> </disk>
would be great using a switch case on VIR_STORAGE_POOL_LIBISCSI inside domain_conf.
Yes. This is one of the places that need change. We tend to use typecasted switch()-es for exactly this reason - to help contributors identify places of interest when adding new type of something (not only storage pool). Michal

On Tue, Jun 05, 2018 at 09:37:06 +0200, Michal Privoznik wrote:
On 06/04/2018 05:54 PM, Clementine Hayat wrote:
Hi everybody!
I am starting this thread to discuss a new storage pool backend for iSCSI using libiSCSI.
Thanks a lot for working on this, I'm looking forward to switching to the new pool.
There already is an iSCSI backend, however, it uses iscsiadm binary to execute the desired operation. The binary can be spawned multiple times during single execution of an API. This is suboptimal.
Moreover the iscsi storage pool is mapped by the kernel into a block device in /dev/. Iscsiadm makes operations directly on that block device. Libiscsi on the other hand is sending the commands directly to a remote iscsi portal. According to that, to be able to use a storage pool using libiscsi we have to implement the storage pool backend entirely.
What we would have:
Pool XML using iscsiadm:
<pool type="iscsi" mode="host">
This sounds reasonable. However, I think for backwards compatibility we need to treat <pool type="iscsi"/> as mode="host". That is, if we don't parse any @mode, we must assume "host" and then we can format it into the XML back.
On the other hand, we could perhaps just introduce a new pool type, something like <pool type='iscsi-direct'>...</pool> which would match with VIR_STORAGE_POOL_ISCSI_DIRECT and avoid the black magic of translating type="iscsi" to VIR_STORAGE_POOL_LIBISCSI or VIR_STORAGE_POOL_ISCSI depending on the mode attribute. Not to mention that old libvirt would just completely ignore the mode attribute, but it would complain about unknown pool type. Jirka

On Tue, Jun 05, 2018 at 10:14:15AM +0200, Jiri Denemark wrote:
On Tue, Jun 05, 2018 at 09:37:06 +0200, Michal Privoznik wrote:
On 06/04/2018 05:54 PM, Clementine Hayat wrote:
Hi everybody!
I am starting this thread to discuss a new storage pool backend for iSCSI using libiSCSI.
Thanks a lot for working on this, I'm looking forward to switching to the new pool.
There already is an iSCSI backend, however, it uses iscsiadm binary to execute the desired operation. The binary can be spawned multiple times during single execution of an API. This is suboptimal.
Moreover the iscsi storage pool is mapped by the kernel into a block device in /dev/. Iscsiadm makes operations directly on that block device. Libiscsi on the other hand is sending the commands directly to a remote iscsi portal. According to that, to be able to use a storage pool using libiscsi we have to implement the storage pool backend entirely.
What we would have:
Pool XML using iscsiadm:
<pool type="iscsi" mode="host">
This sounds reasonable. However, I think for backwards compatibility we need to treat <pool type="iscsi"/> as mode="host". That is, if we don't parse any @mode, we must assume "host" and then we can format it into the XML back.
On the other hand, we could perhaps just introduce a new pool type, something like
<pool type='iscsi-direct'>...</pool>
which would match with VIR_STORAGE_POOL_ISCSI_DIRECT and avoid the black magic of translating type="iscsi" to VIR_STORAGE_POOL_LIBISCSI or VIR_STORAGE_POOL_ISCSI depending on the mode attribute. Not to mention that old libvirt would just completely ignore the mode attribute, but it would complain about unknown pool type.
I think we need to consider the bigger picture too - the idea of using a userspace client vs kernel client applies to the RBD and GlusterFS pools too. I'm not really convinced that adding new pool types for each case makes sense. 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 :|

On Tue, Jun 05, 2018 at 09:31:09 +0100, Daniel P. Berrangé wrote:
On Tue, Jun 05, 2018 at 10:14:15AM +0200, Jiri Denemark wrote:
On Tue, Jun 05, 2018 at 09:37:06 +0200, Michal Privoznik wrote:
On 06/04/2018 05:54 PM, Clementine Hayat wrote:
Hi everybody!
I am starting this thread to discuss a new storage pool backend for iSCSI using libiSCSI.
Thanks a lot for working on this, I'm looking forward to switching to the new pool.
There already is an iSCSI backend, however, it uses iscsiadm binary to execute the desired operation. The binary can be spawned multiple times during single execution of an API. This is suboptimal.
Moreover the iscsi storage pool is mapped by the kernel into a block device in /dev/. Iscsiadm makes operations directly on that block device. Libiscsi on the other hand is sending the commands directly to a remote iscsi portal. According to that, to be able to use a storage pool using libiscsi we have to implement the storage pool backend entirely.
What we would have:
Pool XML using iscsiadm:
<pool type="iscsi" mode="host">
This sounds reasonable. However, I think for backwards compatibility we need to treat <pool type="iscsi"/> as mode="host". That is, if we don't parse any @mode, we must assume "host" and then we can format it into the XML back.
On the other hand, we could perhaps just introduce a new pool type, something like
<pool type='iscsi-direct'>...</pool>
which would match with VIR_STORAGE_POOL_ISCSI_DIRECT and avoid the black magic of translating type="iscsi" to VIR_STORAGE_POOL_LIBISCSI or VIR_STORAGE_POOL_ISCSI depending on the mode attribute. Not to mention that old libvirt would just completely ignore the mode attribute, but it would complain about unknown pool type.
I think we need to consider the bigger picture too - the idea of using a userspace client vs kernel client applies to the RBD and GlusterFS pools too. I'm not really convinced that adding new pool types for each case makes sense.
Hmm, good point. So in that case, I'd just recommend some kind of predictable name for VIR_STORAGE_POOL_ item, such as adding a _DIRECT suffix and use VIR_STORAGE_POOL_ISCSI_DIRECT (and VIR_STORAGE_POOL_*_DIRECT for other pool types) rather than VIR_STORAGE_POOL_LIBISCSI from which the connection to the pool type/mode in the XML is not very clear. Jirka

On Tue, Jun 05, 2018 at 09:31:09 +0100, Daniel Berrange wrote:
On Tue, Jun 05, 2018 at 10:14:15AM +0200, Jiri Denemark wrote:
On Tue, Jun 05, 2018 at 09:37:06 +0200, Michal Privoznik wrote:
On 06/04/2018 05:54 PM, Clementine Hayat wrote:
Hi everybody!
I am starting this thread to discuss a new storage pool backend for iSCSI using libiSCSI.
Thanks a lot for working on this, I'm looking forward to switching to the new pool.
There already is an iSCSI backend, however, it uses iscsiadm binary to execute the desired operation. The binary can be spawned multiple times during single execution of an API. This is suboptimal.
Moreover the iscsi storage pool is mapped by the kernel into a block device in /dev/. Iscsiadm makes operations directly on that block device. Libiscsi on the other hand is sending the commands directly to a remote iscsi portal. According to that, to be able to use a storage pool using libiscsi we have to implement the storage pool backend entirely.
What we would have:
Pool XML using iscsiadm:
<pool type="iscsi" mode="host">
This sounds reasonable. However, I think for backwards compatibility we need to treat <pool type="iscsi"/> as mode="host". That is, if we don't parse any @mode, we must assume "host" and then we can format it into the XML back.
On the other hand, we could perhaps just introduce a new pool type, something like
<pool type='iscsi-direct'>...</pool>
which would match with VIR_STORAGE_POOL_ISCSI_DIRECT and avoid the black magic of translating type="iscsi" to VIR_STORAGE_POOL_LIBISCSI or VIR_STORAGE_POOL_ISCSI depending on the mode attribute. Not to mention that old libvirt would just completely ignore the mode attribute, but it would complain about unknown pool type.
I think we need to consider the bigger picture too - the idea of using a userspace client vs kernel client applies to the RBD and GlusterFS pools too. I'm not really convinced that adding new pool types for each case makes sense.
For 'gluster' we have the native pool type which uses the userspace client library and also we support using 'glusterfs' through the 'netfs' driver which mounts it on the host [1]. The difference here is that with iscsi we have a separate driver now and this would mean to have a different one, but it would not be much different from the gluster/glusterfs [2] scenario. [1] Glusterfs is a FUSE implementation, so it is technicaly userspace as well ... [2] glusterfs is generally the package name for the FUSE client

On 06/05/2018 10:14 AM, Jiri Denemark wrote:
On Tue, Jun 05, 2018 at 09:37:06 +0200, Michal Privoznik wrote:
On 06/04/2018 05:54 PM, Clementine Hayat wrote:
Hi everybody!
I am starting this thread to discuss a new storage pool backend for iSCSI using libiSCSI.
Thanks a lot for working on this, I'm looking forward to switching to the new pool.
There already is an iSCSI backend, however, it uses iscsiadm binary to execute the desired operation. The binary can be spawned multiple times during single execution of an API. This is suboptimal.
Moreover the iscsi storage pool is mapped by the kernel into a block device in /dev/. Iscsiadm makes operations directly on that block device. Libiscsi on the other hand is sending the commands directly to a remote iscsi portal. According to that, to be able to use a storage pool using libiscsi we have to implement the storage pool backend entirely.
What we would have:
Pool XML using iscsiadm:
<pool type="iscsi" mode="host">
This sounds reasonable. However, I think for backwards compatibility we need to treat <pool type="iscsi"/> as mode="host". That is, if we don't parse any @mode, we must assume "host" and then we can format it into the XML back.
On the other hand, we could perhaps just introduce a new pool type, something like
<pool type='iscsi-direct'>...</pool>
which would match with VIR_STORAGE_POOL_ISCSI_DIRECT and avoid the black magic of translating type="iscsi" to VIR_STORAGE_POOL_LIBISCSI or VIR_STORAGE_POOL_ISCSI depending on the mode attribute. Not to mention that old libvirt would just completely ignore the mode attribute, but it would complain about unknown pool type.
I don't see much problem with old libvirt ignoring @mode attribute. Storage pools are not something we migrate back and forth like domains. Sure, there's always the case of downgrading libvirt, but, that means being forward compatible actually. I mean, any new element we add to XML is not parsed by older libvirt. Michal

From: Clementine Hayat <clem@lse.epita.fr> Hello, This is the implementation of the iscsi-direct backend storage pool. The documentation, some API calls and tests are still missing and will be comming in a second part. Best Regards, -- Clementine Hayat Clementine Hayat (3): configure: Introduce libiscsi in build system storage: Introduce iscsi_direct pool type storage: Implement iscsi_direct pool backend configure.ac | 9 +- m4/virt-libiscsi.m4 | 30 ++ m4/virt-storage-iscsi-direct.m4 | 44 ++ src/conf/domain_conf.c | 1 + src/conf/storage_conf.c | 31 +- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 24 ++ src/storage/storage_backend.c | 6 + src/storage/storage_backend_iscsi_direct.c | 444 +++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 + src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 + 13 files changed, 597 insertions(+), 5 deletions(-) create mode 100644 m4/virt-libiscsi.m4 create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h -- 2.17.1

From: Clementine Hayat <clem@lse.epita.fr> The minimal required version is 1.18.0 because the synchrounous function needed were introduced here. Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 3 +++ m4/virt-libiscsi.m4 | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 m4/virt-libiscsi.m4 diff --git a/configure.ac b/configure.ac index a87ca06854..c668630a79 100644 --- a/configure.ac +++ b/configure.ac @@ -250,6 +250,7 @@ LIBVIRT_ARG_FIREWALLD LIBVIRT_ARG_FUSE LIBVIRT_ARG_GLUSTER LIBVIRT_ARG_HAL +LIBVIRT_ARG_LIBISCSI LIBVIRT_ARG_LIBPCAP LIBVIRT_ARG_LIBSSH LIBVIRT_ARG_LIBXML @@ -290,6 +291,7 @@ LIBVIRT_CHECK_FUSE LIBVIRT_CHECK_GLUSTER LIBVIRT_CHECK_GNUTLS LIBVIRT_CHECK_HAL +LIBVIRT_CHECK_LIBISCSI LIBVIRT_CHECK_LIBNL LIBVIRT_CHECK_LIBPARTED LIBVIRT_CHECK_LIBPCAP @@ -970,6 +972,7 @@ LIBVIRT_RESULT_FUSE LIBVIRT_RESULT_GLUSTER LIBVIRT_RESULT_GNUTLS LIBVIRT_RESULT_HAL +LIBVIRT_RESULT_LIBISCSI LIBVIRT_RESULT_LIBNL LIBVIRT_RESULT_LIBPCAP LIBVIRT_RESULT_LIBSSH diff --git a/m4/virt-libiscsi.m4 b/m4/virt-libiscsi.m4 new file mode 100644 index 0000000000..2747f00ec4 --- /dev/null +++ b/m4/virt-libiscsi.m4 @@ -0,0 +1,30 @@ +dnl Libiscsi library +dnl +dnl Copyright (C) 2018 Clementine Hayat. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + +AC_DEFUN([LIBVIRT_ARG_LIBISCSI],[ + LIBVIRT_ARG_WITH_FEATURE([LIBISCSI], [libiscsi], [check], [1.18.0]) +]) + +AC_DEFUN([LIBVIRT_CHECK_LIBISCSI],[ + LIBVIRT_CHECK_PKG([LIBISCSI], [libiscsi], [1.18.0]) +]) + +AC_DEFUN([LIBVIRT_RESULT_LIBISCSI],[ + LIBVIRT_RESULT_LIB(LIBISCSI) +]) -- 2.17.1

From: Clementine Hayat <clem@lse.epita.fr> Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 6 ++- m4/virt-storage-iscsi-direct.m4 | 41 +++++++++++++++++++++ src/conf/domain_conf.c | 1 + src/conf/storage_conf.c | 31 ++++++++++++++-- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 21 +++++++++++ src/storage/storage_backend.c | 6 +++ src/storage/storage_backend_iscsi_direct.c | 43 ++++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 +++ src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 ++ 12 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h diff --git a/configure.ac b/configure.ac index c668630a79..87ac4dc2c3 100644 --- a/configure.ac +++ b/configure.ac @@ -564,6 +564,7 @@ LIBVIRT_STORAGE_ARG_DIR LIBVIRT_STORAGE_ARG_FS LIBVIRT_STORAGE_ARG_LVM LIBVIRT_STORAGE_ARG_ISCSI +LIBVIRT_STORAGE_ARG_ISCSI_DIRECT LIBVIRT_STORAGE_ARG_SCSI LIBVIRT_STORAGE_ARG_MPATH LIBVIRT_STORAGE_ARG_DISK @@ -578,6 +579,7 @@ if test "$with_libvirtd" = "no"; then with_storage_fs=no with_storage_lvm=no with_storage_iscsi=no + with_storage_iscsi_direct=no with_storage_scsi=no with_storage_mpath=no with_storage_disk=no @@ -598,6 +600,7 @@ LIBVIRT_STORAGE_CHECK_DIR LIBVIRT_STORAGE_CHECK_FS LIBVIRT_STORAGE_CHECK_LVM LIBVIRT_STORAGE_CHECK_ISCSI +LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT LIBVIRT_STORAGE_CHECK_SCSI LIBVIRT_STORAGE_CHECK_MPATH LIBVIRT_STORAGE_CHECK_DISK @@ -608,7 +611,7 @@ LIBVIRT_STORAGE_CHECK_ZFS LIBVIRT_STORAGE_CHECK_VSTORAGE with_storage=no -for backend in dir fs lvm iscsi scsi mpath rbd disk; do +for backend in dir fs lvm iscsi iscsi_direct scsi mpath rbd disk; do if eval test \$with_storage_$backend = yes; then with_storage=yes break @@ -936,6 +939,7 @@ LIBVIRT_STORAGE_RESULT_DIR LIBVIRT_STORAGE_RESULT_FS LIBVIRT_STORAGE_RESULT_LVM LIBVIRT_STORAGE_RESULT_ISCSI +LIBVIRT_STORAGE_RESULT_ISCSI_DIRECT LIBVIRT_STORAGE_RESULT_SCSI LIBVIRT_STORAGE_RESULT_MPATH LIBVIRT_STORAGE_RESULT_DISK diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4 new file mode 100644 index 0000000000..cc2d490352 --- /dev/null +++ b/m4/virt-storage-iscsi-direct.m4 @@ -0,0 +1,41 @@ +dnl Iscsi-direct storage +dnl +dnl Copyright (C) 2018 Clementine Hayat. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + +AC_DEFUN([LIBVIRT_STORAGE_ARG_ISCSI_DIRECT], [ + LIBVIRT_ARG_WITH_FEATURE([STORAGE_ISCSI_DIRECT], + [iscsi-direct backend for the storage driver], + [check]) +]) + +AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ + AC_REQUIRE([LIBVIRT_CHECK_LIBISCSI]) + if test "$with_storage_iscsi_direct" = "check"; then + with_storage_iscsi_direct=$with_libiscsi + fi + if test "$with_storage_iscsi_direct" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], + [whether iSCSI backend for storage driver is enabled]) + fi + AM_CONDITIONAL([WITH_STORAGE_ISCSI_DIRECT], + [test "$with_storage_iscsi_direct" = "yes"]) +]) + +AC_DEFUN([LIBVIRT_STORAGE_RESULT_ISCSI_DIRECT], [ + LIBVIRT_RESULT([iscsi-direct], [$with_storage_iscsi_direct]) +]) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7396616eda..0a9509de0b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30163,6 +30163,7 @@ virDomainDiskTranslateSourcePool(virDomainDiskDefPtr def) break; + case VIR_STORAGE_POOL_ISCSI_DIRECT: case VIR_STORAGE_POOL_ISCSI: if (def->startupPolicy) { virReportError(VIR_ERR_XML_ERROR, "%s", diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 5036ab9ef8..7a4b00ad8c 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -62,9 +62,9 @@ VIR_ENUM_IMPL(virStoragePool, VIR_STORAGE_POOL_LAST, "dir", "fs", "netfs", "logical", "disk", "iscsi", - "scsi", "mpath", "rbd", - "sheepdog", "gluster", "zfs", - "vstorage") + "iscsi-direct", "scsi", "mpath", + "rbd", "sheepdog", "gluster", + "zfs", "vstorage") VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, VIR_STORAGE_POOL_FS_LAST, @@ -207,6 +207,16 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .formatToString = virStoragePoolFormatDiskTypeToString, } }, + {.poolType = VIR_STORAGE_POOL_ISCSI_DIRECT, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_NETWORK | + VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN), + }, + .volOptions = { + .formatToString = virStoragePoolFormatDiskTypeToString, + } + }, {.poolType = VIR_STORAGE_POOL_SCSI, .poolOptions = { .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER), @@ -802,6 +812,18 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) "./target/permissions") < 0) goto error; } + if (ret->type == VIR_STORAGE_POOL_ISCSI_DIRECT) { + if (!ret->source.initiator.iqn) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool initiator iqn")); + goto error; + } + if (!ret->source.ndevice) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool device path")); + goto error; + } + } cleanup: VIR_FREE(uuid); @@ -1004,7 +1026,8 @@ virStoragePoolDefFormatBuf(virBufferPtr buf, * files, so they don't have a target */ if (def->type != VIR_STORAGE_POOL_RBD && def->type != VIR_STORAGE_POOL_SHEEPDOG && - def->type != VIR_STORAGE_POOL_GLUSTER) { + def->type != VIR_STORAGE_POOL_GLUSTER && + def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) { virBufferAddLit(buf, "<target>\n"); virBufferAdjustIndent(buf, 2); diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 15dfd8becf..858623783d 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -85,6 +85,7 @@ typedef enum { VIR_STORAGE_POOL_LOGICAL, /* Logical volume groups / volumes */ VIR_STORAGE_POOL_DISK, /* Disk partitions */ VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */ + VIR_STORAGE_POOL_ISCSI_DIRECT, /* iSCSI targets using libiscsi */ VIR_STORAGE_POOL_SCSI, /* SCSI HBA */ VIR_STORAGE_POOL_MPATH, /* Multipath devices */ VIR_STORAGE_POOL_RBD, /* RADOS Block Device */ diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index e66b2ebfb2..1c45bb71b9 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1838,11 +1838,13 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload, break; case VIR_STORAGE_POOL_ISCSI: + case VIR_STORAGE_POOL_ISCSI_DIRECT: case VIR_STORAGE_POOL_FS: case VIR_STORAGE_POOL_LOGICAL: case VIR_STORAGE_POOL_DISK: case VIR_STORAGE_POOL_ZFS: if ((data->def->type == VIR_STORAGE_POOL_ISCSI || + data->def->type == VIR_STORAGE_POOL_ISCSI_DIRECT || data->def->type == VIR_STORAGE_POOL_FS || data->def->type == VIR_STORAGE_POOL_LOGICAL || data->def->type == VIR_STORAGE_POOL_DISK || diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am index ea98c0ee52..d81864f5b9 100644 --- a/src/storage/Makefile.inc.am +++ b/src/storage/Makefile.inc.am @@ -31,6 +31,11 @@ STORAGE_DRIVER_ISCSI_SOURCES = \ storage/storage_backend_iscsi.c \ $(NULL) +STORAGE_DRIVER_ISCSI_DIRECT_SOURCES = \ + storage/storage_backend_iscsi_direct.h \ + storage/storage_backend_iscsi_direct.c \ + $(NULL) + STORAGE_DRIVER_SCSI_SOURCES = \ storage/storage_backend_scsi.h \ storage/storage_backend_scsi.c \ @@ -89,6 +94,7 @@ EXTRA_DIST += \ $(STORAGE_FILE_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ $(STORAGE_DRIVER_ISCSI_SOURCES) \ + $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) \ $(STORAGE_DRIVER_SCSI_SOURCES) \ $(STORAGE_DRIVER_MPATH_SOURCES) \ $(STORAGE_DRIVER_DISK_SOURCES) \ @@ -193,6 +199,21 @@ libvirt_storage_backend_iscsi_la_LIBADD = \ $(NULL) endif WITH_STORAGE_ISCSI +if WITH_STORAGE_ISCSI_DIRECT +libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) +libvirt_storage_backend_iscsi_direct_la_CFLAGS = \ + $(LIBISCSI_CFLAGS) \ + $(AM_CFLAGS) \ + $(NULL) + +storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la +libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD) +libvirt_storage_backend_iscsi_direct_la_LIBADD = \ + libvirt.la \ + ../gnulib/lib/libgnu.la \ + $(NULL) +endif WITH_STORAGE_ISCSI_DIRECT + if WITH_STORAGE_SCSI libvirt_storage_backend_scsi_la_SOURCES = $(STORAGE_DRIVER_SCSI_SOURCES) libvirt_storage_backend_scsi_la_CFLAGS = \ diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 7d226f3d3a..e7fbc37eb1 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -43,6 +43,9 @@ #if WITH_STORAGE_ISCSI # include "storage_backend_iscsi.h" #endif +#if WITH_STORAGE_ISCSI_DIRECT +# include "storage_backend_iscsi_direct.h" +#endif #if WITH_STORAGE_SCSI # include "storage_backend_scsi.h" #endif @@ -122,6 +125,9 @@ virStorageBackendDriversRegister(bool allbackends ATTRIBUTE_UNUSED) #if WITH_STORAGE_ISCSI VIR_STORAGE_BACKEND_REGISTER(virStorageBackendISCSIRegister, "iscsi"); #endif +#if WITH_STORAGE_ISCSI_DIRECT + VIR_STORAGE_BACKEND_REGISTER(virStorageBackendISCSIDirectRegister, "iscsi-direct"); +#endif #if WITH_STORAGE_SCSI VIR_STORAGE_BACKEND_REGISTER(virStorageBackendSCSIRegister, "scsi"); #endif diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c new file mode 100644 index 0000000000..e3c1f75b42 --- /dev/null +++ b/src/storage/storage_backend_iscsi_direct.c @@ -0,0 +1,43 @@ +#include <config.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "datatypes.h" +#include "driver.h" +#include "storage_backend_iscsi_direct.h" +#include "storage_util.h" +#include "virlog.h" +#include "virobject.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_LOG_INIT("storage.storage_backend_iscsi_direct"); + + +static int +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + bool *isActive ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) +{ + return 0; +} + +virStorageBackend virStorageBackendISCSIDirect = { + .type = VIR_STORAGE_POOL_ISCSI_DIRECT, + + .checkPool = virStorageBackendISCSIDirectCheckPool, + .refreshPool = virStorageBackendISCSIDirectRefreshPool, +}; + +int +virStorageBackendISCSIDirectRegister(void) +{ + return virStorageBackendRegister(&virStorageBackendISCSIDirect); +} diff --git a/src/storage/storage_backend_iscsi_direct.h b/src/storage/storage_backend_iscsi_direct.h new file mode 100644 index 0000000000..545579daf7 --- /dev/null +++ b/src/storage/storage_backend_iscsi_direct.h @@ -0,0 +1,6 @@ +#ifndef __VIR_STORAGE_BACKEND_ISCSI_H__ +# define __VIR_STORAGE_BACKEND_ISCSI_H__ + +int virStorageBackendISCSIDirectRegister(void); + +#endif /* __VIR_STORAGE_BACKEND_ISCSI_H__ */ diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 8070d159ea..c108f026ce 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1566,6 +1566,7 @@ storageVolLookupByPathCallback(virStoragePoolObjPtr obj, case VIR_STORAGE_POOL_LOGICAL: case VIR_STORAGE_POOL_DISK: case VIR_STORAGE_POOL_ISCSI: + case VIR_STORAGE_POOL_ISCSI_DIRECT: case VIR_STORAGE_POOL_SCSI: case VIR_STORAGE_POOL_MPATH: case VIR_STORAGE_POOL_VSTORAGE: diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index cc49a5b96d..4604b05020 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -1203,6 +1203,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) case VIR_STORAGE_POOL_ISCSI: flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI; break; + case VIR_STORAGE_POOL_ISCSI_DIRECT: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI; + break; case VIR_STORAGE_POOL_SCSI: flags |= VIR_CONNECT_LIST_STORAGE_POOLS_SCSI; break; -- 2.17.1

On Sat, Jul 14, 2018 at 12:06:14AM +0200, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
I know that this is more like RFC patch series so before we get to the actual patch which should be pushed into upstream there should be some commit message.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 6 ++- m4/virt-storage-iscsi-direct.m4 | 41 +++++++++++++++++++++ src/conf/domain_conf.c | 1 + src/conf/storage_conf.c | 31 ++++++++++++++-- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 21 +++++++++++ src/storage/storage_backend.c | 6 +++ src/storage/storage_backend_iscsi_direct.c | 43 ++++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 +++ src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 ++ 12 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h
[...]
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7396616eda..0a9509de0b 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30163,6 +30163,7 @@ virDomainDiskTranslateSourcePool(virDomainDiskDefPtr def)
break;
+ case VIR_STORAGE_POOL_ISCSI_DIRECT: case VIR_STORAGE_POOL_ISCSI: if (def->startupPolicy) { virReportError(VIR_ERR_XML_ERROR, "%s",
This will not be good enough. We need to set the default def->src->srcpool->mode to VIR_STORAGE_SOURCE_POOL_MODE_DIRECT if the storage pool is "iscsi-direct" and if the mode is already configured in domain XML we need to check whether it's "direct" mode if the storage pool is "iscsi-direct".
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 5036ab9ef8..7a4b00ad8c 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -62,9 +62,9 @@ VIR_ENUM_IMPL(virStoragePool, VIR_STORAGE_POOL_LAST, "dir", "fs", "netfs", "logical", "disk", "iscsi", - "scsi", "mpath", "rbd", - "sheepdog", "gluster", "zfs", - "vstorage") + "iscsi-direct", "scsi", "mpath", + "rbd", "sheepdog", "gluster", + "zfs", "vstorage")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, VIR_STORAGE_POOL_FS_LAST, @@ -207,6 +207,16 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .formatToString = virStoragePoolFormatDiskTypeToString, } }, + {.poolType = VIR_STORAGE_POOL_ISCSI_DIRECT, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_NETWORK | + VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
We need to use VIR_STORAGE_POOL_SOURCE_DEVICE as well, otherwise it would not be formatted back.
+ }, + .volOptions = { + .formatToString = virStoragePoolFormatDiskTypeToString, + } + }, {.poolType = VIR_STORAGE_POOL_SCSI, .poolOptions = { .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER), @@ -802,6 +812,18 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) "./target/permissions") < 0) goto error; }
One empty line would be nice.
+ if (ret->type == VIR_STORAGE_POOL_ISCSI_DIRECT) { + if (!ret->source.initiator.iqn) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool initiator iqn")); + goto error; + } + if (!ret->source.ndevice) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool device path")); + goto error; + } + }
cleanup: VIR_FREE(uuid); @@ -1004,7 +1026,8 @@ virStoragePoolDefFormatBuf(virBufferPtr buf, * files, so they don't have a target */ if (def->type != VIR_STORAGE_POOL_RBD && def->type != VIR_STORAGE_POOL_SHEEPDOG && - def->type != VIR_STORAGE_POOL_GLUSTER) { + def->type != VIR_STORAGE_POOL_GLUSTER && + def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) { virBufferAddLit(buf, "<target>\n"); virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 15dfd8becf..858623783d 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -85,6 +85,7 @@ typedef enum { VIR_STORAGE_POOL_LOGICAL, /* Logical volume groups / volumes */ VIR_STORAGE_POOL_DISK, /* Disk partitions */ VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */ + VIR_STORAGE_POOL_ISCSI_DIRECT, /* iSCSI targets using libiscsi */ VIR_STORAGE_POOL_SCSI, /* SCSI HBA */ VIR_STORAGE_POOL_MPATH, /* Multipath devices */ VIR_STORAGE_POOL_RBD, /* RADOS Block Device */
[...]
diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am index ea98c0ee52..d81864f5b9 100644 --- a/src/storage/Makefile.inc.am +++ b/src/storage/Makefile.inc.am @@ -31,6 +31,11 @@ STORAGE_DRIVER_ISCSI_SOURCES = \ storage/storage_backend_iscsi.c \ $(NULL)
+STORAGE_DRIVER_ISCSI_DIRECT_SOURCES = \ + storage/storage_backend_iscsi_direct.h \ + storage/storage_backend_iscsi_direct.c \ + $(NULL) + STORAGE_DRIVER_SCSI_SOURCES = \ storage/storage_backend_scsi.h \ storage/storage_backend_scsi.c \ @@ -89,6 +94,7 @@ EXTRA_DIST += \ $(STORAGE_FILE_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ $(STORAGE_DRIVER_ISCSI_SOURCES) \ + $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) \ $(STORAGE_DRIVER_SCSI_SOURCES) \ $(STORAGE_DRIVER_MPATH_SOURCES) \ $(STORAGE_DRIVER_DISK_SOURCES) \ @@ -193,6 +199,21 @@ libvirt_storage_backend_iscsi_la_LIBADD = \ $(NULL) endif WITH_STORAGE_ISCSI
+if WITH_STORAGE_ISCSI_DIRECT +libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) +libvirt_storage_backend_iscsi_direct_la_CFLAGS = \
So I remember point out that we don't need '-I$(srcdir)/conf \' here right now but I was wrong. We need it because some files from that directory are indirectly included.
+ $(LIBISCSI_CFLAGS) \ + $(AM_CFLAGS) \ + $(NULL) + +storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la +libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD) +libvirt_storage_backend_iscsi_direct_la_LIBADD = \ + libvirt.la \ + ../gnulib/lib/libgnu.la \ + $(NULL) +endif WITH_STORAGE_ISCSI_DIRECT + if WITH_STORAGE_SCSI libvirt_storage_backend_scsi_la_SOURCES = $(STORAGE_DRIVER_SCSI_SOURCES) libvirt_storage_backend_scsi_la_CFLAGS = \
[...]
diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c new file mode 100644 index 0000000000..e3c1f75b42 --- /dev/null +++ b/src/storage/storage_backend_iscsi_direct.c @@ -0,0 +1,43 @@
Missing copyright comment.
+#include <config.h>
config.h is not a system include so we usually separate it by empty line
+#include <fcntl.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h>
All of these can be removed, they are not needed now.
+ +#include "datatypes.h" +#include "driver.h" +#include "storage_backend_iscsi_direct.h" +#include "storage_util.h" +#include "virlog.h" +#include "virobject.h"
"datatypes.h", "driver.h" and "virobject.h" can be removed from this patche, they are not needed now.
+ +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_LOG_INIT("storage.storage_backend_iscsi_direct"); + + +static int +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + bool *isActive ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) +{ + return 0; +} + +virStorageBackend virStorageBackendISCSIDirect = { + .type = VIR_STORAGE_POOL_ISCSI_DIRECT, + + .checkPool = virStorageBackendISCSIDirectCheckPool, + .refreshPool = virStorageBackendISCSIDirectRefreshPool, +}; + +int +virStorageBackendISCSIDirectRegister(void) +{ + return virStorageBackendRegister(&virStorageBackendISCSIDirect); +}
Some minor issues, otherwise looks good. Pavel

From: Clementine Hayat <clem@lse.epita.fr> We need here libiscsi for the storgae pool backend. For the iscsi-direct storage pool, only checkPool and refreshPool should be necessary. The pool is state-less and just need the informations within the volume to work. Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- m4/virt-storage-iscsi-direct.m4 | 3 + src/storage/Makefile.inc.am | 3 + src/storage/storage_backend_iscsi_direct.c | 407 ++++++++++++++++++++- 3 files changed, 410 insertions(+), 3 deletions(-) diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4 index cc2d490352..dab4414169 100644 --- a/m4/virt-storage-iscsi-direct.m4 +++ b/m4/virt-storage-iscsi-direct.m4 @@ -29,6 +29,9 @@ AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ with_storage_iscsi_direct=$with_libiscsi fi if test "$with_storage_iscsi_direct" = "yes"; then + if test "$with_libiscsi" = "no"; then + AC_MSG_ERROR([Need libiscsi for iscsi-direct storage driver]) + fi AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], [whether iSCSI backend for storage driver is enabled]) fi diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am index d81864f5b9..bd5ea06f8b 100644 --- a/src/storage/Makefile.inc.am +++ b/src/storage/Makefile.inc.am @@ -202,6 +202,8 @@ endif WITH_STORAGE_ISCSI if WITH_STORAGE_ISCSI_DIRECT libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) libvirt_storage_backend_iscsi_direct_la_CFLAGS = \ + -I$(srcdir)/conf \ + -I$(srcdir)/secret \ $(LIBISCSI_CFLAGS) \ $(AM_CFLAGS) \ $(NULL) @@ -210,6 +212,7 @@ storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD) libvirt_storage_backend_iscsi_direct_la_LIBADD = \ libvirt.la \ + $(LIBISCSI_LIBS) \ ../gnulib/lib/libgnu.la \ $(NULL) endif WITH_STORAGE_ISCSI_DIRECT diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c index e3c1f75b42..f93c8e1e67 100644 --- a/src/storage/storage_backend_iscsi_direct.c +++ b/src/storage/storage_backend_iscsi_direct.c @@ -1,34 +1,435 @@ #include <config.h> #include <fcntl.h> +#include <iscsi/iscsi.h> +#include <iscsi/scsi-lowlevel.h> +#include <string.h> #include <sys/stat.h> #include <sys/wait.h> #include <unistd.h> #include "datatypes.h" #include "driver.h" +#include "secret_util.h" #include "storage_backend_iscsi_direct.h" #include "storage_util.h" +#include "viralloc.h" +#include "vircommand.h" +#include "virerror.h" +#include "virfile.h" #include "virlog.h" #include "virobject.h" +#include "virstring.h" +#include "virtime.h" +#include "viruuid.h" #define VIR_FROM_THIS VIR_FROM_STORAGE +#define ISCSI_DEFAULT_TARGET_PORT 3260 +#define VIR_ISCSI_TEST_UNIT_TIMEOUT 30 * 1000 + VIR_LOG_INIT("storage.storage_backend_iscsi_direct"); +static struct iscsi_context * +virISCSIDirectCreateContext(const char* initiator_iqn) +{ + struct iscsi_context *iscsi = NULL; + + iscsi = iscsi_create_context(initiator_iqn); + if (!iscsi) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create iscsi context for %s"), + initiator_iqn); + return iscsi; +} + +static char * +virStorageBackendISCSIDirectPortal(virStoragePoolSourcePtr source) +{ + char *portal = NULL; + + if (source->nhost != 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return NULL; + } + if (source->hosts[0].port == 0) { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + ISCSI_DEFAULT_TARGET_PORT)); + } else if (strchr(source->hosts[0].name, ':')) { + ignore_value(virAsprintf(&portal, "[%s]:%d", + source->hosts[0].name, + source->hosts[0].port)); + } else { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + source->hosts[0].port)); + } + return portal; +} + +static int +virStorageBackendISCSIDirectSetAuth(struct iscsi_context *iscsi, + virStoragePoolSourcePtr source) +{ + unsigned char *secret_value = NULL; + size_t secret_size; + virStorageAuthDefPtr authdef = source->auth; + int ret = -1; + virConnectPtr conn = NULL; + + if (!authdef || authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) + return 0; + + VIR_DEBUG("username='%s' authType=%d seclookupdef.type=%d", + authdef->username, authdef->authType, authdef->seclookupdef.type); + + if (authdef->authType != VIR_STORAGE_AUTH_TYPE_CHAP) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("iscsi-direct pool only supports 'chap' auth type")); + return ret; + } + + if (!(conn = virGetConnectSecret())) + return ret; + + if (virSecretGetSecretString(conn, &authdef->seclookupdef, + VIR_SECRET_USAGE_TYPE_ISCSI, + &secret_value, &secret_size) < 0) + goto cleanup; + + if (iscsi_set_initiator_username_pwd(iscsi, + authdef->username, + (const char *)secret_value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set credential: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret = 0; + cleanup: + VIR_DISPOSE_N(secret_value, secret_size); + virObjectUnref(conn); + return ret; +} + +static int +virISCSIDirectSetContext(struct iscsi_context *iscsi, + const char *target_name) +{ + if (iscsi_init_transport(iscsi, TCP_TRANSPORT) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to init transport: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_targetname(iscsi, target_name) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set target name: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set session type: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} static int -virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - bool *isActive ATTRIBUTE_UNUSED) +virISCSIDirectConnect(struct iscsi_context *iscsi, + const char *portal) { + if (iscsi_connect_sync(iscsi, portal) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to connect: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_login_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to login: %s"), + iscsi_get_error(iscsi)); + return -1; + } return 0; } +static struct scsi_reportluns_list * +virISCSIDirectReportLuns(struct iscsi_context *iscsi) +{ + struct scsi_task *task = NULL; + struct scsi_reportluns_list *list = NULL; + int full_size; + + if (!(task = iscsi_reportluns_sync(iscsi, 0, 16))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + full_size = scsi_datain_getfullsize(task); + + if (full_size > task->datain.size) { + scsi_free_scsi_task(task); + if (!(task = iscsi_reportluns_sync(iscsi, 0, full_size))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + } + + if (!(list = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + cleanup: + scsi_free_scsi_task(task); + return list; +} + static int -virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) +virISCSIDirectTestUnitReady(struct iscsi_context *iscsi, + int lun) { + struct scsi_task *task = NULL; + int ret = -1; + virTimeBackOffVar timebackoff; + + if (virTimeBackOffStart(&timebackoff, 1, + VIR_ISCSI_TEST_UNIT_TIMEOUT) < 0) + goto cleanup; + + do { + if (!(task = iscsi_testunitready_sync(iscsi, lun))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (task->status != SCSI_STATUS_CHECK_CONDITION || + task->sense.key != SCSI_SENSE_UNIT_ATTENTION || + task->sense.ascq != SCSI_SENSE_ASCQ_BUS_RESET) + break; + + scsi_free_scsi_task(task); + } while (virTimeBackOffWait(&timebackoff)); + + if (task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret = 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectSetVolumeAttributes(virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + int lun, + char *portal) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + + if (virAsprintf(&vol->name, "%u", lun) < 0) + return -1; + if (virAsprintf(&vol->key, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; + if (virAsprintf(&vol->target.path, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; return 0; } +static int +virISCSIDirectSetVolumeCapacity(struct iscsi_context *iscsi, + virStorageVolDefPtr vol, int lun) +{ + struct scsi_task *task = NULL; + struct scsi_inquiry_standard *inq = NULL; + long long size = 0; + int ret = -1; + + if (!(task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64)) || + task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to send inquiry command: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(inq = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (inq->device_type == SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { + struct scsi_readcapacity10 *rc10 = NULL; + + scsi_free_scsi_task(task); + task = NULL; + + if (!(task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0)) || + task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get capacity of lun: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(rc10 = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + size = rc10->block_size; + size *= rc10->lba; + vol->target.capacity = size; + vol->target.allocation = size; + + } + + ret = 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectRefreshVol(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + int lun, + char *portal) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + virStorageVolDefPtr vol = NULL; + int ret = -1; + + virStoragePoolObjClearVols(pool); + if (virISCSIDirectTestUnitReady(iscsi, lun) < 0) + goto cleanup; + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_NETWORK; + + if (virISCSIDirectSetVolumeCapacity(iscsi, vol, lun) < 0) + goto cleanup; + + def->capacity += vol->target.capacity; + def->allocation += vol->target.allocation; + + if (virISCSIDirectSetVolumeAttributes(pool, vol, lun, portal) < 0) + goto cleanup; + + if (virStoragePoolObjAddVol(pool, vol) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create volume: %d"), + lun); + goto cleanup; + } + vol = NULL; + + ret = 0; + cleanup: + virStorageVolDefFree(vol); + return ret; +} + +static int +virStorageBackendISCSIDirectRefreshVols(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + char *portal) +{ + struct scsi_reportluns_list *list = NULL; + size_t i; + + if (!(list = virISCSIDirectReportLuns(iscsi))) + return -1; + for (i = 0; i < list->num; i++) { + if (virISCSIDirectRefreshVol(pool, iscsi, list->luns[i], portal) < 0) + return -1; + } + + return 0; +} + +static int +virISCSIDirectDisconnect(struct iscsi_context *iscsi) +{ + if (iscsi_logout_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to logout: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_disconnect(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to disconnect: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} + +static int +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool, + bool *isActive) +{ + *isActive = virStoragePoolObjIsActive(pool); + return 0; +} + +static int +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + struct iscsi_context *iscsi = NULL; + char *portal = NULL; + int ret = -1; + + if (!(iscsi = virISCSIDirectCreateContext(def->source.initiator.iqn))) + goto cleanup; + if (!(portal = virStorageBackendISCSIDirectPortal(&def->source))) + goto cleanup; + if (virStorageBackendISCSIDirectSetAuth(iscsi, &def->source) < 0) + goto cleanup; + if (virISCSIDirectSetContext(iscsi, def->source.devices[0].path) < 0) + goto cleanup; + if (virISCSIDirectConnect(iscsi, portal) < 0) + goto cleanup; + if (virStorageBackendISCSIDirectRefreshVols(pool, iscsi, portal) < 0) + goto disconect; + + ret = 0; + disconect: + virISCSIDirectDisconnect(iscsi); + cleanup: + iscsi_destroy_context(iscsi); + VIR_FREE(portal); + return ret; +} + virStorageBackend virStorageBackendISCSIDirect = { .type = VIR_STORAGE_POOL_ISCSI_DIRECT, -- 2.17.1

On Sat, 14 Jul 2018 00:06:15 +0200 clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
We need here libiscsi for the storgae pool backend. For the iscsi-direct storage pool, only checkPool and refreshPool should be necessary. The pool is state-less and just need the informations within the volume to work.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- m4/virt-storage-iscsi-direct.m4 | 3 + src/storage/Makefile.inc.am | 3 + src/storage/storage_backend_iscsi_direct.c | 407 ++++++++++++++++++++- 3 files changed, 410 insertions(+), 3 deletions(-)
diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4 index cc2d490352..dab4414169 100644 --- a/m4/virt-storage-iscsi-direct.m4 +++ b/m4/virt-storage-iscsi-direct.m4 @@ -29,6 +29,9 @@ AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ with_storage_iscsi_direct=$with_libiscsi fi if test "$with_storage_iscsi_direct" = "yes"; then + if test "$with_libiscsi" = "no"; then + AC_MSG_ERROR([Need libiscsi for iscsi-direct storage driver]) + fi AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], [whether iSCSI backend for storage driver is enabled]) fi diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am index d81864f5b9..bd5ea06f8b 100644 --- a/src/storage/Makefile.inc.am +++ b/src/storage/Makefile.inc.am @@ -202,6 +202,8 @@ endif WITH_STORAGE_ISCSI if WITH_STORAGE_ISCSI_DIRECT libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) libvirt_storage_backend_iscsi_direct_la_CFLAGS = \ + -I$(srcdir)/conf \ + -I$(srcdir)/secret \ $(LIBISCSI_CFLAGS) \ $(AM_CFLAGS) \ $(NULL) @@ -210,6 +212,7 @@ storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD) libvirt_storage_backend_iscsi_direct_la_LIBADD = \ libvirt.la \ + $(LIBISCSI_LIBS) \ ../gnulib/lib/libgnu.la \ $(NULL) endif WITH_STORAGE_ISCSI_DIRECT diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c index e3c1f75b42..f93c8e1e67 100644 --- a/src/storage/storage_backend_iscsi_direct.c +++ b/src/storage/storage_backend_iscsi_direct.c @@ -1,34 +1,435 @@ #include <config.h> #include <fcntl.h> +#include <iscsi/iscsi.h> +#include <iscsi/scsi-lowlevel.h> +#include <string.h> #include <sys/stat.h> #include <sys/wait.h> #include <unistd.h>
#include "datatypes.h" #include "driver.h" +#include "secret_util.h" #include "storage_backend_iscsi_direct.h" #include "storage_util.h" +#include "viralloc.h" +#include "vircommand.h" +#include "virerror.h" +#include "virfile.h" #include "virlog.h" #include "virobject.h" +#include "virstring.h" +#include "virtime.h" +#include "viruuid.h"
From what I see there is a lot of unused headers here:
* fcntl.h * string.h * sys/stat.h * sys/wait.h * unistd.h * driver.h * vircommand.h * virfile.h
#define VIR_FROM_THIS VIR_FROM_STORAGE
+#define ISCSI_DEFAULT_TARGET_PORT 3260 +#define VIR_ISCSI_TEST_UNIT_TIMEOUT 30 * 1000 + VIR_LOG_INIT("storage.storage_backend_iscsi_direct");
+static struct iscsi_context * +virISCSIDirectCreateContext(const char* initiator_iqn) +{ + struct iscsi_context *iscsi = NULL; + + iscsi = iscsi_create_context(initiator_iqn); + if (!iscsi) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create iscsi context for %s"), + initiator_iqn); + return iscsi; +} + +static char * +virStorageBackendISCSIDirectPortal(virStoragePoolSourcePtr source) +{ + char *portal = NULL; + + if (source->nhost != 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return NULL; + } + if (source->hosts[0].port == 0) { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + ISCSI_DEFAULT_TARGET_PORT)); + } else if (strchr(source->hosts[0].name, ':')) { + ignore_value(virAsprintf(&portal, "[%s]:%d", + source->hosts[0].name, + source->hosts[0].port)); + } else { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + source->hosts[0].port)); + } + return portal; +} + +static int +virStorageBackendISCSIDirectSetAuth(struct iscsi_context *iscsi, + virStoragePoolSourcePtr source) +{ + unsigned char *secret_value = NULL; + size_t secret_size; + virStorageAuthDefPtr authdef = source->auth; + int ret = -1; + virConnectPtr conn = NULL; + + if (!authdef || authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) + return 0; + + VIR_DEBUG("username='%s' authType=%d seclookupdef.type=%d", + authdef->username, authdef->authType, authdef->seclookupdef.type); + + if (authdef->authType != VIR_STORAGE_AUTH_TYPE_CHAP) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("iscsi-direct pool only supports 'chap' auth type")); + return ret; + } + + if (!(conn = virGetConnectSecret())) + return ret; + + if (virSecretGetSecretString(conn, &authdef->seclookupdef, + VIR_SECRET_USAGE_TYPE_ISCSI, + &secret_value, &secret_size) < 0) + goto cleanup; + + if (iscsi_set_initiator_username_pwd(iscsi, + authdef->username, + (const char *)secret_value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set credential: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret = 0; + cleanup: + VIR_DISPOSE_N(secret_value, secret_size); + virObjectUnref(conn); + return ret; +} + +static int +virISCSIDirectSetContext(struct iscsi_context *iscsi, + const char *target_name) +{ + if (iscsi_init_transport(iscsi, TCP_TRANSPORT) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to init transport: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_targetname(iscsi, target_name) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set target name: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set session type: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +}
static int -virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - bool *isActive ATTRIBUTE_UNUSED) +virISCSIDirectConnect(struct iscsi_context *iscsi, + const char *portal) { + if (iscsi_connect_sync(iscsi, portal) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to connect: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_login_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to login: %s"), + iscsi_get_error(iscsi)); + return -1; + } return 0; }
+static struct scsi_reportluns_list * +virISCSIDirectReportLuns(struct iscsi_context *iscsi) +{ + struct scsi_task *task = NULL; + struct scsi_reportluns_list *list = NULL; + int full_size; + + if (!(task = iscsi_reportluns_sync(iscsi, 0, 16))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + full_size = scsi_datain_getfullsize(task); + + if (full_size > task->datain.size) { + scsi_free_scsi_task(task); + if (!(task = iscsi_reportluns_sync(iscsi, 0, full_size))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + } + + if (!(list = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + cleanup: + scsi_free_scsi_task(task); + return list; +} + static int -virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) +virISCSIDirectTestUnitReady(struct iscsi_context *iscsi, + int lun) { + struct scsi_task *task = NULL; + int ret = -1; + virTimeBackOffVar timebackoff; + + if (virTimeBackOffStart(&timebackoff, 1, + VIR_ISCSI_TEST_UNIT_TIMEOUT) < 0) + goto cleanup; + + do { + if (!(task = iscsi_testunitready_sync(iscsi, lun))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (task->status != SCSI_STATUS_CHECK_CONDITION || + task->sense.key != SCSI_SENSE_UNIT_ATTENTION || + task->sense.ascq != SCSI_SENSE_ASCQ_BUS_RESET) + break; + + scsi_free_scsi_task(task); + } while (virTimeBackOffWait(&timebackoff)); + + if (task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret = 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectSetVolumeAttributes(virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + int lun, + char *portal) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + + if (virAsprintf(&vol->name, "%u", lun) < 0) + return -1; + if (virAsprintf(&vol->key, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; + if (virAsprintf(&vol->target.path, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; return 0; }
+static int +virISCSIDirectSetVolumeCapacity(struct iscsi_context *iscsi, + virStorageVolDefPtr vol, int lun) +{ + struct scsi_task *task = NULL; + struct scsi_inquiry_standard *inq = NULL; + long long size = 0; + int ret = -1; + + if (!(task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64)) || + task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to send inquiry command: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(inq = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (inq->device_type == SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { + struct scsi_readcapacity10 *rc10 = NULL; + + scsi_free_scsi_task(task); + task = NULL; + + if (!(task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0)) || + task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get capacity of lun: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(rc10 = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + size = rc10->block_size; + size *= rc10->lba; + vol->target.capacity = size; + vol->target.allocation = size; + + } + + ret = 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectRefreshVol(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + int lun, + char *portal) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + virStorageVolDefPtr vol = NULL; + int ret = -1; + + virStoragePoolObjClearVols(pool); + if (virISCSIDirectTestUnitReady(iscsi, lun) < 0) + goto cleanup; + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_NETWORK; + + if (virISCSIDirectSetVolumeCapacity(iscsi, vol, lun) < 0) + goto cleanup; + + def->capacity += vol->target.capacity; + def->allocation += vol->target.allocation; + + if (virISCSIDirectSetVolumeAttributes(pool, vol, lun, portal) < 0) + goto cleanup; + + if (virStoragePoolObjAddVol(pool, vol) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create volume: %d"), + lun); + goto cleanup; + } + vol = NULL; + + ret = 0; + cleanup: + virStorageVolDefFree(vol); + return ret; +} + +static int +virStorageBackendISCSIDirectRefreshVols(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + char *portal) +{ + struct scsi_reportluns_list *list = NULL; + size_t i; + + if (!(list = virISCSIDirectReportLuns(iscsi))) + return -1; + for (i = 0; i < list->num; i++) { + if (virISCSIDirectRefreshVol(pool, iscsi, list->luns[i], portal) < 0) + return -1; + } + + return 0; +} + +static int +virISCSIDirectDisconnect(struct iscsi_context *iscsi) +{ + if (iscsi_logout_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to logout: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_disconnect(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to disconnect: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} + +static int +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool, + bool *isActive) +{ + *isActive = virStoragePoolObjIsActive(pool); + return 0; +} + +static int +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + struct iscsi_context *iscsi = NULL; + char *portal = NULL; + int ret = -1; + + if (!(iscsi = virISCSIDirectCreateContext(def->source.initiator.iqn))) + goto cleanup; + if (!(portal = virStorageBackendISCSIDirectPortal(&def->source))) + goto cleanup; + if (virStorageBackendISCSIDirectSetAuth(iscsi, &def->source) < 0) + goto cleanup; + if (virISCSIDirectSetContext(iscsi, def->source.devices[0].path) < 0) + goto cleanup; + if (virISCSIDirectConnect(iscsi, portal) < 0) + goto cleanup; + if (virStorageBackendISCSIDirectRefreshVols(pool, iscsi, portal) < 0) + goto disconect; + + ret = 0; + disconect: + virISCSIDirectDisconnect(iscsi); + cleanup: + iscsi_destroy_context(iscsi); + VIR_FREE(portal); + return ret;
Here, the cleanup code is not the complete opposite of the initialisation side. Just for clarity: cleanup: VIR_FREE(portal); iscsi_destroy_context(iscsi); return ret;
+} + virStorageBackend virStorageBackendISCSIDirect = { .type = VIR_STORAGE_POOL_ISCSI_DIRECT,
-- Gabriel Laskar

From: Clementine Hayat <clem@lse.epita.fr> Hello, This is the implementation of the iscsi-direct backend storage pool version 2. The documentation, some API calls and tests are still missing and will be comming in a second part. Best Regards, -- Clementine Hayat Clementine Hayat (3): configure: Introduce libiscsi in build system storage: Introduce iscsi_direct pool type storage: Implement iscsi_direct pool backend configure.ac | 9 +- m4/virt-libiscsi.m4 | 30 ++ m4/virt-storage-iscsi-direct.m4 | 44 ++ src/conf/domain_conf.c | 4 + src/conf/storage_conf.c | 33 +- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 24 ++ src/storage/storage_backend.c | 6 + src/storage/storage_backend_iscsi_direct.c | 460 +++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 + src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 + 13 files changed, 618 insertions(+), 5 deletions(-) create mode 100644 m4/virt-libiscsi.m4 create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h -- 2.18.0

From: Clementine Hayat <clem@lse.epita.fr> The minimal required version is 1.18.0 because the synchrounous function needed were introduced here. Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 3 +++ m4/virt-libiscsi.m4 | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 m4/virt-libiscsi.m4 diff --git a/configure.ac b/configure.ac index a87ca06854..c668630a79 100644 --- a/configure.ac +++ b/configure.ac @@ -250,6 +250,7 @@ LIBVIRT_ARG_FIREWALLD LIBVIRT_ARG_FUSE LIBVIRT_ARG_GLUSTER LIBVIRT_ARG_HAL +LIBVIRT_ARG_LIBISCSI LIBVIRT_ARG_LIBPCAP LIBVIRT_ARG_LIBSSH LIBVIRT_ARG_LIBXML @@ -290,6 +291,7 @@ LIBVIRT_CHECK_FUSE LIBVIRT_CHECK_GLUSTER LIBVIRT_CHECK_GNUTLS LIBVIRT_CHECK_HAL +LIBVIRT_CHECK_LIBISCSI LIBVIRT_CHECK_LIBNL LIBVIRT_CHECK_LIBPARTED LIBVIRT_CHECK_LIBPCAP @@ -970,6 +972,7 @@ LIBVIRT_RESULT_FUSE LIBVIRT_RESULT_GLUSTER LIBVIRT_RESULT_GNUTLS LIBVIRT_RESULT_HAL +LIBVIRT_RESULT_LIBISCSI LIBVIRT_RESULT_LIBNL LIBVIRT_RESULT_LIBPCAP LIBVIRT_RESULT_LIBSSH diff --git a/m4/virt-libiscsi.m4 b/m4/virt-libiscsi.m4 new file mode 100644 index 0000000000..2747f00ec4 --- /dev/null +++ b/m4/virt-libiscsi.m4 @@ -0,0 +1,30 @@ +dnl Libiscsi library +dnl +dnl Copyright (C) 2018 Clementine Hayat. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + +AC_DEFUN([LIBVIRT_ARG_LIBISCSI],[ + LIBVIRT_ARG_WITH_FEATURE([LIBISCSI], [libiscsi], [check], [1.18.0]) +]) + +AC_DEFUN([LIBVIRT_CHECK_LIBISCSI],[ + LIBVIRT_CHECK_PKG([LIBISCSI], [libiscsi], [1.18.0]) +]) + +AC_DEFUN([LIBVIRT_RESULT_LIBISCSI],[ + LIBVIRT_RESULT_LIB(LIBISCSI) +]) -- 2.18.0

On 07/23/2018 08:42 PM, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
The minimal required version is 1.18.0 because the synchrounous function needed were introduced here.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 3 +++ m4/virt-libiscsi.m4 | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 m4/virt-libiscsi.m4
ACK Michal

From: Clementine Hayat <clem@lse.epita.fr> Introducing the pool as a noop. Integration inside the build system. Implementation will be in the following commits. Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 6 ++- m4/virt-storage-iscsi-direct.m4 | 41 +++++++++++++++ src/conf/domain_conf.c | 4 ++ src/conf/storage_conf.c | 33 ++++++++++-- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 22 ++++++++ src/storage/storage_backend.c | 6 +++ src/storage/storage_backend_iscsi_direct.c | 58 ++++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 +++ src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 ++ 12 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h diff --git a/configure.ac b/configure.ac index c668630a79..87ac4dc2c3 100644 --- a/configure.ac +++ b/configure.ac @@ -564,6 +564,7 @@ LIBVIRT_STORAGE_ARG_DIR LIBVIRT_STORAGE_ARG_FS LIBVIRT_STORAGE_ARG_LVM LIBVIRT_STORAGE_ARG_ISCSI +LIBVIRT_STORAGE_ARG_ISCSI_DIRECT LIBVIRT_STORAGE_ARG_SCSI LIBVIRT_STORAGE_ARG_MPATH LIBVIRT_STORAGE_ARG_DISK @@ -578,6 +579,7 @@ if test "$with_libvirtd" = "no"; then with_storage_fs=no with_storage_lvm=no with_storage_iscsi=no + with_storage_iscsi_direct=no with_storage_scsi=no with_storage_mpath=no with_storage_disk=no @@ -598,6 +600,7 @@ LIBVIRT_STORAGE_CHECK_DIR LIBVIRT_STORAGE_CHECK_FS LIBVIRT_STORAGE_CHECK_LVM LIBVIRT_STORAGE_CHECK_ISCSI +LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT LIBVIRT_STORAGE_CHECK_SCSI LIBVIRT_STORAGE_CHECK_MPATH LIBVIRT_STORAGE_CHECK_DISK @@ -608,7 +611,7 @@ LIBVIRT_STORAGE_CHECK_ZFS LIBVIRT_STORAGE_CHECK_VSTORAGE with_storage=no -for backend in dir fs lvm iscsi scsi mpath rbd disk; do +for backend in dir fs lvm iscsi iscsi_direct scsi mpath rbd disk; do if eval test \$with_storage_$backend = yes; then with_storage=yes break @@ -936,6 +939,7 @@ LIBVIRT_STORAGE_RESULT_DIR LIBVIRT_STORAGE_RESULT_FS LIBVIRT_STORAGE_RESULT_LVM LIBVIRT_STORAGE_RESULT_ISCSI +LIBVIRT_STORAGE_RESULT_ISCSI_DIRECT LIBVIRT_STORAGE_RESULT_SCSI LIBVIRT_STORAGE_RESULT_MPATH LIBVIRT_STORAGE_RESULT_DISK diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4 new file mode 100644 index 0000000000..cc2d490352 --- /dev/null +++ b/m4/virt-storage-iscsi-direct.m4 @@ -0,0 +1,41 @@ +dnl Iscsi-direct storage +dnl +dnl Copyright (C) 2018 Clementine Hayat. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + +AC_DEFUN([LIBVIRT_STORAGE_ARG_ISCSI_DIRECT], [ + LIBVIRT_ARG_WITH_FEATURE([STORAGE_ISCSI_DIRECT], + [iscsi-direct backend for the storage driver], + [check]) +]) + +AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ + AC_REQUIRE([LIBVIRT_CHECK_LIBISCSI]) + if test "$with_storage_iscsi_direct" = "check"; then + with_storage_iscsi_direct=$with_libiscsi + fi + if test "$with_storage_iscsi_direct" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], + [whether iSCSI backend for storage driver is enabled]) + fi + AM_CONDITIONAL([WITH_STORAGE_ISCSI_DIRECT], + [test "$with_storage_iscsi_direct" = "yes"]) +]) + +AC_DEFUN([LIBVIRT_STORAGE_RESULT_ISCSI_DIRECT], [ + LIBVIRT_RESULT([iscsi-direct], [$with_storage_iscsi_direct]) +]) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7396616eda..5af27a6ad2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30163,6 +30163,10 @@ virDomainDiskTranslateSourcePool(virDomainDiskDefPtr def) break; + case VIR_STORAGE_POOL_ISCSI_DIRECT: + def->src->srcpool->mode = VIR_STORAGE_SOURCE_POOL_MODE_DIRECT; + break; + case VIR_STORAGE_POOL_ISCSI: if (def->startupPolicy) { virReportError(VIR_ERR_XML_ERROR, "%s", diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 5036ab9ef8..ee1586410b 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -62,9 +62,9 @@ VIR_ENUM_IMPL(virStoragePool, VIR_STORAGE_POOL_LAST, "dir", "fs", "netfs", "logical", "disk", "iscsi", - "scsi", "mpath", "rbd", - "sheepdog", "gluster", "zfs", - "vstorage") + "iscsi-direct", "scsi", "mpath", + "rbd", "sheepdog", "gluster", + "zfs", "vstorage") VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, VIR_STORAGE_POOL_FS_LAST, @@ -207,6 +207,17 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .formatToString = virStoragePoolFormatDiskTypeToString, } }, + {.poolType = VIR_STORAGE_POOL_ISCSI_DIRECT, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_DEVICE | + VIR_STORAGE_POOL_SOURCE_NETWORK | + VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN), + }, + .volOptions = { + .formatToString = virStoragePoolFormatDiskTypeToString, + } + }, {.poolType = VIR_STORAGE_POOL_SCSI, .poolOptions = { .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER), @@ -803,6 +814,19 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) goto error; } + if (ret->type == VIR_STORAGE_POOL_ISCSI_DIRECT) { + if (!ret->source.initiator.iqn) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool initiator iqn")); + goto error; + } + if (!ret->source.ndevice) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool device path")); + goto error; + } + } + cleanup: VIR_FREE(uuid); VIR_FREE(type); @@ -1004,7 +1028,8 @@ virStoragePoolDefFormatBuf(virBufferPtr buf, * files, so they don't have a target */ if (def->type != VIR_STORAGE_POOL_RBD && def->type != VIR_STORAGE_POOL_SHEEPDOG && - def->type != VIR_STORAGE_POOL_GLUSTER) { + def->type != VIR_STORAGE_POOL_GLUSTER && + def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) { virBufferAddLit(buf, "<target>\n"); virBufferAdjustIndent(buf, 2); diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 15dfd8becf..858623783d 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -85,6 +85,7 @@ typedef enum { VIR_STORAGE_POOL_LOGICAL, /* Logical volume groups / volumes */ VIR_STORAGE_POOL_DISK, /* Disk partitions */ VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */ + VIR_STORAGE_POOL_ISCSI_DIRECT, /* iSCSI targets using libiscsi */ VIR_STORAGE_POOL_SCSI, /* SCSI HBA */ VIR_STORAGE_POOL_MPATH, /* Multipath devices */ VIR_STORAGE_POOL_RBD, /* RADOS Block Device */ diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index e66b2ebfb2..1c45bb71b9 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1838,11 +1838,13 @@ virStoragePoolObjSourceFindDuplicateCb(const void *payload, break; case VIR_STORAGE_POOL_ISCSI: + case VIR_STORAGE_POOL_ISCSI_DIRECT: case VIR_STORAGE_POOL_FS: case VIR_STORAGE_POOL_LOGICAL: case VIR_STORAGE_POOL_DISK: case VIR_STORAGE_POOL_ZFS: if ((data->def->type == VIR_STORAGE_POOL_ISCSI || + data->def->type == VIR_STORAGE_POOL_ISCSI_DIRECT || data->def->type == VIR_STORAGE_POOL_FS || data->def->type == VIR_STORAGE_POOL_LOGICAL || data->def->type == VIR_STORAGE_POOL_DISK || diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am index ea98c0ee52..b2714fd960 100644 --- a/src/storage/Makefile.inc.am +++ b/src/storage/Makefile.inc.am @@ -31,6 +31,11 @@ STORAGE_DRIVER_ISCSI_SOURCES = \ storage/storage_backend_iscsi.c \ $(NULL) +STORAGE_DRIVER_ISCSI_DIRECT_SOURCES = \ + storage/storage_backend_iscsi_direct.h \ + storage/storage_backend_iscsi_direct.c \ + $(NULL) + STORAGE_DRIVER_SCSI_SOURCES = \ storage/storage_backend_scsi.h \ storage/storage_backend_scsi.c \ @@ -89,6 +94,7 @@ EXTRA_DIST += \ $(STORAGE_FILE_FS_SOURCES) \ $(STORAGE_DRIVER_LVM_SOURCES) \ $(STORAGE_DRIVER_ISCSI_SOURCES) \ + $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) \ $(STORAGE_DRIVER_SCSI_SOURCES) \ $(STORAGE_DRIVER_MPATH_SOURCES) \ $(STORAGE_DRIVER_DISK_SOURCES) \ @@ -193,6 +199,22 @@ libvirt_storage_backend_iscsi_la_LIBADD = \ $(NULL) endif WITH_STORAGE_ISCSI +if WITH_STORAGE_ISCSI_DIRECT +libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) +libvirt_storage_backend_iscsi_direct_la_CFLAGS = \ + -I$(srcdir)/conf \ + $(LIBISCSI_CFLAGS) \ + $(AM_CFLAGS) \ + $(NULL) + +storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la +libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD) +libvirt_storage_backend_iscsi_direct_la_LIBADD = \ + libvirt.la \ + ../gnulib/lib/libgnu.la \ + $(NULL) +endif WITH_STORAGE_ISCSI_DIRECT + if WITH_STORAGE_SCSI libvirt_storage_backend_scsi_la_SOURCES = $(STORAGE_DRIVER_SCSI_SOURCES) libvirt_storage_backend_scsi_la_CFLAGS = \ diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 7d226f3d3a..e7fbc37eb1 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -43,6 +43,9 @@ #if WITH_STORAGE_ISCSI # include "storage_backend_iscsi.h" #endif +#if WITH_STORAGE_ISCSI_DIRECT +# include "storage_backend_iscsi_direct.h" +#endif #if WITH_STORAGE_SCSI # include "storage_backend_scsi.h" #endif @@ -122,6 +125,9 @@ virStorageBackendDriversRegister(bool allbackends ATTRIBUTE_UNUSED) #if WITH_STORAGE_ISCSI VIR_STORAGE_BACKEND_REGISTER(virStorageBackendISCSIRegister, "iscsi"); #endif +#if WITH_STORAGE_ISCSI_DIRECT + VIR_STORAGE_BACKEND_REGISTER(virStorageBackendISCSIDirectRegister, "iscsi-direct"); +#endif #if WITH_STORAGE_SCSI VIR_STORAGE_BACKEND_REGISTER(virStorageBackendSCSIRegister, "scsi"); #endif diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c new file mode 100644 index 0000000000..94c4c989ff --- /dev/null +++ b/src/storage/storage_backend_iscsi_direct.c @@ -0,0 +1,58 @@ +/* + * storage_backend_iscsi_direct.c: storage backend for iSCSI using libiscsi + * + * Copyright (C) 2018 Clementine Hayat. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Clementine Hayat <clem@lse.epita.fr> + */ + +#include <config.h> + +#include "storage_backend_iscsi_direct.h" +#include "storage_util.h" +#include "virlog.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_LOG_INIT("storage.storage_backend_iscsi_direct"); + + +static int +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, + bool *isActive ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) +{ + return 0; +} + +virStorageBackend virStorageBackendISCSIDirect = { + .type = VIR_STORAGE_POOL_ISCSI_DIRECT, + + .checkPool = virStorageBackendISCSIDirectCheckPool, + .refreshPool = virStorageBackendISCSIDirectRefreshPool, +}; + +int +virStorageBackendISCSIDirectRegister(void) +{ + return virStorageBackendRegister(&virStorageBackendISCSIDirect); +} diff --git a/src/storage/storage_backend_iscsi_direct.h b/src/storage/storage_backend_iscsi_direct.h new file mode 100644 index 0000000000..545579daf7 --- /dev/null +++ b/src/storage/storage_backend_iscsi_direct.h @@ -0,0 +1,6 @@ +#ifndef __VIR_STORAGE_BACKEND_ISCSI_H__ +# define __VIR_STORAGE_BACKEND_ISCSI_H__ + +int virStorageBackendISCSIDirectRegister(void); + +#endif /* __VIR_STORAGE_BACKEND_ISCSI_H__ */ diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 8070d159ea..c108f026ce 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -1566,6 +1566,7 @@ storageVolLookupByPathCallback(virStoragePoolObjPtr obj, case VIR_STORAGE_POOL_LOGICAL: case VIR_STORAGE_POOL_DISK: case VIR_STORAGE_POOL_ISCSI: + case VIR_STORAGE_POOL_ISCSI_DIRECT: case VIR_STORAGE_POOL_SCSI: case VIR_STORAGE_POOL_MPATH: case VIR_STORAGE_POOL_VSTORAGE: diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index cc49a5b96d..4604b05020 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -1203,6 +1203,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) case VIR_STORAGE_POOL_ISCSI: flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI; break; + case VIR_STORAGE_POOL_ISCSI_DIRECT: + flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI; + break; case VIR_STORAGE_POOL_SCSI: flags |= VIR_CONNECT_LIST_STORAGE_POOLS_SCSI; break; -- 2.18.0

On 07/23/2018 08:43 PM, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
Introducing the pool as a noop. Integration inside the build system. Implementation will be in the following commits.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 6 ++- m4/virt-storage-iscsi-direct.m4 | 41 +++++++++++++++ src/conf/domain_conf.c | 4 ++ src/conf/storage_conf.c | 33 ++++++++++-- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 22 ++++++++ src/storage/storage_backend.c | 6 +++ src/storage/storage_backend_iscsi_direct.c | 58 ++++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 +++ src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 ++ 12 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h
Missing documentation. I can not push these without any documentation. You need to document what the new type is doing, what the XML should look like. Also, might be worth putting some test cases into storagepoolxml2xmltest. Since you will be sending v3, can you add docs/news.xml entry (in a separate patch) too please?
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7396616eda..5af27a6ad2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30163,6 +30163,10 @@ virDomainDiskTranslateSourcePool(virDomainDiskDefPtr def)
break;
+ case VIR_STORAGE_POOL_ISCSI_DIRECT: + def->src->srcpool->mode = VIR_STORAGE_SOURCE_POOL_MODE_DIRECT; + break; + case VIR_STORAGE_POOL_ISCSI: if (def->startupPolicy) { virReportError(VIR_ERR_XML_ERROR, "%s", diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 5036ab9ef8..ee1586410b 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -62,9 +62,9 @@ VIR_ENUM_IMPL(virStoragePool, VIR_STORAGE_POOL_LAST, "dir", "fs", "netfs", "logical", "disk", "iscsi", - "scsi", "mpath", "rbd", - "sheepdog", "gluster", "zfs", - "vstorage") + "iscsi-direct", "scsi", "mpath", + "rbd", "sheepdog", "gluster", + "zfs", "vstorage")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, VIR_STORAGE_POOL_FS_LAST, @@ -207,6 +207,17 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .formatToString = virStoragePoolFormatDiskTypeToString, } }, + {.poolType = VIR_STORAGE_POOL_ISCSI_DIRECT, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_DEVICE | + VIR_STORAGE_POOL_SOURCE_NETWORK | + VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN), + }, + .volOptions = { + .formatToString = virStoragePoolFormatDiskTypeToString, + } + }, {.poolType = VIR_STORAGE_POOL_SCSI, .poolOptions = { .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER), @@ -803,6 +814,19 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) goto error; }
+ if (ret->type == VIR_STORAGE_POOL_ISCSI_DIRECT) { + if (!ret->source.initiator.iqn) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool initiator iqn")); + goto error; + } + if (!ret->source.ndevice) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool device path")); + goto error; + } + }
So the wole idea of poolOptions and volOptions is to specify which parts of pool/volume XML are required so that we don't have to base checks like this on ret->type rather than flags. On the other hand, comment just above VIR_STORAGE_POOL_SOURCE_* enum says it declares mandatory components which it clearly doesn't. So after all I think we are safe here.
+ cleanup: VIR_FREE(uuid); VIR_FREE(type); @@ -1004,7 +1028,8 @@ virStoragePoolDefFormatBuf(virBufferPtr buf, * files, so they don't have a target */ if (def->type != VIR_STORAGE_POOL_RBD && def->type != VIR_STORAGE_POOL_SHEEPDOG && - def->type != VIR_STORAGE_POOL_GLUSTER) { + def->type != VIR_STORAGE_POOL_GLUSTER && + def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) { virBufferAddLit(buf, "<target>\n"); virBufferAdjustIndent(buf, 2);
Might be worth updating the comment just above this block ;-) Michal

2018-07-24 14:24 GMT+02:00 Michal Privoznik <mprivozn@redhat.com>:
On 07/23/2018 08:43 PM, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
Introducing the pool as a noop. Integration inside the build system. Implementation will be in the following commits.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 6 ++- m4/virt-storage-iscsi-direct.m4 | 41 +++++++++++++++ src/conf/domain_conf.c | 4 ++ src/conf/storage_conf.c | 33 ++++++++++-- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 22 ++++++++ src/storage/storage_backend.c | 6 +++ src/storage/storage_backend_iscsi_direct.c | 58 ++++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 +++ src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 ++ 12 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h
Missing documentation. I can not push these without any documentation. You need to document what the new type is doing, what the XML should look like. Also, might be worth putting some test cases into storagepoolxml2xmltest. Since you will be sending v3, can you add docs/news.xml entry (in a separate patch) too please?
Yes sure.
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7396616eda..5af27a6ad2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30163,6 +30163,10 @@ virDomainDiskTranslateSourcePool(virDomainDiskDefPtr def)
break;
+ case VIR_STORAGE_POOL_ISCSI_DIRECT: + def->src->srcpool->mode = VIR_STORAGE_SOURCE_POOL_MODE_DIRECT; + break; + case VIR_STORAGE_POOL_ISCSI: if (def->startupPolicy) { virReportError(VIR_ERR_XML_ERROR, "%s", diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 5036ab9ef8..ee1586410b 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -62,9 +62,9 @@ VIR_ENUM_IMPL(virStoragePool, VIR_STORAGE_POOL_LAST, "dir", "fs", "netfs", "logical", "disk", "iscsi", - "scsi", "mpath", "rbd", - "sheepdog", "gluster", "zfs", - "vstorage") + "iscsi-direct", "scsi", "mpath", + "rbd", "sheepdog", "gluster", + "zfs", "vstorage")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, VIR_STORAGE_POOL_FS_LAST, @@ -207,6 +207,17 @@ static virStoragePoolTypeInfo poolTypeInfo[] = { .formatToString = virStoragePoolFormatDiskTypeToString, } }, + {.poolType = VIR_STORAGE_POOL_ISCSI_DIRECT, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_DEVICE | + VIR_STORAGE_POOL_SOURCE_NETWORK | + VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN), + }, + .volOptions = { + .formatToString = virStoragePoolFormatDiskTypeToString, + } + }, {.poolType = VIR_STORAGE_POOL_SCSI, .poolOptions = { .flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER), @@ -803,6 +814,19 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) goto error; }
+ if (ret->type == VIR_STORAGE_POOL_ISCSI_DIRECT) { + if (!ret->source.initiator.iqn) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool initiator iqn")); + goto error; + } + if (!ret->source.ndevice) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool device path")); + goto error; + } + }
So the wole idea of poolOptions and volOptions is to specify which parts of pool/volume XML are required so that we don't have to base checks like this on ret->type rather than flags. On the other hand, comment just above VIR_STORAGE_POOL_SOURCE_* enum says it declares mandatory components which it clearly doesn't. So after all I think we are safe here.
That actually isn't the case for the initiator iqn flag. Is it on purpose or should I patch it in another thread?
+ cleanup: VIR_FREE(uuid); VIR_FREE(type); @@ -1004,7 +1028,8 @@ virStoragePoolDefFormatBuf(virBufferPtr buf, * files, so they don't have a target */ if (def->type != VIR_STORAGE_POOL_RBD && def->type != VIR_STORAGE_POOL_SHEEPDOG && - def->type != VIR_STORAGE_POOL_GLUSTER) { + def->type != VIR_STORAGE_POOL_GLUSTER && + def->type != VIR_STORAGE_POOL_ISCSI_DIRECT) { virBufferAddLit(buf, "<target>\n"); virBufferAdjustIndent(buf, 2);
Might be worth updating the comment just above this block ;-)
Sure! -- Clementine Hayat

On 07/24/2018 06:19 PM, Clementine Hayat wrote:
2018-07-24 14:24 GMT+02:00 Michal Privoznik <mprivozn@redhat.com>:
On 07/23/2018 08:43 PM, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
Introducing the pool as a noop. Integration inside the build system. Implementation will be in the following commits.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 6 ++- m4/virt-storage-iscsi-direct.m4 | 41 +++++++++++++++ src/conf/domain_conf.c | 4 ++ src/conf/storage_conf.c | 33 ++++++++++-- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 22 ++++++++ src/storage/storage_backend.c | 6 +++ src/storage/storage_backend_iscsi_direct.c | 58 ++++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 +++ src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 ++ 12 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h
@@ -803,6 +814,19 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) goto error; }
+ if (ret->type == VIR_STORAGE_POOL_ISCSI_DIRECT) { + if (!ret->source.initiator.iqn) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool initiator iqn")); + goto error; + } + if (!ret->source.ndevice) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing storage pool device path")); + goto error; + } + }
So the wole idea of poolOptions and volOptions is to specify which parts of pool/volume XML are required so that we don't have to base checks like this on ret->type rather than flags. On the other hand, comment just above VIR_STORAGE_POOL_SOURCE_* enum says it declares mandatory components which it clearly doesn't. So after all I think we are safe here.
That actually isn't the case for the initiator iqn flag. Is it on purpose or should I patch it in another thread?
I think saving that for a separate patch is okay. Speaking of threads, I forgot to mention, feel free to send v3 as a completely new thread. We don't really thread versions under v1. Michal

On Mon, Jul 23, 2018 at 08:43:00PM +0200, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
Introducing the pool as a noop. Integration inside the build system. Implementation will be in the following commits.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- configure.ac | 6 ++- m4/virt-storage-iscsi-direct.m4 | 41 +++++++++++++++ src/conf/domain_conf.c | 4 ++ src/conf/storage_conf.c | 33 ++++++++++-- src/conf/storage_conf.h | 1 + src/conf/virstorageobj.c | 2 + src/storage/Makefile.inc.am | 22 ++++++++ src/storage/storage_backend.c | 6 +++ src/storage/storage_backend_iscsi_direct.c | 58 ++++++++++++++++++++++ src/storage/storage_backend_iscsi_direct.h | 6 +++ src/storage/storage_driver.c | 1 + tools/virsh-pool.c | 3 ++ 12 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 m4/virt-storage-iscsi-direct.m4 create mode 100644 src/storage/storage_backend_iscsi_direct.c create mode 100644 src/storage/storage_backend_iscsi_direct.h
diff --git a/configure.ac b/configure.ac index c668630a79..87ac4dc2c3 100644 --- a/configure.ac +++ b/configure.ac @@ -564,6 +564,7 @@ LIBVIRT_STORAGE_ARG_DIR LIBVIRT_STORAGE_ARG_FS LIBVIRT_STORAGE_ARG_LVM LIBVIRT_STORAGE_ARG_ISCSI +LIBVIRT_STORAGE_ARG_ISCSI_DIRECT LIBVIRT_STORAGE_ARG_SCSI LIBVIRT_STORAGE_ARG_MPATH LIBVIRT_STORAGE_ARG_DISK @@ -578,6 +579,7 @@ if test "$with_libvirtd" = "no"; then with_storage_fs=no with_storage_lvm=no with_storage_iscsi=no + with_storage_iscsi_direct=no with_storage_scsi=no with_storage_mpath=no with_storage_disk=no @@ -598,6 +600,7 @@ LIBVIRT_STORAGE_CHECK_DIR LIBVIRT_STORAGE_CHECK_FS LIBVIRT_STORAGE_CHECK_LVM LIBVIRT_STORAGE_CHECK_ISCSI +LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT LIBVIRT_STORAGE_CHECK_SCSI LIBVIRT_STORAGE_CHECK_MPATH LIBVIRT_STORAGE_CHECK_DISK @@ -608,7 +611,7 @@ LIBVIRT_STORAGE_CHECK_ZFS LIBVIRT_STORAGE_CHECK_VSTORAGE
with_storage=no -for backend in dir fs lvm iscsi scsi mpath rbd disk; do +for backend in dir fs lvm iscsi iscsi_direct scsi mpath rbd disk; do if eval test \$with_storage_$backend = yes; then with_storage=yes break @@ -936,6 +939,7 @@ LIBVIRT_STORAGE_RESULT_DIR LIBVIRT_STORAGE_RESULT_FS LIBVIRT_STORAGE_RESULT_LVM LIBVIRT_STORAGE_RESULT_ISCSI +LIBVIRT_STORAGE_RESULT_ISCSI_DIRECT LIBVIRT_STORAGE_RESULT_SCSI LIBVIRT_STORAGE_RESULT_MPATH LIBVIRT_STORAGE_RESULT_DISK diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4 new file mode 100644 index 0000000000..cc2d490352 --- /dev/null +++ b/m4/virt-storage-iscsi-direct.m4 @@ -0,0 +1,41 @@ +dnl Iscsi-direct storage +dnl +dnl Copyright (C) 2018 Clementine Hayat. +dnl +dnl This library is free software; you can redistribute it and/or +dnl modify it under the terms of the GNU Lesser General Public +dnl License as published by the Free Software Foundation; either +dnl version 2.1 of the License, or (at your option) any later version. +dnl +dnl This library is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl Lesser General Public License for more details. +dnl +dnl You should have received a copy of the GNU Lesser General Public +dnl License along with this library. If not, see +dnl <http://www.gnu.org/licenses/>. +dnl + +AC_DEFUN([LIBVIRT_STORAGE_ARG_ISCSI_DIRECT], [ + LIBVIRT_ARG_WITH_FEATURE([STORAGE_ISCSI_DIRECT], + [iscsi-direct backend for the storage driver], + [check]) +]) + +AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ + AC_REQUIRE([LIBVIRT_CHECK_LIBISCSI]) + if test "$with_storage_iscsi_direct" = "check"; then + with_storage_iscsi_direct=$with_libiscsi + fi + if test "$with_storage_iscsi_direct" = "yes"; then + AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], + [whether iSCSI backend for storage driver is enabled]) + fi + AM_CONDITIONAL([WITH_STORAGE_ISCSI_DIRECT], + [test "$with_storage_iscsi_direct" = "yes"]) +]) + +AC_DEFUN([LIBVIRT_STORAGE_RESULT_ISCSI_DIRECT], [ + LIBVIRT_RESULT([iscsi-direct], [$with_storage_iscsi_direct]) +]) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7396616eda..5af27a6ad2 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30163,6 +30163,10 @@ virDomainDiskTranslateSourcePool(virDomainDiskDefPtr def)
break;
+ case VIR_STORAGE_POOL_ISCSI_DIRECT: + def->src->srcpool->mode = VIR_STORAGE_SOURCE_POOL_MODE_DIRECT; + break;
This is not exactly what I meant, this will not work. Firstly, we should error out if startupPolicy is set the same way as we do for VIR_STORAGE_POOL_ISCSI. We also need to call all this code to translate the storage pool into domain disk definition: case VIR_STORAGE_SOURCE_POOL_MODE_DIRECT: def->src->srcpool->actualtype = VIR_STORAGE_TYPE_NETWORK; def->src->protocol = VIR_STORAGE_NET_PROTOCOL_ISCSI; if (virDomainDiskTranslateSourcePoolAuth(def, &pooldef->source) < 0) goto cleanup; /* Source pool may not fill in the secrettype field, * so we need to do so here */ if (def->src->auth && !def->src->auth->secrettype) { const char *secrettype = virSecretUsageTypeToString(VIR_SECRET_USAGE_TYPE_ISCSI); if (VIR_STRDUP(def->src->auth->secrettype, secrettype) < 0) goto cleanup; } if (virDomainDiskAddISCSIPoolSourceHost(def, pooldef) < 0) goto cleanup; So I would suggest moving that code into separate function and calling that function for VIR_STORAGE_POOL_ISCSI_DIRECT and also in the original place of that code. You can test this part by creating domain with this disk definition: ... <disk type='volume' device='disk'> <driver name='qemu' type='raw'/> <source pool='storage-pool-name' volume='storage-volume-name'/> <target dev='vda' bus='virtio'/> </disk> ... Pavel

From: Clementine Hayat <clem@lse.epita.fr> We need here libiscsi for the storgae pool backend. For the iscsi-direct storage pool, only checkPool and refreshPool should be necessary. The pool is state-less and just need the informations within the volume to work. Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- m4/virt-storage-iscsi-direct.m4 | 3 + src/storage/Makefile.inc.am | 2 + src/storage/storage_backend_iscsi_direct.c | 408 ++++++++++++++++++++- 3 files changed, 410 insertions(+), 3 deletions(-) diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4 index cc2d490352..dab4414169 100644 --- a/m4/virt-storage-iscsi-direct.m4 +++ b/m4/virt-storage-iscsi-direct.m4 @@ -29,6 +29,9 @@ AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ with_storage_iscsi_direct=$with_libiscsi fi if test "$with_storage_iscsi_direct" = "yes"; then + if test "$with_libiscsi" = "no"; then + AC_MSG_ERROR([Need libiscsi for iscsi-direct storage driver]) + fi AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], [whether iSCSI backend for storage driver is enabled]) fi diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am index b2714fd960..bd5ea06f8b 100644 --- a/src/storage/Makefile.inc.am +++ b/src/storage/Makefile.inc.am @@ -203,6 +203,7 @@ if WITH_STORAGE_ISCSI_DIRECT libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) libvirt_storage_backend_iscsi_direct_la_CFLAGS = \ -I$(srcdir)/conf \ + -I$(srcdir)/secret \ $(LIBISCSI_CFLAGS) \ $(AM_CFLAGS) \ $(NULL) @@ -211,6 +212,7 @@ storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD) libvirt_storage_backend_iscsi_direct_la_LIBADD = \ libvirt.la \ + $(LIBISCSI_LIBS) \ ../gnulib/lib/libgnu.la \ $(NULL) endif WITH_STORAGE_ISCSI_DIRECT diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c index 94c4c989ff..b9a9bb3eb0 100644 --- a/src/storage/storage_backend_iscsi_direct.c +++ b/src/storage/storage_backend_iscsi_direct.c @@ -22,28 +22,430 @@ #include <config.h> +#include <iscsi/iscsi.h> +#include <iscsi/scsi-lowlevel.h> + +#include "datatypes.h" +#include "secret_util.h" #include "storage_backend_iscsi_direct.h" #include "storage_util.h" +#include "viralloc.h" +#include "virerror.h" #include "virlog.h" +#include "virobject.h" +#include "virstring.h" +#include "virtime.h" +#include "viruuid.h" #define VIR_FROM_THIS VIR_FROM_STORAGE +#define ISCSI_DEFAULT_TARGET_PORT 3260 +#define VIR_ISCSI_TEST_UNIT_TIMEOUT 30 * 1000 + VIR_LOG_INIT("storage.storage_backend_iscsi_direct"); +static struct iscsi_context * +virISCSIDirectCreateContext(const char* initiator_iqn) +{ + struct iscsi_context *iscsi = NULL; + + iscsi = iscsi_create_context(initiator_iqn); + if (!iscsi) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create iscsi context for %s"), + initiator_iqn); + return iscsi; +} + +static char * +virStorageBackendISCSIDirectPortal(virStoragePoolSourcePtr source) +{ + char *portal = NULL; + + if (source->nhost != 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return NULL; + } + if (source->hosts[0].port == 0) { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + ISCSI_DEFAULT_TARGET_PORT)); + } else if (strchr(source->hosts[0].name, ':')) { + ignore_value(virAsprintf(&portal, "[%s]:%d", + source->hosts[0].name, + source->hosts[0].port)); + } else { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + source->hosts[0].port)); + } + return portal; +} + +static int +virStorageBackendISCSIDirectSetAuth(struct iscsi_context *iscsi, + virStoragePoolSourcePtr source) +{ + unsigned char *secret_value = NULL; + size_t secret_size; + virStorageAuthDefPtr authdef = source->auth; + int ret = -1; + virConnectPtr conn = NULL; + + if (!authdef || authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) + return 0; + + VIR_DEBUG("username='%s' authType=%d seclookupdef.type=%d", + authdef->username, authdef->authType, authdef->seclookupdef.type); + + if (authdef->authType != VIR_STORAGE_AUTH_TYPE_CHAP) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("iscsi-direct pool only supports 'chap' auth type")); + return ret; + } + + if (!(conn = virGetConnectSecret())) + return ret; + + if (virSecretGetSecretString(conn, &authdef->seclookupdef, + VIR_SECRET_USAGE_TYPE_ISCSI, + &secret_value, &secret_size) < 0) + goto cleanup; + + if (iscsi_set_initiator_username_pwd(iscsi, + authdef->username, + (const char *)secret_value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set credential: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret = 0; + cleanup: + VIR_DISPOSE_N(secret_value, secret_size); + virObjectUnref(conn); + return ret; +} + +static int +virISCSIDirectSetContext(struct iscsi_context *iscsi, + const char *target_name) +{ + if (iscsi_init_transport(iscsi, TCP_TRANSPORT) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to init transport: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_targetname(iscsi, target_name) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set target name: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set session type: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} + +static int +virISCSIDirectConnect(struct iscsi_context *iscsi, + const char *portal) +{ + if (iscsi_connect_sync(iscsi, portal) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to connect: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_login_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to login: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} + +static struct scsi_reportluns_list * +virISCSIDirectReportLuns(struct iscsi_context *iscsi) +{ + struct scsi_task *task = NULL; + struct scsi_reportluns_list *list = NULL; + int full_size; + + if (!(task = iscsi_reportluns_sync(iscsi, 0, 16))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + full_size = scsi_datain_getfullsize(task); + + if (full_size > task->datain.size) { + scsi_free_scsi_task(task); + if (!(task = iscsi_reportluns_sync(iscsi, 0, full_size))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + } + + if (!(list = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + cleanup: + scsi_free_scsi_task(task); + return list; +} + +static int +virISCSIDirectTestUnitReady(struct iscsi_context *iscsi, + int lun) +{ + struct scsi_task *task = NULL; + int ret = -1; + virTimeBackOffVar timebackoff; + + if (virTimeBackOffStart(&timebackoff, 1, + VIR_ISCSI_TEST_UNIT_TIMEOUT) < 0) + goto cleanup; + + do { + if (!(task = iscsi_testunitready_sync(iscsi, lun))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (task->status != SCSI_STATUS_CHECK_CONDITION || + task->sense.key != SCSI_SENSE_UNIT_ATTENTION || + task->sense.ascq != SCSI_SENSE_ASCQ_BUS_RESET) + break; + + scsi_free_scsi_task(task); + } while (virTimeBackOffWait(&timebackoff)); + + if (task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret = 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectSetVolumeAttributes(virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + int lun, + char *portal) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + + if (virAsprintf(&vol->name, "%u", lun) < 0) + return -1; + if (virAsprintf(&vol->key, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; + if (virAsprintf(&vol->target.path, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; + return 0; +} + +static int +virISCSIDirectSetVolumeCapacity(struct iscsi_context *iscsi, + virStorageVolDefPtr vol, + int lun) +{ + struct scsi_task *task = NULL; + struct scsi_inquiry_standard *inq = NULL; + long long size = 0; + int ret = -1; + + if (!(task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64)) || + task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to send inquiry command: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(inq = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (inq->device_type == SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { + struct scsi_readcapacity10 *rc10 = NULL; + + scsi_free_scsi_task(task); + task = NULL; + + if (!(task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0)) || + task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get capacity of lun: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(rc10 = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + size = rc10->block_size; + size *= rc10->lba; + vol->target.capacity = size; + vol->target.allocation = size; + + } + + ret = 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectRefreshVol(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + int lun, + char *portal) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + virStorageVolDefPtr vol = NULL; + int ret = -1; + + virStoragePoolObjClearVols(pool); + if (virISCSIDirectTestUnitReady(iscsi, lun) < 0) + goto cleanup; + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_NETWORK; + + if (virISCSIDirectSetVolumeCapacity(iscsi, vol, lun) < 0) + goto cleanup; + + def->capacity += vol->target.capacity; + def->allocation += vol->target.allocation; + + if (virISCSIDirectSetVolumeAttributes(pool, vol, lun, portal) < 0) + goto cleanup; + + if (virStoragePoolObjAddVol(pool, vol) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create volume: %d"), + lun); + goto cleanup; + } + vol = NULL; + + ret = 0; + cleanup: + virStorageVolDefFree(vol); + return ret; +} static int -virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - bool *isActive ATTRIBUTE_UNUSED) +virStorageBackendISCSIDirectRefreshVols(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + char *portal) { + struct scsi_reportluns_list *list = NULL; + size_t i; + + if (!(list = virISCSIDirectReportLuns(iscsi))) + return -1; + for (i = 0; i < list->num; i++) { + if (virISCSIDirectRefreshVol(pool, iscsi, list->luns[i], portal) < 0) + return -1; + } + return 0; } static int -virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) +virISCSIDirectDisconnect(struct iscsi_context *iscsi) { + if (iscsi_logout_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to logout: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_disconnect(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to disconnect: %s"), + iscsi_get_error(iscsi)); + return -1; + } return 0; } +static int +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool, + bool *isActive) +{ + *isActive = virStoragePoolObjIsActive(pool); + return 0; +} + +static int +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + struct iscsi_context *iscsi = NULL; + char *portal = NULL; + int ret = -1; + + if (!(iscsi = virISCSIDirectCreateContext(def->source.initiator.iqn))) + goto cleanup; + if (!(portal = virStorageBackendISCSIDirectPortal(&def->source))) + goto cleanup; + if (virStorageBackendISCSIDirectSetAuth(iscsi, &def->source) < 0) + goto cleanup; + if (virISCSIDirectSetContext(iscsi, def->source.devices[0].path) < 0) + goto cleanup; + if (virISCSIDirectConnect(iscsi, portal) < 0) + goto cleanup; + if (virStorageBackendISCSIDirectRefreshVols(pool, iscsi, portal) < 0) + goto disconect; + + ret = 0; + disconect: + virISCSIDirectDisconnect(iscsi); + cleanup: + VIR_FREE(portal); + iscsi_destroy_context(iscsi); + return ret; +} + virStorageBackend virStorageBackendISCSIDirect = { .type = VIR_STORAGE_POOL_ISCSI_DIRECT, -- 2.18.0

On 07/23/2018 08:43 PM, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
We need here libiscsi for the storgae pool backend. For the iscsi-direct storage pool, only checkPool and refreshPool should be necessary.
Well, they are necessary only for basic support. There is still couple of APIs worth implementing ;-)
The pool is state-less and just need the informations within the volume to work.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- m4/virt-storage-iscsi-direct.m4 | 3 + src/storage/Makefile.inc.am | 2 + src/storage/storage_backend_iscsi_direct.c | 408 ++++++++++++++++++++- 3 files changed, 410 insertions(+), 3 deletions(-)
ACK Michal

On Mon, Jul 23, 2018 at 08:43:01PM +0200, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
We need here libiscsi for the storgae pool backend. For the iscsi-direct storage pool, only checkPool and refreshPool should be necessary. The pool is state-less and just need the informations within the volume to work.
Signed-off-by: Clementine Hayat <clem@lse.epita.fr> --- m4/virt-storage-iscsi-direct.m4 | 3 + src/storage/Makefile.inc.am | 2 + src/storage/storage_backend_iscsi_direct.c | 408 ++++++++++++++++++++- 3 files changed, 410 insertions(+), 3 deletions(-)
diff --git a/m4/virt-storage-iscsi-direct.m4 b/m4/virt-storage-iscsi-direct.m4 index cc2d490352..dab4414169 100644 --- a/m4/virt-storage-iscsi-direct.m4 +++ b/m4/virt-storage-iscsi-direct.m4 @@ -29,6 +29,9 @@ AC_DEFUN([LIBVIRT_STORAGE_CHECK_ISCSI_DIRECT], [ with_storage_iscsi_direct=$with_libiscsi fi if test "$with_storage_iscsi_direct" = "yes"; then + if test "$with_libiscsi" = "no"; then + AC_MSG_ERROR([Need libiscsi for iscsi-direct storage driver]) + fi AC_DEFINE_UNQUOTED([WITH_STORAGE_ISCSI_DIRECT], [1], [whether iSCSI backend for storage driver is enabled]) fi diff --git a/src/storage/Makefile.inc.am b/src/storage/Makefile.inc.am index b2714fd960..bd5ea06f8b 100644 --- a/src/storage/Makefile.inc.am +++ b/src/storage/Makefile.inc.am @@ -203,6 +203,7 @@ if WITH_STORAGE_ISCSI_DIRECT libvirt_storage_backend_iscsi_direct_la_SOURCES = $(STORAGE_DRIVER_ISCSI_DIRECT_SOURCES) libvirt_storage_backend_iscsi_direct_la_CFLAGS = \ -I$(srcdir)/conf \ + -I$(srcdir)/secret \ $(LIBISCSI_CFLAGS) \ $(AM_CFLAGS) \ $(NULL) @@ -211,6 +212,7 @@ storagebackend_LTLIBRARIES += libvirt_storage_backend_iscsi-direct.la libvirt_storage_backend_iscsi_direct_la_LDFLAGS = $(AM_LDFLAGS_MOD) libvirt_storage_backend_iscsi_direct_la_LIBADD = \ libvirt.la \ + $(LIBISCSI_LIBS) \ ../gnulib/lib/libgnu.la \ $(NULL) endif WITH_STORAGE_ISCSI_DIRECT diff --git a/src/storage/storage_backend_iscsi_direct.c b/src/storage/storage_backend_iscsi_direct.c index 94c4c989ff..b9a9bb3eb0 100644 --- a/src/storage/storage_backend_iscsi_direct.c +++ b/src/storage/storage_backend_iscsi_direct.c @@ -22,28 +22,430 @@
#include <config.h>
+#include <iscsi/iscsi.h> +#include <iscsi/scsi-lowlevel.h> + +#include "datatypes.h" +#include "secret_util.h" #include "storage_backend_iscsi_direct.h" #include "storage_util.h" +#include "viralloc.h" +#include "virerror.h" #include "virlog.h" +#include "virobject.h" +#include "virstring.h" +#include "virtime.h" +#include "viruuid.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
+#define ISCSI_DEFAULT_TARGET_PORT 3260 +#define VIR_ISCSI_TEST_UNIT_TIMEOUT 30 * 1000 + VIR_LOG_INIT("storage.storage_backend_iscsi_direct");
+static struct iscsi_context * +virISCSIDirectCreateContext(const char* initiator_iqn) +{ + struct iscsi_context *iscsi = NULL; + + iscsi = iscsi_create_context(initiator_iqn); + if (!iscsi) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create iscsi context for %s"), + initiator_iqn); + return iscsi; +} + +static char * +virStorageBackendISCSIDirectPortal(virStoragePoolSourcePtr source) +{ + char *portal = NULL; + + if (source->nhost != 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return NULL; + } + if (source->hosts[0].port == 0) { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + ISCSI_DEFAULT_TARGET_PORT)); + } else if (strchr(source->hosts[0].name, ':')) { + ignore_value(virAsprintf(&portal, "[%s]:%d", + source->hosts[0].name, + source->hosts[0].port)); + } else { + ignore_value(virAsprintf(&portal, "%s:%d", + source->hosts[0].name, + source->hosts[0].port)); + } + return portal; +} + +static int +virStorageBackendISCSIDirectSetAuth(struct iscsi_context *iscsi, + virStoragePoolSourcePtr source) +{ + unsigned char *secret_value = NULL; + size_t secret_size; + virStorageAuthDefPtr authdef = source->auth; + int ret = -1; + virConnectPtr conn = NULL; + + if (!authdef || authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) + return 0; + + VIR_DEBUG("username='%s' authType=%d seclookupdef.type=%d", + authdef->username, authdef->authType, authdef->seclookupdef.type); + + if (authdef->authType != VIR_STORAGE_AUTH_TYPE_CHAP) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("iscsi-direct pool only supports 'chap' auth type")); + return ret; + } + + if (!(conn = virGetConnectSecret())) + return ret; + + if (virSecretGetSecretString(conn, &authdef->seclookupdef, + VIR_SECRET_USAGE_TYPE_ISCSI, + &secret_value, &secret_size) < 0) + goto cleanup; + + if (iscsi_set_initiator_username_pwd(iscsi, + authdef->username, + (const char *)secret_value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set credential: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret = 0; + cleanup: + VIR_DISPOSE_N(secret_value, secret_size); + virObjectUnref(conn); + return ret; +} + +static int +virISCSIDirectSetContext(struct iscsi_context *iscsi, + const char *target_name) +{ + if (iscsi_init_transport(iscsi, TCP_TRANSPORT) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to init transport: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_targetname(iscsi, target_name) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set target name: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to set session type: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} + +static int +virISCSIDirectConnect(struct iscsi_context *iscsi, + const char *portal) +{ + if (iscsi_connect_sync(iscsi, portal) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to connect: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_login_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to login: %s"), + iscsi_get_error(iscsi)); + return -1; + } + return 0; +} + +static struct scsi_reportluns_list * +virISCSIDirectReportLuns(struct iscsi_context *iscsi) +{ + struct scsi_task *task = NULL; + struct scsi_reportluns_list *list = NULL; + int full_size; + + if (!(task = iscsi_reportluns_sync(iscsi, 0, 16))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + }
Here we create new task.
+ + full_size = scsi_datain_getfullsize(task); + + if (full_size > task->datain.size) { + scsi_free_scsi_task(task); + if (!(task = iscsi_reportluns_sync(iscsi, 0, full_size))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + }
Here we get all the available LUNs.
+ + if (!(list = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reportluns: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + }
And here we get the list of the available LUNs, so far so good. But there is a hidden issue, the memory returned here and stored into @list is not newly allocated memory but it's part of the @task data structure.
+ + cleanup: + scsi_free_scsi_task(task);
Here we free all the memory allocated by the @task together with the @list and then we return pointer to freed memory.
+ return list; +} + +static int +virISCSIDirectTestUnitReady(struct iscsi_context *iscsi, + int lun) +{ + struct scsi_task *task = NULL; + int ret = -1; + virTimeBackOffVar timebackoff; + + if (virTimeBackOffStart(&timebackoff, 1, + VIR_ISCSI_TEST_UNIT_TIMEOUT) < 0) + goto cleanup; + + do { + if (!(task = iscsi_testunitready_sync(iscsi, lun))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (task->status != SCSI_STATUS_CHECK_CONDITION || + task->sense.key != SCSI_SENSE_UNIT_ATTENTION || + task->sense.ascq != SCSI_SENSE_ASCQ_BUS_RESET) + break; + + scsi_free_scsi_task(task); + } while (virTimeBackOffWait(&timebackoff)); + + if (task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed testunitready: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + ret = 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectSetVolumeAttributes(virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, + int lun, + char *portal) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + + if (virAsprintf(&vol->name, "%u", lun) < 0) + return -1; + if (virAsprintf(&vol->key, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1; + if (virAsprintf(&vol->target.path, "ip-%s-iscsi-%s-lun-%u", portal, + def->source.devices[0].path, lun) < 0) + return -1;
Now that I'm testing the code I'm not sure about these values. For example the name cannot be only the number of the LUN, that will not work in domain XML if we use virDomainDiskAddISCSIPoolSourceHost() in order to translate storage volume into domain disk definition. I thing we should use these values: name unit:0:0:$LUN path $poolName/$volName key can remain as it is.
+ return 0; +} + +static int +virISCSIDirectSetVolumeCapacity(struct iscsi_context *iscsi, + virStorageVolDefPtr vol, + int lun) +{ + struct scsi_task *task = NULL; + struct scsi_inquiry_standard *inq = NULL; + long long size = 0; + int ret = -1; + + if (!(task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64)) || + task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to send inquiry command: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(inq = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (inq->device_type == SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { + struct scsi_readcapacity10 *rc10 = NULL; + + scsi_free_scsi_task(task); + task = NULL; + + if (!(task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0)) || + task->status != SCSI_STATUS_GOOD) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get capacity of lun: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + if (!(rc10 = scsi_datain_unmarshall(task))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to unmarshall reply: %s"), + iscsi_get_error(iscsi)); + goto cleanup; + } + + size = rc10->block_size; + size *= rc10->lba; + vol->target.capacity = size; + vol->target.allocation = size; + + } + + ret = 0; + cleanup: + scsi_free_scsi_task(task); + return ret; +} + +static int +virISCSIDirectRefreshVol(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + int lun, + char *portal) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + virStorageVolDefPtr vol = NULL; + int ret = -1; + + virStoragePoolObjClearVols(pool); + if (virISCSIDirectTestUnitReady(iscsi, lun) < 0) + goto cleanup; + + if (VIR_ALLOC(vol) < 0) + goto cleanup; + + vol->type = VIR_STORAGE_VOL_NETWORK; + + if (virISCSIDirectSetVolumeCapacity(iscsi, vol, lun) < 0) + goto cleanup; + + def->capacity += vol->target.capacity; + def->allocation += vol->target.allocation; + + if (virISCSIDirectSetVolumeAttributes(pool, vol, lun, portal) < 0) + goto cleanup; + + if (virStoragePoolObjAddVol(pool, vol) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create volume: %d"), + lun); + goto cleanup; + } + vol = NULL; + + ret = 0; + cleanup: + virStorageVolDefFree(vol); + return ret; +}
static int -virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, - bool *isActive ATTRIBUTE_UNUSED) +virStorageBackendISCSIDirectRefreshVols(virStoragePoolObjPtr pool, + struct iscsi_context *iscsi, + char *portal) { + struct scsi_reportluns_list *list = NULL; + size_t i; + + if (!(list = virISCSIDirectReportLuns(iscsi))) + return -1;
Unfortunately this will not work :/. Documentation of libiscsi really sucks, sigh.
+ for (i = 0; i < list->num; i++) { + if (virISCSIDirectRefreshVol(pool, iscsi, list->luns[i], portal) < 0) + return -1; + }
This for loop needs to be moved into virISCSIDirectReportLuns(), witch means that we can remove expand content of that function here and remove it completely. The result would be only having virStorageBackendISCSIDirectRefreshVols() with code from virISCSIDirectReportLuns() as well. Pavel
+ return 0; }
static int -virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool ATTRIBUTE_UNUSED) +virISCSIDirectDisconnect(struct iscsi_context *iscsi) { + if (iscsi_logout_sync(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to logout: %s"), + iscsi_get_error(iscsi)); + return -1; + } + if (iscsi_disconnect(iscsi) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to disconnect: %s"), + iscsi_get_error(iscsi)); + return -1; + } return 0; }
+static int +virStorageBackendISCSIDirectCheckPool(virStoragePoolObjPtr pool, + bool *isActive) +{ + *isActive = virStoragePoolObjIsActive(pool); + return 0; +} + +static int +virStorageBackendISCSIDirectRefreshPool(virStoragePoolObjPtr pool) +{ + virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool); + struct iscsi_context *iscsi = NULL; + char *portal = NULL; + int ret = -1; + + if (!(iscsi = virISCSIDirectCreateContext(def->source.initiator.iqn))) + goto cleanup; + if (!(portal = virStorageBackendISCSIDirectPortal(&def->source))) + goto cleanup; + if (virStorageBackendISCSIDirectSetAuth(iscsi, &def->source) < 0) + goto cleanup; + if (virISCSIDirectSetContext(iscsi, def->source.devices[0].path) < 0) + goto cleanup; + if (virISCSIDirectConnect(iscsi, portal) < 0) + goto cleanup; + if (virStorageBackendISCSIDirectRefreshVols(pool, iscsi, portal) < 0) + goto disconect; + + ret = 0; + disconect: + virISCSIDirectDisconnect(iscsi); + cleanup: + VIR_FREE(portal); + iscsi_destroy_context(iscsi); + return ret; +} + virStorageBackend virStorageBackendISCSIDirect = { .type = VIR_STORAGE_POOL_ISCSI_DIRECT,
-- 2.18.0
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 07/23/2018 08:42 PM, clem@lse.epita.fr wrote:
From: Clementine Hayat <clem@lse.epita.fr>
Hello,
This is the implementation of the iscsi-direct backend storage pool version 2. The documentation, some API calls and tests are still missing and will be comming in a second part.
Best Regards,
When posting patches to the list, always make sure they are rebased onto current HEAD. Fortunately, the merge conflict was small so I could resolve it instantly. Usually, the cover letter for any new version of patches looks like this: There is a link to previous version (at least), there is a diff to previous version. A good example looks something like this: https://www.redhat.com/archives/libvir-list/2018-July/msg01343.html Also, no need to put extra -- at the end of the cover letter - MTAs usually interpret it as end of git commit message. Michal
participants (8)
-
clem@lse.epita.fr
-
Clementine Hayat
-
Daniel P. Berrangé
-
Gabriel Laskar
-
Jiri Denemark
-
Michal Privoznik
-
Pavel Hrdina
-
Peter Krempa