mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 12:35:17 +00:00
fe65e9c8b5
There are few places where a return variable is introduced (ret or retval), but then is never changed and is then passed to return. Well, we can return the value that the variable is initialized to directly. Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
276 lines
6.1 KiB
C
276 lines
6.1 KiB
C
/*
|
|
* storage_backend_mpath.c: storage backend for multipath handling
|
|
*
|
|
* Copyright (C) 2009-2014 Red Hat, Inc.
|
|
* Copyright (C) 2009-2008 Dave Allan
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <libdevmapper.h>
|
|
|
|
#include "virerror.h"
|
|
#include "storage_conf.h"
|
|
#include "storage_backend.h"
|
|
#include "storage_backend_mpath.h"
|
|
#include "viralloc.h"
|
|
#include "virlog.h"
|
|
#include "virfile.h"
|
|
#include "virstring.h"
|
|
#include "virutil.h"
|
|
#include "storage_util.h"
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
|
|
|
VIR_LOG_INIT("storage.storage_backend_mpath");
|
|
|
|
static int
|
|
virStorageBackendMpathNewVol(virStoragePoolObjPtr pool,
|
|
const int devnum,
|
|
const char *dev)
|
|
{
|
|
virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
|
|
g_autoptr(virStorageVolDef) vol = NULL;
|
|
|
|
if (VIR_ALLOC(vol) < 0)
|
|
return -1;
|
|
|
|
vol->type = VIR_STORAGE_VOL_BLOCK;
|
|
|
|
(vol->name) = g_strdup_printf("dm-%u", devnum);
|
|
|
|
vol->target.path = g_strdup_printf("/dev/%s", dev);
|
|
|
|
if (virStorageBackendUpdateVolInfo(vol, true,
|
|
VIR_STORAGE_VOL_OPEN_DEFAULT, 0) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
/* XXX should use logical unit's UUID instead */
|
|
vol->key = g_strdup(vol->target.path);
|
|
|
|
if (virStoragePoolObjAddVol(pool, vol) < 0)
|
|
return -1;
|
|
|
|
def->capacity += vol->target.capacity;
|
|
def->allocation += vol->target.allocation;
|
|
vol = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
virStorageBackendIsMultipath(const char *dev_name)
|
|
{
|
|
int ret = 0;
|
|
struct dm_task *dmt = NULL;
|
|
void *next = NULL;
|
|
uint64_t start, length;
|
|
char *target_type = NULL;
|
|
char *params = NULL;
|
|
|
|
dmt = dm_task_create(DM_DEVICE_TABLE);
|
|
if (dmt == NULL) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (dm_task_set_name(dmt, dev_name) == 0) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
dm_task_no_open_count(dmt);
|
|
|
|
if (!dm_task_run(dmt)) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
|
|
|
if (STREQ_NULLABLE(target_type, "multipath"))
|
|
ret = 1;
|
|
|
|
out:
|
|
if (dmt != NULL)
|
|
dm_task_destroy(dmt);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
virStorageBackendGetMinorNumber(const char *dev_name, uint32_t *minor)
|
|
{
|
|
int ret = -1;
|
|
struct dm_task *dmt;
|
|
struct dm_info info;
|
|
|
|
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
|
|
goto out;
|
|
|
|
if (!dm_task_set_name(dmt, dev_name))
|
|
goto out;
|
|
|
|
if (!dm_task_run(dmt))
|
|
goto out;
|
|
|
|
if (!dm_task_get_info(dmt, &info))
|
|
goto out;
|
|
|
|
*minor = info.minor;
|
|
ret = 0;
|
|
|
|
out:
|
|
if (dmt != NULL)
|
|
dm_task_destroy(dmt);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
virStorageBackendCreateVols(virStoragePoolObjPtr pool,
|
|
struct dm_names *names)
|
|
{
|
|
int is_mpath = 0;
|
|
uint32_t minor = -1;
|
|
uint32_t next;
|
|
g_autofree char *map_device = NULL;
|
|
|
|
do {
|
|
is_mpath = virStorageBackendIsMultipath(names->name);
|
|
|
|
if (is_mpath < 0)
|
|
return -1;
|
|
|
|
if (is_mpath == 1) {
|
|
|
|
map_device = g_strdup_printf("mapper/%s", names->name);
|
|
|
|
if (virStorageBackendGetMinorNumber(names->name, &minor) < 0) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
_("Failed to get %s minor number"),
|
|
names->name);
|
|
return -1;
|
|
}
|
|
|
|
if (virStorageBackendMpathNewVol(pool, minor, map_device) < 0)
|
|
return -1;
|
|
|
|
VIR_FREE(map_device);
|
|
}
|
|
|
|
/* Given the way libdevmapper returns its data, I don't see
|
|
* any way to avoid this series of casts. */
|
|
VIR_WARNINGS_NO_CAST_ALIGN
|
|
next = names->next;
|
|
names = (struct dm_names *)(((char *)names) + next);
|
|
VIR_WARNINGS_RESET
|
|
|
|
} while (next);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
virStorageBackendGetMaps(virStoragePoolObjPtr pool)
|
|
{
|
|
int retval = 0;
|
|
struct dm_task *dmt = NULL;
|
|
struct dm_names *names = NULL;
|
|
|
|
if (!(dmt = dm_task_create(DM_DEVICE_LIST))) {
|
|
retval = 1;
|
|
goto out;
|
|
}
|
|
|
|
dm_task_no_open_count(dmt);
|
|
|
|
if (!dm_task_run(dmt)) {
|
|
retval = 1;
|
|
goto out;
|
|
}
|
|
|
|
if (!(names = dm_task_get_names(dmt))) {
|
|
retval = 1;
|
|
goto out;
|
|
}
|
|
|
|
if (!names->dev) {
|
|
/* No devices found */
|
|
goto out;
|
|
}
|
|
|
|
virStorageBackendCreateVols(pool, names);
|
|
|
|
out:
|
|
if (dmt != NULL)
|
|
dm_task_destroy(dmt);
|
|
return retval;
|
|
}
|
|
|
|
static int
|
|
virStorageBackendMpathCheckPool(virStoragePoolObjPtr pool G_GNUC_UNUSED,
|
|
bool *isActive)
|
|
{
|
|
*isActive = virFileExists("/dev/mapper") ||
|
|
virFileExists("/dev/mpath");
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
virStorageBackendMpathRefreshPool(virStoragePoolObjPtr pool)
|
|
{
|
|
virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
|
|
|
|
VIR_DEBUG("pool=%p", pool);
|
|
|
|
def->allocation = def->capacity = def->available = 0;
|
|
|
|
virWaitForDevices();
|
|
|
|
virStorageBackendGetMaps(pool);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
virStorageBackend virStorageBackendMpath = {
|
|
.type = VIR_STORAGE_POOL_MPATH,
|
|
|
|
.checkPool = virStorageBackendMpathCheckPool,
|
|
.refreshPool = virStorageBackendMpathRefreshPool,
|
|
.uploadVol = virStorageBackendVolUploadLocal,
|
|
.downloadVol = virStorageBackendVolDownloadLocal,
|
|
.wipeVol = virStorageBackendVolWipeLocal,
|
|
};
|
|
|
|
|
|
int
|
|
virStorageBackendMpathRegister(void)
|
|
{
|
|
return virStorageBackendRegister(&virStorageBackendMpath);
|
|
}
|