diff options
Diffstat (limited to 'xlators/features/snapview-server/src/snapview-server-helpers.c')
| -rw-r--r-- | xlators/features/snapview-server/src/snapview-server-helpers.c | 715 |
1 files changed, 715 insertions, 0 deletions
diff --git a/xlators/features/snapview-server/src/snapview-server-helpers.c b/xlators/features/snapview-server/src/snapview-server-helpers.c new file mode 100644 index 00000000000..62c1ddac49c --- /dev/null +++ b/xlators/features/snapview-server/src/snapview-server-helpers.c @@ -0,0 +1,715 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#include "snapview-server.h" +#include "snapview-server-mem-types.h" + +#include <glusterfs/xlator.h> +#include "rpc-clnt.h" +#include "xdr-generic.h" +#include "protocol-common.h" +#include <pthread.h> + +int +__svs_inode_ctx_set(xlator_t *this, inode_t *inode, svs_inode_t *svs_inode) +{ + uint64_t value = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, inode, out); + GF_VALIDATE_OR_GOTO(this->name, svs_inode, out); + + value = (uint64_t)(long)svs_inode; + + ret = __inode_ctx_set(inode, this, &value); + +out: + return ret; +} + +svs_inode_t * +__svs_inode_ctx_get(xlator_t *this, inode_t *inode) +{ + svs_inode_t *svs_inode = NULL; + uint64_t value = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, inode, out); + + ret = __inode_ctx_get(inode, this, &value); + if (ret) + goto out; + + svs_inode = (svs_inode_t *)((long)value); + +out: + return svs_inode; +} + +svs_inode_t * +svs_inode_ctx_get(xlator_t *this, inode_t *inode) +{ + svs_inode_t *svs_inode = NULL; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, inode, out); + + LOCK(&inode->lock); + { + svs_inode = __svs_inode_ctx_get(this, inode); + } + UNLOCK(&inode->lock); + +out: + return svs_inode; +} + +int32_t +svs_inode_ctx_set(xlator_t *this, inode_t *inode, svs_inode_t *svs_inode) +{ + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, inode, out); + GF_VALIDATE_OR_GOTO(this->name, svs_inode, out); + + LOCK(&inode->lock); + { + ret = __svs_inode_ctx_set(this, inode, svs_inode); + } + UNLOCK(&inode->lock); + +out: + return ret; +} + +svs_inode_t * +svs_inode_new(void) +{ + svs_inode_t *svs_inode = NULL; + + svs_inode = GF_CALLOC(1, sizeof(*svs_inode), gf_svs_mt_svs_inode_t); + + return svs_inode; +} + +svs_inode_t * +svs_inode_ctx_get_or_new(xlator_t *this, inode_t *inode) +{ + svs_inode_t *svs_inode = NULL; + int ret = -1; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, inode, out); + + LOCK(&inode->lock); + { + svs_inode = __svs_inode_ctx_get(this, inode); + if (!svs_inode) { + svs_inode = svs_inode_new(); + if (svs_inode) { + ret = __svs_inode_ctx_set(this, inode, svs_inode); + if (ret) { + GF_FREE(svs_inode); + svs_inode = NULL; + } + } + } + } + UNLOCK(&inode->lock); + +out: + return svs_inode; +} + +svs_fd_t * +svs_fd_new(void) +{ + svs_fd_t *svs_fd = NULL; + + svs_fd = GF_CALLOC(1, sizeof(*svs_fd), gf_svs_mt_svs_fd_t); + + return svs_fd; +} + +int +__svs_fd_ctx_set(xlator_t *this, fd_t *fd, svs_fd_t *svs_fd) +{ + uint64_t value = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, fd, out); + GF_VALIDATE_OR_GOTO(this->name, svs_fd, out); + + value = (uint64_t)(long)svs_fd; + + ret = __fd_ctx_set(fd, this, value); + +out: + return ret; +} + +svs_fd_t * +__svs_fd_ctx_get(xlator_t *this, fd_t *fd) +{ + svs_fd_t *svs_fd = NULL; + uint64_t value = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, fd, out); + + ret = __fd_ctx_get(fd, this, &value); + if (ret) + return NULL; + + svs_fd = (svs_fd_t *)((long)value); + +out: + return svs_fd; +} + +svs_fd_t * +svs_fd_ctx_get(xlator_t *this, fd_t *fd) +{ + svs_fd_t *svs_fd = NULL; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, fd, out); + + LOCK(&fd->lock); + { + svs_fd = __svs_fd_ctx_get(this, fd); + } + UNLOCK(&fd->lock); + +out: + return svs_fd; +} + +int32_t +svs_fd_ctx_set(xlator_t *this, fd_t *fd, svs_fd_t *svs_fd) +{ + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, fd, out); + GF_VALIDATE_OR_GOTO(this->name, svs_fd, out); + + LOCK(&fd->lock); + { + ret = __svs_fd_ctx_set(this, fd, svs_fd); + } + UNLOCK(&fd->lock); + +out: + return ret; +} + +svs_fd_t * +__svs_fd_ctx_get_or_new(xlator_t *this, fd_t *fd) +{ + svs_fd_t *svs_fd = NULL; + int ret = -1; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + svs_inode_t *inode_ctx = NULL; + glfs_fd_t *glfd = NULL; + inode_t *inode = NULL; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, fd, out); + + inode = fd->inode; + svs_fd = __svs_fd_ctx_get(this, fd); + if (svs_fd) { + ret = 0; + goto out; + } + + svs_fd = svs_fd_new(); + if (!svs_fd) { + gf_msg(this->name, GF_LOG_ERROR, 0, SVS_MSG_NEW_FD_CTX_FAILED, + "failed to allocate new fd " + "context for gfid %s", + uuid_utoa(inode->gfid)); + goto out; + } + + if (fd_is_anonymous(fd)) { + inode_ctx = svs_inode_ctx_get(this, inode); + if (!inode_ctx) { + gf_msg(this->name, GF_LOG_ERROR, 0, + SVS_MSG_GET_INODE_CONTEXT_FAILED, + "failed to get inode " + "context for %s", + uuid_utoa(inode->gfid)); + goto out; + } + + fs = inode_ctx->fs; + object = inode_ctx->object; + + if (inode->ia_type == IA_IFDIR) { + glfd = glfs_h_opendir(fs, object); + if (!glfd) { + gf_msg(this->name, GF_LOG_ERROR, errno, SVS_MSG_OPENDIR_FAILED, + "failed to " + "open the directory %s", + uuid_utoa(inode->gfid)); + goto out; + } + } + + if (inode->ia_type == IA_IFREG) { + glfd = glfs_h_open(fs, object, O_RDONLY | O_LARGEFILE); + if (!glfd) { + gf_msg(this->name, GF_LOG_ERROR, errno, SVS_MSG_OPEN_FAILED, + "failed to " + "open the file %s", + uuid_utoa(inode->gfid)); + goto out; + } + } + + svs_fd->fd = glfd; + } + + ret = __svs_fd_ctx_set(this, fd, svs_fd); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, SVS_MSG_SET_FD_CONTEXT_FAILED, + "failed to set fd context " + "for gfid %s", + uuid_utoa(inode->gfid)); + if (svs_fd->fd) { + if (inode->ia_type == IA_IFDIR) { + ret = glfs_closedir(svs_fd->fd); + if (ret) + gf_msg(this->name, GF_LOG_ERROR, errno, + SVS_MSG_CLOSEDIR_FAILED, + "failed to close the fd for %s", + uuid_utoa(inode->gfid)); + } + if (inode->ia_type == IA_IFREG) { + ret = glfs_close(svs_fd->fd); + if (ret) + gf_msg(this->name, GF_LOG_ERROR, 0, SVS_MSG_CLOSE_FAILED, + "failed to close the fd for %s", + uuid_utoa(inode->gfid)); + } + } + ret = -1; + } + +out: + if (ret) { + GF_FREE(svs_fd); + svs_fd = NULL; + } + + return svs_fd; +} + +svs_fd_t * +svs_fd_ctx_get_or_new(xlator_t *this, fd_t *fd) +{ + svs_fd_t *svs_fd = NULL; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, fd, out); + + LOCK(&fd->lock); + { + svs_fd = __svs_fd_ctx_get_or_new(this, fd); + } + UNLOCK(&fd->lock); + +out: + return svs_fd; +} + +int +svs_uuid_generate(xlator_t *this, uuid_t gfid, char *snapname, + uuid_t origin_gfid) +{ + char ino_string[NAME_MAX + 32] = ""; + uuid_t tmp = { + 0, + }; + int ret = -1; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, snapname, out); + + (void)snprintf(ino_string, sizeof(ino_string), "%s%s", snapname, + uuid_utoa(origin_gfid)); + + if (gf_gfid_generate_from_xxh64(tmp, ino_string)) { + gf_msg(this->name, GF_LOG_WARNING, 0, SVS_MSG_GFID_GEN_FAILED, + "failed to generate " + "gfid for object with actual gfid of %s " + "(snapname: %s, key: %s)", + uuid_utoa(origin_gfid), snapname, ino_string); + goto out; + } + + gf_uuid_copy(gfid, tmp); + + ret = 0; + + gf_msg_debug(this->name, 0, "gfid generated is %s ", uuid_utoa(gfid)); + +out: + return ret; +} + +void +svs_fill_ino_from_gfid(struct iatt *buf) +{ + xlator_t *this = NULL; + + this = THIS; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, buf, out); + + /* consider least significant 8 bytes of value out of gfid */ + if (gf_uuid_is_null(buf->ia_gfid)) { + buf->ia_ino = -1; + goto out; + } + + buf->ia_ino = gfid_to_ino(buf->ia_gfid); +out: + return; +} + +void +svs_iatt_fill(uuid_t gfid, struct iatt *buf) +{ + struct timeval tv = { + 0, + }; + xlator_t *this = NULL; + + this = THIS; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, buf, out); + + buf->ia_type = IA_IFDIR; + buf->ia_uid = 0; + buf->ia_gid = 0; + buf->ia_size = 0; + buf->ia_nlink = 2; + buf->ia_blocks = 8; + buf->ia_size = 4096; + + gf_uuid_copy(buf->ia_gfid, gfid); + svs_fill_ino_from_gfid(buf); + + buf->ia_prot = ia_prot_from_st_mode(0755); + + gettimeofday(&tv, 0); + + buf->ia_mtime = buf->ia_atime = buf->ia_ctime = tv.tv_sec; + buf->ia_mtime_nsec = buf->ia_atime_nsec = buf->ia_ctime_nsec = (tv.tv_usec * + 1000); + +out: + return; +} + +/* priv->snaplist_lock should be held before calling this function */ +snap_dirent_t * +__svs_get_snap_dirent(xlator_t *this, const char *name) +{ + svs_private_t *private = NULL; + int i = 0; + snap_dirent_t *dirents = NULL; + snap_dirent_t *tmp_dirent = NULL; + snap_dirent_t *dirent = NULL; + + private + = this->private; + + dirents = private->dirents; + if (!dirents) { + goto out; + } + + tmp_dirent = dirents; + for (i = 0; i < private->num_snaps; i++) { + if (!strcmp(tmp_dirent->name, name)) { + dirent = tmp_dirent; + break; + } + tmp_dirent++; + } + +out: + return dirent; +} + +glfs_t * +__svs_initialise_snapshot_volume(xlator_t *this, const char *name, + int32_t *op_errno) +{ + svs_private_t *priv = NULL; + int32_t ret = -1; + int32_t local_errno = ESTALE; + snap_dirent_t *dirent = NULL; + char volname[PATH_MAX] = { + 0, + }; + glfs_t *fs = NULL; + int loglevel = GF_LOG_INFO; + char logfile[PATH_MAX] = { + 0, + }; + char *volfile_server = NULL; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + GF_VALIDATE_OR_GOTO(this->name, name, out); + + priv = this->private; + + dirent = __svs_get_snap_dirent(this, name); + if (!dirent) { + gf_msg_debug(this->name, 0, + "snap entry for " + "name %s not found", + name); + local_errno = ENOENT; + goto out; + } + + if (dirent->fs) { + ret = 0; + fs = dirent->fs; + goto out; + } + + snprintf(volname, sizeof(volname), "/snaps/%s/%s/%s", dirent->name, + dirent->snap_volname, dirent->snap_volname); + + fs = glfs_new(volname); + if (!fs) { + local_errno = ENOMEM; + gf_msg(this->name, GF_LOG_ERROR, local_errno, SVS_MSG_GLFS_NEW_FAILED, + "glfs instance for snap volume %s " + "failed", + dirent->name); + goto out; + } + + /* + * Before, localhost was used as the volfile server. But, with that + * method, accessing snapshots started giving ENOENT error if a + * specific bind address is mentioned in the glusterd volume file. + * Check the bug https://bugzilla.redhat.com/show_bug.cgi?id=1725211. + * So, the new method is tried below, where, snapview-server first + * uses the volfile server used by the snapd (obtained from the + * command line arguments saved in the global context of the process). + * If the volfile server in global context is NULL, then localhost + * is tried (like before). + */ + if (this->ctx->cmd_args.volfile_server) { + volfile_server = gf_strdup(this->ctx->cmd_args.volfile_server); + if (!volfile_server) { + gf_msg(this->name, GF_LOG_WARNING, ENOMEM, + SVS_MSG_VOLFILE_SERVER_GET_FAIL, + "failed to copy volfile server %s. ", + this->ctx->cmd_args.volfile_server); + ret = -1; + goto out; + } + } else { + gf_msg(this->name, GF_LOG_WARNING, ENOMEM, + SVS_MSG_VOLFILE_SERVER_GET_FAIL, + "volfile server is NULL in cmd args. " + "Trying with localhost"); + volfile_server = gf_strdup("localhost"); + if (!volfile_server) { + gf_msg(this->name, GF_LOG_WARNING, ENOMEM, + SVS_MSG_VOLFILE_SERVER_GET_FAIL, + "failed to copy volfile server localhost."); + ret = -1; + goto out; + } + } + + ret = glfs_set_volfile_server(fs, "tcp", volfile_server, 24007); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, local_errno, + SVS_MSG_SET_VOLFILE_SERVR_FAILED, + "setting the " + "volfile server %s for snap volume %s " + "failed", + volfile_server, dirent->name); + goto out; + } + + snprintf(logfile, sizeof(logfile), + DEFAULT_SVD_LOG_FILE_DIRECTORY "/snaps/%s/%s-%s.log", + priv->volname, name, dirent->uuid); + + ret = glfs_set_logging(fs, logfile, loglevel); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, local_errno, + SVS_MSG_SET_LOGGING_FAILED, + "failed to set the " + "log file path"); + goto out; + } + + ret = glfs_init(fs); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, local_errno, SVS_MSG_GLFS_INIT_FAILED, + "initing the " + "fs for %s failed", + dirent->name); + goto out; + } + + ret = 0; + +out: + if (ret) { + if (op_errno) + *op_errno = local_errno; + + if (fs) + glfs_fini(fs); + fs = NULL; + } + + if (fs) { + dirent->fs = fs; + } + + GF_FREE(volfile_server); + return fs; +} + +glfs_t * +svs_initialise_snapshot_volume(xlator_t *this, const char *name, + int32_t *op_errno) +{ + glfs_t *fs = NULL; + svs_private_t *priv = NULL; + + GF_VALIDATE_OR_GOTO("snapview-server", this, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + GF_VALIDATE_OR_GOTO(this->name, name, out); + + priv = this->private; + + LOCK(&priv->snaplist_lock); + { + fs = __svs_initialise_snapshot_volume(this, name, op_errno); + } + UNLOCK(&priv->snaplist_lock); + +out: + + return fs; +} + +snap_dirent_t * +svs_get_latest_snap_entry(xlator_t *this) +{ + svs_private_t *priv = NULL; + snap_dirent_t *dirents = NULL; + snap_dirent_t *dirent = NULL; + + GF_VALIDATE_OR_GOTO("svs", this, out); + + priv = this->private; + + LOCK(&priv->snaplist_lock); + { + dirents = priv->dirents; + if (!dirents) { + goto unlock; + } + if (priv->num_snaps) + dirent = &dirents[priv->num_snaps - 1]; + } +unlock: + UNLOCK(&priv->snaplist_lock); + +out: + return dirent; +} + +glfs_t * +svs_get_latest_snapshot(xlator_t *this) +{ + glfs_t *fs = NULL; + snap_dirent_t *dirent = NULL; + svs_private_t *priv = NULL; + + GF_VALIDATE_OR_GOTO("svs", this, out); + priv = this->private; + + dirent = svs_get_latest_snap_entry(this); + + if (dirent) { + LOCK(&priv->snaplist_lock); + { + fs = dirent->fs; + } + UNLOCK(&priv->snaplist_lock); + } + +out: + return fs; +} + +glfs_t * +svs_inode_ctx_glfs_mapping(xlator_t *this, svs_inode_t *inode_ctx) +{ + glfs_t *fs = NULL; + + GF_VALIDATE_OR_GOTO("svs", this, out); + GF_VALIDATE_OR_GOTO(this->name, inode_ctx, out); + + fs = inode_ctx->fs; + + SVS_CHECK_VALID_SNAPSHOT_HANDLE(fs, this); + +out: + return fs; +} + +glfs_t * +svs_inode_glfs_mapping(xlator_t *this, inode_t *inode) +{ + svs_inode_t *inode_ctx = NULL; + glfs_t *fs = NULL; + + inode_ctx = svs_inode_ctx_get(this, inode); + if (!inode_ctx) { + gf_msg(this->name, GF_LOG_ERROR, 0, SVS_MSG_GET_INODE_CONTEXT_FAILED, + "inode context not found for" + " the inode %s", + uuid_utoa(inode->gfid)); + goto out; + } + + fs = svs_inode_ctx_glfs_mapping(this, inode_ctx); + +out: + return fs; +} |
