/* Copyright (c) 2014 Red Hat, Inc. 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 "xlator.h" #include "rpc-clnt.h" #include "xdr-generic.h" #include "protocol-common.h" #include 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_log(this->name, GF_LOG_ERROR, "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_log(this->name, GF_LOG_ERROR, "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_log(this->name, GF_LOG_ERROR, "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_log(this->name, GF_LOG_ERROR, "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_log(this->name, GF_LOG_ERROR, "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_log(this->name, GF_LOG_ERROR, "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_log(this->name, GF_LOG_ERROR, "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_log(this->name, GF_LOG_WARNING, "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_log(this->name, GF_LOG_DEBUG, "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, }; 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_log(this->name, GF_LOG_DEBUG, "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) { gf_log(this->name, GF_LOG_ERROR, "glfs instance for snap volume %s " "failed", dirent->name); local_errno = ENOMEM; goto out; } ret = glfs_set_volfile_server(fs, "tcp", "localhost", 24007); if (ret) { gf_log(this->name, GF_LOG_ERROR, "setting the " "volfile server for snap volume %s " "failed", 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_log(this->name, GF_LOG_ERROR, "failed to set the " "log file path"); goto out; } ret = glfs_init(fs); if (ret) { gf_log(this->name, GF_LOG_ERROR, "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; } 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_log(this->name, GF_LOG_ERROR, "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; }