From cc0378d39f4082f51d5ef6e02b3007fe9e78cb31 Mon Sep 17 00:00:00 2001 From: Raghavendra Bhat Date: Wed, 7 May 2014 20:13:43 +0530 Subject: user servicable snapshots Change-Id: Idbf27dbe088e646a8ab81cedc5818413795895ea Signed-off-by: Raghavendra Bhat Signed-off-by: Anand Subramanian Signed-off-by: Raghavendra Bhat Reviewed-on: http://review.gluster.org/7700 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- xlators/features/snapview-server/Makefile.am | 1 + xlators/features/snapview-server/src/Makefile.am | 22 + .../src/snapview-server-mem-types.h | 25 + .../features/snapview-server/src/snapview-server.c | 2395 ++++++++++++++++++++ .../features/snapview-server/src/snapview-server.h | 88 + 5 files changed, 2531 insertions(+) create mode 100644 xlators/features/snapview-server/Makefile.am create mode 100644 xlators/features/snapview-server/src/Makefile.am create mode 100644 xlators/features/snapview-server/src/snapview-server-mem-types.h create mode 100644 xlators/features/snapview-server/src/snapview-server.c create mode 100644 xlators/features/snapview-server/src/snapview-server.h (limited to 'xlators/features/snapview-server') diff --git a/xlators/features/snapview-server/Makefile.am b/xlators/features/snapview-server/Makefile.am new file mode 100644 index 00000000000..af437a64d6d --- /dev/null +++ b/xlators/features/snapview-server/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/xlators/features/snapview-server/src/Makefile.am b/xlators/features/snapview-server/src/Makefile.am new file mode 100644 index 00000000000..0966ae4cc56 --- /dev/null +++ b/xlators/features/snapview-server/src/Makefile.am @@ -0,0 +1,22 @@ +xlator_LTLIBRARIES = snapview-server.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features + +snapview_server_la_LDFLAGS = -module -avoid-version + +snapview_server_la_SOURCES = snapview-server.c +snapview_server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la\ + $(top_builddir)/api/src/libgfapi.la\ + $(RLLIBS) $(top_builddir)/rpc/xdr/src/libgfxdr.la \ + $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la + +noinst_HEADERS = snapview-server.h snapview-server-mem-types.h + +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \ + -I$(top_srcdir)/api/src \ + -I$(top_srcdir)/rpc/rpc-lib/src \ + -I$(top_srcdir)/rpc/xdr/src \ + -DDATADIR=\"$(localstatedir)\" + +AM_CFLAGS = -Wall $(GF_CFLAGS) + +CLEANFILES = diff --git a/xlators/features/snapview-server/src/snapview-server-mem-types.h b/xlators/features/snapview-server/src/snapview-server-mem-types.h new file mode 100644 index 00000000000..6820b5e16f1 --- /dev/null +++ b/xlators/features/snapview-server/src/snapview-server-mem-types.h @@ -0,0 +1,25 @@ +/* + 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. +*/ + +#ifndef __SNAP_VIEW_MEM_TYPES_H +#define __SNAP_VIEW_MEM_TYPES_H + +#include "mem-types.h" + +enum snapview_mem_types { + gf_svs_mt_priv_t = gf_common_mt_end + 1, + gf_svs_mt_svs_inode_t, + gf_svs_mt_dirents_t, + gf_svs_mt_svs_fd_t, + gf_svs_mt_end +}; + +#endif + diff --git a/xlators/features/snapview-server/src/snapview-server.c b/xlators/features/snapview-server/src/snapview-server.c new file mode 100644 index 00000000000..655372347fb --- /dev/null +++ b/xlators/features/snapview-server/src/snapview-server.c @@ -0,0 +1,2395 @@ +/* + 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. +*/ +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "snapview-server.h" +#include "snapview-server-mem-types.h" + +/* + * Helper functions + */ + +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 () +{ + 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 (this, inode); + 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 () +{ + 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 (this, fd); + 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; +} + +void +svs_fill_ino_from_gfid (struct iatt *buf) +{ + uint64_t temp_ino = 0; + int j = 0; + int i = 0; + 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 (uuid_is_null (buf->ia_gfid)) { + buf->ia_ino = -1; + goto out; + } + for (i = 15; i > (15 - 8); i--) { + temp_ino += (uint64_t)(buf->ia_gfid[i]) << j; + j += 8; + } + buf->ia_ino = temp_ino; +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; + + 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; +} + +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; + + 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); + + private = this->private; + + dirents = private->dirents; + + 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) +{ + svs_private_t *priv = NULL; + int32_t ret = -1; + 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_ERROR, "snap entry for name %s " + "not found", name); + goto out; + } + + if (dirent->fs) { + ret = 0; + fs = dirent->fs; + goto out; + } + + snprintf (volname, sizeof (volname), "/snaps/%s/%s", + dirent->name, dirent->uuid); + + fs = glfs_new (volname); + if (!fs) { + gf_log (this->name, GF_LOG_ERROR, + "glfs instance for snap volume %s " + "failed", dirent->name); + goto out; + } + + ret = glfs_set_volfile_server (fs, "tcp", "localhost", + 24007); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "setting the " + "volfile srever for snap volume %s " + "failed", dirent->name); + 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; + } + + snprintf (logfile, sizeof (logfile), + DEFAULT_SVD_LOG_FILE_DIRECTORY "/%s-%s.log", 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 = 0; + +out: + if (ret && fs) { + glfs_fini (fs); + fs = NULL; + } + + if (fs) + dirent->fs = fs; + + 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; + snap_dirent_t *tmp_dirent = NULL; + + GF_VALIDATE_OR_GOTO ("svs", this, out); + + priv = this->private; + + dirents = priv->dirents; + + if (priv->num_snaps) { + tmp_dirent = &dirents[priv->num_snaps - 1]; + dirent = tmp_dirent; + } + +out: + return dirent; +} + +glfs_t * +svs_get_latest_snapshot (xlator_t *this) +{ + glfs_t *fs = NULL; + snap_dirent_t *dirent = NULL; + + GF_VALIDATE_OR_GOTO ("svs", this, out); + + dirent = svs_get_latest_snap_entry (this); + + if (dirent) + fs = dirent->fs; + +out: + return fs; +} + +int32_t +svs_lookup_entry_point (xlator_t *this, loc_t *loc, inode_t *parent, + struct iatt *buf, struct iatt *postparent, + int32_t *op_errno) +{ + uuid_t gfid; + svs_inode_t *inode_ctx = NULL; + int op_ret = -1; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + GF_VALIDATE_OR_GOTO (this->name, buf, out); + GF_VALIDATE_OR_GOTO (this->name, postparent, out); + + if (uuid_is_null (loc->inode->gfid)) { + uuid_generate (gfid); + svs_iatt_fill (gfid, buf); + + /* Here the inode context of the entry point directory + is filled with just the type of the inode and the gfid + of the parent from where the entry point was entered. + The glfs object and the fs instance will be NULL. + */ + if (parent) + svs_iatt_fill (parent->gfid, postparent); + else { + svs_iatt_fill (buf->ia_gfid, postparent); + } + + inode_ctx = svs_inode_ctx_get_or_new (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "allocate inode context for entry point " + "directory"); + op_ret = -1; + *op_errno = ENOMEM; + goto out; + } + uuid_copy (inode_ctx->pargfid, loc->pargfid); + memcpy (&inode_ctx->buf, buf, sizeof (*buf)); + inode_ctx->type = SNAP_VIEW_ENTRY_POINT_INODE; + } else { + if (inode_ctx) { + memcpy (buf, &inode_ctx->buf, sizeof (*buf)); + svs_iatt_fill (inode_ctx->pargfid, postparent); + } else { + svs_iatt_fill (loc->inode->gfid, buf); + if (parent) + svs_iatt_fill (parent->gfid, + postparent); + else { + svs_iatt_fill (loc->inode->gfid, + postparent); + } + } + } + op_ret = 0; + goto out; + +out: + return op_ret; +} + +/* When lookup comes from client and the protocol/server tries to resolve + the pargfid via just sending the gfid as part of lookup, if the inode + for the parent gfid is not found. But since that gfid has not yet been + looked up yet, inode will not be having inode context and parent is not + there (as it is the parent of the entry that is being resolved). So + without parent and inode context, svs cannot know which snapshot + to look into. In such cases, the amguity is handled by looking + into the latest snapshot. If the directory is there in the latest + snapshot, lookup is successful, otherwise it is a failure. So for + any directory created after taking the latest snapshot, entry into + snapshot world is denied. i.e you have to be part of snapshot world + to enter it. If the gfid is not found there, then unwind with + ESTALE + This gets executed mainly in the situation where the snapshot entry + point is entered from a non-root directory and that non-root directory's + inode (or gfid) is not yet looked up. And in each case when a gfid has to + be looked up (without any inode contex and parent context present), last + snapshot is referred and a random gfid is not generated. +*/ +int32_t +svs_lookup_gfid (xlator_t *this, loc_t *loc, struct iatt *buf, + struct iatt *postparent, int32_t *op_errno) +{ + int32_t op_ret = -1; + unsigned char handle_obj[GFAPI_HANDLE_LENGTH] = {0, }; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + struct stat statbuf = {0, }; + svs_inode_t *inode_ctx = NULL; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + GF_VALIDATE_OR_GOTO (this->name, buf, out); + GF_VALIDATE_OR_GOTO (this->name, postparent, out); + + if (uuid_is_null (loc->gfid) && uuid_is_null (loc->inode->gfid)) { + gf_log (this->name, GF_LOG_ERROR, "gfid is NULL"); + goto out; + } + + if (!uuid_is_null (loc->inode->gfid)) + memcpy (handle_obj, loc->inode->gfid, + GFAPI_HANDLE_LENGTH); + else + memcpy (handle_obj, loc->gfid, + GFAPI_HANDLE_LENGTH); + + fs = svs_get_latest_snapshot (this); + if (!fs) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the latest " + "snapshot"); + op_ret = -1; + *op_errno = EINVAL; + goto out; + } + + + object = glfs_h_create_from_handle (fs, handle_obj, GFAPI_HANDLE_LENGTH, + &statbuf); + if (!object) { + gf_log (this->name, GF_LOG_ERROR, "failed to do lookup and get " + "the handle on the snapshot %s (path: %s, gfid: %s)", + loc->name, loc->path, uuid_utoa (loc->gfid)); + op_ret = -1; + *op_errno = ESTALE; + goto out; + } + + inode_ctx = svs_inode_ctx_get_or_new (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate inode " + "context"); + op_ret = -1; + *op_errno = ENOMEM; + goto out; + } + + iatt_from_stat (buf, &statbuf); + if (loc->gfid) + uuid_copy (buf->ia_gfid, loc->gfid); + else + uuid_copy (buf->ia_gfid, loc->inode->gfid); + + inode_ctx->type = SNAP_VIEW_VIRTUAL_INODE; + inode_ctx->fs = fs; + inode_ctx->object = object; + memcpy (&inode_ctx->buf, buf, sizeof (*buf)); + svs_iatt_fill (buf->ia_gfid, postparent); + + op_ret = 0; + +out: + return op_ret; +} + +/* If the parent is an entry point inode, then create the handle for the + snapshot on which lookup came. i.e in reality lookup came on + the directory from which the entry point directory was entered, but + lookup is into the past. So create the handle for it by doing + the name-less lookup on the gfid (which can be obtained from + parent's context +*/ +int32_t +svs_lookup_snapshot (xlator_t *this, loc_t *loc, struct iatt *buf, + struct iatt *postparent, inode_t *parent, + svs_inode_t *parent_ctx, int32_t *op_errno) +{ + int32_t op_ret = -1; + unsigned char handle_obj[GFAPI_HANDLE_LENGTH] = {0, }; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + struct stat statbuf = {0, }; + svs_inode_t *inode_ctx = NULL; + uuid_t gfid; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + GF_VALIDATE_OR_GOTO (this->name, buf, out); + GF_VALIDATE_OR_GOTO (this->name, postparent, out); + GF_VALIDATE_OR_GOTO (this->name, parent_ctx, out); + GF_VALIDATE_OR_GOTO (this->name, parent, out); + + fs = svs_initialise_snapshot_volume (this, loc->name); + if (!fs) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "create the fs instance for snap %s", + loc->name); + op_ret = -1; + *op_errno = ESTALE; + goto out; + } + + memcpy (handle_obj, parent_ctx->pargfid, + GFAPI_HANDLE_LENGTH); + object = glfs_h_create_from_handle (fs, handle_obj, GFAPI_HANDLE_LENGTH, + &statbuf); + if (!object) { + gf_log (this->name, GF_LOG_ERROR, "failed to do lookup and " + "get the handle on the snapshot %s", loc->name); + op_ret = -1; + *op_errno = errno; + goto out; + } + + inode_ctx = svs_inode_ctx_get_or_new (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "allocate inode context"); + op_ret = -1; + *op_errno = ENOMEM; + goto out; + } + + if (uuid_is_null (loc->gfid) && + uuid_is_null (loc->inode->gfid)) + uuid_generate (gfid); + else { + if (!uuid_is_null (loc->inode->gfid)) + uuid_copy (gfid, loc->inode->gfid); + else + uuid_copy (gfid, loc->gfid); + } + iatt_from_stat (buf, &statbuf); + uuid_copy (buf->ia_gfid, gfid); + svs_fill_ino_from_gfid (buf); + inode_ctx->type = SNAP_VIEW_VIRTUAL_INODE; + inode_ctx->fs = fs; + inode_ctx->object = object; + memcpy (&inode_ctx->buf, buf, sizeof (*buf)); + svs_iatt_fill (parent->gfid, postparent); + + op_ret = 0; + +out: + return op_ret; +} + +/* Both parent and entry are from snapshot world */ +int32_t +svs_lookup_entry (xlator_t *this, loc_t *loc, struct iatt *buf, + struct iatt *postparent, inode_t *parent, + svs_inode_t *parent_ctx, int32_t *op_errno) +{ + int32_t op_ret = -1; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + struct stat statbuf = {0, }; + svs_inode_t *inode_ctx = NULL; + glfs_object_t *parent_object = NULL; + uuid_t gfid; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + GF_VALIDATE_OR_GOTO (this->name, buf, out); + GF_VALIDATE_OR_GOTO (this->name, postparent, out); + GF_VALIDATE_OR_GOTO (this->name, parent_ctx, out); + GF_VALIDATE_OR_GOTO (this->name, parent, out); + + parent_object = parent_ctx->object; + fs = parent_ctx->fs; + + object = glfs_h_lookupat (fs, parent_object, loc->name, + &statbuf); + if (!object) { + gf_log (this->name, GF_LOG_ERROR, "failed to do lookup and " + "get the handle for entry %s (path: %s)", loc->name, + loc->path); + op_ret = -1; + *op_errno = errno; + goto out; + } + + inode_ctx = svs_inode_ctx_get_or_new (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "allocate inode context"); + op_ret = -1; + *op_errno = ENOMEM; + goto out; + } + + if (uuid_is_null (loc->gfid) && + uuid_is_null (loc->inode->gfid)) + uuid_generate (gfid); + else { + if (!uuid_is_null (loc->inode->gfid)) + uuid_copy (gfid, loc->inode->gfid); + else + uuid_copy (gfid, loc->gfid); + } + + iatt_from_stat (buf, &statbuf); + uuid_copy (buf->ia_gfid, gfid); + svs_fill_ino_from_gfid (buf); + inode_ctx->type = SNAP_VIEW_VIRTUAL_INODE; + inode_ctx->fs = fs; + inode_ctx->object = object; + memcpy (&inode_ctx->buf, buf, sizeof (*buf)); + svs_iatt_fill (parent->gfid, postparent); + + op_ret = 0; + +out: + return op_ret; +} + +/* inode context is there means lookup has come on an object which was + built either as part of lookup or as part of readdirp. But in readdirp + we would not have got the handle to access the object in the gfapi + world. + So if inode context contains glfs_t instance for the right + gfapi world and glfs_object_t handle for accessing it in the gfapi + world, then unwind with success as the snapshots as of now are + read-only. + If the above condition is not met, then send lookup call again to + the gfapi world. It can happen only if both parent context and + the name of the entry are present. + + If parent is an entry point to snapshot world: + * parent is needed for getting the gfid on which lookup has to be done + (the gfid present in the inode is a virtual gfid) in the snapshot + world. + * name is required to get the right glfs_t instance on which lookup + has to be done + + If parent is a directory from snapshot world: + * parent context is needed to get the glfs_t instance and to get the + handle to parent directory in the snapshot world. + * name is needed to do the lookup on the right entry in the snapshot + world +*/ +int32_t +svs_revalidate (xlator_t *this, loc_t *loc, inode_t *parent, + svs_inode_t *inode_ctx, svs_inode_t *parent_ctx, + struct iatt *buf, struct iatt *postparent, int32_t *op_errno) +{ + int32_t op_ret = -1; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + unsigned char handle_obj[GFAPI_HANDLE_LENGTH] = {0, }; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, buf, out); + GF_VALIDATE_OR_GOTO (this->name, postparent, out); + GF_VALIDATE_OR_GOTO (this->name, inode_ctx, out); + + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + svs_iatt_fill (loc->inode->gfid, buf); + if (parent) + svs_iatt_fill (parent->gfid, + postparent); + else + svs_iatt_fill (loc->inode->gfid, postparent); + op_ret = 0; + goto out; + } else { + if (inode_ctx->fs && inode_ctx->object) { + memcpy (buf, &inode_ctx->buf, sizeof (*buf)); + if (parent) + svs_iatt_fill (parent->gfid, postparent); + else + svs_iatt_fill (buf->ia_gfid, postparent); + op_ret = 0; + goto out; + } + + /* To send the lookup to gfapi world, both the name of the + entry as well as the parent context is needed. + */ + if (!loc->name || !parent_ctx) { + *op_errno = ESTALE; + goto out; + } + + if (parent_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) + op_ret = svs_lookup_snapshot (this, loc, buf, + postparent, parent, + parent_ctx, op_errno); + else + op_ret = svs_lookup_entry (this, loc, buf, postparent, + parent, parent_ctx, + op_errno); + if (op_ret) + *op_errno = ESTALE; + + goto out; + } + +out: + return op_ret; +} + +int32_t +svs_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) +{ + struct iatt buf = {0, }; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + struct iatt postparent = {0,}; + svs_inode_t *inode_ctx = NULL; + svs_inode_t *parent_ctx = NULL; + int32_t ret = -1; + svs_private_t *private = NULL; + inode_t *parent = NULL; + glfs_t *fs = NULL; + snap_dirent_t *dirent = NULL; + gf_boolean_t entry_point = _gf_false; + + GF_VALIDATE_OR_GOTO ("svs", this, out); + GF_VALIDATE_OR_GOTO (this->name, this->private, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + + private = this->private; + + if (loc->name) { + ret = dict_get_str_boolean (xdata, "entry-point", _gf_false); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the " + "entry point info"); + entry_point = _gf_false; + } else { + entry_point = ret; + } + } + + if (loc->parent) + parent = inode_ref (loc->parent); + else { + parent = inode_find (loc->inode->table, loc->pargfid); + if (!parent) + parent = inode_parent (loc->inode, NULL, NULL); + } + if (parent) + parent_ctx = svs_inode_ctx_get (this, parent); + + inode_ctx = svs_inode_ctx_get (this, loc->inode); + + /* Initialize latest snapshot, which is used for nameless lookups */ + dirent = svs_get_latest_snap_entry (this); + if (!dirent->fs) + fs = svs_initialise_snapshot_volume (this, dirent->name); + + /* lookup is on the entry point to the snapshot world */ + if (entry_point) { + op_ret = svs_lookup_entry_point (this, loc, parent, &buf, + &postparent, &op_errno); + goto out; + } + + /* revalidate */ + if (inode_ctx) { + op_ret = svs_revalidate (this, loc, parent, inode_ctx, + parent_ctx, &buf, &postparent, + &op_errno); + goto out; + } + + /* This can happen when entry point directory is entered from non-root + directory. (ex: if /mnt/glusterfs is the mount point, then entry + point (say .snaps) is entered from /mnt/glusterfs/dir/.snaps). Also + it can happen when client sends a nameless lookup on just a gfid and + the server does not have the inode in the inode table. + */ + if (!inode_ctx && !parent_ctx) { + op_ret = svs_lookup_gfid (this, loc, &buf, &postparent, + &op_errno); + goto out; + } + + if (parent_ctx) { + if (parent_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) + op_ret = svs_lookup_snapshot (this, loc, &buf, + &postparent, parent, + parent_ctx, &op_errno); + else + op_ret = svs_lookup_entry (this, loc, &buf, + &postparent, parent, + parent_ctx, &op_errno); + goto out; + } + +out: + STACK_UNWIND_STRICT (lookup, frame, op_ret, op_errno, + loc?loc->inode:NULL, &buf, xdata, &postparent); + + if (parent) + inode_unref (parent); + + return 0; +} + +int32_t +svs_opendir (call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd, + dict_t *xdata) +{ + int32_t ret = -1; + svs_inode_t *inode_ctx = NULL; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + svs_fd_t *svs_fd = NULL; + glfs_fd_t *glfd = NULL; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + + inode_ctx = svs_inode_ctx_get (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "inode context not found " + "for the inode %s", uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = ESTALE; + goto out; + } + + /* Fake success is sent if the opendir is on the entry point directory + or the inode is SNAP_VIEW_ENTRY_POINT_INODE + */ + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + op_ret = 0; + op_errno = 0; + goto out; + } else if (inode_ctx->type == SNAP_VIEW_VIRTUAL_INODE) { + fs = inode_ctx->fs; + object = inode_ctx->object; + glfd = glfs_h_opendir (fs, object); + if (!glfd) { + op_ret = -1; + op_errno = errno; + gf_log (this->name, GF_LOG_ERROR, "opendir on %s " + "failed (gfid: %s)", loc->name, + uuid_utoa (loc->inode->gfid)); + goto out; + } + svs_fd = svs_fd_ctx_get_or_new (this, fd); + if (!svs_fd) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate " + "fd context %s (gfid: %s)", loc->name, + uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = ENOMEM; + glfs_closedir (glfd); + goto out; + } + svs_fd->fd = glfd; + + op_ret = 0; + op_errno = 0; + } + +out: + STACK_UNWIND_STRICT (opendir, frame, op_ret, op_errno, fd, NULL); + + return 0; +} + +int32_t +svs_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, const char *name, + dict_t *xdata) +{ + svs_inode_t *inode_ctx = NULL; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + char *value = 0; + ssize_t size = 0; + dict_t *dict = NULL; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO ("snap-view-daemon", frame, out); + GF_VALIDATE_OR_GOTO ("snap-view-daemon", loc, out); + GF_VALIDATE_OR_GOTO ("snap-view-daemon", loc->inode, out); + + inode_ctx = svs_inode_ctx_get (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "inode context not found " + "for the inode %s", uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = ESTALE; + goto out; + } + + /* Fake success is sent if the getxattr is on entry point directory + or the inode is SNAP_VIEW_ENTRY_POINT_INODE + */ + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + op_ret = -1; + op_errno = EINVAL; + goto out; + } else if (inode_ctx->type == SNAP_VIEW_VIRTUAL_INODE) { + fs = inode_ctx->fs; + object = inode_ctx->object; + size = glfs_h_getxattrs (fs, object, name, NULL, 0); + if (!size == -1) { + gf_log (this->name, GF_LOG_ERROR, "getxattr on %s " + "failed (key: %s)", loc->name, name); + op_ret = -1; + op_errno = errno; + goto out; + } + value = GF_CALLOC (size + 1, sizeof (char), gf_common_mt_char); + if (!value) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate " + "memory for getxattr on %s (key: %s)", + loc->name, name); + op_ret = -1; + op_errno = ENOMEM; + goto out; + } + + size = glfs_h_getxattrs (fs, object, name, value, size); + if (size == -1) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the " + "xattr %s for entry %s", name, loc->name); + op_ret = -1; + op_errno = errno; + goto out; + } + value[size] = '\0'; + + dict = dict_new (); + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate " + "dict"); + op_ret = -1; + op_errno = ENOMEM; + goto out; + } + + op_ret = dict_set_dynptr (dict, (char *)name, value, size); + if (op_ret < 0) { + op_errno = -op_ret; + gf_log (this->name, GF_LOG_ERROR, "dict set operation " + "for %s for the key %s failed.", loc->path, + name); + GF_FREE (value); + goto out; + } + + op_ret = 0; + op_errno = 0; + } + +out: + if (op_ret) + GF_FREE (value); + + STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, dict, NULL); + + return 0; +} + +int32_t +svs_fgetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, const char *name, + dict_t *xdata) +{ + svs_inode_t *inode_ctx = NULL; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + char *value = 0; + ssize_t size = 0; + dict_t *dict = NULL; + svs_fd_t *sfd = NULL; + glfs_fd_t *glfd = NULL; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO ("snap-view-daemon", frame, out); + GF_VALIDATE_OR_GOTO ("snap-view-daemon", fd, out); + GF_VALIDATE_OR_GOTO ("snap-view-daemon", fd->inode, out); + + inode_ctx = svs_inode_ctx_get (this, fd->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "inode context not found " + "for the inode %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = ESTALE; + goto out; + } + + sfd = svs_fd_ctx_get_or_new (this, fd); + if (!sfd) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the fd " + "context for %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EBADFD; + goto out; + } + + glfd = sfd->fd; + /* Fake success is sent if the getxattr is on entry point directory + or the inode is SNAP_VIEW_ENTRY_POINT_INODE + */ + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (inode_ctx->type == SNAP_VIEW_VIRTUAL_INODE) { + size = glfs_fgetxattr (glfd, name, NULL, 0); + if (!size == -1) { + gf_log (this->name, GF_LOG_ERROR, "getxattr on %s " + "failed (key: %s)", uuid_utoa (fd->inode->gfid), + name); + op_ret = -1; + op_errno = errno; + goto out; + } + value = GF_CALLOC (size + 1, sizeof (char), gf_common_mt_char); + if (!value) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate " + "memory for getxattr on %s (key: %s)", + uuid_utoa (fd->inode->gfid), name); + op_ret = -1; + op_errno = ENOMEM; + goto out; + } + + size = glfs_fgetxattr (glfd, name, value, size); + if (size == -1) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the " + "xattr %s for inode %s", name, + uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = errno; + goto out; + } + value[size] = '\0'; + + dict = dict_new (); + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate " + "dict"); + op_ret = -1; + op_errno = ENOMEM; + goto out; + } + + op_ret = dict_set_dynptr (dict, (char *)name, value, size); + if (op_ret < 0) { + op_errno = -op_ret; + gf_log (this->name, GF_LOG_ERROR, "dict set operation " + "for gfid %s for the key %s failed.", + uuid_utoa (fd->inode->gfid), name); + GF_FREE (value); + goto out; + } + + op_ret = 0; + op_errno = 0; + } + +out: + if (op_ret) + GF_FREE (value); + + STACK_UNWIND_STRICT (fgetxattr, frame, op_ret, op_errno, dict, NULL); + + return 0; +} + +int32_t +svs_releasedir (xlator_t *this, fd_t *fd) +{ + svs_fd_t *sfd = NULL; + uint64_t tmp_pfd = 0; + int ret = 0; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + ret = fd_ctx_del (fd, this, &tmp_pfd); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "pfd from fd=%p is NULL", fd); + goto out; + } + + sfd = (svs_fd_t *)(long)tmp_pfd; + if (sfd->fd) { + ret = glfs_closedir (sfd->fd); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "failed to close " + "the glfd for directory %s", + uuid_utoa (fd->inode->gfid)); + } + +out: + return 0; +} + +int32_t +svs_flush (call_frame_t *frame, xlator_t *this, + fd_t *fd, dict_t *xdata) +{ + int32_t op_ret = -1; + int32_t op_errno = 0; + int ret = -1; + uint64_t value = 0; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + ret = fd_ctx_get (fd, this, &value); + if (ret < 0) { + op_errno = EINVAL; + gf_log (this->name, GF_LOG_WARNING, + "pfd is NULL on fd=%p", fd); + goto out; + } + + op_ret = 0; + +out: + STACK_UNWIND_STRICT (flush, frame, op_ret, op_errno, NULL); + + return 0; +} + +int32_t +svs_release (xlator_t *this, fd_t *fd) +{ + svs_fd_t *sfd = NULL; + uint64_t tmp_pfd = 0; + int ret = 0; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + ret = fd_ctx_del (fd, this, &tmp_pfd); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "pfd from fd=%p is NULL", fd); + goto out; + } + + sfd = (svs_fd_t *)(long)tmp_pfd; + if (sfd->fd) { + ret = glfs_close (sfd->fd); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to close " + "the glfd for %s", + uuid_utoa (fd->inode->gfid)); + } + } + +out: + return 0; +} + +int32_t +svs_forget (xlator_t *this, inode_t *inode) +{ + int ret = -1; + uint64_t value = 0; + svs_inode_t *inode_ctx = NULL; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, inode, out); + + ret = inode_ctx_del (inode, this, &value); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to delte the inode " + "context of %s", uuid_utoa (inode->gfid)); + goto out; + } + + inode_ctx = (svs_inode_t *)value; + + if (inode_ctx->object) + glfs_h_close (inode_ctx->object); + + GF_FREE (inode_ctx); + +out: + return 0; +} + +/* As of now, the list of snapshots is obtained by reading a predefined file + (which the user has to generate using these commands) +* /usr/local/sbin/gluster snapshot info | grep -i snap | grep -i Volume | + grep -i Name | cut -d':' -f 2 > /tmp/tmp-snap-uuids + /usr/local/sbin/gluster snapshot info | grep Snapshot | cut -d':' -f 2 + > /tmp/tmp-snap_names + This is a temporary workaround which will be changed to a notification + based mechanism where snapd gets the list of snapshots from glusterd +*/ +int +svs_get_snapshot_list (xlator_t *this, svs_private_t *priv) +{ + int ret = -1; + char str_uuid[256] = {'\0'}; + char str_name[256] = {'\0'}; + int snap_count = 0; + snap_dirent_t *dirents = NULL; + FILE *fpn = NULL; + FILE *fpu = NULL; + int i = 0; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, priv, out); + + dirents = GF_CALLOC (sizeof (*dirents), SNAP_VIEW_MAX_NUM_SNAPS, + gf_svs_mt_dirents_t); + if (!dirents) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate memory"); + goto out; + /* error, bail */ + } + priv->dirents = dirents; + + fpu = fopen ("/tmp/tmp-snap-uuids", "r+"); + fpn = fopen ("/tmp/tmp-snap_names", "r+"); + + if (!fpu || !fpn) { + gf_log (this->name, GF_LOG_ERROR, "failed to open the file"); + goto out; + } + + while ((fscanf (fpu, "%s", str_uuid) != -1) && + (fscanf (fpn, "%s", str_name) != -1)) { + strncpy (dirents[i].uuid, str_uuid, strlen (str_uuid) + 1); + strncpy (dirents[i].name, str_name, strlen (str_name) + 1); + ++snap_count; + ++i; + } + priv->num_snaps = snap_count; + + fclose (fpn); + fclose (fpu); + + ret = 0; + +out: + return ret; +} + +int +svs_fill_readdir (xlator_t *this, gf_dirent_t *entries, size_t size, off_t off) +{ + gf_dirent_t *entry = NULL; + svs_private_t *priv = NULL; + int i = 0; + snap_dirent_t *dirents = NULL; + int this_size = 0; + int filled_size = 0; + int count = 0; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO ("snap-view-daemon", entries, out); + + priv = this->private; + /* create the dir entries */ + dirents = priv->dirents; + + for (i = off; i < priv->num_snaps; ) { + this_size = sizeof (gf_dirent_t) + + strlen (dirents[i].name) + 1; + if (this_size + filled_size > size ) + goto out; + + entry = gf_dirent_for_name (dirents[i].name); + if (!entry) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate " + "dentry for %s", dirents[i].name); + goto out; + } + + entry->d_off = i + 1; + entry->d_ino = i + 2*42; + entry->d_type = DT_DIR; + list_add_tail (&entry->list, &entries->list); + ++i; + count++; + filled_size += this_size; + } + +out: + return count; +} + +int32_t +svs_glfs_readdir (xlator_t *this, glfs_fd_t *glfd, gf_dirent_t *entries, + int32_t *op_errno, struct iatt *buf, gf_boolean_t readdirplus, + size_t size) +{ + int filled_size = 0; + int this_size = 0; + int32_t ret = -1; + int32_t count = 0; + gf_dirent_t *entry = NULL; + struct dirent *dirents = NULL; + struct dirent de = {0, }; + struct stat statbuf = {0, }; + off_t in_case = -1; + + GF_VALIDATE_OR_GOTO ("svs", this, out); + GF_VALIDATE_OR_GOTO (this->name, glfd, out); + GF_VALIDATE_OR_GOTO (this->name, entries, out); + GF_VALIDATE_OR_GOTO (this->name, buf, out); + + while (filled_size < size) { + in_case = glfs_telldir (glfd); + if (in_case == -1) { + gf_log (this->name, GF_LOG_ERROR, "telldir failed"); + break; + } + + if (readdirplus) + ret = glfs_readdirplus_r (glfd, &statbuf, &de, + &dirents); + else + ret = glfs_readdir_r (glfd, &de, &dirents); + + if (ret == 0 && dirents != NULL) { + if (readdirplus) + this_size = max (sizeof (gf_dirent_t), + sizeof (gfs3_dirplist)) + + strlen (de.d_name) + 1; + else + this_size = sizeof (gf_dirent_t) + + strlen (de.d_name) + 1; + + if (this_size + filled_size > size) { + glfs_seekdir (glfd, in_case); + break; + } + + entry = gf_dirent_for_name (de.d_name); + if (!entry) { + gf_log (this->name, GF_LOG_ERROR, + "could not create gf_dirent " + "for entry %s: (%s)", + entry->d_name, + strerror (errno)); + break; + } + entry->d_off = de.d_off; + entry->d_ino = de.d_ino; + entry->d_type = de.d_type; + iatt_from_stat (buf, &statbuf); + if (readdirplus) + entry->d_stat = *buf; + list_add_tail (&entry->list, &entries->list); + + filled_size += this_size; + count++; + } else if (ret == 0 && dirents == NULL) { + *op_errno = ENOENT; + break; + } else if (ret != 0) { + *op_errno = errno; + break; + } + dirents = NULL; + ret = -1; + } + +out: + return count; +} + +/* readdirp can be of 2 types. + 1) It can come on entry point directory where the list of snapshots + is sent as dirents. In this case, the iatt structure is filled + on the fly if the inode is not found for the entry or the inode + context is NULL. Other wise if inode is found and inode context + is there the iatt structure saved in the context is used. + 2) It can be on a directory in one of the snapshots. In this case, + the readdirp call would have sent us a iatt structure. So the same + structure is used with the exception that the gfid and the inode + numbers will be newly generated and filled in. +*/ +void +svs_readdirp_fill (xlator_t *this, inode_t *parent, svs_inode_t *parent_ctx, + gf_dirent_t *entry) +{ + inode_t *inode = NULL; + uuid_t random_gfid = {0,}; + struct iatt buf = {0, }; + svs_inode_t *inode_ctx = NULL; + + GF_VALIDATE_OR_GOTO ("snapview-server", this, out); + GF_VALIDATE_OR_GOTO (this->name, parent, out); + GF_VALIDATE_OR_GOTO (this->name, parent_ctx, out); + GF_VALIDATE_OR_GOTO (this->name, entry, out); + + inode = inode_grep (parent->table, parent, entry->d_name); + if (inode) { + entry->inode = inode; + inode_ctx = svs_inode_ctx_get (this, inode); + if (!inode_ctx) { + uuid_copy (buf.ia_gfid, inode->gfid); + svs_iatt_fill (inode->gfid, &buf); + buf.ia_type = inode->ia_type; + } else { + buf = inode_ctx->buf; + } + + entry->d_ino = buf.ia_ino; + + if (parent_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) + entry->d_stat = buf; + else { + entry->d_stat.ia_ino = buf.ia_ino; + uuid_copy (entry->d_stat.ia_gfid, buf.ia_gfid); + } + } else { + inode = inode_new (parent->table); + entry->inode = inode; + uuid_generate (random_gfid); + uuid_copy (buf.ia_gfid, random_gfid); + svs_fill_ino_from_gfid (&buf); + entry->d_ino = buf.ia_ino; + + /* If inode context allocation fails, then do not send the + inode for that particular entry as part of readdirp + response. Fuse and protocol/server will link the inodes + in readdirp only if the entry contains inode in it. + */ + inode_ctx = svs_inode_ctx_get_or_new (this, inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate " + "inode context for %s", entry->d_name); + inode_unref (entry->inode); + entry->inode = NULL; + goto out; + } + + inode_ctx->type = SNAP_VIEW_VIRTUAL_INODE; + + if (parent_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + buf.ia_type = IA_IFDIR; + inode_ctx->buf = buf; + entry->d_stat = buf; + } else { + uuid_copy (entry->d_stat.ia_gfid, buf.ia_gfid); + entry->d_stat.ia_ino = buf.ia_ino; + inode_ctx->buf = entry->d_stat; + } + } + +out: + return; +} + +/* In readdirp, though new inode is created along with the generation of + new gfid, the inode context created will not contain the glfs_t instance + for the filesystem it belongs to and the handle for it in the gfapi + world. (handle is obtained only by doing the lookup call on the entry + and doing lookup on each entry received as part of readdir call is a + costly operation. So the fs and handle is NULL in the inode context + and is filled in when lookup comes on that object. +*/ +int32_t +svs_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t off, dict_t *dict) +{ + gf_dirent_t entries; + gf_dirent_t *entry = NULL; + struct iatt buf = {0, }; + int count = 0; + int op_ret = -1; + int op_errno = EINVAL; + svs_inode_t *inode_ctx = NULL; + svs_inode_t *parent_ctx = NULL; + svs_fd_t *svs_fd = NULL; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, unwind); + GF_VALIDATE_OR_GOTO (this->name, frame, unwind); + GF_VALIDATE_OR_GOTO (this->name, fd, unwind); + GF_VALIDATE_OR_GOTO (this->name, fd->inode, unwind); + + INIT_LIST_HEAD (&entries.list); + + parent_ctx = svs_inode_ctx_get (this, fd->inode); + if (!parent_ctx) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto unwind; + } + + if (parent_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + LOCK (&fd->lock); + { + count = svs_fill_readdir (this, &entries, size, off); + } + UNLOCK (&fd->lock); + + op_ret = count; + + list_for_each_entry (entry, &entries.list, list) { + svs_readdirp_fill (this, fd->inode, parent_ctx, entry); + } + + goto unwind; + } else { + svs_fd = svs_fd_ctx_get_or_new (this, fd); + if (!svs_fd) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the " + "fd context %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EBADFD; + goto unwind; + } + + glfs_seekdir (svs_fd->fd, off); + + LOCK (&fd->lock); + { + count = svs_glfs_readdir (this, svs_fd->fd, &entries, + &op_errno, &buf, _gf_true, + size); + } + UNLOCK (&fd->lock); + + op_ret = count; + + list_for_each_entry (entry, &entries.list, list) { + svs_readdirp_fill (this, fd->inode, parent_ctx, entry); + } + + goto unwind; + } + +unwind: + STACK_UNWIND_STRICT (readdirp, frame, op_ret, op_errno, &entries, dict); + + gf_dirent_free (&entries); + + return 0; +} + +int32_t +svs_readdir (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t off, dict_t *xdata) +{ + svs_private_t *priv = NULL; + gf_dirent_t entries; + int count = 0; + svs_inode_t *inode_ctx = NULL; + int op_errno = EINVAL; + int op_ret = -1; + svs_fd_t *svs_fd = NULL; + glfs_fd_t *glfd = NULL; + + GF_VALIDATE_OR_GOTO ("snap-view-server", this, unwind); + GF_VALIDATE_OR_GOTO (this->name, frame, unwind); + GF_VALIDATE_OR_GOTO (this->name, fd, unwind); + GF_VALIDATE_OR_GOTO (this->name, fd->inode, unwind); + + priv = this->private; + + inode_ctx = svs_inode_ctx_get (this, fd->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "inode context not found in " + "the inode %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto unwind; + } + + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + LOCK (&fd->lock); + { + count = svs_fill_readdir (this, &entries, size, off); + } + UNLOCK (&fd->lock); + } else { + svs_fd = svs_fd_ctx_get_or_new (this, fd); + if (!svs_fd) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the " + "fd context %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EBADFD; + goto unwind; + } + + glfd = svs_fd->fd; + + LOCK (&fd->lock); + { + count = svs_glfs_readdir (this, glfd, &entries, + &op_errno, NULL, _gf_false, + size); + } + UNLOCK (&fd->lock); + } + + op_ret = count; + +unwind: + STACK_UNWIND_STRICT (readdir, frame, op_ret, op_errno, &entries, xdata); + + gf_dirent_free (&entries); + + return 0; +} + +int32_t +svs_stat (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) +{ + svs_private_t *priv = NULL; + struct iatt buf = {0, }; + int32_t op_errno = EINVAL; + int32_t op_ret = -1; + svs_inode_t *inode_ctx = NULL; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + struct stat stat = {0, }; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + + priv = this->private; + + /* Instead of doing the check of whether it is a entry point directory + or not by checking the name of the entry and then deciding what + to do, just check the inode context and decide what to be done. + */ + + inode_ctx = svs_inode_ctx_get (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "inode context not found for" + " %s", uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + svs_iatt_fill (loc->inode->gfid, &buf); + op_ret = 0; + } else if (inode_ctx->type == SNAP_VIEW_VIRTUAL_INODE) { + fs = inode_ctx->fs; + object = inode_ctx->object; + ret = glfs_h_stat (fs, object, &stat); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "glfs_h_stat on %s " + "(gfid: %s) failed", loc->name, + uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = errno; + goto out; + } + + iatt_from_stat (&buf, &stat); + uuid_copy (buf.ia_gfid, loc->inode->gfid); + svs_fill_ino_from_gfid (&buf); + op_ret = ret; + } + +out: + STACK_UNWIND_STRICT (stat, frame, op_ret, op_errno, &buf, xdata); + return 0; +} + +int32_t +svs_fstat (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) +{ + svs_private_t *priv = NULL; + struct iatt buf = {0, }; + int32_t op_errno = EINVAL; + int32_t op_ret = -1; + svs_inode_t *inode_ctx = NULL; + struct stat stat = {0, }; + int ret = -1; + glfs_fd_t *glfd = NULL; + svs_fd_t *sfd = NULL; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + GF_VALIDATE_OR_GOTO (this->name, fd->inode, out); + + priv = this->private; + + /* Instead of doing the check of whether it is a entry point directory + or not by checking the name of the entry and then deciding what + to do, just check the inode context and decide what to be done. + */ + + inode_ctx = svs_inode_ctx_get (this, fd->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "inode context not found for" + " the inode %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + svs_iatt_fill (fd->inode->gfid, &buf); + op_ret = 0; + } else if (inode_ctx->type == SNAP_VIEW_VIRTUAL_INODE) { + sfd = svs_fd_ctx_get_or_new (this, fd); + if (!sfd) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the " + "fd context for %s", + uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EBADFD; + goto out; + } + + glfd = sfd->fd; + ret = glfs_fstat (glfd, &stat); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "glfs_fstat on " + "gfid: %s failed", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = errno; + goto out; + } + + iatt_from_stat (&buf, &stat); + uuid_copy (buf.ia_gfid, fd->inode->gfid); + svs_fill_ino_from_gfid (&buf); + op_ret = ret; + } + +out: + STACK_UNWIND_STRICT (fstat, frame, op_ret, op_errno, &buf, xdata); + return 0; +} + +int32_t +svs_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata) +{ + int32_t ret = -1; + svs_inode_t *inode_ctx = NULL; + svs_fd_t *sfd = NULL; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + glfs_fd_t *glfd = NULL; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + + inode_ctx = svs_inode_ctx_get (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "inode context for %s " + "(gfid: %s) not found", loc->name, + uuid_utoa (loc->inode->gfid)); + goto out; + } + + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) + GF_ASSERT (0); // on entry point it should always be opendir + + fs = inode_ctx->fs; + object = inode_ctx->object; + + glfd = glfs_h_open (fs, object, flags); + if (!glfd) { + gf_log (this->name, GF_LOG_ERROR, "glfs_h_open on %s failed " + "(gfid: %s)", loc->name, uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = errno; + goto out; + } + + sfd = svs_fd_ctx_get_or_new (this, fd); + if (!sfd) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate fd " + "context for %s (gfid: %s)", loc->name, + uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = ENOMEM; + glfs_close (glfd); + goto out; + } + sfd->fd = glfd; + + op_ret = 0; + +out: + STACK_UNWIND_STRICT (open, frame, op_ret, op_errno, fd, NULL); + return 0; +} + +int32_t +svs_readv (call_frame_t *frame, xlator_t *this, + fd_t *fd, size_t size, off_t offset, uint32_t flags, dict_t *xdata) +{ + int32_t op_ret = -1; + int32_t op_errno = 0; + svs_private_t *priv = NULL; + struct iobuf *iobuf = NULL; + struct iobref *iobref = NULL; + struct iovec vec = {0,}; + svs_fd_t *sfd = NULL; + int ret = -1; + struct stat fstatbuf = {0, }; + glfs_fd_t *glfd = NULL; + struct iatt stbuf = {0, }; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + GF_VALIDATE_OR_GOTO (this->name, fd->inode, out); + + priv = this->private; + VALIDATE_OR_GOTO (priv, out); + + sfd = svs_fd_ctx_get_or_new (this, fd); + if (!sfd) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the fd " + "context for %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EBADFD; + goto out; + } + + glfd = sfd->fd; + + iobuf = iobuf_get2 (this->ctx->iobuf_pool, size); + if (!iobuf) { + op_ret = -1; + op_errno = ENOMEM; + goto out; + } + + ret = glfs_pread (glfd, iobuf->ptr, size, offset, 0); + if (ret < 0) { + op_ret = -1; + op_errno = errno; + gf_log (this->name, GF_LOG_ERROR, "glfs_read failed (%s)", + strerror (op_errno)); + goto out; + } + + vec.iov_base = iobuf->ptr; + vec.iov_len = ret; + + iobref = iobref_new (); + + iobref_add (iobref, iobuf); + + ret = glfs_fstat (glfd, &fstatbuf); + if (ret) { + op_ret = -1; + op_errno = errno; + gf_log (this->name, GF_LOG_ERROR, "glfs_fstat failed after " + "readv on %s", uuid_utoa (fd->inode->gfid)); + goto out; + } + + iatt_from_stat (&stbuf, &fstatbuf); + uuid_copy (stbuf.ia_gfid, fd->inode->gfid); + svs_fill_ino_from_gfid (&stbuf); + + /* Hack to notify higher layers of EOF. */ + if (!stbuf.ia_size || (offset + vec.iov_len) >= stbuf.ia_size) + op_errno = ENOENT; + + op_ret = vec.iov_len; + +out: + + STACK_UNWIND_STRICT (readv, frame, op_ret, op_errno, + &vec, 1, &stbuf, iobref, NULL); + + if (iobref) + iobref_unref (iobref); + if (iobuf) + iobuf_unref (iobuf); + + return 0; +} + +int32_t +svs_readlink (call_frame_t *frame, xlator_t *this, + loc_t *loc, size_t size, dict_t *xdata) +{ + svs_inode_t *inode_ctx = NULL; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + int op_ret = -1; + int op_errno = EINVAL; + char *buf = NULL; + struct iatt stbuf = {0, }; + int ret = -1; + struct stat stat = {0, }; + + GF_VALIDATE_OR_GOTO ("snap-view-daemon", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + + inode_ctx = svs_inode_ctx_get (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "failed to get inode context " + "for %s (gfid: %s)", loc->name, + uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + fs = inode_ctx->fs; + if (!fs) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the fs " + "instance for %s (gfid: %s)", loc->name, + uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = ESTALE; + goto out; + } + + object = inode_ctx->object; + if (!object) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the object " + "for %s (gfid: %s)", loc->name, + uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = ESTALE; + goto out; + } + + ret = glfs_h_stat (fs, object, &stat); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "glfs_h_stat on %s " + "(gfid: %s) failed", loc->name, + uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = errno; + goto out; + } + + iatt_from_stat (&stbuf, &stat); + uuid_copy (stbuf.ia_gfid, loc->inode->gfid); + svs_fill_ino_from_gfid (&stbuf); + + buf = alloca (size + 1); + op_ret = glfs_h_readlink (fs, object, buf, size); + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "readlink on %s failed " + "(gfid: %s)", loc->name, uuid_utoa (loc->inode->gfid)); + op_errno = errno; + goto out; + } + + buf[op_ret] = 0; + +out: + STACK_UNWIND_STRICT (readlink, frame, op_ret, op_errno, buf, &stbuf, + NULL); + + return 0; +} + +int32_t +svs_access (call_frame_t *frame, xlator_t *this, loc_t *loc, int mask, + dict_t *xdata) +{ + int ret = -1; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + svs_private_t *priv = NULL; + glfs_t *fs = NULL; + glfs_object_t *object = NULL; + svs_inode_t *inode_ctx = NULL; + gf_boolean_t is_fuse_call = 0; + int perm = 0; + int mode = 0; + + GF_VALIDATE_OR_GOTO ("svs", this, out); + GF_VALIDATE_OR_GOTO (this->name, this->private, out); + GF_VALIDATE_OR_GOTO (this->name, loc, out); + GF_VALIDATE_OR_GOTO (this->name, loc->inode, out); + + priv = this->private; + + inode_ctx = svs_inode_ctx_get (this, loc->inode); + if (!inode_ctx) { + gf_log (this->name, GF_LOG_ERROR, "inode context not found for" + " %s", uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + is_fuse_call = __is_fuse_call (frame); + + if (inode_ctx->type == SNAP_VIEW_ENTRY_POINT_INODE) { + if (is_fuse_call) { + op_ret = 0; + op_errno = 0; + } else { + op_ret = 0; + mode |= POSIX_ACL_READ; + mode |= POSIX_ACL_EXECUTE; + op_errno = mode; + } + goto out; + } + + fs = inode_ctx->fs; + object = inode_ctx->object; + + if (!is_fuse_call) + syncopctx_setfspid (&frame->root->pid); + + ret = glfs_h_access (fs, object, mask); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to access %s " + "(gfid: %s)", loc->path, uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = errno; + goto out; + } + + /* The actual posix_acl xlator does acl checks differently for + fuse and nfs. In this case how to send the information of + whether the call came from fuse or nfs to the snapshot volume + via gfapi? + */ + + op_ret = 0; + op_errno = ret; + +out: + + STACK_UNWIND_STRICT (access, frame, op_ret, op_errno, NULL); + return 0; +} + + +int32_t +mem_acct_init (xlator_t *this) +{ + int ret = -1; + + if (!this) + return ret; + + ret = xlator_mem_acct_init (this, gf_svs_mt_end + 1); + + if (ret != 0) { + gf_log (this->name, GF_LOG_WARNING, "Memory accounting" + " init failed"); + return ret; + } + + return ret; +} + +int32_t +init (xlator_t *this) +{ + svs_private_t *priv = NULL; + int ret = -1; + + /* This can be the top of graph in certain cases */ + if (!this->parents) { + gf_log (this->name, GF_LOG_DEBUG, + "dangling volume. check volfile "); + } + + /* TODO: define a mem-type structure */ + priv = GF_CALLOC (1, sizeof (*priv), gf_svs_mt_priv_t); + if (!priv) + goto out; + + this->private = priv; + + /* get the list of snaps first to return to client xlator */ + ret = svs_get_snapshot_list (this, priv); + + ret = 0; +out: + if (ret && priv) { + GF_FREE (priv); + } + + return ret; +} + +void +fini (xlator_t *this) +{ + svs_private_t *priv = NULL; + priv = this->private; + this->private = NULL; + + if (priv) { + GF_FREE (priv); + } + + return; +} + +struct xlator_fops fops = { + .lookup = svs_lookup, + .stat = svs_stat, + .opendir = svs_opendir, + .readdirp = svs_readdirp, + .readdir = svs_readdir, + .open = svs_open, + .readv = svs_readv, + .flush = svs_flush, + .fstat = svs_fstat, + .getxattr = svs_getxattr, + .access = svs_access, + /* entry fops */ +}; + +struct xlator_cbks cbks = { + .release = svs_release, + .releasedir = svs_releasedir, + .forget = svs_forget, +}; + +struct volume_options options[] = { + /* This translator doesn't take any options, or provide any options */ + { .key = {NULL} }, +}; diff --git a/xlators/features/snapview-server/src/snapview-server.h b/xlators/features/snapview-server/src/snapview-server.h new file mode 100644 index 00000000000..b0e051e0fc3 --- /dev/null +++ b/xlators/features/snapview-server/src/snapview-server.h @@ -0,0 +1,88 @@ +/* + 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. +*/ +#ifndef __SNAP_VIEW_H__ +#define __SNAP_VIEW_H__ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "dict.h" +#include "defaults.h" +#include "mem-types.h" +#include "call-stub.h" +#include "inode.h" +#include "byte-order.h" +#include "iatt.h" +#include +#include +#include "glusterfs.h" +#include "xlator.h" +#include "logging.h" +#include "glfs.h" +#include "common-utils.h" +#include "glfs-handles.h" +#include "glfs-internal.h" +#include "glusterfs3-xdr.h" +#include "glusterfs-acl.h" +#include "syncop.h" +#include "list.h" + +/* + * The max number of snap entries we consider currently + */ +#define SNAP_VIEW_MAX_NUM_SNAPS 128 + +#define DEFAULT_SVD_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs" + +typedef enum { + SNAP_VIEW_ENTRY_POINT_INODE = 0, + SNAP_VIEW_VIRTUAL_INODE +} inode_type_t; + +struct svs_inode { + glfs_t *fs; + glfs_object_t *object; + inode_type_t type; + + /* used only for entry point directory where gfid of the directory + from where the entry point was entered is saved. + */ + uuid_t pargfid; + struct iatt buf; +}; +typedef struct svs_inode svs_inode_t; + +struct svs_fd { + glfs_fd_t *fd; +}; +typedef struct svs_fd svs_fd_t; + +struct snap_dirent { + char name[NAME_MAX]; + char uuid[UUID_CANONICAL_FORM_LEN + 1]; + glfs_t *fs; +}; +typedef struct snap_dirent snap_dirent_t; + +struct svs_private { + snap_dirent_t *dirents; + int num_snaps; +}; +typedef struct svs_private svs_private_t; + +glfs_t * +svs_intialise_snapshot_volume (xlator_t *this, const char *name); + +snap_dirent_t * +svs_get_snap_dirent (xlator_t *this, const char *name); + +#endif /* __SNAP_VIEW_H__ */ -- cgit