2018-04-25 09:17:13 +00:00
|
|
|
/*
|
|
|
|
* storage_file_gluster.c: storage file backend for Gluster handling
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013-2018 Red Hat, 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/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <glusterfs/api/glfs.h>
|
|
|
|
|
|
|
|
#include "storage_file_gluster.h"
|
|
|
|
#include "viralloc.h"
|
|
|
|
#include "virerror.h"
|
|
|
|
#include "virlog.h"
|
|
|
|
#include "virstoragefilebackend.h"
|
|
|
|
#include "virstring.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
|
|
|
|
|
|
|
VIR_LOG_INIT("storage.storage_file_gluster");
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _virStorageFileBackendGlusterPriv virStorageFileBackendGlusterPriv;
|
|
|
|
typedef virStorageFileBackendGlusterPriv *virStorageFileBackendGlusterPrivPtr;
|
|
|
|
|
|
|
|
struct _virStorageFileBackendGlusterPriv {
|
|
|
|
glfs_t *vol;
|
|
|
|
char *canonpath;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
virStorageFileBackendGlusterDeinit(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
|
|
|
|
|
|
|
VIR_DEBUG("deinitializing gluster storage file %p (gluster://%s:%u/%s%s)",
|
|
|
|
src, src->hosts->name, src->hosts->port, src->volume, src->path);
|
|
|
|
|
|
|
|
if (priv->vol)
|
|
|
|
glfs_fini(priv->vol);
|
|
|
|
VIR_FREE(priv->canonpath);
|
|
|
|
|
|
|
|
VIR_FREE(priv);
|
|
|
|
src->drv->priv = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virStorageFileBackendGlusterInitServer(virStorageFileBackendGlusterPrivPtr priv,
|
|
|
|
virStorageNetHostDefPtr host)
|
|
|
|
{
|
|
|
|
const char *transport = virStorageNetHostTransportTypeToString(host->transport);
|
|
|
|
const char *hoststr = NULL;
|
|
|
|
int port = 0;
|
|
|
|
|
|
|
|
switch ((virStorageNetHostTransport) host->transport) {
|
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_RDMA:
|
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_TCP:
|
|
|
|
hoststr = host->name;
|
|
|
|
port = host->port;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_UNIX:
|
|
|
|
hoststr = host->socket;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_STORAGE_NET_HOST_TRANS_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("adding gluster host for %p: transport=%s host=%s port=%d",
|
|
|
|
priv, transport, hoststr, port);
|
|
|
|
|
|
|
|
if (glfs_set_volfile_server(priv->vol, transport, hoststr, port) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("failed to set gluster volfile server '%s'"),
|
|
|
|
hoststr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virStorageFileBackendGlusterInit(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = NULL;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!src->volume) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing gluster volume name for path '%s'"),
|
|
|
|
src->path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(priv) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
VIR_DEBUG("initializing gluster storage file %p "
|
|
|
|
"(priv='%p' volume='%s' path='%s') as [%u:%u]",
|
|
|
|
src, priv, src->volume, src->path,
|
|
|
|
(unsigned int)src->drv->uid, (unsigned int)src->drv->gid);
|
|
|
|
|
|
|
|
if (!(priv->vol = glfs_new(src->volume))) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < src->nhosts; i++) {
|
|
|
|
if (virStorageFileBackendGlusterInitServer(priv, src->hosts + i) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (glfs_init(priv->vol) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("failed to initialize gluster connection "
|
|
|
|
"(src=%p priv=%p)"), src, priv);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
src->drv->priv = priv;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (priv->vol)
|
|
|
|
glfs_fini(priv->vol);
|
|
|
|
VIR_FREE(priv);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virStorageFileBackendGlusterCreate(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
|
|
|
glfs_fd_t *fd = NULL;
|
|
|
|
mode_t mode = S_IRUSR;
|
|
|
|
|
|
|
|
if (!src->readonly)
|
|
|
|
mode |= S_IWUSR;
|
|
|
|
|
|
|
|
if (!(fd = glfs_creat(priv->vol, src->path,
|
|
|
|
O_CREAT | O_TRUNC | O_WRONLY, mode)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ignore_value(glfs_close(fd));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virStorageFileBackendGlusterUnlink(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
|
|
|
|
|
|
|
return glfs_unlink(priv->vol, src->path);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virStorageFileBackendGlusterStat(virStorageSourcePtr src,
|
|
|
|
struct stat *st)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
|
|
|
|
|
|
|
return glfs_stat(priv->vol, src->path, st);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
virStorageFileBackendGlusterRead(virStorageSourcePtr src,
|
|
|
|
size_t offset,
|
|
|
|
size_t len,
|
|
|
|
char **buf)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
|
|
|
glfs_fd_t *fd = NULL;
|
|
|
|
ssize_t ret = -1;
|
|
|
|
char *s;
|
|
|
|
size_t nread = 0;
|
|
|
|
|
|
|
|
*buf = NULL;
|
|
|
|
|
|
|
|
if (!(fd = glfs_open(priv->vol, src->path, O_RDONLY))) {
|
|
|
|
virReportSystemError(errno, _("Failed to open file '%s'"),
|
|
|
|
src->path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (offset > 0) {
|
|
|
|
if (glfs_lseek(fd, offset, SEEK_SET) == (off_t) -1) {
|
|
|
|
virReportSystemError(errno, _("cannot seek into '%s'"), src->path);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(*buf, len) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
s = *buf;
|
|
|
|
while (len) {
|
|
|
|
ssize_t r = glfs_read(fd, s, len, 0);
|
|
|
|
if (r < 0 && errno == EINTR)
|
|
|
|
continue;
|
|
|
|
if (r < 0) {
|
|
|
|
VIR_FREE(*buf);
|
|
|
|
virReportSystemError(errno, _("unable to read '%s'"), src->path);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
if (r == 0)
|
|
|
|
return nread;
|
|
|
|
s += r;
|
|
|
|
len -= r;
|
|
|
|
nread += r;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = nread;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (fd)
|
|
|
|
glfs_close(fd);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virStorageFileBackendGlusterAccess(virStorageSourcePtr src,
|
|
|
|
int mode)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
|
|
|
|
|
|
|
return glfs_access(priv->vol, src->path, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virStorageFileBackendGlusterReadlinkCallback(const char *path,
|
|
|
|
char **linkpath,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = data;
|
|
|
|
char *buf = NULL;
|
|
|
|
size_t bufsiz = 0;
|
|
|
|
ssize_t ret;
|
|
|
|
struct stat st;
|
2019-02-12 11:23:01 +00:00
|
|
|
int retval = -1;
|
2018-04-25 09:17:13 +00:00
|
|
|
|
|
|
|
*linkpath = NULL;
|
|
|
|
|
|
|
|
if (glfs_stat(priv->vol, path, &st) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("failed to stat gluster path '%s'"),
|
|
|
|
path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISLNK(st.st_mode))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
realloc:
|
|
|
|
if (VIR_EXPAND_N(buf, bufsiz, 256) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if ((ret = glfs_readlink(priv->vol, path, buf, bufsiz)) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("failed to read link of gluster file '%s'"),
|
|
|
|
path);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == bufsiz)
|
|
|
|
goto realloc;
|
|
|
|
|
|
|
|
buf[ret] = '\0';
|
|
|
|
|
2019-02-12 11:23:01 +00:00
|
|
|
VIR_STEAL_PTR(*linkpath, buf);
|
2018-04-25 09:17:13 +00:00
|
|
|
|
2019-02-12 11:23:01 +00:00
|
|
|
retval = 0;
|
2018-04-25 09:17:13 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(buf);
|
2019-02-12 11:23:01 +00:00
|
|
|
return retval;
|
2018-04-25 09:17:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
virStorageFileBackendGlusterGetUniqueIdentifier(virStorageSourcePtr src)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
|
|
|
char *filePath = NULL;
|
|
|
|
|
|
|
|
if (priv->canonpath)
|
|
|
|
return priv->canonpath;
|
|
|
|
|
|
|
|
if (!(filePath = virStorageFileCanonicalizePath(src->path,
|
|
|
|
virStorageFileBackendGlusterReadlinkCallback,
|
|
|
|
priv)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ignore_value(virAsprintf(&priv->canonpath, "gluster://%s:%u/%s/%s",
|
|
|
|
src->hosts->name,
|
|
|
|
src->hosts->port,
|
|
|
|
src->volume,
|
|
|
|
filePath));
|
|
|
|
|
|
|
|
VIR_FREE(filePath);
|
|
|
|
|
|
|
|
return priv->canonpath;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
virStorageFileBackendGlusterChown(const virStorageSource *src,
|
|
|
|
uid_t uid,
|
|
|
|
gid_t gid)
|
|
|
|
{
|
|
|
|
virStorageFileBackendGlusterPrivPtr priv = src->drv->priv;
|
|
|
|
|
|
|
|
return glfs_chown(priv->vol, src->path, uid, gid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virStorageFileBackend virStorageFileBackendGluster = {
|
|
|
|
.type = VIR_STORAGE_TYPE_NETWORK,
|
|
|
|
.protocol = VIR_STORAGE_NET_PROTOCOL_GLUSTER,
|
|
|
|
|
|
|
|
.backendInit = virStorageFileBackendGlusterInit,
|
|
|
|
.backendDeinit = virStorageFileBackendGlusterDeinit,
|
|
|
|
|
|
|
|
.storageFileCreate = virStorageFileBackendGlusterCreate,
|
|
|
|
.storageFileUnlink = virStorageFileBackendGlusterUnlink,
|
|
|
|
.storageFileStat = virStorageFileBackendGlusterStat,
|
|
|
|
.storageFileRead = virStorageFileBackendGlusterRead,
|
|
|
|
.storageFileAccess = virStorageFileBackendGlusterAccess,
|
|
|
|
.storageFileChown = virStorageFileBackendGlusterChown,
|
|
|
|
|
|
|
|
.storageFileGetUniqueIdentifier = virStorageFileBackendGlusterGetUniqueIdentifier,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virStorageFileGlusterRegister(void)
|
|
|
|
{
|
|
|
|
if (virStorageFileBackendRegister(&virStorageFileBackendGluster) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|