libvirt/src/util/virscsivhost.c
Michal Privoznik 10f94828ea virobject: Introduce VIR_CLASS_NEW() macro
So far we are repeating the following lines over and over:

  if (!(virSomeObjectClass = virClassNew(virClassForObject(),
                             "virSomeObject",
                             sizeof(virSomeObject),
                             virSomeObjectDispose)))
      return -1;

While this works, it is impossible to do some checking. Firstly,
the class name (the 2nd argument) doesn't match the name in the
code in all cases (the 3rd argument). Secondly, the current style
is needlessly verbose. This commit turns example into following:

  if (!(VIR_CLASS_NEW(virSomeObject,
                      virClassForObject)))
      return -1;

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
2018-04-18 10:04:55 +02:00

297 lines
6.4 KiB
C

/*
* virscsivhost.c: helper APIs for managing scsi_host devices
*
* Copyright (C) 2016 IBM Corporation
*
* 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/>.
*
* Authors:
* Eric Farman <farman@linux.vnet.ibm.com>
*/
#include <config.h>
#include <fcntl.h>
#include "virscsivhost.h"
#include "virlog.h"
#include "viralloc.h"
#include "virerror.h"
#include "virfile.h"
#include "virstring.h"
/* For virReportOOMError() and virReportSystemError() */
#define VIR_FROM_THIS VIR_FROM_NONE
VIR_LOG_INIT("util.scsihost");
#define SYSFS_VHOST_SCSI_DEVICES "/sys/kernel/config/target/vhost/"
#define VHOST_SCSI_DEVICE "/dev/vhost-scsi"
struct _virSCSIVHostDevice {
char *name; /* naa.<wwn> */
char *path;
char *used_by_drvname;
char *used_by_domname;
};
struct _virSCSIVHostDeviceList {
virObjectLockable parent;
size_t count;
virSCSIVHostDevicePtr *devs;
};
static virClassPtr virSCSIVHostDeviceListClass;
static void
virSCSIVHostDeviceListDispose(void *obj)
{
virSCSIVHostDeviceListPtr list = obj;
size_t i;
for (i = 0; i < list->count; i++)
virSCSIVHostDeviceFree(list->devs[i]);
VIR_FREE(list->devs);
}
static int
virSCSIVHostOnceInit(void)
{
if (!VIR_CLASS_NEW(virSCSIVHostDeviceList, virClassForObjectLockable()))
return -1;
return 0;
}
VIR_ONCE_GLOBAL_INIT(virSCSIVHost)
int
virSCSIVHostOpenVhostSCSI(int *vhostfd)
{
if (!virFileExists(VHOST_SCSI_DEVICE)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("vhost-scsi device file '%s' cannot be found"),
VHOST_SCSI_DEVICE);
return -1;
}
*vhostfd = open(VHOST_SCSI_DEVICE, O_RDWR);
if (*vhostfd < 0) {
virReportSystemError(errno, _("Failed to open %s"), VHOST_SCSI_DEVICE);
goto error;
}
return 0;
error:
VIR_FORCE_CLOSE(*vhostfd);
return -1;
}
void
virSCSIVHostDeviceListDel(virSCSIVHostDeviceListPtr list,
virSCSIVHostDevicePtr dev)
{
virSCSIVHostDevicePtr tmp = virSCSIVHostDeviceListSteal(list, dev);
virSCSIVHostDeviceFree(tmp);
}
static int
virSCSIVHostDeviceListFindIndex(virSCSIVHostDeviceListPtr list,
virSCSIVHostDevicePtr dev)
{
size_t i;
for (i = 0; i < list->count; i++) {
virSCSIVHostDevicePtr other = list->devs[i];
if (STREQ_NULLABLE(other->name, dev->name))
return i;
}
return -1;
}
virSCSIVHostDevicePtr
virSCSIVHostDeviceListGet(virSCSIVHostDeviceListPtr list, int idx)
{
if (idx >= list->count || idx < 0)
return NULL;
return list->devs[idx];
}
size_t
virSCSIVHostDeviceListCount(virSCSIVHostDeviceListPtr list)
{
return list->count;
}
virSCSIVHostDevicePtr
virSCSIVHostDeviceListSteal(virSCSIVHostDeviceListPtr list,
virSCSIVHostDevicePtr dev)
{
virSCSIVHostDevicePtr ret = NULL;
size_t i;
for (i = 0; i < list->count; i++) {
if (STREQ_NULLABLE(list->devs[i]->name, dev->name)) {
ret = list->devs[i];
VIR_DELETE_ELEMENT(list->devs, i, list->count);
break;
}
}
return ret;
}
virSCSIVHostDevicePtr
virSCSIVHostDeviceListFind(virSCSIVHostDeviceListPtr list,
virSCSIVHostDevicePtr dev)
{
int idx;
if ((idx = virSCSIVHostDeviceListFindIndex(list, dev)) >= 0)
return list->devs[idx];
else
return NULL;
}
int
virSCSIVHostDeviceListAdd(virSCSIVHostDeviceListPtr list,
virSCSIVHostDevicePtr dev)
{
if (virSCSIVHostDeviceListFind(list, dev)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Device %s is already in use"), dev->name);
return -1;
}
return VIR_APPEND_ELEMENT(list->devs, list->count, dev);
}
virSCSIVHostDeviceListPtr
virSCSIVHostDeviceListNew(void)
{
if (virSCSIVHostInitialize() < 0)
return NULL;
return virObjectLockableNew(virSCSIVHostDeviceListClass);
}
int
virSCSIVHostDeviceSetUsedBy(virSCSIVHostDevicePtr dev,
const char *drvname,
const char *domname)
{
VIR_FREE(dev->used_by_drvname);
VIR_FREE(dev->used_by_domname);
if (VIR_STRDUP(dev->used_by_drvname, drvname) < 0)
return -1;
if (VIR_STRDUP(dev->used_by_domname, domname) < 0)
return -1;
return 0;
}
void
virSCSIVHostDeviceGetUsedBy(virSCSIVHostDevicePtr dev,
const char **drv_name,
const char **dom_name)
{
*drv_name = dev->used_by_drvname;
*dom_name = dev->used_by_domname;
}
int
virSCSIVHostDeviceFileIterate(virSCSIVHostDevicePtr dev,
virSCSIVHostDeviceFileActor actor,
void *opaque)
{
return (actor)(dev, dev->path, opaque);
}
const char *
virSCSIVHostDeviceGetName(virSCSIVHostDevicePtr dev)
{
return dev->name;
}
const char *
virSCSIVHostDeviceGetPath(virSCSIVHostDevicePtr dev)
{
return dev->path;
}
virSCSIVHostDevicePtr
virSCSIVHostDeviceNew(const char *name)
{
virSCSIVHostDevicePtr dev;
if (VIR_ALLOC(dev) < 0)
return NULL;
if (VIR_STRDUP(dev->name, name) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("dev->name buffer overflow: %s"),
name);
goto error;
}
if (virAsprintf(&dev->path, "%s/%s",
SYSFS_VHOST_SCSI_DEVICES, name) < 0)
goto error;
VIR_DEBUG("%s: initialized", dev->name);
cleanup:
return dev;
error:
virSCSIVHostDeviceFree(dev);
dev = NULL;
goto cleanup;
}
void
virSCSIVHostDeviceFree(virSCSIVHostDevicePtr dev)
{
if (!dev)
return;
VIR_DEBUG("%s: freeing", dev->name);
VIR_FREE(dev->name);
VIR_FREE(dev->path);
VIR_FREE(dev->used_by_drvname);
VIR_FREE(dev->used_by_domname);
VIR_FREE(dev);
}