diff options
author | Mohammed Junaid Ahmed <junaid@gluster.com> | 2011-03-15 22:25:55 +0000 |
---|---|---|
committer | Vijay Bellur <vijay@dev.gluster.com> | 2011-03-16 00:32:11 -0700 |
commit | 4db0bc5977eb3e2d5bc0e3666bb6de5719d153a4 (patch) | |
tree | 6a1877fb9d143db23cb0b58391e430c3cc28a0e8 /xlators/features | |
parent | fa4e997970fb0e1d0abaae742a35701bcb576150 (diff) |
features/marker: QUOTA related changes in marker translator.
Signed-off-by: Junaid <junaid@gluster.com>
Signed-off-by: Vijay Bellur <vijay@dev.gluster.com>
BUG: 2473 (Support for volume and directory level quota)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=2473
Diffstat (limited to 'xlators/features')
-rw-r--r-- | xlators/features/marker/src/Makefile.am | 4 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-common.c | 70 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-common.h | 33 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-mem-types.h | 5 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-quota-helper.c | 366 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-quota-helper.h | 76 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-quota.c | 1815 | ||||
-rw-r--r-- | xlators/features/marker/src/marker-quota.h | 167 | ||||
-rw-r--r-- | xlators/features/marker/src/marker.c | 517 | ||||
-rw-r--r-- | xlators/features/marker/src/marker.h | 24 |
10 files changed, 2986 insertions, 91 deletions
diff --git a/xlators/features/marker/src/Makefile.am b/xlators/features/marker/src/Makefile.am index 58b12b3f594..501586a76b6 100644 --- a/xlators/features/marker/src/Makefile.am +++ b/xlators/features/marker/src/Makefile.am @@ -3,10 +3,10 @@ xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features marker_la_LDFLAGS = -module -avoidversion -marker_la_SOURCES = marker.c +marker_la_SOURCES = marker.c marker-quota.c marker-quota-helper.c marker-common.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 +noinst_HEADERS = marker-mem-types.h marker.h marker-quota.h marker-quota-helper.h marker-common.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 diff --git a/xlators/features/marker/src/marker-common.c b/xlators/features/marker/src/marker-common.c new file mode 100644 index 00000000000..3e2d7f00047 --- /dev/null +++ b/xlators/features/marker/src/marker-common.c @@ -0,0 +1,70 @@ +/*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 "marker-common.h" + +marker_inode_ctx_t * +marker_inode_ctx_new () +{ + marker_inode_ctx_t *ctx = NULL; + + ctx = GF_CALLOC (1, sizeof (marker_inode_ctx_t), + gf_marker_mt_marker_inode_ctx_t); + if (ctx == NULL) + goto out; + + ctx->quota_ctx = NULL; +out: + return ctx; +} + +int32_t +marker_force_inode_ctx_get (inode_t *inode, xlator_t *this, + marker_inode_ctx_t **ctx) +{ + int32_t ret = -1; + uint64_t ctx_int; + + LOCK (&inode->lock); + { + ret = __inode_ctx_get (inode, this, &ctx_int); + if (ret == 0) + *ctx = (marker_inode_ctx_t *) ctx_int; + else { + *ctx = marker_inode_ctx_new (); + if (*ctx == NULL) + goto unlock; + + ret = __inode_ctx_put (inode, this, (uint64_t ) *ctx); + if (ret == -1) { + GF_FREE (*ctx); + goto unlock; + } + ret = 0; + } + } +unlock: UNLOCK (&inode->lock); + + return ret; +} + diff --git a/xlators/features/marker/src/marker-common.h b/xlators/features/marker/src/marker-common.h new file mode 100644 index 00000000000..311e4e23832 --- /dev/null +++ b/xlators/features/marker/src/marker-common.h @@ -0,0 +1,33 @@ +/*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 _MARKER_COMMON_H +#define _MARKER_COMMON_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "inode.h" +#include "xlator.h" +#include "marker.h" + +int32_t +marker_force_inode_ctx_get (inode_t *, xlator_t *, marker_inode_ctx_t **); +#endif diff --git a/xlators/features/marker/src/marker-mem-types.h b/xlators/features/marker/src/marker-mem-types.h index 3936ef794fc..847bfa67c05 100644 --- a/xlators/features/marker/src/marker-mem-types.h +++ b/xlators/features/marker/src/marker-mem-types.h @@ -27,6 +27,11 @@ enum gf_marker_mem_types_ { gf_marker_mt_marker_conf_t, gf_marker_mt_loc_t, gf_marker_mt_volume_mark, + gf_marker_mt_int64_t, + gf_marker_mt_quota_inode_ctx_t, + gf_marker_mt_marker_inode_ctx_t, + gf_marker_mt_quota_local_t, + gf_marker_mt_inode_contribution_t, gf_marker_mt_end }; #endif diff --git a/xlators/features/marker/src/marker-quota-helper.c b/xlators/features/marker/src/marker-quota-helper.c new file mode 100644 index 00000000000..b6a87698eed --- /dev/null +++ b/xlators/features/marker/src/marker-quota-helper.c @@ -0,0 +1,366 @@ +/*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 "locking.h" +#include "marker-quota.h" +#include "marker-common.h" +#include "marker-quota-helper.h" +#include "marker-mem-types.h" + +int +quota_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; +} + + +int32_t +quota_inode_loc_fill (const char *parent_gfid, 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; + } + + if (parent_gfid == NULL) + parent = inode_parent (inode, 0, NULL); + else + parent = inode_find (inode->table, + (unsigned char *) parent_gfid); + + if (parent == NULL) + goto err; + +ignore_parent: + ret = inode_path (inode, NULL, &resolvedpath); + if (ret < 0) + goto err; + + ret = quota_loc_fill (loc, inode, parent, resolvedpath); + if (ret < 0) + goto err; + +err: + if (parent) + inode_unref (parent); + + GF_FREE (resolvedpath); + + return ret; +} + + +quota_inode_ctx_t * +quota_alloc_inode_ctx () +{ + int32_t ret = -1; + quota_inode_ctx_t *ctx = NULL; + + QUOTA_ALLOC (ctx, quota_inode_ctx_t, ret); + if (ret == -1) + goto out; + + ctx->size = 0; + ctx->dirty = 0; + LOCK_INIT (&ctx->lock); + INIT_LIST_HEAD (&ctx->contribution_head); +out: + return ctx; +} + +inode_contribution_t * +get_contribution_node (inode_t *inode, quota_inode_ctx_t *ctx) +{ + inode_contribution_t *contri = NULL; + inode_contribution_t *temp = NULL; + + GF_VALIDATE_OR_GOTO ("marker", inode, out); + GF_VALIDATE_OR_GOTO ("marker", ctx, out); + + list_for_each_entry (temp, &ctx->contribution_head, contri_list) { + if (uuid_compare (temp->gfid, inode->gfid) == 0) { + contri = temp; + goto out; + } + } +out: + return contri; +} + + +int32_t +delete_contribution_node (dict_t *dict, char *key, + inode_contribution_t *contribution) +{ + if (dict_get (dict, key) != NULL) + goto out; + + QUOTA_FREE_CONTRIBUTION_NODE (contribution); +out: + return 0; +} + + +inode_contribution_t * +__add_new_contribution_node (xlator_t *this, quota_inode_ctx_t *ctx, loc_t *loc) +{ + int32_t ret = 0; + inode_contribution_t *contribution = NULL; + + list_for_each_entry (contribution, &ctx->contribution_head, contri_list) { + if (uuid_compare (contribution->gfid, loc->parent->gfid) == 0) { + goto out; + } + } + + QUOTA_ALLOC (contribution, inode_contribution_t, ret); + if (ret == -1) + goto out; + + contribution->contribution = 0; + + uuid_copy (contribution->gfid, loc->parent->gfid); + + list_add_tail (&contribution->contri_list, &ctx->contribution_head); + +out: + return contribution; +} + + +inode_contribution_t * +add_new_contribution_node (xlator_t *this, quota_inode_ctx_t *ctx, loc_t *loc) +{ + inode_contribution_t *contribution = NULL; + + if (ctx == NULL || loc == NULL) + return NULL; + + if (strcmp (loc->path, "/") == 0) + return NULL; + + LOCK (&ctx->lock); + { + contribution = __add_new_contribution_node (this, ctx, loc); + } + UNLOCK (&ctx->lock); + + return contribution; +} + + +int32_t +dict_set_contribution (xlator_t *this, dict_t *dict, + loc_t *loc) +{ + int32_t ret = -1; + char contri_key [512] = {0, }; + + GET_CONTRI_KEY (contri_key, loc->parent->gfid, ret); + if (ret < 0) { + ret = -1; + goto out; + } + + ret = dict_set_int64 (dict, contri_key, 0); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "unable to set dict value."); + goto out; + } + + ret = 0; +out: + return ret; +} + + +int32_t +quota_inode_ctx_get (inode_t *inode, xlator_t *this, + quota_inode_ctx_t **ctx) +{ + int32_t ret = -1; + uint64_t ctx_int = 0; + marker_inode_ctx_t *mark_ctx = NULL; + + GF_VALIDATE_OR_GOTO ("marker", inode, out); + GF_VALIDATE_OR_GOTO ("marker", this, out); + GF_VALIDATE_OR_GOTO ("marker", ctx, out); + + ret = inode_ctx_get (inode, this, &ctx_int); + if (ret < 0) { + ret = -1; + *ctx = NULL; + goto out; + } + + mark_ctx = (marker_inode_ctx_t *) ctx_int; + if (mark_ctx->quota_ctx == NULL) { + ret = -1; + goto out; + } + + *ctx = mark_ctx->quota_ctx; + + ret = 0; + +out: + return ret; +} + + +quota_inode_ctx_t * +__quota_inode_ctx_new (inode_t *inode, xlator_t *this) +{ + int32_t ret = -1; + quota_inode_ctx_t *quota_ctx = NULL; + marker_inode_ctx_t *mark_ctx = NULL; + + ret = marker_force_inode_ctx_get (inode, this, &mark_ctx); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "marker_force_inode_ctx_get() failed"); + goto out; + } + + LOCK (&inode->lock); + { + if (mark_ctx->quota_ctx == NULL) { + quota_ctx = quota_alloc_inode_ctx (); + if (quota_ctx == NULL) { + ret = -1; + goto unlock; + } + mark_ctx->quota_ctx = quota_ctx; + } else + quota_ctx = mark_ctx->quota_ctx; + + ret = 0; + } +unlock: UNLOCK (&inode->lock); + +out: + return quota_ctx; +} + + +quota_inode_ctx_t * +quota_inode_ctx_new (inode_t * inode, xlator_t *this) +{ + return __quota_inode_ctx_new (inode, this); +} + +quota_local_t * +quota_local_new () +{ + int32_t ret = -1; + quota_local_t *local = NULL; + + QUOTA_ALLOC (local, quota_local_t, ret); + if (ret < 0) + goto out; + + local->ref = 1; + local->delta = 0; + local->err = 0; + LOCK_INIT (&local->lock); + + memset (&local->loc, 0, sizeof (loc_t)); + memset (&local->parent_loc, 0, sizeof (loc_t)); + + local->ctx = NULL; + local->contri = NULL; + +out: + return local; +} + +quota_local_t * +quota_local_ref (quota_local_t *local) +{ + LOCK (&local->lock); + { + local->ref ++; + } + UNLOCK (&local->lock); + + return local; +} + + +int32_t +quota_local_unref (xlator_t *this, quota_local_t *local) +{ + if (local == NULL) + goto out; + + QUOTA_SAFE_DECREMENT (&local->lock, local->ref); + + if (local->ref > 0) + goto out; + + loc_wipe (&local->loc); + + loc_wipe (&local->parent_loc); + + LOCK_DESTROY (&local->lock); +out: + return 0; +} diff --git a/xlators/features/marker/src/marker-quota-helper.h b/xlators/features/marker/src/marker-quota-helper.h new file mode 100644 index 00000000000..9a24c8c3d94 --- /dev/null +++ b/xlators/features/marker/src/marker-quota-helper.h @@ -0,0 +1,76 @@ +/*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 _MARKER_QUOTA_HELPER_H +#define _MARKER_QUOTA_HELPER + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif +#include "marker-quota.h" + +#define QUOTA_FREE_CONTRIBUTION_NODE(_contribution) \ + do { \ + list_del (&_contribution->contri_list); \ + GF_FREE (_contribution); \ + } while (0) + +#define QUOTA_SAFE_INCREMENT(lock, var) \ + do { \ + LOCK (lock); \ + var ++; \ + UNLOCK (lock); \ + } while (0) + +#define QUOTA_SAFE_DECREMENT(lock, var) \ + do { \ + LOCK (lock); \ + var --; \ + UNLOCK (lock); \ + } while (0) + +inode_contribution_t * +add_new_contribution_node (xlator_t *, quota_inode_ctx_t *, loc_t *); + +int32_t +dict_set_contribution (xlator_t *, dict_t *, loc_t *); + +quota_inode_ctx_t * +quota_inode_ctx_new (inode_t *, xlator_t *); + +int32_t +quota_inode_ctx_get (inode_t *, xlator_t *, quota_inode_ctx_t **); + +int32_t +delete_contribution_node (dict_t *, char *, inode_contribution_t *); + +int32_t +quota_inode_loc_fill (const char *, inode_t *, loc_t *); + +quota_local_t * +quota_local_new (); + +quota_local_t * +quota_local_ref (quota_local_t *); + +int32_t +quota_local_unref (xlator_t *, quota_local_t *); + +inode_contribution_t * +get_contribution_node (inode_t *, quota_inode_ctx_t *); +#endif diff --git a/xlators/features/marker/src/marker-quota.c b/xlators/features/marker/src/marker-quota.c new file mode 100644 index 00000000000..f7b397a5a84 --- /dev/null +++ b/xlators/features/marker/src/marker-quota.c @@ -0,0 +1,1815 @@ +/*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 "dict.h" +#include "xlator.h" +#include "defaults.h" +#include "libxlator.h" +#include "common-utils.h" +#include "byte-order.h" +#include "marker-quota.h" +#include "marker-quota-helper.h" + +int32_t +loc_fill_from_name (xlator_t *this, loc_t *newloc, loc_t *oldloc, uint64_t ino, char *name) +{ + int32_t ret = 0; + int32_t len = 0; + char *path = NULL; + + + newloc->ino = ino; + + newloc->inode = inode_new (oldloc->inode->table); + + if (!newloc->inode) { + ret = -1; + goto out; + } + + newloc->parent = inode_ref (oldloc->inode); + + len = strlen (oldloc->path); + + if (oldloc->path [len - 1] == '/') + ret = gf_asprintf ((char **) &path, "%s%s", + oldloc->path, name); + else + ret = gf_asprintf ((char **) &path, "%s/%s", + oldloc->path, name); + + if (ret < 0) + goto out; + + newloc->path = path; + + newloc->name = strrchr (newloc->path, '/'); + + if (newloc->name) + newloc->name++; + + gf_log (this->name, GF_LOG_INFO, "path = %s name =%s",newloc->path, newloc->name); +out: + return ret; +} + +int32_t +dirty_inode_updation_done (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + quota_local_t *local = NULL; + + local = frame->local; + + if (!local->err) + QUOTA_SAFE_DECREMENT (&local->lock, local->ref); + else + frame->local = NULL; + + QUOTA_STACK_DESTROY (frame, this); + + return 0; +} + +int32_t +release_lock_on_dirty_inode (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + struct gf_flock lock; + quota_local_t *local = NULL; + + if (op_ret == -1) { + local->err = -1; + + dirty_inode_updation_done (frame, NULL, this, 0, 0); + + return 0; + } + + local = frame->local; + + if (op_ret == 0) + local->ctx->dirty = 0; + + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = 0; + + STACK_WIND (frame, + dirty_inode_updation_done, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->inodelk, + this->name, &local->loc, F_SETLKW, &lock); + + return 0; +} + +int32_t +mark_inode_undirty (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + int32_t ret = -1; + int64_t *size = NULL; + dict_t *newdict = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + + if (op_ret == -1) + goto err; + + priv = (marker_conf_t *) this->private; + + local = (quota_local_t *) frame->local; + + if (!dict) + goto wind; + + ret = dict_get_bin (dict, priv->size_key, (void **) &size); + if (ret) + goto wind; + + local->ctx->size = ntoh64 (*size); + +wind: + newdict = dict_new (); + if (!newdict) + goto err; + + ret = dict_set_int8 (newdict, priv->dirty_key, 0); + if (ret) + goto err; + + STACK_WIND (frame, release_lock_on_dirty_inode, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setxattr, + &local->loc, newdict, 0); + ret = 0; + +err: + if (op_ret == -1 || ret == -1) { + local->err = -1; + + release_lock_on_dirty_inode (frame, NULL, this, 0, 0); + } + + if (newdict) + dict_unref (newdict); + + return 0; +} + +int32_t +update_size_xattr (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 *dict, struct iatt *postparent) +{ + int32_t ret = -1; + dict_t *new_dict = NULL; + int64_t *size = NULL; + int64_t *delta = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + + if (op_ret == -1) + goto err; + + priv = this->private; + + if (!dict) + goto err; + + local = frame->local; + + ret = dict_get_bin (dict, priv->size_key, (void **) &size); + if (!size) + goto err; + + QUOTA_ALLOC_OR_GOTO (delta, int64_t, ret, err); + + *delta = ntoh64 (ntoh64 (*size) - local->sum); + + gf_log (this->name, GF_LOG_DEBUG, "calculated size = %ld, original size = %ld" + "path = %s diff = %ld", local->sum, ntoh64 (*size), + local->loc.path, ntoh64 (*delta)); + + new_dict = dict_new (); + if (!new_dict); + + ret = dict_set_bin (new_dict, priv->size_key, delta, 8); + if (ret) + goto err; + + STACK_WIND (frame, mark_inode_undirty, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->xattrop, &local->loc, + GF_XATTROP_ADD_ARRAY64, new_dict); + + ret = 0; + +err: + if (op_ret == -1 || ret == -1) { + local->err = -1; + + release_lock_on_dirty_inode (frame, NULL, this, 0, 0); + } + + if (new_dict) + dict_unref (dict); + + return 0; +} + +int32_t +get_dirty_inode_size (call_frame_t *frame, xlator_t *this) +{ + int32_t ret = -1; + dict_t *dict = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + + local = (quota_local_t *) frame->local; + + priv = (marker_conf_t *) this->private; + + dict = dict_new (); + if (!dict) { + ret = -1; + goto err; + } + + ret = dict_set_int64 (dict, priv->size_key, 0); + if (ret) + goto err; + + STACK_WIND (frame, update_size_xattr, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->lookup, &local->loc, dict); + ret =0; + +err: + if (ret) { + local->err = -1; + + release_lock_on_dirty_inode (frame, NULL, this, 0, 0); + } + + return 0; +} + +int32_t +get_child_contribution (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 *dict, + struct iatt *postparent) +{ + int32_t ret = -1; + char contri_key [512] = {0, }; + int64_t *contri = NULL; + quota_local_t *local = NULL; + + local = frame->local; + + frame->local = NULL; + + QUOTA_STACK_DESTROY (frame, this); + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s", strerror (op_errno)); + + local->err = -2; + + release_lock_on_dirty_inode (local->frame, NULL, this, 0, 0); + + goto out; + } + + if (local->err) + goto out; + + GET_CONTRI_KEY (contri_key, local->loc.inode->gfid, ret); + if (ret < 0) + goto out; + + if (!dict) + goto out; + + if (dict_get_bin (dict, contri_key, (void **) &contri) == 0) + local->sum += ntoh64 (*contri); + +out: + LOCK (&local->lock); + { + local->dentry_child_count--; + } + UNLOCK (&local->lock); + + if (local->dentry_child_count == 0) { + if (local->err) { + QUOTA_SAFE_DECREMENT (&local->lock, local->ref); + + quota_local_unref (this, local); + } else + quota_dirty_inode_readdir (local->frame, NULL, this, + 0, 0, NULL); + } + + return 0; +} + +int32_t +quota_readdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + gf_dirent_t *entries) +{ + char contri_key [512] = {0, }; + loc_t loc; + int32_t ret = 0; + off_t offset = 0; + int32_t count = 0; + dict_t *dict = NULL; + quota_local_t *local = NULL; + gf_dirent_t *entry = NULL; + call_frame_t *newframe = NULL; + + local = frame->local; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, + "readdir failed %s", strerror (op_errno)); + local->err = -1; + + release_lock_on_dirty_inode (frame, NULL, this, 0, 0); + + return 0; + } else if (op_ret == 0) { + get_dirty_inode_size (frame, this); + + return 0; + } + + local->dentry_child_count = 0; + + list_for_each_entry (entry, (&entries->list), list) { + gf_log (this->name, GF_LOG_INFO, "entry = %s", entry->d_name); + + if ((!strcmp (entry->d_name, ".")) || (!strcmp (entry->d_name, ".."))) { + gf_log (this->name, GF_LOG_INFO, "entry = %s", entry->d_name); + continue; + } + count++; + } + + local->frame = frame; + + list_for_each_entry (entry, (&entries->list), list) { + gf_log (this->name, GF_LOG_INFO, "entry = %s", entry->d_name); + + if ((!strcmp (entry->d_name, ".")) || (!strcmp (entry->d_name, ".."))) { + gf_log (this->name, GF_LOG_INFO, "entry = %s", entry->d_name); + offset = entry->d_off; + continue; + } + + ret = loc_fill_from_name (this, &loc, &local->loc, + entry->d_ino, entry->d_name); + if (ret < 0) + goto out; + + newframe = copy_frame (frame); + if (!newframe) { + ret = -1; + goto out; + } + + newframe->local = local; + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + GET_CONTRI_KEY (contri_key, local->loc.inode->gfid, ret); + if (ret < 0) + goto out; + + ret = dict_set_int64 (dict, contri_key, 0); + if (ret) + goto out; + + QUOTA_SAFE_INCREMENT (&local->lock, local->dentry_child_count); + + STACK_WIND (newframe, + get_child_contribution, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->lookup, + &loc, dict); + + offset = entry->d_off; + + loc_wipe (&loc); + + out: + if (dict) { + dict_unref (dict); + dict = NULL; + } + + if (ret) { + LOCK (&local->lock); + { + if (local->dentry_child_count == 0) + local->err = -1; + else + local->err = -2; + } + UNLOCK (&local->lock); + + if (newframe) { + newframe->local = NULL; + + QUOTA_STACK_DESTROY (newframe, this); + } + + break; + } + } + gf_log (this->name, GF_LOG_INFO, "offset before =%lu",local->d_off); + local->d_off +=offset; + gf_log (this->name, GF_LOG_INFO, "offset after = %lu",local->d_off); + + if (ret) + release_lock_on_dirty_inode (frame, NULL, this, 0, 0); + + else if (count == 0 ) + get_dirty_inode_size (frame, this); + + return 0; +} + +int32_t +quota_dirty_inode_readdir (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd) +{ + quota_local_t *local = NULL; + + if (op_ret == -1) { + local->err = -1; + release_lock_on_dirty_inode (frame, NULL, this, 0, 0); + return 0; + } + + local = frame->local; + + if (local->fd == NULL) + local->fd = fd_ref (fd); + + STACK_WIND (frame, + quota_readdir_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->readdir, + local->fd, READDIR_BUF, local->d_off); + + return 0; +} + +int32_t +check_if_still_dirty (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 *dict, + struct iatt *postparent) +{ + int8_t dirty = -1; + int32_t ret = -1; + fd_t *fd = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + + local = frame->local; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "failed to get " + "the dirty xattr for %s", local->loc.path); + goto err; + } + + priv = this->private; + + if (!dict) { + ret = -1; + goto err; + } + + ret = dict_get_int8 (dict, priv->dirty_key, &dirty); + if (ret) + goto err; + + //the inode is not dirty anymore + if (dirty == 0) { + release_lock_on_dirty_inode (frame, NULL, this, 0, 0); + + return 0; + } + + fd = fd_create (local->loc.inode, frame->root->pid); + + local->d_off = 0; + + STACK_WIND(frame, + quota_dirty_inode_readdir, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->opendir, + &local->loc, fd); + + ret = 0; + +err: + if (op_ret == -1 || ret == -1) { + local->err = -1; + release_lock_on_dirty_inode (frame, NULL, this, 0, 0); + } + + return 0; +} + +int32_t +get_dirty_xattr (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno) +{ + int32_t ret = -1; + dict_t *xattr_req = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + + if (op_ret == -1) { + dirty_inode_updation_done (frame, NULL, this, 0, 0); + return 0; + } + + priv = (marker_conf_t *) this->private; + + local = frame->local; + + xattr_req = dict_new (); + if (xattr_req == NULL) { + ret = -1; + goto err; + } + + ret = dict_set_int8 (xattr_req, priv->dirty_key, 0); + if (ret) + goto err; + + STACK_WIND (frame, + check_if_still_dirty, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->lookup, + &local->loc, + xattr_req); + ret = 0; + +err: + if (ret) { + local->err = -1; + release_lock_on_dirty_inode(frame, NULL, this, 0, 0); + } + + if (xattr_req) + dict_unref (xattr_req); + + return 0; +} + +int32_t +update_dirty_inode (xlator_t *this, + loc_t *loc, + quota_inode_ctx_t *ctx, + inode_contribution_t *contribution) +{ + int32_t ret = -1; + quota_local_t *local = NULL; + struct gf_flock lock; + call_frame_t *frame = NULL; + + frame = create_frame (this, this->ctx->pool); + if (frame == NULL) { + ret = -1; + goto out; + } + + local = quota_local_new (); + if (local == NULL) + goto fr_destroy; + + frame->local = local; + + ret = loc_copy (&local->loc, loc); + if (ret < 0) + goto fr_destroy; + + local->ctx = ctx; + + local->contri = contribution; + + frame->root->lk_owner = cn++; + + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + STACK_WIND (frame, + get_dirty_xattr, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->inodelk, + this->name, &local->loc, F_SETLKW, &lock); + +fr_destroy: + QUOTA_STACK_DESTROY (frame, this); +out: + + return 0; +} + + +int32_t +quota_inode_creation_done (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + quota_local_t *local = NULL; + + if (frame == NULL) + return 0; + + local = frame->local; + + QUOTA_STACK_DESTROY (frame, this); + + return 0; +} + +int32_t +create_dirty_xattr (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + int32_t ret = -1; + dict_t *newdict = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + + if (op_ret == -1 && op_errno == ENOTCONN) + goto err; + + local = frame->local; + + priv = (marker_conf_t *) this->private; + + if (local->loc.inode->ia_type == IA_IFDIR) { + newdict = dict_new (); + if (!newdict) + goto err; + + ret = dict_set_int8 (newdict, priv->dirty_key, 0); + if (ret == -1) + goto err; + + STACK_WIND (frame, quota_inode_creation_done, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setxattr, + &local->loc, newdict, 0); + } else + quota_inode_creation_done (frame, NULL, this, 0, 0); + + ret = 0; + +err: + if (ret == -1) + quota_inode_creation_done (frame, NULL, this, -1, 0); + + if (newdict) + dict_unref (newdict); + + return 0; +} + + +int32_t +quota_set_inode_xattr (xlator_t *this, loc_t *loc) +{ + int32_t ret = 0; + int64_t *value = NULL; + int64_t *size = NULL; + dict_t *dict = NULL; + char key[512] = {0, }; + call_frame_t *frame = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + quota_inode_ctx_t *ctx = NULL; + inode_contribution_t *contri = NULL; + + if (loc == NULL || this == NULL) + return 0; + + priv = (marker_conf_t *) this->private; + + ret = quota_inode_ctx_get (loc->inode, this, &ctx); + if (ret < 0) { + ctx = quota_inode_ctx_new (loc->inode, this); + if (ctx == NULL) { + gf_log (this->name, GF_LOG_WARNING, + "quota_inode_ctx_new failed"); + ret = -1; + goto out; + } + } + + dict = dict_new (); + if (!dict) + goto out; + + if (loc->inode->ia_type == IA_IFDIR) { + QUOTA_ALLOC_OR_GOTO (size, int64_t, ret, err); + ret = dict_set_bin (dict, priv->size_key, size, 8); + if (ret < 0) + goto free_size; + } + + //if '/' then dont set contribution xattr + if (strcmp (loc->path, "/") == 0) + goto wind; + + contri = add_new_contribution_node (this, ctx, loc); + if (contri == NULL) + goto err; + + QUOTA_ALLOC_OR_GOTO (value, int64_t, ret, err); + GET_CONTRI_KEY (key, loc->parent->gfid, ret); + + ret = dict_set_bin (dict, key, value, 8); + if (ret < 0) + goto free_value; + +wind: + frame = create_frame (this, this->ctx->pool); + if (!frame) { + ret = -1; + goto err; + } + + local = quota_local_new (); + if (local == NULL) + goto free_size; + + local->ctx = ctx; + + local->contri = contri; + + ret = loc_copy (&local->loc, loc); + if (ret < 0) + quota_local_unref (this, local); + + frame->local = local; + + STACK_WIND (frame, create_dirty_xattr, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->xattrop, &local->loc, + GF_XATTROP_ADD_ARRAY64, dict); + ret = 0; + +free_size: + if (ret < 0) + GF_FREE (size); + +free_value: + if (ret < 0) + GF_FREE (value); + +err: + dict_unref (dict); + +out: + if (ret < 0) + quota_inode_creation_done (NULL, NULL, this, -1, 0); + + return 0; +} + + +int32_t +get_parent_inode_local (xlator_t *this, quota_local_t *local) +{ + uint32_t ret; + quota_inode_ctx_t *ctx = NULL; + + loc_wipe (&local->loc); + + loc_copy (&local->loc, &local->parent_loc); + + loc_wipe (&local->parent_loc); + + quota_inode_loc_fill (NULL, local->loc.parent, &local->parent_loc); + + ret = quota_inode_ctx_get (local->loc.inode, this, &ctx); + if (ret < 0) + return -1; + + local->ctx = ctx; + + local->contri = (inode_contribution_t *) ctx->contribution_head.next; + + return 0; +} + + +int32_t +xattr_updation_done (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *dict) +{ + QUOTA_STACK_DESTROY (frame, this); + return 0; +} + + +int32_t +quota_inodelk_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno) +{ + int32_t ret = 0; + quota_local_t *local = NULL; + + trap (); + + local = frame->local; + + if (op_ret == -1 || local->err) { + gf_log (this->name, GF_LOG_INFO, "lock setting failed"); + xattr_updation_done (frame, NULL, this, 0, 0, NULL); + + return 0; + } + + gf_log (this->name, GF_LOG_DEBUG, + "inodelk released on %s", local->parent_loc.path); + + if (strcmp (local->parent_loc.path, "/") == 0) { + xattr_updation_done (frame, NULL, this, 0, 0, NULL); + } else { + ret = get_parent_inode_local (this, local); + if (ret < 0) { + xattr_updation_done (frame, NULL, this, 0, 0, NULL); + goto out; + } + + get_lock_on_parent (frame, this); + } +out: + return 0; +} + + +//now release lock on the parent inode +int32_t +quota_release_parent_lock (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno) +{ + int32_t ret = 0; + struct gf_flock lock; + quota_local_t *local = NULL; + quota_inode_ctx_t *ctx = NULL; + + trap (); + + local = frame->local; + + ret = quota_inode_ctx_get (local->parent_loc.inode, this, &ctx); + if (ret < 0) + goto wind; + + LOCK (&ctx->lock); + { + ctx->dirty = 0; + } + UNLOCK (&ctx->lock); + +wind: + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = 0; + + STACK_WIND (frame, + quota_inodelk_cbk, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->inodelk, + this->name, &local->parent_loc, + F_SETLKW, &lock); + + return 0; +} + + +int32_t +quota_mark_undirty (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *dict) +{ + int32_t ret = -1; + int64_t *size = NULL; + dict_t *newdict = NULL; + quota_local_t *local = NULL; + quota_inode_ctx_t *ctx = NULL; + marker_conf_t *priv = NULL; + + trap (); + + local = frame->local; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_WARNING, "%s occurred while" + " updating the size of %s", strerror (op_errno), + local->parent_loc.path); + + goto err; + } + + priv = this->private; + + //update the size of the parent inode + if (dict != NULL) { + ret = quota_inode_ctx_get (local->parent_loc.inode, this, &ctx); + if (ret < 0) + goto err; + + ret = dict_get_bin (dict, priv->size_key, (void **) &size); + if (ret < 0) + goto err; + + LOCK (&ctx->lock); + { + if (size) + ctx->size = ntoh64 (*size); + } + UNLOCK (&ctx->lock); + } + + newdict = dict_new (); + + if (!newdict) + goto err; + + ret = dict_set_int8 (newdict, priv->dirty_key, 0); + + if (ret == -1) + goto err; + + STACK_WIND (frame, quota_release_parent_lock, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setxattr, + &local->parent_loc, newdict, 0); + + ret = 0; +err: + if (op_ret == -1 || ret == -1) { + local->err = 1; + + quota_release_parent_lock (frame, NULL, this, 0, 0); + } + + if (newdict) + dict_unref (newdict); + + return 0; +} + + +int32_t +quota_update_parent_size (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *dict) +{ + int64_t *size = NULL; + int32_t ret = -1; + dict_t *newdict = NULL; + marker_conf_t *priv = NULL; + quota_local_t *local = NULL; + quota_inode_ctx_t *ctx = NULL; + + trap (); + + local = frame->local; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "%s", strerror (op_errno)); + + goto err; + } + + priv = this->private; + + if (dict == NULL) + goto err; + + ret = quota_inode_ctx_get (local->parent_loc.inode, this, &ctx); + if (ret < 0) + goto err; + + newdict = dict_new (); + if (!newdict) { + ret = -1; + goto err; + } + + QUOTA_ALLOC_OR_GOTO (size, int64_t, ret, err); + + *size = ntoh64 (local->delta); + + ret = dict_set_bin (newdict, priv->size_key, size, 8); + if (ret < 0) + goto err; + + STACK_WIND (frame, + quota_mark_undirty, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->xattrop, + &local->parent_loc, + GF_XATTROP_ADD_ARRAY64, + newdict); + ret = 0; +err: + if (op_ret == -1 || ret < 0) { + local->err = 1; + quota_release_parent_lock (frame, NULL, this, 0, 0); + } + + if (dict) + dict_unref (newdict); + + return 0; +} + +int32_t +quota_update_inode_contribution (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 *dict, + struct iatt *postparent) +{ + int32_t ret = -1; + int64_t *size = NULL; + int64_t *contri = NULL; + int64_t *delta = NULL; + char contri_key [512] = {0, }; + dict_t *newdict = NULL; + quota_local_t *local = NULL; + quota_inode_ctx_t *ctx = NULL; + marker_conf_t *priv = NULL; + inode_contribution_t *contribution = NULL; + + trap (); + + local = frame->local; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "failed to get size and " + "contribution with %s error", strerror (op_errno)); + goto err; + } + + priv = this->private; + + ctx = local->ctx; + contribution = local->contri; + + //prepare to update size & contribution of the inode + GET_CONTRI_KEY (contri_key, contribution->gfid, ret); + if (ret == -1) + goto err; + + LOCK (&ctx->lock); + { + if (local->loc.inode->ia_type == IA_IFDIR ) { + ret = dict_get_bin (dict, priv->size_key, + (void **) &size); + if (ret < 0) + goto unlock; + + ctx->size = ntoh64 (*size); + } else + ctx->size = buf->ia_size; + + ret = dict_get_bin (dict, contri_key, (void **) &contri); + if (ret < 0) + contribution->contribution = 0; + else + contribution->contribution = ntoh64 (*contri); + + ret = 0; + } +unlock: + UNLOCK (&ctx->lock); + + if (ret < 0) + goto err; + + newdict = dict_new (); + if (newdict == NULL) { + ret = -1; + goto err; + } + + local->delta = ctx->size - contribution->contribution; + + QUOTA_ALLOC_OR_GOTO (delta, int64_t, ret, err); + + *delta = hton64 (local->delta); + + ret = dict_set_bin (newdict, contri_key, delta, 8); + if (ret < 0) { + ret = -1; + goto err; + } + + STACK_WIND (frame, + quota_update_parent_size, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->xattrop, + &local->loc, + GF_XATTROP_ADD_ARRAY64, + newdict); + ret = 0; + +err: + if (op_ret == -1 || ret < 0) { + local->err = 1; + + quota_release_parent_lock (frame, NULL, this, 0, 0); + } + + if (newdict) + dict_unref (newdict); + + return 0; +} + +int32_t +quota_fetch_child_size_and_contri (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno) +{ + int32_t ret = -1; + char contri_key [512] = {0, }; + dict_t *newdict = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + quota_inode_ctx_t *ctx = NULL; + + trap (); + + local = frame->local; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_ERROR, + "%s couldnt mark dirty", local->parent_loc.path); + goto err; + } + + gf_log (this->name, GF_LOG_DEBUG, "%s marked dirty", local->parent_loc.path); + + priv = this->private; + + //update parent ctx + ret = quota_inode_ctx_get (local->parent_loc.inode, this, &ctx); + if (ret == -1) + goto err; + + LOCK (&ctx->lock); + { + ctx->dirty = 1; + } + UNLOCK (&ctx->lock); + + newdict = dict_new (); + if (newdict == NULL) + goto err; + + if (local->loc.inode->ia_type == IA_IFDIR) { + ret = dict_set_int64 (newdict, priv->size_key, 0); + } + + GET_CONTRI_KEY (contri_key, local->contri->gfid, ret); + if (ret < 0) + goto err; + + ret = dict_set_int64 (newdict, contri_key, 0); + + STACK_WIND (frame, quota_update_inode_contribution, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->lookup, &local->loc, newdict); + + ret = 0; + +err: + if (op_ret == -1 || ret == -1) { + local->err = 1; + + quota_release_parent_lock (frame, NULL, this, 0, 0); + } + + if (newdict) + dict_unref (newdict); + + return 0; +} + +int32_t +quota_markdirty (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno) +{ + int32_t ret = -1; + dict_t *dict = NULL; + quota_local_t *local = NULL; + marker_conf_t *priv = NULL; + + local = frame->local; + + if (op_ret == -1){ + gf_log (this->name, GF_LOG_ERROR, + "lock setting failed %s", strerror (op_errno)); + + local->err = 1; + + quota_inodelk_cbk (frame, NULL, this, 0, 0); + + return 0; + } + + gf_log (this->name, GF_LOG_TRACE, + "inodelk succeeded on %s", local->parent_loc.path); + + priv = this->private; + + dict = dict_new (); + if (!dict) { + ret = -1; + goto err; + } + + ret = dict_set_int8 (dict, priv->dirty_key, 1); + if (ret == -1) + goto err; + + STACK_WIND (frame, quota_fetch_child_size_and_contri, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setxattr, + &local->parent_loc, dict, 0); + + ret = 0; +err: + if (ret == -1) { + local->err = 1; + + quota_release_parent_lock (frame, NULL, this, 0, 0); + } + + if (dict) + dict_unref (dict); + + return 0; +} + + +int32_t +get_lock_on_parent (call_frame_t *frame, xlator_t *this) +{ + struct gf_flock lock; + quota_local_t *local = NULL; + + GF_VALIDATE_OR_GOTO ("marker", frame, fr_destroy); + + local = frame->local; + + lock.l_len = 0; + lock.l_start = 0; + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + + STACK_WIND (frame, + quota_markdirty, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->inodelk, + this->name, &local->parent_loc, F_SETLKW, &lock); + + return 0; + +fr_destroy: + QUOTA_STACK_DESTROY (frame, this); + + return 0; +} + + +int +start_quota_txn (xlator_t *this, loc_t *loc, + quota_inode_ctx_t *ctx, + inode_contribution_t *contri) +{ + int32_t ret = -1; + call_frame_t *frame = NULL; + quota_local_t *local = NULL; + + frame = create_frame (this, this->ctx->pool); + if (frame == NULL) + goto err; + + frame->root->lk_owner = cn++; + + local = quota_local_new (); + if (local == NULL) + goto fr_destroy; + + frame->local = local; + + ret = loc_copy (&local->loc, loc); + if (ret < 0) + goto local_unref; + + ret = quota_inode_loc_fill (NULL, local->loc.parent, + &local->parent_loc); + if (ret < 0) + goto local_unref; + + local->ctx = ctx; + local->contri = contri; + + get_lock_on_parent (frame, this); + + return 0; + +local_unref: + quota_local_unref (this, local); + +fr_destroy: + QUOTA_STACK_DESTROY (frame, this); + +err: + return -1; +} + + +int +initiate_quota_txn (xlator_t *this, loc_t *loc) +{ + int32_t ret = -1; + quota_inode_ctx_t *ctx = NULL; + inode_contribution_t *contribution = NULL; + + trap (); + + VALIDATE_OR_GOTO (loc, out); + + ret = quota_inode_ctx_get (loc->inode, this, &ctx); + if (ret == -1) { + gf_log (this->name, GF_LOG_WARNING, + "inode ctx get failed, aborting quota txn"); + ret = -1; + goto out; + } + + contribution = get_contribution_node (loc->parent, ctx); + if (contribution == NULL) + goto out; + + start_quota_txn (this, loc, ctx, contribution); +out: + return 0; +} + + +int32_t +validate_inode_size_contribution (xlator_t *this, + loc_t *loc, + quota_inode_ctx_t *ctx, + inode_contribution_t *contribution) +{ + if (ctx->size != contribution->contribution) + initiate_quota_txn (this, loc); + + return 0; +} + + +int32_t +inspect_directory_xattr (xlator_t *this, + loc_t *loc, + dict_t *dict, + struct iatt buf) +{ + int32_t ret = 0; + int8_t dirty = -1; + int64_t *size = NULL; + int64_t *contri = NULL; + char contri_key [512] = {0, }; + marker_conf_t *priv = NULL; + quota_inode_ctx_t *ctx = NULL; + inode_contribution_t *contribution = NULL; + + priv = this->private; + + ret = quota_inode_ctx_get (loc->inode, this, &ctx); + if (ret < 0) { + ctx = quota_inode_ctx_new (loc->inode, this); + if (ctx == NULL) { + gf_log (this->name, GF_LOG_WARNING, + "quota_inode_ctx_new failed"); + ret = -1; + goto out; + } + } + + ret = dict_get_bin (dict, priv->size_key, (void **) &size); + if (ret < 0) + goto out; + + ret = dict_get_int8 (dict, priv->dirty_key, &dirty); + if (ret < 0) + goto out; + + if (strcmp (loc->path, "/") != 0) { + contribution = add_new_contribution_node (this, ctx, loc); + if (contribution == NULL) { + gf_log (this->name, GF_LOG_DEBUG, + "cannot add a new contributio node"); + goto out; + } + + GET_CONTRI_KEY (contri_key, contribution->gfid, ret); + if (ret < 0) + goto out; + + ret = dict_get_bin (dict, contri_key, (void **) &contri); + if (ret < 0) + goto out; + + contribution->contribution = ntoh64 (*contri); + } + + ctx->size = ntoh64 (*size); + + ctx->dirty = dirty; + if (ctx->dirty == 1) + update_dirty_inode (this, loc, ctx, contribution); + + ret = 0; +out: + if (ret) + quota_set_inode_xattr (this, loc); + + return 0; +} + +int32_t +inspect_file_xattr (xlator_t *this, + loc_t *loc, + dict_t *dict, + struct iatt buf) +{ + int32_t ret = -1; + uint64_t contri_int = 0; + int64_t *contri_ptr = NULL; + char contri_key [512] = {0, }; + marker_conf_t *priv = NULL; + quota_inode_ctx_t *ctx = NULL; + inode_contribution_t *contribution = NULL; + + priv = this->private; + + ret = quota_inode_ctx_get (loc->inode, this, &ctx); + if (ret < 0) { + ctx = quota_inode_ctx_new (loc->inode, this); + if (ctx == NULL) { + gf_log (this->name, GF_LOG_WARNING, + "quota_inode_ctx_new failed"); + ret = -1; + goto out; + } + } + + contribution = add_new_contribution_node (this, ctx, loc); + if (contribution == NULL) + goto out; + + LOCK (&ctx->lock); + { + ctx->size = buf.ia_size; + } + UNLOCK (&ctx->lock); + + list_for_each_entry (contribution, &ctx->contribution_head, contri_list) { + GET_CONTRI_KEY (contri_key, contribution->gfid, ret); + if (ret < 0) + continue; + + ret = dict_get_bin (dict, contri_key, (void **) &contri_int); + if (ret == 0) { + contri_ptr = (int64_t *) contri_int; + + contribution->contribution = ntoh64 (*contri_ptr); + + ret = validate_inode_size_contribution + (this, loc, ctx, contribution); + } else + initiate_quota_txn (this, loc); + } + +out: + return ret; +} + +int32_t +quota_xattr_state (xlator_t *this, + loc_t *loc, + dict_t *dict, + struct iatt buf) +{ + if (buf.ia_type == IA_IFREG || + buf.ia_type == IA_IFLNK) { + k ++; + inspect_file_xattr (this, loc, dict, buf); + } else if (buf.ia_type == IA_IFDIR) + inspect_directory_xattr (this, loc, dict, buf); + + return 0; +} + +int32_t +quota_req_xattr (xlator_t *this, + loc_t *loc, + dict_t *dict) +{ + int32_t ret = -1; + marker_conf_t *priv = NULL; + + GF_VALIDATE_OR_GOTO ("marker", this, out); + GF_VALIDATE_OR_GOTO ("marker", loc, out); + GF_VALIDATE_OR_GOTO ("marker", dict, out); + + priv = this->private; + + //if not "/" then request contribution + if (strcmp (loc->path, "/") == 0) + goto set_size; + + ret = dict_set_contribution (this, dict, loc); + if (ret == -1) + goto out; + +set_size: + ret = dict_set_uint64 (dict, priv->size_key, 0); + if (ret < 0) { + ret = -1; + goto out; + } + + ret = dict_set_int8 (dict, priv->dirty_key, 0); + if (ret < 0) { + ret = -1; + goto out; + } + + ret = 0; + +out: + return ret; +} + + +int32_t +quota_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno) +{ + QUOTA_STACK_DESTROY (frame, this); + + return 0; +} + +int32_t +quota_inode_remove_done (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict) +{ + int32_t ret = 0; + char contri_key [512] = {0, }; + quota_local_t *local = NULL; + + local = (quota_local_t *) frame->local; + + if (local->hl_count > 1) { + GET_CONTRI_KEY (contri_key, local->contri->gfid, ret); + + STACK_WIND (frame, quota_removexattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->removexattr, + &local->loc, contri_key); + ret = 0; + } + + if (strcmp (local->parent_loc.path, "/") != 0) { + get_parent_inode_local (this, local); + + start_quota_txn (this, &local->loc, local->ctx, local->contri); + } + + quota_local_unref (this, local); + + return 0; +} + +int32_t +reduce_parent_size (xlator_t *this, loc_t *loc) +{ + int32_t ret = -1; + int64_t *size = NULL; + dict_t *dict = NULL; + call_frame_t *frame = NULL; + marker_conf_t *priv = NULL; + quota_local_t *local = NULL; + quota_inode_ctx_t *ctx = NULL; + inode_contribution_t *contribution = NULL; + + GF_VALIDATE_OR_GOTO ("marker", this, out); + GF_VALIDATE_OR_GOTO ("marker", loc, out); + + priv = this->private; + + ret = quota_inode_ctx_get (loc->inode, this, &ctx); + if (ret < 0) + goto out; + + contribution = get_contribution_node (loc->parent, ctx); + if (contribution == NULL) + goto out; + + local = quota_local_new (); + if (local == NULL) { + ret = -1; + goto out; + } + + ret = quota_inode_loc_fill ((const char *) loc->parent->gfid, + loc->parent, &local->parent_loc); + if (ret < 0) + goto free_local; + + dict = dict_new (); + if (dict == NULL) { + ret = -1; + goto free_local; + } + + QUOTA_ALLOC_OR_GOTO (size, int64_t, ret, free_local); + + *size = hton64 (-contribution->contribution); + + ret = dict_set_bin (dict, priv->size_key, size, 8); + if (ret < 0) + goto free_size; + + frame = create_frame (this, this->ctx->pool); + if (!frame) { + ret = -1; + goto free_size; + } + + frame->local = local; + + STACK_WIND (frame, quota_inode_remove_done, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->xattrop, &local->parent_loc, + GF_XATTROP_ADD_ARRAY64, dict); + ret = 0; + +free_size: + if (ret < 0) + GF_FREE (size); +free_local: + if (ret < 0) + quota_local_unref (this, local); +out: + dict_unref (dict); + + return ret; +} + + +int32_t +init_quota_priv (xlator_t *this) +{ + marker_conf_t *priv = NULL; + + priv = this->private; + + strcpy (volname, "quota"); + + gf_asprintf (&priv->size_key, QUOTA_XATTR_PREFIX + ".%s.size", volname); + + gf_asprintf (&priv->dirty_key, QUOTA_XATTR_PREFIX + ".%s.dirty", volname); + + return 0; +} + + +int32_t +quota_rename_update_newpath (xlator_t *this, loc_t *loc, inode_t *inode) +{ + int32_t ret = -1; + quota_inode_ctx_t *ctx = NULL; + inode_contribution_t *contribution = NULL; + + GF_VALIDATE_OR_GOTO ("marker", this, out); + GF_VALIDATE_OR_GOTO ("marker", loc, out); + GF_VALIDATE_OR_GOTO ("marker", inode, out); + + if (loc->inode == NULL) + loc->inode = inode_ref (inode); + + ret = quota_inode_ctx_get (loc->inode, this, &ctx); + if (ret < 0) + goto out; + + contribution = add_new_contribution_node (this, ctx, loc); + if (contribution == NULL) { + ret = -1; + goto out; + } + + initiate_quota_txn (this, loc); +out: + return ret; +} + +int32_t +quota_forget (xlator_t *this, quota_inode_ctx_t *ctx) +{ + inode_contribution_t *contri = NULL; + inode_contribution_t *next = NULL; + + GF_VALIDATE_OR_GOTO ("marker", this, out); + GF_VALIDATE_OR_GOTO ("marker", ctx, out); + + list_for_each_entry_safe (contri, next, &ctx->contribution_head, + contri_list) { + list_del (&contri->contri_list); + GF_FREE (contri); + } + + LOCK_DESTROY (&ctx->lock); + GF_FREE (ctx); +out: + return 0; +} diff --git a/xlators/features/marker/src/marker-quota.h b/xlators/features/marker/src/marker-quota.h new file mode 100644 index 00000000000..fdec1230fb8 --- /dev/null +++ b/xlators/features/marker/src/marker-quota.h @@ -0,0 +1,167 @@ +/*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 _MARKER_QUOTA_H +#define _MARKER_QUOTA_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "marker.h" +#include "xlator.h" +#include "marker-mem-types.h" + +#define QUOTA_XATTR_PREFIX "trusted.glusterfs" +#define CONTRIBUTION "contri" +#define VOL_NAME volname +#define CONTRI_KEY_MAX 512 +#define READDIR_BUF 4096 + +char volname [40]; + +#define QUOTA_STACK_DESTROY(_frame, _this) \ + do { \ + quota_local_t *_local = NULL; \ + _local = _frame->local; \ + _frame->local = NULL; \ + STACK_DESTROY (_frame->root); \ + quota_local_unref (_this, _local); \ + GF_FREE (_local); \ + } while (0) + + +#define QUOTA_ALLOC(var, type, ret) \ + do { \ + var = GF_CALLOC (sizeof (type), 1, \ + gf_marker_mt_##type); \ + if (!var) { \ + gf_log ("", GF_LOG_ERROR, \ + "out of memory"); \ + ret = -1; \ + } \ + ret = 0; \ + } while (0); + +#define QUOTA_ALLOC_OR_GOTO(var, type, ret, label) \ + do { \ + var = GF_CALLOC (sizeof (type), 1, \ + gf_marker_mt_##type); \ + if (!var) { \ + gf_log ("", GF_LOG_ERROR, \ + "out of memory"); \ + ret = -1; \ + goto label; \ + } \ + ret = 0; \ + } while (0); + +#define GET_CONTRI_KEY(var, _gfid, _ret) \ + do { \ + char _gfid_unparsed[40]; \ + uuid_unparse (_gfid, _gfid_unparsed); \ + _ret = snprintf (var, CONTRI_KEY_MAX, QUOTA_XATTR_PREFIX \ + ".%s.%s." CONTRIBUTION, VOL_NAME, \ + _gfid_unparsed); \ + } while (0); + +#define QUOTA_SAFE_INCREMENT(lock, var) \ + do { \ + LOCK (lock); \ + var ++; \ + UNLOCK (lock); \ + } while (0) + +#define QUOTA_SAFE_DECREMENT(lock, var) \ + do { \ + LOCK (lock); \ + var --; \ + UNLOCK (lock); \ + } while (0) + + +struct quota_inode_ctx { + int64_t size; + int8_t dirty; + gf_lock_t lock; + struct list_head contribution_head; +}; +typedef struct quota_inode_ctx quota_inode_ctx_t; + +struct inode_contribution { + struct list_head contri_list; + int64_t contribution; + uuid_t gfid; +}; +typedef struct inode_contribution inode_contribution_t; + +struct quota_local { + int64_t delta; + int64_t d_off; + int32_t err; + int32_t ref; + int64_t sum; + int32_t hl_count; + int32_t dentry_child_count; + + fd_t *fd; + call_frame_t *frame; + gf_lock_t lock; + + loc_t loc; + loc_t parent_loc; + + quota_inode_ctx_t *ctx; + inode_contribution_t *contri; +}; +typedef struct quota_local quota_local_t; + +int32_t cn; + +int32_t +get_lock_on_parent (call_frame_t *, xlator_t *); + +int32_t +quota_req_xattr (xlator_t *, loc_t *, dict_t *); + +int32_t +init_quota_priv (xlator_t *); + +int32_t +quota_xattr_state (xlator_t *, loc_t *, dict_t *, struct iatt); + +int32_t +quota_set_inode_xattr (xlator_t *, loc_t *); + +int +initiate_quota_txn (xlator_t *, loc_t *); + +int32_t +quota_dirty_inode_readdir (call_frame_t *, void *, xlator_t *, + int32_t, int32_t, fd_t *); + +int32_t +reduce_parent_size (xlator_t *, loc_t *); + +int32_t +quota_rename_update_newpath (xlator_t *, loc_t *, inode_t *); + +int32_t +quota_forget (xlator_t *, quota_inode_ctx_t *); +#endif diff --git a/xlators/features/marker/src/marker.c b/xlators/features/marker/src/marker.c index f6302247e5e..83824891235 100644 --- a/xlators/features/marker/src/marker.c +++ b/xlators/features/marker/src/marker.c @@ -26,6 +26,7 @@ #include "libxlator.h" #include "marker.h" #include "marker-mem-types.h" +#include "marker-quota.h" void fini (xlator_t *this); @@ -33,6 +34,22 @@ fini (xlator_t *this); int32_t marker_start_setxattr (call_frame_t *, xlator_t *); +marker_local_t * +marker_local_ref (marker_local_t *local) +{ + GF_VALIDATE_OR_GOTO ("marker", local, err); + + LOCK (&local->lock); + { + local->ref++; + } + UNLOCK (&local->lock); + + return local; +err: + return NULL; +} + int marker_loc_fill (loc_t *loc, inode_t *inode, inode_t *parent, char *path) { @@ -139,8 +156,20 @@ marker_error_handler (xlator_t *this) } int32_t -marker_free_local (marker_local_t *local) +marker_local_unref (marker_local_t *local) { + if (local == NULL) + return -1; + + LOCK (&local->lock); + { + local->ref--; + } + UNLOCK (&local->lock); + + if (local->ref != 0) + goto out; + loc_wipe (&local->loc); if (local->oplocal) { @@ -148,7 +177,7 @@ marker_free_local (marker_local_t *local) GF_FREE (local->oplocal); } GF_FREE (local); - +out: return 0; } @@ -263,7 +292,7 @@ marker_setxattr_done (call_frame_t *frame) STACK_DESTROY (frame->root); - marker_free_local (local); + marker_local_unref (local); return 0; } @@ -365,32 +394,30 @@ marker_create_frame (xlator_t *this, marker_local_t *local) } int32_t -update_marks (xlator_t *this, marker_local_t *local, int32_t ret) +update_marks (xlator_t *this, marker_local_t *local) { - if (ret == -1 || local->pid < 0) - marker_free_local (local); - else { - marker_gettimeofday (local); + marker_gettimeofday (local); - marker_create_frame (this, local); - } + marker_local_ref (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_conf_t *priv = NULL; 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; @@ -400,7 +427,19 @@ marker_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno, inode, buf, preparent, postparent); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + quota_set_inode_xattr (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); + +out: + marker_local_unref (local); return 0; } @@ -431,19 +470,19 @@ err: 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; + marker_conf_t *priv = 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; @@ -453,7 +492,19 @@ marker_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (create, frame, op_ret, op_errno, fd, inode, buf, preparent, postparent); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + quota_set_inode_xattr (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); + +out: + marker_local_unref (local); return 0; } @@ -484,18 +535,18 @@ err: 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_conf_t *priv = NULL; 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; @@ -504,7 +555,19 @@ marker_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (writev, frame, op_ret, op_errno, prebuf, postbuf); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + initiate_quota_txn (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); + +out: + marker_local_unref (local); return 0; } @@ -540,18 +603,18 @@ err: 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_conf_t *priv = NULL; 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; @@ -561,7 +624,18 @@ marker_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (rmdir, frame, op_ret, op_errno, preparent, postparent); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + reduce_parent_size (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -590,19 +664,18 @@ err: 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_conf_t *priv = NULL; 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; @@ -612,7 +685,18 @@ marker_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (unlink, frame, op_ret, op_errno, preparent, postparent); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + reduce_parent_size (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -641,19 +725,19 @@ err: 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; + marker_conf_t *priv = 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; @@ -663,7 +747,18 @@ marker_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (link, frame, op_ret, op_errno, inode, buf, preparent, postparent); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + initiate_quota_txn (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -692,20 +787,20 @@ err: 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_conf_t *priv = NULL; marker_local_t *local = NULL; marker_local_t *oplocal = 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; @@ -718,10 +813,25 @@ marker_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, oplocal = local->oplocal; local->oplocal = NULL; - //update marks on oldpath - update_marks (this, oplocal, ret); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + if (priv->feature_enabled & GF_QUOTA) { + reduce_parent_size (this, &oplocal->loc); + quota_rename_update_newpath (this, &local->loc, + oplocal->loc.inode); + } + + if (priv->feature_enabled & GF_GSYNC) { + //update marks on oldpath + update_marks (this, oplocal); + update_marks (this, local); + } +out: + marker_local_unref (local); + marker_local_unref (oplocal); return 0; } @@ -763,18 +873,18 @@ err: 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; + marker_conf_t *priv = 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; @@ -784,7 +894,19 @@ marker_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (truncate, frame, op_ret, op_errno, prebuf, postbuf); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + initiate_quota_txn (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); + +out: + marker_local_unref (local); return 0; } @@ -813,18 +935,18 @@ err: 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; + marker_conf_t *priv = 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; @@ -834,7 +956,18 @@ marker_ftruncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (ftruncate, frame, op_ret, op_errno, prebuf, postbuf); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + initiate_quota_txn (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -863,19 +996,19 @@ err: 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_conf_t *priv = NULL; 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; @@ -885,7 +1018,18 @@ marker_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (symlink, frame, op_ret, op_errno, inode, buf, preparent, postparent); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled & GF_QUOTA) + initiate_quota_txn (this, &local->loc); + + if (priv->feature_enabled & GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -915,19 +1059,19 @@ err: 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; + marker_conf_t *priv = 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; @@ -937,7 +1081,15 @@ marker_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (mknod, frame, op_ret, op_errno, inode, buf, preparent, postparent); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled == GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -967,6 +1119,7 @@ err: 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 @@ -1027,17 +1180,17 @@ out: 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; + marker_conf_t *priv = 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; @@ -1046,7 +1199,15 @@ marker_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (setxattr, frame, op_ret, op_errno); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled == GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -1080,17 +1241,17 @@ err: 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; + marker_conf_t *priv = 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; @@ -1099,7 +1260,15 @@ marker_fsetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (fsetxattr, frame, op_ret, op_errno); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled == GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -1133,18 +1302,18 @@ err: 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; + marker_conf_t *priv = 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; @@ -1154,11 +1323,20 @@ marker_fsetattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (fsetattr, frame, op_ret, op_errno, statpre, statpost); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled == GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } + int32_t marker_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, struct iatt *stbuf, int32_t valid) @@ -1184,18 +1362,18 @@ err: 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; + marker_conf_t *priv = 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; @@ -1205,7 +1383,15 @@ marker_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (setattr, frame, op_ret, op_errno, statpre, statpost); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled == GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -1235,17 +1421,17 @@ err: 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; + marker_conf_t *priv = 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; @@ -1254,7 +1440,15 @@ marker_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, STACK_UNWIND_STRICT (removexattr, frame, op_ret, op_errno); - update_marks (this, local, ret); + if (op_ret == -1) + goto out; + + priv = this->private; + + if (priv->feature_enabled == GF_GSYNC) + update_marks (this, local); +out: + marker_local_unref (local); return 0; } @@ -1284,6 +1478,79 @@ err: return 0; } + +int32_t +marker_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 *dict, struct iatt *postparent) +{ + struct iatt stat_buf; + marker_conf_t *priv = NULL; + marker_local_t *local = NULL; + + if (op_ret == -1) { + gf_log (this->name, GF_LOG_TRACE, "lookup failed with %s", + strerror (op_errno)); + } + + priv = this->private; + + dict_ref (dict); + + memmove (&stat_buf, buf, sizeof (struct iatt)); + + local = (marker_local_t *) frame->local; + + frame->local = NULL; + + STACK_UNWIND_STRICT (lookup, frame, op_ret, op_errno, inode, buf, + dict, postparent); + + if (op_ret == -1) + goto out; + + if (priv->feature_enabled & GF_QUOTA) { + quota_xattr_state (this, &local->loc, dict, stat_buf); + } + +out: + marker_local_unref (local); + + dict_unref (dict); + + return 0; +} + +int32_t +marker_lookup (call_frame_t *frame, xlator_t *this, + loc_t *loc, dict_t *xattr_req) +{ + int32_t ret = 0; + marker_conf_t *priv = NULL; + marker_local_t *local = NULL; + + priv = this->private; + + ALLOCATE_OR_GOTO (local, marker_local_t, err); + + MARKER_INIT_LOCAL (frame, local); + + ret = loc_copy (&local->loc, loc); + if (ret == -1) + goto err; + + if (priv->feature_enabled & GF_QUOTA) + quota_req_xattr (this, loc, xattr_req); + + STACK_WIND (frame, marker_lookup_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->lookup, loc, xattr_req); + return 0; +err: + STACK_UNWIND_STRICT (lookup, frame, -1, 0, NULL, NULL, NULL, NULL); + + return 0; +} + int32_t mem_acct_init (xlator_t *this) { @@ -1303,39 +1570,24 @@ mem_acct_init (xlator_t *this) return ret; } + int32_t -init (xlator_t *this) +init_gsync_priv (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; - } + dict_t *options = NULL; + data_t *data = NULL; + int32_t ret = 0; + marker_conf_t *priv = NULL; options = this->options; - ALLOCATE_OR_GOTO (this->private, marker_conf_t, err); - - priv = this->private; - - if( (data = dict_get (options, VOLUME_UUID)) != NULL) { + 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; + goto out; } ret = gf_asprintf (& (priv->marker_xattr), "%s.%s.%s", @@ -1346,7 +1598,7 @@ init (xlator_t *this) gf_log (this->name, GF_LOG_ERROR, "Failed to allocate memory"); - goto err; + goto out; } gf_log (this->name, GF_LOG_DEBUG, @@ -1375,6 +1627,68 @@ init (xlator_t *this) "please specify the timestamp-file" "in the translator options"); + goto out; + } + + ret = 0; +out: + 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; + + priv->feature_enabled = 0; + + data = dict_get (options, "quota"); + if (data) { + if (strcmp (data->data, "on") == 0) { + priv->feature_enabled |= GF_QUOTA; + ret = init_quota_priv (this); + if (ret < 0) + goto err; + } + } + + data = dict_get (options, "marker"); + if (data) { + if (strcmp (data->data, "on") == 0) { + priv->feature_enabled |= GF_GSYNC; + ret = init_gsync_priv (this); + if (ret < 0) + goto err; + } + } + + if (priv->feature_enabled == 0) { + gf_log (this->name, GF_LOG_WARNING, + "Marker translator in the volfile " + "but no functionality is enabled " + "failing marker init()"); + goto err; } @@ -1385,6 +1699,21 @@ err: return -1; } +int32_t +marker_forget (xlator_t *this, inode_t *inode) +{ + marker_inode_ctx_t *ctx = NULL; + + if (inode_ctx_get (inode, this, (uint64_t *) &ctx) != 0) + goto out; + + quota_forget (this, ctx->quota_ctx); + + GF_FREE (ctx); +out: + return 0; +} + void fini (xlator_t *this) { @@ -1404,22 +1733,29 @@ fini (xlator_t *this) if (priv->marker_xattr != NULL) GF_FREE (priv->marker_xattr); + if (priv->size_key != NULL) + GF_FREE (priv->size_key); + + if (priv->dirty_key != NULL) + GF_FREE (priv->dirty_key); + GF_FREE (priv); out: return ; } struct xlator_fops fops = { + .lookup = marker_lookup, .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, + .link = marker_link, + .unlink = marker_unlink, + .rmdir = marker_rmdir, + .rename = marker_rename, .mknod = marker_mknod, .setxattr = marker_setxattr, .fsetxattr = marker_fsetxattr, @@ -1430,10 +1766,13 @@ struct xlator_fops fops = { }; struct xlator_cbks cbks = { + .forget = marker_forget }; struct volume_options options[] = { {.key = {"volume-uuid"}}, {.key = {"timestamp-file"}}, + {.key = {"quota"}}, + {.key = {"marker"}}, {.key = {NULL}} }; diff --git a/xlators/features/marker/src/marker.h b/xlators/features/marker/src/marker.h index eeb64a16a87..5602456ff5d 100644 --- a/xlators/features/marker/src/marker.h +++ b/xlators/features/marker/src/marker.h @@ -16,11 +16,15 @@ <http://www.gnu.org/licenses/>. */ +#ifndef _MARKER_H +#define _MARKER_H + #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" #endif +#include "marker-quota.h" #include "xlator.h" #include "defaults.h" #include "uuid.h" @@ -31,11 +35,18 @@ #define VOLUME_UUID "volume-uuid" #define TIMESTAMP_FILE "timestamp-file" +enum { + GF_QUOTA=1, + GF_GSYNC=2 +}; + /*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)); \ + _local->ref = 1; \ + LOCK_INIT (&_local->lock); \ _local->oplocal = NULL; \ } while (0) @@ -54,15 +65,28 @@ struct marker_local{ uint32_t timebuf[2]; pid_t pid; loc_t loc; + int32_t ref; + gf_lock_t lock; struct marker_local *oplocal; }; typedef struct marker_local marker_local_t; +struct marker_inode_ctx { + struct quota_inode_ctx *quota_ctx; +}; +typedef struct marker_inode_ctx marker_inode_ctx_t; + struct marker_conf{ + char feature_enabled; + char *size_key; + char *dirty_key; char *volume_uuid; uuid_t volume_uuid_bin; char *timestamp_file; char *marker_xattr; }; typedef struct marker_conf marker_conf_t; + +int32_t k; +#endif |