diff options
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | xlators/features/Makefile.am | 4 | ||||
-rw-r--r-- | xlators/features/marker/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/features/marker/src/Makefile.am | 15 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-mem-types.h | 32 | ||||
-rw-r--r-- | xlators/features/marker/src/marker.c | 1420 | ||||
-rw-r--r-- | xlators/features/marker/src/marker.h | 65 |
7 files changed, 1540 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac index fedde7582cd..e8d3c07a897 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ AM_INIT_AUTOMAKE AM_CONFIG_HEADER([config.h]) AC_CONFIG_FILES([Makefile - libglusterfs/Makefile + libglusterfs/Makefile libglusterfs/src/Makefile glusterfsd/Makefile glusterfsd/src/Makefile @@ -91,6 +91,8 @@ AC_CONFIG_FILES([Makefile xlators/features/trash/src/Makefile xlators/features/quota/Makefile xlators/features/quota/src/Makefile + xlators/features/marker/Makefile + xlators/features/marker/src/Makefile xlators/features/read-only/Makefile xlators/features/read-only/src/Makefile xlators/features/mac-compat/Makefile diff --git a/xlators/features/Makefile.am b/xlators/features/Makefile.am index 8b23b939b0e..96e503938a8 100644 --- a/xlators/features/Makefile.am +++ b/xlators/features/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = locks trash quota read-only access-control mac-compat quiesce #path-converter # filter +SUBDIRS = locks trash quota read-only access-control mac-compat quiesce marker#path-converter # filter -CLEANFILES = +CLEANFILES = diff --git a/xlators/features/marker/Makefile.am b/xlators/features/marker/Makefile.am new file mode 100644 index 00000000000..a985f42a877 --- /dev/null +++ b/xlators/features/marker/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/xlators/features/marker/src/Makefile.am b/xlators/features/marker/src/Makefile.am new file mode 100644 index 00000000000..58b12b3f594 --- /dev/null +++ b/xlators/features/marker/src/Makefile.am @@ -0,0 +1,15 @@ +xlator_LTLIBRARIES = marker.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features + +marker_la_LDFLAGS = -module -avoidversion + +marker_la_SOURCES = marker.c +marker_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = marker-mem-types.h marker.h $(top_builddir)/xlators/lib/src/libxlator.h + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -fno-strict-aliasing -D$(GF_HOST_OS) \ + -I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/xlators/lib/src $(GF_CFLAGS) -shared -nostartfiles + +CLEANFILES = + diff --git a/xlators/features/marker/src/marker-mem-types.h b/xlators/features/marker/src/marker-mem-types.h new file mode 100644 index 00000000000..3936ef794fc --- /dev/null +++ b/xlators/features/marker/src/marker-mem-types.h @@ -0,0 +1,32 @@ +/* + Copyright (c) 2008-2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef __MARKER_MEM_TYPES_H__ +#define __MARKER_MEM_TYPES_H__ + +#include "mem-types.h" + +enum gf_marker_mem_types_ { + gf_marker_mt_marker_local_t = gf_common_mt_end + 1, + gf_marker_mt_marker_conf_t, + gf_marker_mt_loc_t, + gf_marker_mt_volume_mark, + gf_marker_mt_end +}; +#endif diff --git a/xlators/features/marker/src/marker.c b/xlators/features/marker/src/marker.c new file mode 100644 index 00000000000..a66b0fd03e0 --- /dev/null +++ b/xlators/features/marker/src/marker.c @@ -0,0 +1,1420 @@ +/*Copyright (c) 2008-2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "xlator.h" +#include "defaults.h" +#include "libxlator.h" +#include "marker.h" +#include "marker-mem-types.h" + +void +fini (xlator_t *this); + +int32_t +marker_start_setxattr (call_frame_t *, xlator_t *); + +int +marker_loc_fill (loc_t *loc, inode_t *inode, inode_t *parent, char *path) +{ + int ret = -1; + + if (!loc) + return ret; + + if (inode) { + loc->inode = inode_ref (inode); + loc->ino = inode->ino; + } + + if (parent) + loc->parent = inode_ref (parent); + + loc->path = gf_strdup (path); + if (!loc->path) { + gf_log ("loc fill", GF_LOG_ERROR, "strdup failed"); + goto loc_wipe; + } + + loc->name = strrchr (loc->path, '/'); + if (loc->name) + loc->name++; + else + goto loc_wipe; + + ret = 0; +loc_wipe: + if (ret < 0) + loc_wipe (loc); + + return ret; +} + +int +marker_inode_loc_fill (inode_t *inode, loc_t *loc) +{ + char *resolvedpath = NULL; + inode_t *parent = NULL; + int ret = -1; + + if ((!inode) || (!loc)) + return ret; + + if ((inode) && (inode->ino == 1)) { + loc->parent = NULL; + goto ignore_parent; + } + + parent = inode_parent (inode, 0, NULL); + if (!parent) { + goto err; + } + +ignore_parent: + ret = inode_path (inode, NULL, &resolvedpath); + if (ret < 0) + goto err; + + ret = marker_loc_fill (loc, inode, parent, resolvedpath); + if (ret < 0) + goto err; + +err: + if (parent) + inode_unref (parent); + + if (resolvedpath) + GF_FREE (resolvedpath); + + return ret; +} + +int32_t +marker_trav_parent (marker_local_t *local) +{ + int32_t ret = 0; + loc_t loc = {0, }; + + ret = marker_inode_loc_fill (local->loc.parent, &loc); + + if (ret == -1) + goto out; + + loc_wipe (&local->loc); + + local->loc = loc; +out: + return ret; +} + +int32_t +marker_error_handler (xlator_t *this) +{ + marker_conf_t *priv = NULL; + + priv = (marker_conf_t *) this->private; + + unlink (priv->timestamp_file); + + return 0; +} + +int32_t +marker_free_local (marker_local_t *local) +{ + loc_wipe (&local->loc); + + GF_FREE (local); + + return 0; +} + +int32_t +stat_stampfile (xlator_t *this, marker_conf_t *priv, struct volume_mark **status) +{ + struct stat buf; + struct volume_mark *vol_mark; + + vol_mark = GF_CALLOC (sizeof (struct volume_mark), 1, + gf_marker_mt_volume_mark); + + vol_mark->major = 1; + vol_mark->minor = 0; + + GF_ASSERT (sizeof (priv->volume_uuid_bin) == 16); + memcpy (vol_mark->uuid, priv->volume_uuid_bin, 16); + + if (stat (priv->timestamp_file, &buf) != -1) { + vol_mark->retval = 0; + vol_mark->sec = htonl (buf.st_ctime); + vol_mark->usec = htonl (ST_CTIM_NSEC (&buf)/1000); + } else + vol_mark->retval = 0; + + *status = vol_mark; + + return 0; +} + +int32_t +marker_getxattr_stampfile_cbk (call_frame_t *frame, xlator_t *this, + const char *name, struct volume_mark *vol_mark) +{ + int32_t ret; + dict_t *dict = NULL; + + if (vol_mark == NULL){ + STACK_UNWIND_STRICT (getxattr, frame, -1, ENOMEM, NULL); + + goto out; + } + + dict = dict_new (); + + ret = dict_set_bin (dict, (char *)name, vol_mark, + sizeof (struct volume_mark)); + + STACK_UNWIND_STRICT (getxattr, frame, 0, 0, dict); + + dict_unref (dict); +out: + return 0; +} + +int32_t +call_from_special_client (call_frame_t *frame, xlator_t *this, const char *name) +{ + struct volume_mark *vol_mark = NULL; + marker_conf_t *priv = NULL; + gf_boolean_t ret = _gf_true; + + priv = (marker_conf_t *)this->private; + + if (frame->root->pid != -1 || name == NULL || + strcmp (name, MARKER_XATTR_PREFIX "." VOLUME_MARK) != 0) { + ret = _gf_false; + goto out; + } + + stat_stampfile (this, priv, &vol_mark); + + marker_getxattr_stampfile_cbk (frame, this, name, vol_mark); +out: + return ret; +} + +int32_t +marker_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, dict); + return 0; +} + +int32_t +marker_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name) +{ + gf_boolean_t ret; + + gf_log (this->name, GF_LOG_DEBUG, "USER:PID = %d", frame->root->pid); + + ret = call_from_special_client (frame, this, name); + + if (ret == _gf_false) + STACK_WIND (frame, marker_getxattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->getxattr, loc, name); + + return 0; +} + + +int32_t +marker_setxattr_done (call_frame_t *frame) +{ + marker_local_t *local = NULL; + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_DESTROY (frame->root); + + marker_free_local (local); + + return 0; +} + +int +marker_specific_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + int32_t ret = 0; + int32_t done = 0; + marker_local_t *local = NULL; + + local = (marker_local_t*) frame->local; + + if (op_ret == -1 && op_errno == ENOSPC) { + marker_error_handler (this); + done = 1; + goto out; + } + + if (strcmp (local->loc.path, "/") == 0) { + done = 1; + goto out; + } + + ret = marker_trav_parent (local); + + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, "Error occured " + "while traversing to the parent, stopping marker"); + + done = 1; + + goto out; + } + + marker_start_setxattr (frame, this); + +out: + if (done) { + marker_setxattr_done (frame); + } + + return 0; +} + +int32_t +marker_start_setxattr (call_frame_t *frame, xlator_t *this) +{ + int32_t ret = 0; + dict_t *dict = NULL; + marker_local_t *local = NULL; + marker_conf_t *priv = NULL; + + priv = this->private; + + local = (marker_local_t*) frame->local; + + dict = dict_new (); + + ret = dict_set_static_bin (dict, priv->marker_xattr, + (void *)local->timebuf, 8); + + gf_log (this->name, GF_LOG_DEBUG, "path = %s", local->loc.path); + + STACK_WIND (frame, marker_specific_setxattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setxattr, &local->loc, dict, 0); + + dict_unref (dict); + + return 0; +} + +void +marker_gettimeofday (marker_local_t *local) +{ + struct timeval tv; + + gettimeofday (&tv, NULL); + + local->timebuf [0] = htonl (tv.tv_sec); + local->timebuf [1] = htonl (tv.tv_usec); + + return; +} + +int32_t +marker_create_frame (xlator_t *this, marker_local_t *local) +{ + call_frame_t *frame = NULL; + + frame = create_frame (this, this->ctx->pool); + + frame->local = (void *) local; + + marker_start_setxattr (frame, this); + + return 0; +} + +int32_t +update_marks (xlator_t *this, marker_local_t *local, int32_t ret) +{ + if (ret == -1 || local->pid < 0) + marker_free_local (local); + else { + marker_gettimeofday (local); + + marker_create_frame (this, local); + } + + return 0; +} + +int32_t +marker_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) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "error occurred " + "while Creating a file %s", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno, inode, + buf, preparent, postparent); + + update_marks (this, local, ret); + + return 0; +} + +int +marker_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dict_t *params) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_mkdir_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->mkdir, loc, mode, params); + + return 0; +err: + STACK_UNWIND_STRICT (mkdir, frame, -1, ENOMEM, NULL, + NULL, NULL, NULL); + return 0; +} + +int32_t +marker_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 *buf, struct iatt *preparent, + struct iatt *postparent) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "error occurred " + "while Creating a file %s", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (create, frame, op_ret, op_errno, fd, inode, buf, + preparent, postparent); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_create (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + mode_t mode, fd_t *fd, dict_t *params) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_create_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->create, loc, flags, mode, fd, + params); + return 0; +err: + STACK_UNWIND_STRICT (create, frame, -1, ENOMEM, NULL, NULL, NULL, NULL, NULL); + + return 0; +} + +int32_t +marker_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "error occurred " + "while write, %s", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (writev, frame, op_ret, op_errno, prebuf, postbuf); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_writev (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + struct iovec *vector, + int32_t count, + off_t offset, + struct iobref *iobref) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = marker_inode_loc_fill (fd->inode, &local->loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_writev_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->writev, fd, vector, count, offset, + iobref); + return 0; +err: + STACK_UNWIND_STRICT (writev, frame, -1, ENOMEM, NULL, NULL); + + return 0; +} + +int32_t +marker_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "error occurred " + "rmdir %s", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (rmdir, frame, op_ret, op_errno, preparent, + postparent); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_rmdir_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rmdir, loc, flags); + return 0; +err: + STACK_UNWIND_STRICT (rmdir, frame, -1, ENOMEM, NULL, NULL); + + return 0; +} + +int32_t +marker_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, + "%s occurred in unlink", strerror (op_errno)); + + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (unlink, frame, op_ret, op_errno, preparent, + postparent); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_unlink_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, loc); + return 0; +err: + STACK_UNWIND_STRICT (unlink, frame, -1, ENOMEM, NULL, NULL); + + return 0; +} + +int32_t +marker_link_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) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "linking a file ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (link, frame, op_ret, op_errno, inode, buf, + preparent, postparent); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_link (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, newloc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_link_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->link, oldloc, newloc); + return 0; +err: + STACK_UNWIND_STRICT (link, frame, -1, ENOMEM, NULL, NULL, NULL, NULL); + + return 0; +} + +int32_t +marker_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "renaming a file ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (rename, frame, op_ret, op_errno, buf, preoldparent, + postoldparent, prenewparent, postnewparent); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, + loc_t *newloc) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, newloc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_rename_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rename, oldloc, newloc); + return 0; +err: + STACK_UNWIND_STRICT (rename, frame, -1, ENOMEM, NULL, + NULL, NULL, NULL, NULL); + + return 0; +} + +int32_t +marker_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "truncating a file ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (truncate, frame, op_ret, op_errno, prebuf, + postbuf); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_truncate_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->truncate, loc, offset); + return 0; +err: + STACK_UNWIND_STRICT (truncate, frame, -1, ENOMEM, NULL, NULL); + + return 0; +} + +int32_t +marker_ftruncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "truncating a file ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (ftruncate, frame, op_ret, op_errno, prebuf, + postbuf); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_ftruncate (call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = marker_inode_loc_fill (fd->inode, &local->loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_ftruncate_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->ftruncate, fd, offset); + return 0; +err: + STACK_UNWIND_STRICT (ftruncate, frame, -1, ENOMEM, NULL, NULL); + + return 0; +} + +int32_t +marker_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) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "creating symlinks ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (symlink, frame, op_ret, op_errno, inode, buf, + preparent, postparent); + + update_marks (this, local, ret); + + return 0; +} + +int +marker_symlink (call_frame_t *frame, xlator_t *this, const char *linkpath, + loc_t *loc, dict_t *params) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_symlink_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->symlink, linkpath, loc, params); + return 0; +err: + STACK_UNWIND_STRICT (symlink, frame, -1, ENOMEM, NULL, + NULL, NULL, NULL); + return 0; +} + +int32_t +marker_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) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "creating symlinks ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (mknod, frame, op_ret, op_errno, inode, + buf, preparent, postparent); + + update_marks (this, local, ret); + + return 0; +} + +int +marker_mknod (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dev_t rdev, dict_t *parms) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_mknod_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->mknod, loc, mode, rdev, parms); + return 0; +err: + STACK_UNWIND_STRICT (mknod, frame, -1, ENOMEM, NULL, + NULL, NULL, NULL); + return 0; +} + +/* when a call from the special client is received on + * key trusted.glusterfs.volume-mark with value "RESET" + * or if the value is 0length, update the change the + * access time and modification time via touching the + * timestamp file. + */ +int32_t +call_from_sp_client_to_reset_tmfile (call_frame_t *frame, + xlator_t *this, + dict_t *dict) +{ + int32_t fd = 0; + int32_t op_ret = 0; + int32_t op_errno = 0; + data_t *data = NULL; + marker_conf_t *priv = NULL; + + if (frame == NULL || this == NULL || dict == NULL) + return -1; + + priv = this->private; + + data = dict_get (dict, "trusted.glusterfs.volume-mark"); + if (data == NULL) + return -1; + + if (frame->root->pid != -1) { + op_ret = -1; + op_errno = EPERM; + + goto out; + } + + if (data->len == 0 || (data->len == 5 && + memcmp (data->data, "RESET", 5) == 0)) { + fd = open (priv->timestamp_file, O_WRONLY); + if (fd != -1) { + /* this call is needed because of the unsurity + * whether the O_TRUNC would update the timestamps + * on a zero length file as well. Hence updating it + * manually. + */ + futimens (fd, NULL); + close (fd); + } + + if (fd != -1 || errno == ENOENT) { + op_ret = 0; + op_errno = 0; + } else { + op_ret = -1; + op_errno = errno; + } + } else { + op_ret = -1; + op_errno = EINVAL; + } +out: + STACK_UNWIND_STRICT (setxattr, frame, op_ret, op_errno); + + return 0; +} + +int32_t +marker_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "creating symlinks ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (setxattr, frame, op_ret, op_errno); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + int32_t flags) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ret = call_from_sp_client_to_reset_tmfile (frame, this, dict); + if (ret == 0) + return 0; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_setxattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setxattr, loc, dict, flags); + return 0; +err: + STACK_UNWIND_STRICT (setxattr, frame, -1, ENOMEM); + + return 0; +} + +int32_t +marker_fsetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "creating symlinks ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (fsetxattr, frame, op_ret, op_errno); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, + int32_t flags) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ret = call_from_sp_client_to_reset_tmfile (frame, this, dict); + if (ret == 0) + return 0; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = marker_inode_loc_fill (fd->inode, &local->loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_fsetxattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsetxattr, fd, dict, flags); + return 0; +err: + STACK_UNWIND_STRICT (fsetxattr, frame, -1, ENOMEM); + + return 0; +} + +int32_t +marker_fsetattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *statpre, + struct iatt *statpost) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "creating symlinks ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (fsetattr, frame, op_ret, op_errno, statpre, + statpost); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iatt *stbuf, int32_t valid) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = marker_inode_loc_fill (fd->inode, &local->loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_fsetattr_cbk, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->fsetattr, fd, stbuf, valid); + return 0; +err: + STACK_UNWIND_STRICT (fsetattr, frame, -1, ENOMEM, NULL, NULL); + + return 0; +} + +int32_t +marker_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *statpre, + struct iatt *statpost) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "creating symlinks ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (setattr, frame, op_ret, op_errno, statpre, + statpost); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_setattr_cbk, FIRST_CHILD (this), + FIRST_CHILD (this)->fops->setattr, loc, stbuf, valid); + return 0; +err: + STACK_UNWIND_STRICT (setattr, frame, -1, ENOMEM, NULL, NULL); + + return 0; +} + +int32_t +marker_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s occured while " + "creating symlinks ", strerror (op_errno)); + ret = -1; + } + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (removexattr, frame, op_ret, op_errno); + + update_marks (this, local, ret); + + return 0; +} + +int32_t +marker_removexattr (call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name) +{ + int32_t ret = 0; + marker_local_t *local = NULL; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + + if (ret == -1) + goto err; + + STACK_WIND (frame, marker_removexattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->removexattr, loc, name); + return 0; +err: + STACK_UNWIND_STRICT (removexattr, frame, -1, ENOMEM); + + return 0; +} + +int32_t +mem_acct_init (xlator_t *this) +{ + int ret = -1; + + if (!this) + return ret; + + ret = xlator_mem_acct_init (this, gf_marker_mt_end + 1); + + if (ret != 0) { + gf_log(this->name, GF_LOG_ERROR, "Memory accounting init" + "failed"); + return ret; + } + + return ret; +} + +int32_t +init (xlator_t *this) +{ + dict_t *options = NULL; + data_t *data = NULL; + int32_t ret = 0; + marker_conf_t *priv = NULL; + + if (!this->children) { + gf_log (this->name, GF_LOG_ERROR, + "marker translator needs subvolume defined."); + return -1; + } + + if (!this->parents) { + gf_log (this->name, GF_LOG_WARNING, + "Volume is dangling."); + return -1; + } + + options = this->options; + + ALLOCATE_OR_GOTO (this->private, marker_conf_t, err); + + priv = this->private; + + if( (data = dict_get (options, VOLUME_UUID)) != NULL) { + priv->volume_uuid = data->data; + + ret = uuid_parse (priv->volume_uuid, priv->volume_uuid_bin); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "invalid volume uuid %s", priv->volume_uuid); + goto err; + } + + ret = gf_asprintf (& (priv->marker_xattr), "%s.%s.%s", + MARKER_XATTR_PREFIX, priv->volume_uuid, XTIME); + + if (ret == -1){ + priv->marker_xattr = NULL; + + gf_log (this->name, GF_LOG_ERROR, + "Failed to allocate memory"); + goto err; + } + + gf_log (this->name, GF_LOG_DEBUG, + "the volume-uuid = %s", priv->volume_uuid); + } else { + priv->volume_uuid = NULL; + + gf_log (this->name, GF_LOG_ERROR, + "please specify the volume-uuid" + "in the translator options"); + + return -1; + } + + if ((data = dict_get (options, TIMESTAMP_FILE)) != NULL) { + priv->timestamp_file = data->data; + + gf_log (this->name, GF_LOG_DEBUG, + "the timestamp-file is = %s", + priv->timestamp_file); + + } else { + priv->timestamp_file = NULL; + + gf_log (this->name, GF_LOG_ERROR, + "please specify the timestamp-file" + "in the translator options"); + + goto err; + } + + return 0; +err: + fini (this); + + return -1; +} + +void +fini (xlator_t *this) +{ + marker_conf_t *priv = NULL; + + priv = (marker_conf_t *) this->private; + + if (priv == NULL) + goto out; + + if (priv->volume_uuid != NULL) + GF_FREE (priv->volume_uuid); + + if (priv->timestamp_file != NULL) + GF_FREE (priv->timestamp_file); + + if (priv->marker_xattr != NULL) + GF_FREE (priv->marker_xattr); + + GF_FREE (priv); +out: + return ; +} + +struct xlator_fops fops = { + .create = marker_create, + .unlink = marker_unlink, + .link = marker_link, + .mkdir = marker_mkdir, + .rmdir = marker_rmdir, + .writev = marker_writev, + .rename = marker_rename, + .truncate = marker_truncate, + .ftruncate = marker_ftruncate, + .symlink = marker_symlink, + .mknod = marker_mknod, + .setxattr = marker_setxattr, + .fsetxattr = marker_fsetxattr, + .setattr = marker_setattr, + .fsetattr = marker_fsetattr, + .removexattr = marker_removexattr, + .getxattr = marker_getxattr +}; + +struct xlator_cbks cbks = { +}; + +struct volume_options options[] = { + {.key = {"volume-uuid"}}, + {.key = {"timestamp-file"}}, + {.key = {NULL}} +}; diff --git a/xlators/features/marker/src/marker.h b/xlators/features/marker/src/marker.h new file mode 100644 index 00000000000..60567c3b828 --- /dev/null +++ b/xlators/features/marker/src/marker.h @@ -0,0 +1,65 @@ +/*Copyright (c) 2008-2010 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "xlator.h" +#include "defaults.h" +#include "uuid.h" + +#define MARKER_XATTR_PREFIX "trusted.glusterfs" +#define XTIME "xtime" +#define VOLUME_MARK "volume-mark" +#define VOLUME_UUID "volume-uuid" +#define TIMESTAMP_FILE "timestamp-file" + +/*initialize the local variable*/ +#define MARKER_INIT_LOCAL(_frame,_local) do { \ + _frame->local = _local; \ + _local->pid = _frame->root->pid; \ + memset (&_local->loc, 0, sizeof (loc_t)); \ + } while (0) + +/* try alloc and if it fails, goto label */ +#define ALLOCATE_OR_GOTO(var, type, label) do { \ + var = GF_CALLOC (sizeof (type), 1, \ + gf_marker_mt_##type); \ + if (!var) { \ + gf_log (this->name, GF_LOG_ERROR, \ + "out of memory :("); \ + goto label; \ + } \ + } while (0) + +struct marker_local{ + uint32_t timebuf[2]; + pid_t pid; + loc_t loc; +}; +typedef struct marker_local marker_local_t; + +struct marker_conf{ + char *volume_uuid; + uuid_t volume_uuid_bin; + char *timestamp_file; + char *marker_xattr; +}; +typedef struct marker_conf marker_conf_t; |