On Mon, Apr 01, 2013 at 08:00:57PM +0800, Han Cheng wrote: > This patch add util functions for scsi hostdev. > > Signed-off-by: Han Cheng <hanc.fnst@xxxxxxxxxxxxxx> > --- > po/POTFILES.in | 1 + > src/Makefile.am | 1 + > src/libvirt_private.syms | 22 +++ > src/util/virscsi.c | 399 ++++++++++++++++++++++++++++++++++++++++++++++ > src/util/virscsi.h | 83 ++++++++++ > 5 files changed, 506 insertions(+), 0 deletions(-) > create mode 100644 src/util/virscsi.c > create mode 100644 src/util/virscsi.h > > diff --git a/po/POTFILES.in b/po/POTFILES.in > index 91e5c02..39a0a19 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -174,6 +174,7 @@ src/util/virportallocator.c > src/util/virprocess.c > src/util/virrandom.c > src/util/virsexpr.c > +src/util/virscsi.c > src/util/virsocketaddr.c > src/util/virstatslinux.c > src/util/virstoragefile.c > diff --git a/src/Makefile.am b/src/Makefile.am > index 3f69d39..49d7f88 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -111,6 +111,7 @@ UTIL_SOURCES = \ > util/virportallocator.c util/virportallocator.h \ > util/virprocess.c util/virprocess.h \ > util/virrandom.h util/virrandom.c \ > + util/virscsi.c util/virscsi.h \ > util/virsexpr.c util/virsexpr.h \ > util/virsocketaddr.h util/virsocketaddr.c \ > util/virstatslinux.c util/virstatslinux.h \ > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > index f2eefc3..6a5962e 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -1665,6 +1665,28 @@ virRandomGenerateWWN; > virRandomInt; > > > +# util/virscsi.h > +virSCSIDeviceFileIterate; > +virSCSIDeviceFree; > +virSCSIDeviceGetAdapter; > +virSCSIDeviceGetBus; > +virSCSIDeviceGetDevStr; > +virSCSIDeviceGetName; > +virSCSIDeviceGetReadonly; > +virSCSIDeviceGetTarget; > +virSCSIDeviceGetUnit; > +virSCSIDeviceGetUsedBy; > +virSCSIDeviceListAdd; > +virSCSIDeviceListCount; > +virSCSIDeviceListDel; > +virSCSIDeviceListFind; > +virSCSIDeviceListGet; > +virSCSIDeviceListNew; > +virSCSIDeviceListSteal; > +virSCSIDeviceNew; > +virSCSIDeviceSetUsedBy; > + > + > # util/virsexpr.h > sexpr2string; > sexpr_append; > diff --git a/src/util/virscsi.c b/src/util/virscsi.c > new file mode 100644 > index 0000000..5d0dcd7 > --- /dev/null > +++ b/src/util/virscsi.c > @@ -0,0 +1,399 @@ > +/* > + * virscsi.c: helper APIs for managing host SCSI devices > + * > + * Copyright (C) 2013 Fujitsu, Inc. > + * > + * 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: > + * Han Cheng <hanc.fnst@xxxxxxxxxxxxxx> > + */ > + > +#include <config.h> > + > +#include <dirent.h> > +#include <fcntl.h> > +#include <inttypes.h> > +#include <limits.h> > +#include <stdio.h> > +#include <string.h> > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <unistd.h> > + > +#include "virscsi.h" > +#include "virlog.h" > +#include "viralloc.h" > +#include "virutil.h" > +#include "virerror.h" > + > +#define SCSI_DEVFS "/sys/bus/scsi/devices" > + > +/* For virReportOOMError() and virReportSystemError() */ > +#define VIR_FROM_THIS VIR_FROM_NONE > + > +struct _virSCSIDevice { > + unsigned int adapter; > + unsigned int bus; > + unsigned int target; > + unsigned int unit; > + > + char *name; /* adapter:bus:target:unit */ > + char *id; /* model vendor */ > + char *path; > + const char *used_by; /* name of the domain using this dev */ > + > + unsigned int readonly : 1; > +}; > + > +struct _virSCSIDeviceList { > + virObjectLockable parent; > + unsigned int count; > + virSCSIDevicePtr *devs; > +}; I think it's better to implement a generic object list, otherwise everytime who wants a list, he/she has to re-implement a list. > + > +static virClassPtr virSCSIDeviceListClass; > + > +static void virSCSIDeviceListDispose(void *obj); > + > +static int virSCSIOnceInit(void) > +{ > + if (!(virSCSIDeviceListClass = virClassNew(virClassForObjectLockable(), > + "virSCSIDeviceList", > + sizeof(virSCSIDeviceList), > + virSCSIDeviceListDispose))) The indentation style is: virClassNew(... ... ^ Please correct them everywhere in your patches. You want to have a look at HACKING for configs of editors. > + return -1; > + > + return 0; > +} > + > +VIR_ONCE_GLOBAL_INIT(virSCSI) > + > +static int virSCSIDeviceGetAdapterId(char *adapter, unsigned int *adapterid) > +{ > + if (STRSKIP(adapter, "scsi_host") && > + virStrToLong_ui(adapter + strlen("scsi_host"), NULL, 0, > + adapterid) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Cannot parse adapter %s"), adapter); > + return -1; > + } > + > + return 0; > +} > + > +char * > +virSCSIDeviceGetDevStr(char *adapter, > + unsigned int bus, > + unsigned int target, > + unsigned int unit) > +{ > + DIR *dir = NULL; > + struct dirent *entry; > + char *path = NULL; > + char *sg = NULL; > + unsigned int adapterid; > + > + if (virSCSIDeviceGetAdapterId(adapter, &adapterid) < 0) > + goto out; > + > + if (virAsprintf(&path, > + SCSI_DEVFS "/%d:%d:%d:%d/scsi_generic", > + adapterid, bus, target, unit) < 0) { > + virReportOOMError(); > + goto out; > + } > + if (!(dir = opendir(path))) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to open %s"), path); > + goto out; > + } > + > + while ((entry = readdir(dir))) { > + if (entry->d_name[0] == '.') > + continue; > + > + if (virAsprintf(&sg, "%s", entry->d_name) < 0) { > + virReportOOMError(); > + goto out; > + } > + } > + > +out: > + closedir(dir); > + VIR_FREE(path); > + return sg; > +} > + > +virSCSIDevicePtr > +virSCSIDeviceNew(char *adapter, > + unsigned int bus, > + unsigned int target, > + unsigned int unit, > + unsigned int readonly) > +{ > + virSCSIDevicePtr dev; > + char *sg = NULL; > + char *vendor = NULL; > + char *model = NULL; > + char *tmp = NULL; > + > + if (VIR_ALLOC(dev) < 0) { > + virReportOOMError(); > + return NULL; > + } > + > + dev->bus = bus; > + dev->target = target; > + dev->unit = unit; > + dev->readonly = readonly; > + > + if (!(sg = virSCSIDeviceGetDevStr(adapter, bus, target, unit))) { > + goto out; > + } > + if (virSCSIDeviceGetAdapterId(adapter, &dev->adapter) < 0) { > + goto out; > + } > + if (virAsprintf(&dev->name, "%d:%d:%d:%d", > + dev->adapter, dev->bus, dev->bus, > + dev->unit) < 0) { > + virReportOOMError(); > + goto out; > + } > + if (virAsprintf(&dev->path, "/dev/%s", sg) < 0) { > + virReportOOMError(); > + goto out; > + } > + if (access(dev->path, F_OK) != 0) { > + virReportSystemError(errno, > + _("Device %s not found: could not access %s"), > + dev->name, dev->path); > + goto out; > + } > + if (virAsprintf(&tmp, SCSI_DEVFS "/%s/vendor", dev->name) < 0) { > + virReportOOMError(); > + goto out; > + } > + if (virFileReadAll(tmp, 1024, &vendor) < 0) > + goto out; > + VIR_FREE(tmp); > + tmp = NULL; > + if (virAsprintf(&tmp, SCSI_DEVFS "/%s/model", dev->name) < 0) { > + virReportOOMError(); > + goto out; > + } > + if (virFileReadAll(tmp, 1024, &model) < 0) > + goto out; > + *(vendor + strlen(vendor) - 1) = '\0'; > + *(model + strlen(model) - 1) = '\0'; > + if (virAsprintf(&dev->id, "%s %s", vendor, model) < 0) { > + virReportOOMError(); > + goto out; > + } > + VIR_FREE(tmp); > + VIR_FREE(vendor); > + VIR_FREE(model); > + > + VIR_DEBUG("%s %s: initialized", dev->id, dev->name); > + > + return dev; > + > +out: > + VIR_FREE(tmp); > + VIR_FREE(vendor); > + VIR_FREE(model); > + virSCSIDeviceFree(dev); > + return NULL; > +} > + > +void > +virSCSIDeviceFree(virSCSIDevicePtr dev) > +{ > + if (!dev) > + return; > + VIR_DEBUG("%s %s: freeing", dev->id, dev->name); > + VIR_FREE(dev->id); > + VIR_FREE(dev->name); > + VIR_FREE(dev->path); > + VIR_FREE(dev); > +} > + > + > +void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, > + const char *name) > +{ > + dev->used_by = name; > +} > + > +const char *virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev) > +{ > + return dev->used_by; > +} > + > +const char *virSCSIDeviceGetName(virSCSIDevicePtr dev) > +{ > + return dev->name; > +} > + > +unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev) > +{ > + return dev->adapter; > +} > + > +unsigned int virSCSIDeviceGetBus(virSCSIDevicePtr dev) > +{ > + return dev->bus; > +} > + > +unsigned int virSCSIDeviceGetTarget(virSCSIDevicePtr dev) > +{ > + return dev->target; > +} > + > +unsigned int virSCSIDeviceGetUnit(virSCSIDevicePtr dev) > +{ > + return dev->unit; > +} > + > +unsigned int virSCSIDeviceGetReadonly(virSCSIDevicePtr dev) > +{ > + return dev->readonly; > +} Simple enough to make them inline. > + > +int virSCSIDeviceFileIterate(virSCSIDevicePtr dev, > + virSCSIDeviceFileActor actor, > + void *opaque) > +{ > + return (actor)(dev, dev->path, opaque); > +} What's the difference with directly calling actor? > + > +virSCSIDeviceListPtr > +virSCSIDeviceListNew(void) > +{ > + virSCSIDeviceListPtr list; > + > + if (virSCSIInitialize() < 0) > + return NULL; > + > + if (!(list = virObjectLockableNew(virSCSIDeviceListClass))) > + return NULL; > + > + return list; > +} > + > +static void > +virSCSIDeviceListDispose(void *obj) > +{ > + virSCSIDeviceListPtr list = obj; > + int i; > + > + for (i = 0; i < list->count; i++) > + virSCSIDeviceFree(list->devs[i]); > + > + VIR_FREE(list->devs); > +} > + > +int > +virSCSIDeviceListAdd(virSCSIDeviceListPtr list, > + virSCSIDevicePtr dev) > +{ > + if (virSCSIDeviceListFind(list, dev)) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Device %s is already in use"), > + dev->name); > + return -1; > + } > + > + if (VIR_REALLOC_N(list->devs, list->count+1) < 0) { > + virReportOOMError(); > + return -1; > + } > + > + list->devs[list->count++] = dev; The list is lockable, but you're not protecting it with lock. > + > + return 0; > +} > + > +virSCSIDevicePtr > +virSCSIDeviceListGet(virSCSIDeviceListPtr list, > + int idx) > +{ > + if (idx >= list->count || > + idx < 0) It fits in one line. > + return NULL; > + > + return list->devs[idx]; > +} > + > +int > +virSCSIDeviceListCount(virSCSIDeviceListPtr list) > +{ > + return list->count; > +} > + > +virSCSIDevicePtr > +virSCSIDeviceListSteal(virSCSIDeviceListPtr list, > + virSCSIDevicePtr dev) > +{ > + virSCSIDevicePtr ret = NULL; > + int i; > + > + for (i = 0; i < list->count; i++) { > + if (list->devs[i]->adapter != dev->adapter || > + list->devs[i]->bus != dev->bus || > + list->devs[i]->target != dev->target || > + list->devs[i]->unit != dev->unit) > + continue; > + > + ret = list->devs[i]; > + > + if (i != list->count--) > + memmove(&list->devs[i], > + &list->devs[i+1], > + sizeof(*list->devs) * (list->count - i)); > + > + if (VIR_REALLOC_N(list->devs, list->count) < 0) { > + ; /* not fatal */ > + } > + > + break; > + } > + return ret; > +} > + > +void > +virSCSIDeviceListDel(virSCSIDeviceListPtr list, > + virSCSIDevicePtr dev) > +{ > + virSCSIDevicePtr ret = virSCSIDeviceListSteal(list, dev); > + virSCSIDeviceFree(ret); > +} > + > +virSCSIDevicePtr > +virSCSIDeviceListFind(virSCSIDeviceListPtr list, > + virSCSIDevicePtr dev) > +{ > + int i; > + > + for (i = 0; i < list->count; i++) { > + if (list->devs[i]->adapter == dev->adapter && > + list->devs[i]->bus == dev->bus && > + list->devs[i]->target == dev->target && > + list->devs[i]->unit == dev->unit) > + return list->devs[i]; > + } > + > + return NULL; > +} > diff --git a/src/util/virscsi.h b/src/util/virscsi.h > new file mode 100644 > index 0000000..fbf143c > --- /dev/null > +++ b/src/util/virscsi.h > @@ -0,0 +1,83 @@ > +/* > + * virscsi.h: helper APIs for managing host SCSI devices > + * > + * Copyright (C) 2013 Fujitsu, Inc. > + * > + * 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: > + * Han Cheng <hanc.fnst@xxxxxxxxxxxxxx> > + */ > + > +#ifndef __VIR_SCSI_H__ > +# define __VIR_SCSI_H__ > + > +# include "internal.h" > +# include "virobject.h" > + > +typedef struct _virSCSIDevice virSCSIDevice; > +typedef virSCSIDevice *virSCSIDevicePtr; > +typedef struct _virSCSIDeviceList virSCSIDeviceList; > +typedef virSCSIDeviceList *virSCSIDeviceListPtr; > + > +char *virSCSIDeviceGetDevStr(char *adapter, > + unsigned int bus, > + unsigned int target, > + unsigned int unit); > + > +virSCSIDevicePtr virSCSIDeviceNew(char *adapter, > + unsigned int bus, > + unsigned int target, > + unsigned int unit, > + unsigned int readonly); > + > +void virSCSIDeviceFree(virSCSIDevicePtr dev); > +void virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name); > +const char *virSCSIDeviceGetUsedBy(virSCSIDevicePtr dev); > +const char *virSCSIDeviceGetName(virSCSIDevicePtr dev); > +unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev); > +unsigned int virSCSIDeviceGetBus(virSCSIDevicePtr dev); > +unsigned int virSCSIDeviceGetTarget(virSCSIDevicePtr dev); > +unsigned int virSCSIDeviceGetUnit(virSCSIDevicePtr dev); > +unsigned int virSCSIDeviceGetReadonly(virSCSIDevicePtr dev); > + > +/* > + * Callback that will be invoked once for each file > + * associated with / used for SCSI host device access. > + * > + * Should return 0 if successfully processed, or > + * -1 to indicate error and abort iteration > + */ > +typedef int (*virSCSIDeviceFileActor)(virSCSIDevicePtr dev, > + const char *path, void *opaque); > + > +int virSCSIDeviceFileIterate(virSCSIDevicePtr dev, > + virSCSIDeviceFileActor actor, > + void *opaque); > + > +virSCSIDeviceListPtr virSCSIDeviceListNew(void); > +int virSCSIDeviceListAdd(virSCSIDeviceListPtr list, > + virSCSIDevicePtr dev); > +virSCSIDevicePtr virSCSIDeviceListGet(virSCSIDeviceListPtr list, > + int idx); > +int virSCSIDeviceListCount(virSCSIDeviceListPtr list); > +virSCSIDevicePtr virSCSIDeviceListSteal(virSCSIDeviceListPtr list, > + virSCSIDevicePtr dev); > +void virSCSIDeviceListDel(virSCSIDeviceListPtr list, > + virSCSIDevicePtr dev); > +virSCSIDevicePtr virSCSIDeviceListFind(virSCSIDeviceListPtr list, > + virSCSIDevicePtr dev); > + > +#endif /* __VIR_SCSI_H__ */ > -- > 1.7.1 > > -- > libvir-list mailing list > libvir-list@xxxxxxxxxx > https://www.redhat.com/mailman/listinfo/libvir-list -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list