diff options
author | Raghavendra Bhat <raghavendra@redhat.com> | 2014-05-07 20:13:43 +0530 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2014-05-29 09:25:46 -0700 |
commit | cc0378d39f4082f51d5ef6e02b3007fe9e78cb31 (patch) | |
tree | f5c82bece9cf1a2fd79685ef2d89bcd2a5b8428f /xlators/features/snapview-client | |
parent | 58b9edee87bba3ffe812cf15f171926be017575b (diff) |
user servicable snapshots
Change-Id: Idbf27dbe088e646a8ab81cedc5818413795895ea
Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
Signed-off-by: Anand Subramanian <anands@redhat.com>
Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
Reviewed-on: http://review.gluster.org/7700
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Diffstat (limited to 'xlators/features/snapview-client')
-rw-r--r-- | xlators/features/snapview-client/Makefile.am | 1 | ||||
-rw-r--r-- | xlators/features/snapview-client/src/Makefile.am | 15 | ||||
-rw-r--r-- | xlators/features/snapview-client/src/snapview-client-mem-types.h | 23 | ||||
-rw-r--r-- | xlators/features/snapview-client/src/snapview-client.c | 1687 | ||||
-rw-r--r-- | xlators/features/snapview-client/src/snapview-client.h | 110 |
5 files changed, 1836 insertions, 0 deletions
diff --git a/xlators/features/snapview-client/Makefile.am b/xlators/features/snapview-client/Makefile.am new file mode 100644 index 00000000000..af437a64d6d --- /dev/null +++ b/xlators/features/snapview-client/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/xlators/features/snapview-client/src/Makefile.am b/xlators/features/snapview-client/src/Makefile.am new file mode 100644 index 00000000000..8a3f6fe4ea2 --- /dev/null +++ b/xlators/features/snapview-client/src/Makefile.am @@ -0,0 +1,15 @@ +xlator_LTLIBRARIES = snapview-client.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features + +snapview_client_la_LDFLAGS = -module -avoid-version + +snapview_client_la_SOURCES = snapview-client.c +snapview_client_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = snapview-client.h snapview-client-mem-types.h + +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src + +AM_CFLAGS = -Wall $(GF_CFLAGS) + +CLEANFILES = diff --git a/xlators/features/snapview-client/src/snapview-client-mem-types.h b/xlators/features/snapview-client/src/snapview-client-mem-types.h new file mode 100644 index 00000000000..b6fa0ef7cfb --- /dev/null +++ b/xlators/features/snapview-client/src/snapview-client-mem-types.h @@ -0,0 +1,23 @@ +/* + 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. +*/ + +#ifndef _SVC_MEM_TYPES_H +#define _SVC_MEM_TYPES_H + +#include "mem-types.h" + +enum svc_mem_types { + gf_svc_mt_svc_private_t = gf_common_mt_end + 1, + gf_svc_mt_svc_local_t, + gf_svc_mt_svc_inode_t, + gf_svc_mt_end +}; + +#endif diff --git a/xlators/features/snapview-client/src/snapview-client.c b/xlators/features/snapview-client/src/snapview-client.c new file mode 100644 index 00000000000..a86339901b9 --- /dev/null +++ b/xlators/features/snapview-client/src/snapview-client.c @@ -0,0 +1,1687 @@ +/* + 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. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "snapview-client.h" +#include "inode.h" +#include "byte-order.h" + + +void +svc_local_free (svc_local_t *local) +{ + if (local) + loc_wipe (&local->loc); +} + +xlator_t * +svc_get_subvolume (xlator_t *this, int inode_type) +{ + xlator_t *subvolume = NULL; + + GF_VALIDATE_OR_GOTO ("snapview-client", this, out); + + if (inode_type == VIRTUAL_INODE) + subvolume = SECOND_CHILD (this); + else + subvolume = FIRST_CHILD (this); + +out: + return subvolume; +} + +int32_t +__svc_inode_ctx_set (xlator_t *this, inode_t *inode, int inode_type) +{ + uint64_t value = 0; + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO ("snapview-client", this, out); + GF_VALIDATE_OR_GOTO (this->name, inode, out); + + value = inode_type; + + ret = __inode_ctx_set (inode, this, &value); + +out: + return ret; +} + +int +__svc_inode_ctx_get (xlator_t *this, inode_t *inode, int *inode_type) +{ + uint64_t value = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO ("snapview-client", this, out); + GF_VALIDATE_OR_GOTO (this->name, inode, out); + + ret = __inode_ctx_get (inode, this, &value); + if (ret < 0) + goto out; + + *inode_type = (int)(value); + +out: + return ret; +} + +int +svc_inode_ctx_get (xlator_t *this, inode_t *inode, int *inode_type) +{ + int ret = -1; + + GF_VALIDATE_OR_GOTO ("snapview-client", this, out); + GF_VALIDATE_OR_GOTO (this->name, inode, out); + + LOCK (&inode->lock); + { + ret = __svc_inode_ctx_get (this, inode, inode_type); + } + UNLOCK (&inode->lock); + +out: + return ret; +} + +int32_t +svc_inode_ctx_set (xlator_t *this, inode_t *inode, int inode_type) +{ + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO ("snapview-client", this, out); + GF_VALIDATE_OR_GOTO (this->name, inode, out); + + LOCK (&inode->lock); + { + ret = __svc_inode_ctx_set (this, inode, inode_type); + } + UNLOCK (&inode->lock); + +out: + return ret; +} + +int32_t +svc_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xdata, struct iatt *postparent) +{ + svc_local_t *local = NULL; + inode_t *parent = NULL; + xlator_t *subvolume = NULL; + gf_boolean_t do_unwind = _gf_true; + int inode_type = -1; + int parent_type = -1; + int ret = -1; + + local = frame->local; + subvolume = local->subvolume; + if (!subvolume) { + gf_log_callingfn (this->name, GF_LOG_ERROR, "path: %s, " + "gfid: %s ", local->loc.path, + inode?uuid_utoa (inode->gfid):""); + GF_ASSERT (0); + } + + /* There is a possibility that, the client process just came online + and does not have the inode on which the lookup came. In that case, + the fresh inode created from fuse for the lookup fop, wont have + the inode context set without which svc cannot decide where to + STACK_WIND to. So by default it decides to send the fop to the + regular subvolume (i.e first child of the xlator). If lookup fails + on the regular volume, then there is a possibility that the lookup + is happening on a virtual inode (i.e history data residing in snaps). + So if lookup fails with ENOENT and the inode context is not there, + then send the lookup to the 2nd child of svc. + */ + ret = svc_inode_ctx_get (this, inode, &inode_type); + if (op_ret) { + if (op_errno == ENOENT && (ret < 0) && + !uuid_is_null (local->loc.gfid) && + !__is_root_gfid (local->loc.gfid)) { + if (subvolume == FIRST_CHILD (this)) { + subvolume = SECOND_CHILD (this); + STACK_WIND (frame, svc_lookup_cbk, subvolume, + subvolume->fops->lookup, + &local->loc, xdata); + do_unwind = _gf_false; + } + } + goto out; + } + + if (local->loc.parent) + parent = inode_ref (local->loc.parent); + else { + parent = inode_parent (inode, NULL, NULL); + if (!parent && !uuid_is_null (local->loc.pargfid)) { + parent = inode_find (inode->table, + local->loc.pargfid); + } + } + + if (!__is_root_gfid (buf->ia_gfid) && parent) { + ret = svc_inode_ctx_get (this, parent, &parent_type); + if (ret < 0) { + op_ret = -1; + op_errno = EINVAL; + goto out; + } + } + + if (subvolume == FIRST_CHILD (this)) + inode_type = NORMAL_INODE; + else + inode_type = VIRTUAL_INODE; + + ret = svc_inode_ctx_set (this, inode, inode_type); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "failed to set inode type" + "into the context"); + +out: + if (do_unwind) { + SVC_STACK_UNWIND (lookup, frame, op_ret, op_errno, inode, buf, + xdata, postparent); + } + + if (parent) + inode_unref (parent); + + return 0; +} + +int32_t +svc_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata) +{ + int32_t ret = -1; + svc_local_t *local = NULL; + xlator_t *subvolume = NULL; + int op_ret = -1; + int op_errno = EINVAL; + inode_t *parent = NULL; + svc_private_t *priv = NULL; + dict_t *new_xdata = NULL; + int inode_type = -1; + int parent_type = -1; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + priv = this->private; + + ret = svc_inode_ctx_get (this, loc->inode, &inode_type); + if (!__is_root_gfid (loc->gfid)) { + if (loc->parent) { + parent = inode_ref (loc->parent); + ret = svc_inode_ctx_get (this, loc->parent, + &parent_type); + } else { + parent = inode_parent (loc->inode, loc->pargfid, NULL); + if (parent) + ret = svc_inode_ctx_get (this, parent, + &parent_type); + } + } + + local = mem_get0 (this->local_pool); + if (!local) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate local"); + op_ret = -1; + op_errno = ENOMEM; + goto out; + } + + frame->local = local; + loc_copy (&local->loc, loc); + + if (__is_root_gfid (loc->inode->gfid)) { + subvolume = FIRST_CHILD (this); + GF_ASSERT (subvolume); + local->subvolume = subvolume; + wind = _gf_true; + goto out; + } + + /* nfs sends nameless lookups directly using the gfid. In that case + loc->name will be NULL. So check if loc->name is NULL. If so, then + try to get the subvolume using inode context. But if the inode has + not been looked up yet, then send the lookup call to the first + subvolume. + */ + + if (!loc->name) { + if (uuid_is_null (loc->inode->gfid)) { + subvolume = FIRST_CHILD (this); + local->subvolume = subvolume; + wind = _gf_true; + goto out; + } else { + if (inode_type >= 0) + subvolume = svc_get_subvolume (this, + inode_type); + else + subvolume = FIRST_CHILD (this); + local->subvolume = subvolume; + wind = _gf_true; + goto out; + } + } + + if (strcmp (loc->name, priv->path)) { + if (parent_type == NORMAL_INODE) { + subvolume = FIRST_CHILD (this); + local->subvolume = subvolume; + } else { + subvolume = SECOND_CHILD (this); + local->subvolume = subvolume; + } + } else { + if (parent_type == NORMAL_INODE) { + subvolume = SECOND_CHILD (this); + local->subvolume = subvolume; + /* Indication of whether the lookup is happening on the + entry point or not, to the snapview-server. + */ + SVC_ENTRY_POINT_SET (this, xdata, op_ret, op_errno, + new_xdata, priv, ret, out); + } else { + /* Either error can be sent to application as + the entry point directory can exist only within + real directories and here the parent is a virtual + directory or send the call all the way to svs and + let it send the error back. For now it is sending + the error to application itself. (Saves the + network latency) + */ + op_ret = -1; + op_errno = ENOENT; + goto out; + } + } + + wind = _gf_true; + +out: + if (wind) + STACK_WIND (frame, svc_lookup_cbk, + subvolume, subvolume->fops->lookup, loc, xdata); + else + SVC_STACK_UNWIND (lookup, frame, op_ret, op_errno, NULL, + NULL, NULL, NULL); + if (new_xdata) + dict_unref (new_xdata); + + if (parent) + inode_unref (parent); + + return 0; +} + +/* should all the fops be handled like lookup is supposed to be + handled? i.e just based on inode type decide where the call should + be sent and in the call back update the contexts. +*/ +int32_t +svc_stat (call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + xlator_t *subvolume = NULL; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + loc->inode, subvolume, out); + + STACK_WIND_TAIL (frame,subvolume, subvolume->fops->stat, loc, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (stat, frame, op_ret, op_errno, + NULL, NULL); + return 0; +} + +int32_t +svc_fstat (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + xlator_t *subvolume = NULL; + int32_t op_ret = -1; + int32_t op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + fd->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->fstat, fd, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (fstat, frame, op_ret, op_errno, NULL, NULL); + + return ret; +} + +/* If the inode represents a directory which is actually + present in a snapshot, then opendir on that directory + should be sent to the snap-view-server which opens + the directory in the corresponding graph. + In fact any opendir call on a virtual directory + should be sent to svs. Because if it fakes success + here, then later when readdir on that fd comes, there + will not be any corresponding fd opened on svs and + svc has to do things that open-behind is doing. +*/ +int32_t +svc_opendir (call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd, + dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + xlator_t *subvolume = NULL; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + loc->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->opendir, loc, fd, + xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (opendir, frame, op_ret, op_errno, NULL, NULL); + + return 0; +} + +int32_t +svc_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + ret = svc_inode_ctx_get (this, loc->inode, &inode_type); + if (ret < 0) { + op_ret = -1; + op_errno = EINVAL; + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for %s (gfid: %s)", loc->path, + uuid_utoa (loc->inode->gfid)); + goto out; + } + + if (inode_type == NORMAL_INODE) { + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->setattr, loc, stbuf, + valid, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (setattr, frame, op_ret, op_errno, + NULL, NULL, NULL); + return 0; +} + +int32_t +svc_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, struct iatt *stbuf, + int32_t valid, dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + ret = svc_inode_ctx_get (this, fd->inode, &inode_type); + if (ret < 0) { + 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 out; + } + + if (inode_type == NORMAL_INODE) { + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->fsetattr, fd, stbuf, + valid, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (fsetattr, frame, op_ret, op_errno, + NULL, NULL, NULL); + return 0; +} + +int32_t +svc_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, const char *name, + dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + xlator_t *subvolume = NULL; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + loc->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->getxattr, loc, name, + xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (getxattr, frame, op_ret, op_errno, + NULL, NULL); + + return 0; +} + +int32_t +svc_fgetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, const char *name, + dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + xlator_t *subvolume = NULL; + gf_boolean_t wind = _gf_false; + int op_ret = -1; + int op_errno = EINVAL; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + fd->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, + subvolume->fops->fgetxattr, fd, name, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (fgetxattr, frame, op_ret, op_errno, + NULL, NULL); + return 0; +} + +int32_t +svc_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + int32_t flags, dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + ret = svc_inode_ctx_get (this, loc->inode, &inode_type); + if (ret < 0) { + 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; + } + + if (inode_type == NORMAL_INODE) { + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->setxattr, loc, dict, + flags, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (setxattr, frame, op_ret, op_errno, + NULL); + + return 0; +} + +int32_t +svc_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, + int32_t flags, dict_t *xdata) +{ + int32_t ret = -1; + int inode_type = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + ret = svc_inode_ctx_get (this, fd->inode, &inode_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get inode context " + "for %s", uuid_utoa (fd->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (inode_type == NORMAL_INODE) { + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->fsetxattr, fd, dict, + flags, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + STACK_UNWIND_STRICT (fsetxattr, frame, op_ret, op_errno, + NULL); + + return 0; +} + +int32_t +svc_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, + dict_t *xdata) +{ + int inode_type = -1; + int ret = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + ret = svc_inode_ctx_get (this, loc->inode, &inode_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for %s (gfid: %s)", loc->name, + uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (inode_type == NORMAL_INODE) { + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->rmdir, loc, flags, + xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (rmdir, frame, op_ret, op_errno, + NULL, NULL, NULL); + return 0; +} + +int32_t +svc_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + int inode_type = -1; + int ret = -1; + + if (op_ret < 0) + goto out; + + inode_type = NORMAL_INODE; + ret = svc_inode_ctx_set (this, inode, inode_type); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "failed to set inode " + "context"); + + +out: + SVC_STACK_UNWIND (mkdir, frame, op_ret, op_errno, inode, + buf, preparent, postparent, xdata); + return 0; +} + +int32_t +svc_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, dict_t *xdata) +{ + int parent_type = -1; + int ret = -1; + int op_ret = -1; + int op_errno = EINVAL; + svc_private_t *priv = NULL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + priv = this->private; + + ret = svc_inode_ctx_get (this, loc->parent, &parent_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for %s", uuid_utoa (loc->parent->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (strcmp (loc->name, priv->path) && parent_type == NORMAL_INODE) { + STACK_WIND (frame, svc_mkdir_cbk, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->mkdir, loc, mode, + umask, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (mkdir, frame, op_ret, op_errno, NULL, NULL, + NULL, NULL, NULL); + return 0; +} + +int32_t +svc_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + int inode_type = -1; + int ret = -1; + + if (op_ret < 0) + goto out; + + inode_type = NORMAL_INODE; + ret = svc_inode_ctx_set (this, inode, inode_type); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "failed to set inode " + "context"); + +out: + SVC_STACK_UNWIND (mknod, frame, op_ret, op_errno, inode, + buf, preparent, postparent, xdata); + return 0; +} + +int32_t +svc_mknod (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dev_t rdev, mode_t umask, dict_t *xdata) +{ + int parent_type = -1; + int ret = -1; + int op_ret = -1; + int op_errno = EINVAL; + svc_private_t *priv = NULL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + priv = this->private; + + ret = svc_inode_ctx_get (this, loc->parent, &parent_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for %s", uuid_utoa (loc->parent->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (strcmp (loc->name, priv->path) && parent_type == NORMAL_INODE) { + STACK_WIND (frame, svc_mknod_cbk, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->mknod, loc, mode, + rdev, umask, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (mknod, frame, op_ret, op_errno, NULL, NULL, + NULL, NULL, NULL); + return 0; +} + +/* If the flags of the open call contain O_WRONLY or O_RDWR and the inode is + a virtual inode, then unwind the call back with EPERM. Otherwise simply + STACK_WIND the call to the first child of svc xlator. +*/ +int32_t +svc_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata) +{ + xlator_t *subvolume = NULL; + int inode_type = -1; + int op_ret = -1; + int op_errno = EINVAL; + int ret = -1; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + /* Another way is to STACK_WIND to normal subvolume, if inode + type is not there in the context. If the file actually resides + in snapshots, then ENOENT would be returned. Needs more analysis. + */ + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + loc->inode, subvolume, out); + + if (((flags & O_ACCMODE) == O_WRONLY) || + ((flags & O_ACCMODE) == O_RDWR)) { + if (subvolume != FIRST_CHILD (this)) { + op_ret = -1; + op_errno = EINVAL; + goto out; + } + } + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->open, loc, + flags, fd, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (open, frame, op_ret, op_errno, NULL, + NULL); + return 0; +} + +int32_t +svc_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *stbuf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + int inode_type = -1; + int ret = -1; + + if (op_ret < 0) + goto out; + + inode_type = NORMAL_INODE; + ret = svc_inode_ctx_set (this, inode, inode_type); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "failed to set inode " + "context"); + +out: + SVC_STACK_UNWIND (create, frame, op_ret, op_errno, fd, + inode, stbuf, preparent, postparent, xdata); + + return 0; +} + +int32_t +svc_create (call_frame_t *frame, xlator_t *this, + loc_t *loc, int32_t flags, mode_t mode, + mode_t umask, fd_t *fd, dict_t *xdata) +{ + int parent_type = -1; + int ret = -1; + int op_ret = -1; + int op_errno = EINVAL; + svc_private_t *priv = NULL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + GF_VALIDATE_OR_GOTO (this->name, fd, out); + + priv = this->private; + + ret = svc_inode_ctx_get (this, loc->parent, &parent_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for %s", uuid_utoa (loc->parent->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (strcmp (loc->name, priv->path) && parent_type == NORMAL_INODE) { + STACK_WIND (frame, svc_create_cbk, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->create, loc, flags, + mode, umask, fd, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (create, frame, op_ret, op_errno, + NULL, NULL, NULL, NULL, NULL, NULL); + return 0; +} + +int32_t +svc_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + int inode_type = -1; + int ret = -1; + + if (op_ret < 0) + goto out; + + inode_type = NORMAL_INODE; + ret = svc_inode_ctx_set (this, inode, inode_type); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "failed to set inode " + "context"); + +out: + SVC_STACK_UNWIND (symlink, frame, op_ret, op_errno, inode, + buf, preparent, postparent, xdata); + + return 0; +} + +int32_t +svc_symlink (call_frame_t *frame, xlator_t *this, const char *linkpath, + loc_t *loc, mode_t umask, dict_t *xdata) +{ + int parent_type = -1; + int op_ret = -1; + int op_errno = EINVAL; + int ret = -1; + svc_private_t *priv = NULL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, 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; + + ret = svc_inode_ctx_get (this, loc->parent, &parent_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for %s", uuid_utoa (loc->parent->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (strcmp (loc->name, priv->path) && parent_type == NORMAL_INODE) { + STACK_WIND (frame, svc_symlink_cbk, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->symlink, linkpath, loc, + umask, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (symlink, frame, op_ret, op_errno, + NULL, NULL, NULL, NULL, NULL); + return 0; +} + +int32_t +svc_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, + dict_t *xdata) +{ + int inode_type = -1; + int op_ret = -1; + int op_errno = EINVAL; + int ret = -1; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + ret = svc_inode_ctx_get (this, loc->inode, &inode_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for %s", uuid_utoa (loc->parent->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (inode_type == NORMAL_INODE) { + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->unlink, loc, flags, + xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (unlink, frame, op_ret, op_errno, NULL, NULL, + NULL); + return 0; +} + +int32_t +svc_readv (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t offset, uint32_t flags, dict_t *xdata) +{ + int inode_type = -1; + xlator_t *subvolume = NULL; + int ret = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + fd->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->readv, + fd, size, offset, flags, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (readv, frame, op_ret, op_errno, NULL, 0, NULL, + NULL, NULL); + return 0; +} + +int32_t +svc_readlink (call_frame_t *frame, xlator_t *this, + loc_t *loc, size_t size, dict_t *xdata) +{ + int inode_type = -1; + xlator_t *subvolume = NULL; + int ret = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + loc->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->readlink, loc, size, + xdata); + + wind = _gf_true; + +out: + if (!wind) + STACK_UNWIND_STRICT (readlink, frame, op_ret, op_errno, NULL, NULL, + NULL); + return 0; +} + +int32_t +svc_access (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t mask, + dict_t *xdata) +{ + int ret = -1; + int inode_type = -1; + xlator_t *subvolume = NULL; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + loc->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->access, loc, mask, + xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (access, frame, op_ret, op_errno, NULL); + + return 0; +} + +int32_t +svc_readdir (call_frame_t *frame, xlator_t *this, fd_t *fd, + size_t size, off_t off, + dict_t *xdata) +{ + int inode_type = -1; + xlator_t *subvolume = NULL; + int ret = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + fd->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->readdir, fd, size, + off, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (readdir, frame, op_ret, op_errno, NULL, + NULL); + return 0; +} + +int32_t +svc_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + gf_dirent_t *entries, dict_t *xdata) +{ + gf_dirent_t *entry = NULL; + svc_local_t *local = NULL; + gf_boolean_t real = _gf_true; + int inode_type = -1; + int ret = -1; + + if (op_ret < 0) + goto out; + + local = frame->local; + frame->local = NULL; + + if (local->subvolume == FIRST_CHILD (this)) + real = _gf_true; + else + real = _gf_false; + + list_for_each_entry (entry, &entries->list, list) { + if (!entry->inode) + continue; + + if (real) + inode_type = NORMAL_INODE; + else + inode_type = VIRTUAL_INODE; + + ret = svc_inode_ctx_set (this, entry->inode, inode_type); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "failed to set inode " + "context"); + } + + +out: + SVC_STACK_UNWIND (readdirp, frame, op_ret, op_errno, entries, xdata); + + return 0; +} + +int32_t +svc_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd, + size_t size, off_t off, + dict_t *xdata) +{ + int inode_type = -1; + xlator_t *subvolume = NULL; + svc_local_t *local = NULL; + int ret = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + local = mem_get0 (this->local_pool); + if (!local) { + gf_log (this->name, GF_LOG_ERROR, "failed to allocate local"); + goto out; + } + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + fd->inode, subvolume, out); + + local->subvolume = subvolume; + frame->local = local; + + STACK_WIND (frame, svc_readdirp_cbk, subvolume, + subvolume->fops->readdirp, fd, size, off, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (readdirp, frame, op_ret, op_errno, NULL, NULL); + + return 0; +} + +/* Renaming the entries from or to snapshots is not allowed as the snapshots + are read-only. +*/ +int32_t +svc_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, + loc_t *newloc, dict_t *xdata) +{ + int src_inode_type = -1; + int dst_inode_type = -1; + int dst_parent_type = -1; + int32_t op_ret = -1; + int32_t op_errno = 0; + int32_t ret = -1; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, oldloc, out); + GF_VALIDATE_OR_GOTO (this->name, oldloc->inode, out); + GF_VALIDATE_OR_GOTO (this->name, newloc, out); + + ret = svc_inode_ctx_get (this, oldloc->inode, &src_inode_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get the inode " + "context for the inode %s", + uuid_utoa (oldloc->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (src_inode_type == VIRTUAL_INODE) { + gf_log (this->name, GF_LOG_ERROR, "rename happening on a entry" + " %s residing in snapshot", oldloc->name); + op_ret = -1; + op_errno = EPERM; + goto out; + } + + if (newloc->inode) { + ret = svc_inode_ctx_get (this, newloc->inode, &dst_inode_type); + if (!ret && dst_inode_type == VIRTUAL_INODE) { + gf_log (this->name, GF_LOG_ERROR, "rename of %s " + "happening to a entry %s residing in snapshot", + oldloc->name, newloc->name); + op_ret = -1; + op_errno = EPERM; + goto out; + } + } + + if (dst_inode_type < 0) { + ret = svc_inode_ctx_get (this, newloc->parent, + &dst_parent_type); + if (!ret && dst_parent_type == VIRTUAL_INODE) { + gf_log (this->name, GF_LOG_ERROR, "rename of %s " + "happening to a entry %s residing in snapshot", + oldloc->name, newloc->name); + op_ret = -1; + op_errno = EPERM; + goto out; + } + } + + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->rename, oldloc, newloc, + xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (rename, frame, op_ret, op_errno, NULL, + NULL, NULL, NULL, NULL, NULL); + return 0; +} + +/* Creating hardlinks for the files from the snapshot is not allowed as it + will be equivalent of creating hardlinks across different filesystems. + And so is vise versa. +*/ +int32_t +svc_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) +{ + int src_inode_type = -1; + int dst_parent_type = -1; + int32_t op_ret = -1; + int32_t op_errno = 0; + int32_t ret = -1; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", this, out); + GF_VALIDATE_OR_GOTO (this->name, frame, out); + GF_VALIDATE_OR_GOTO (this->name, oldloc, out); + GF_VALIDATE_OR_GOTO (this->name, oldloc->inode, out); + GF_VALIDATE_OR_GOTO (this->name, newloc, out); + + ret = svc_inode_ctx_get (this, oldloc->inode, &src_inode_type); + if (!ret && src_inode_type == VIRTUAL_INODE) { + gf_log (this->name, GF_LOG_ERROR, "rename happening on a entry" + " %s residing in snapshot", oldloc->name); + op_ret = -1; + op_errno = EPERM; + goto out; + } + + ret = svc_inode_ctx_get (this, newloc->parent, &dst_parent_type); + if (!ret && dst_parent_type == VIRTUAL_INODE) { + gf_log (this->name, GF_LOG_ERROR, "rename of %s " + "happening to a entry %s residing in snapshot", + oldloc->name, newloc->name); + op_ret = -1; + op_errno = EPERM; + goto out; + } + + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->link, oldloc, newloc, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (link, frame, op_ret, op_errno, + NULL, NULL, NULL, NULL, NULL); + return 0; +} + +int32_t +svc_removexattr (call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata) +{ + int ret = -1; + int inode_type = -1; + int op_ret = -1; + int op_errno = EINVAL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + ret = svc_inode_ctx_get (this, loc->inode, &inode_type); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to get te inode " + "context for %s (gfid: %s)", loc->path, + uuid_utoa (loc->inode->gfid)); + op_ret = -1; + op_errno = EINVAL; + goto out; + } + + if (inode_type == NORMAL_INODE) { + STACK_WIND_TAIL (frame, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->removexattr, loc, + name, xdata); + } else { + op_ret = -1; + op_errno = EPERM; + goto out; + } + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (removexattr, frame, op_ret, op_errno, + NULL); + + return 0; +} + +int32_t +svc_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; + int inode_type = -1; + xlator_t *subvolume = NULL; + gf_boolean_t wind = _gf_false; + + GF_VALIDATE_OR_GOTO ("svc", 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); + + SVC_GET_SUBVOL_FROM_CTX (this, op_ret, op_errno, inode_type, ret, + fd->inode, subvolume, out); + + STACK_WIND_TAIL (frame, subvolume, subvolume->fops->flush, fd, xdata); + + wind = _gf_true; + +out: + if (!wind) + SVC_STACK_UNWIND (flush, frame, op_ret, op_errno, NULL); + + return 0; +} + +int32_t +svc_forget (xlator_t *this, inode_t *inode) +{ + int ret = -1; + uint64_t value = 0; + + GF_VALIDATE_OR_GOTO ("svc", 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 delete inode " + "context for %s", uuid_utoa (inode->gfid)); + goto out; + } + +out: + return 0; +} + +int +reconfigure (xlator_t *this, dict_t *options) +{ + svc_private_t *priv = NULL; + + priv = this->private; + + GF_OPTION_RECONF ("snapshot-directory", priv->path, options, str, out); + +out: + return 0; +} + +int32_t +mem_acct_init (xlator_t *this) +{ + int32_t ret = -1; + + if (!this) + return ret; + + ret = xlator_mem_acct_init (this, gf_svc_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) +{ + svc_private_t *private = NULL; + int ret = -1; + int children = 0; + xlator_list_t *xl = NULL; + + if (!this->children) { + gf_log (this->name, GF_LOG_ERROR, + "configured without any child"); + goto out; + } + + xl = this->children; + while (xl) { + children++; + xl = xl->next; + } + + if (children != 2) { + gf_log (this->name, GF_LOG_ERROR, "snap-view-client has got " + "%d subvolumes. It can have only 2 subvolumes.", + children); + goto out; + } + + /* This can be the top of graph in certain cases */ + if (!this->parents) { + gf_log (this->name, GF_LOG_DEBUG, + "dangling volume. check volfile "); + } + + private = GF_CALLOC (1, sizeof (*private), gf_svc_mt_svc_private_t); + if (!private) + goto out; + + GF_OPTION_INIT ("snapshot-directory", private->path, str, out); + + this->private = private; + this->local_pool = mem_pool_new (svc_local_t, 128); + if (!this->local_pool) { + gf_log (this->name, GF_LOG_ERROR, "could not get mem pool for " + "frame->local"); + goto out; + } + + ret = 0; + +out: + if (ret) + GF_FREE (private); + + return ret; +} + +void +fini (xlator_t *this) +{ + svc_private_t *priv = NULL; + + if (!this) + return; + + priv = this->private; + if (!priv) + return; + + this->private = NULL; + + GF_FREE (priv->path); + GF_FREE (priv); + + return; +} + +struct xlator_fops fops = { + .lookup = svc_lookup, + .opendir = svc_opendir, + .stat = svc_stat, + .fstat = svc_fstat, + .rmdir = svc_rmdir, + .rename = svc_rename, + .mkdir = svc_mkdir, + .open = svc_open, + .unlink = svc_unlink, + .setattr = svc_setattr, + .getxattr = svc_getxattr, + .setxattr = svc_setxattr, + .fsetxattr = svc_fsetxattr, + .readv = svc_readv, + .readdir = svc_readdir, + .readdirp = svc_readdirp, + .create = svc_create, + .readlink = svc_readlink, + .mknod = svc_mknod, + .symlink = svc_symlink, + .flush = svc_flush, + .link = svc_link, + .access = svc_access, + .removexattr = svc_removexattr, +}; + +struct xlator_cbks cbks = { + .forget = svc_forget, +}; + +struct volume_options options[] = { + { .key = {"snapshot-directory"}, + .type = GF_OPTION_TYPE_STR, + .default_value = ".snaps", + }, + { .key = {NULL} }, +}; diff --git a/xlators/features/snapview-client/src/snapview-client.h b/xlators/features/snapview-client/src/snapview-client.h new file mode 100644 index 00000000000..000490393c1 --- /dev/null +++ b/xlators/features/snapview-client/src/snapview-client.h @@ -0,0 +1,110 @@ + /* + 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. +*/ +#ifndef __SNAP_VIEW_CLIENT_H__ +#define __SNAP_VIEW_CLIENT_H__ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "logging.h" +#include "dict.h" +#include "xlator.h" +#include "defaults.h" +#include "snapview-client-mem-types.h" + +struct __svc_local { + loc_t loc; + xlator_t *subvolume; +}; +typedef struct __svc_local svc_local_t; + +void +svc_local_free (svc_local_t *local); + +#define SVC_STACK_UNWIND(fop, frame, params ...) do { \ + svc_local_t *__local = NULL; \ + if (frame) { \ + __local = frame->local; \ + frame->local = NULL; \ + } \ + STACK_UNWIND_STRICT (fop, frame, params); \ + svc_local_free (__local); \ + } while (0) + +#define SVC_ENTRY_POINT_SET(this, xdata, op_ret, op_errno, new_xdata, \ + priv, ret, label) \ + do { \ + if (!xdata) { \ + xdata = new_xdata = dict_new (); \ + if (!new_xdata) { \ + gf_log (this->name, GF_LOG_ERROR, \ + "failed to allocate new dict"); \ + op_ret = -1; \ + op_errno = ENOMEM; \ + goto label; \ + } \ + } \ + ret = dict_set_str (xdata, "entry-point", "true"); \ + if (ret) { \ + gf_log (this->name, GF_LOG_ERROR, \ + "failed to set dict"); \ + op_ret = -1; \ + op_errno = ENOMEM; \ + goto label; \ + } \ + } while (0); + +#define SVC_GET_SUBVOL_FROM_CTX(this, op_ret, op_errno, inode_type, ret, \ + inode, subvolume, label) \ + do { \ + ret = svc_inode_ctx_get (this, inode, &inode_type); \ + if (ret < 0) { \ + gf_log (this->name, GF_LOG_ERROR, \ + "inode context not found for gfid %s", \ + uuid_utoa (inode->gfid)); \ + op_ret = -1; \ + op_errno = EINVAL; \ + goto label; \ + } \ + \ + subvolume = svc_get_subvolume (this, inode_type); \ + } while (0); + +struct svc_private { + char *path; //might be helpful for samba +}; +typedef struct svc_private svc_private_t; + +typedef enum { + NORMAL_INODE = 1, + VIRTUAL_INODE +} inode_type_t; + +void svc_local_free (svc_local_t *local); + +xlator_t * +svc_get_subvolume (xlator_t *this, int inode_type); + +int +__svc_inode_ctx_get (xlator_t *this, inode_t *inode, int *inode_type); + +int +svc_inode_ctx_get (xlator_t *this, inode_t *inode, int *inode_type); + +int32_t +svc_inode_ctx_set (xlator_t *this, inode_t *inode, int inode_type); + +void +svc_local_free (svc_local_t *local); + +#endif /* __SNAP_VIEW_CLIENT_H__ */ |