From 6cb2106c22e1ea3758ac63dc725b888470f5dd5a Mon Sep 17 00:00:00 2001 From: Varun Shastry Date: Tue, 22 Oct 2013 16:12:58 +0530 Subject: features/quota: Metadata cleanup Quota and marker uses 'trusted.glusterfs.quota*' and 'trusted.pgfid*' xattrs to store its configurations and accounting information and also to build the parent inode chain in case of absense of path. Problem: After disabling and then enabling quota back, the xattrs may contain stale data leading to impaired accounting and thus improper enforcement. Solution: Clean up all the quota related xattrs after quota disable. Marker xlator implements a virtual xattr to cleanup quota and pgfid xattrs. In this approach glusterd mounts an auxiliary mount and sends the below command to all the files by crawling the mountpoint. #setfattr -n "glusterfs.quota-xattr-cleanup" -v 1 Credit: Krishnan Parthasarathi Varun Shastry Change-Id: I9380eca58a285dc27dd572de1767aac8f2cd8049 BUG: 969461 Signed-off-by: Varun Shastry Reviewed-on: http://review.gluster.org/6369 Reviewed-by: Raghavendra G Tested-by: Gluster Build System Reviewed-by: Krishnan Parthasarathi Reviewed-by: Vijay Bellur Reviewed-on: http://review.gluster.org/6838 --- extras/Makefile.am | 10 +- extras/quota-metadata-cleanup.sh | 24 ----- extras/quota-remove-xattr.sh | 24 ----- libglusterfs/src/glusterfs.h | 1 + xlators/features/marker/src/marker.c | 143 ++++++++++++++++++++++++++++- xlators/mgmt/glusterd/src/glusterd-quota.c | 30 +++++- 6 files changed, 169 insertions(+), 63 deletions(-) delete mode 100755 extras/quota-metadata-cleanup.sh delete mode 100755 extras/quota-remove-xattr.sh diff --git a/extras/Makefile.am b/extras/Makefile.am index cf619329b..2633e20a5 100644 --- a/extras/Makefile.am +++ b/extras/Makefile.am @@ -1,4 +1,3 @@ - EditorModedir = $(docdir) EditorMode_DATA = glusterfs-mode.el glusterfs.vim @@ -13,8 +12,7 @@ vol_DATA = glusterd.vol EXTRA_DIST = specgen.scm MacOSX/Portfile glusterfs-mode.el glusterfs.vim \ migrate-unify-to-distribute.sh backend-xattr-sanitize.sh \ - backend-cleanup.sh disk_usage_sync.sh quota-remove-xattr.sh \ - quota-metadata-cleanup.sh glusterfs-logrotate clear_xattrs.sh \ - group-virt.example glusterd-sysconfig gluster-rsyslog-7.2.conf \ - gluster-rsyslog-5.8.conf logger.conf.example glusterd.vol \ - glusterfs-georep-logrotate + backend-cleanup.sh disk_usage_sync.sh glusterfs-logrotate \ + clear_xattrs.sh group-virt.example glusterd-sysconfig \ + gluster-rsyslog-7.2.conf gluster-rsyslog-5.8.conf \ + logger.conf.example glusterd.vol glusterfs-georep-logrotate diff --git a/extras/quota-metadata-cleanup.sh b/extras/quota-metadata-cleanup.sh deleted file mode 100755 index 37ad8bc31..000000000 --- a/extras/quota-metadata-cleanup.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# This script is used to cleanup xattrs setup by quota-translator in (a) -# backend directory(ies). It takes a single or list of backend directories -# as argument(s). - -usage () -{ - echo >&2 "usage: $0 " -} - -main () -{ - [ $# -lt 1 ] && usage - - INSTALL_DIR=`dirname $0` - - for i in $@; do - find $i -exec $INSTALL_DIR/quota-remove-xattr.sh '{}' \; - done - -} - -main $@ diff --git a/extras/quota-remove-xattr.sh b/extras/quota-remove-xattr.sh deleted file mode 100755 index 7191f9bd4..000000000 --- a/extras/quota-remove-xattr.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# This script is used to remove xattrs set by quota translator on a path. -# It is generally invoked from quota-metadata-cleanup.sh, but can -# also be used stand-alone. - -usage () -{ - echo >&2 "usage: $0 " -} - -main () -{ - [ $# -ne 1 ] && usage $0 - - XATTR_KEY_VALUE_PAIRS=`getfattr -h -d -m 'trusted.glusterfs.quota' $1 2>/dev/null | sed -e '/^# file/d'` - - for i in $XATTR_KEY_VALUE_PAIRS; do - XATTR_KEY=`echo $i | sed -e 's/\([^=]*\).*/\1/g'` - setfattr -h -x $XATTR_KEY $1 - done -} - -main $@ diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index 4f7a52353..2b2676364 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -86,6 +86,7 @@ #define GF_XATTR_LOCKINFO_KEY "trusted.glusterfs.lockinfo" #define GF_XATTR_GET_REAL_FILENAME_KEY "user.glusterfs.get_real_filename:" #define QUOTA_LIMIT_KEY "trusted.glusterfs.quota.limit-set" +#define VIRTUAL_QUOTA_XATTR_CLEANUP_KEY "glusterfs.quota-xattr-cleanup" #define GF_READDIR_SKIP_DIRS "readdir-filter-directories" diff --git a/xlators/features/marker/src/marker.c b/xlators/features/marker/src/marker.c index dbe9d530f..596a65184 100644 --- a/xlators/features/marker/src/marker.c +++ b/xlators/features/marker/src/marker.c @@ -21,6 +21,7 @@ #include "marker-quota-helper.h" #include "marker-common.h" #include "byte-order.h" +#include "syncop.h" #define _GF_UID_GID_CHANGED 1 @@ -2086,16 +2087,150 @@ out: return 0; } +int +remove_quota_keys (dict_t *dict, char *k, data_t *v, void *data) +{ + call_frame_t *frame = data; + marker_local_t *local = frame->local; + xlator_t *this = frame->this; + int ret = -1; + + ret = syncop_removexattr (FIRST_CHILD (this), &local->loc, k); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s: Failed to remove " + "extended attribute: %s", local->loc.path, k); + return -1; + } + return 0; +} + +int +quota_xattr_cleaner_cbk (int ret, call_frame_t *frame, void *args) +{ + dict_t *xdata = args; + int op_ret = -1; + int op_errno = 0; + marker_local_t *local = NULL; + + local = frame->local; + frame->local = NULL; + + op_ret = (ret < 0)? -1: 0; + op_errno = -ret; + + STACK_UNWIND_STRICT (setxattr, frame, op_ret, op_errno, xdata); + marker_local_unref (local); + return ret; +} + +int +quota_xattr_cleaner (void *args) +{ + struct synctask *task = NULL; + call_frame_t *frame = NULL; + xlator_t *this = NULL; + marker_local_t *local = NULL; + dict_t *xdata = NULL; + int ret = -1; + + task = synctask_get (); + if (!task) + goto out; + + frame = task->frame; + this = frame->this; + local = frame->local; + + ret = syncop_listxattr (FIRST_CHILD(this), &local->loc, &xdata); + if (ret == -1) { + ret = -errno; + goto out; + } + + ret = dict_foreach_fnmatch (xdata, "trusted.glusterfs.quota.*", + remove_quota_keys, frame); + if (ret == -1) { + ret = -errno; + goto out; + } + ret = dict_foreach_fnmatch (xdata, PGFID_XATTR_KEY_PREFIX"*", + remove_quota_keys, frame); + if (ret == -1) { + ret = -errno; + goto out; + } + + ret = 0; +out: + if (xdata) + dict_unref (xdata); + + return ret; +} + +int +marker_do_xattr_cleanup (call_frame_t *frame, xlator_t *this, dict_t *xdata, + loc_t *loc) +{ + int ret = -1; + marker_local_t *local = NULL; + + local = mem_get0 (this->local_pool); + if (!local) + goto out; + + MARKER_INIT_LOCAL (frame, local); + + loc_copy (&local->loc, loc); + ret = synctask_new (this->ctx->env, quota_xattr_cleaner, + quota_xattr_cleaner_cbk, frame, xdata); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to create synctask " + "for cleaning up quota extended attributes"); + goto out; + } + + ret = 0; +out: + if (ret) { + frame->local = NULL; + STACK_UNWIND_STRICT (setxattr, frame, -1, ENOMEM, xdata); + marker_local_unref (local); + } + return ret; +} + +static inline gf_boolean_t +marker_xattr_cleanup_cmd (dict_t *dict) +{ + return (dict_get (dict, VIRTUAL_QUOTA_XATTR_CLEANUP_KEY) != NULL); +} + int32_t marker_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata) { - int32_t ret = 0; - marker_local_t *local = NULL; - marker_conf_t *priv = NULL; + int32_t ret = 0; + marker_local_t *local = NULL; + marker_conf_t *priv = NULL; + int op_errno = ENOMEM; priv = this->private; + if (marker_xattr_cleanup_cmd (dict)) { + if (frame->root->uid != 0 || frame->root->gid != 0) { + op_errno = EPERM; + ret = -1; + goto err; + } + + /* The following function does the cleanup and then unwinds the + * corresponding call*/ + loc_path (loc, NULL); + marker_do_xattr_cleanup (frame, this, xdata, loc); + return 0; + } + if (priv->feature_enabled == 0) goto wind; @@ -2116,7 +2251,7 @@ wind: FIRST_CHILD(this)->fops->setxattr, loc, dict, flags, xdata); return 0; err: - STACK_UNWIND_STRICT (setxattr, frame, -1, ENOMEM, NULL); + STACK_UNWIND_STRICT (setxattr, frame, -1, op_errno, NULL); return 0; } diff --git a/xlators/mgmt/glusterd/src/glusterd-quota.c b/xlators/mgmt/glusterd/src/glusterd-quota.c index f46f08787..979dac69b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-quota.c +++ b/xlators/mgmt/glusterd/src/glusterd-quota.c @@ -28,6 +28,8 @@ #include #include +/* Any negative pid to make it special client */ +#define QUOTA_CRAWL_PID "-100" const char *gd_quota_op_list[GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT+1] = { [GF_QUOTA_OPTION_TYPE_NONE] = "none", @@ -158,7 +160,8 @@ out: } int32_t -glusterd_quota_initiate_fs_crawl (glusterd_conf_t *priv, char *volname) +glusterd_quota_initiate_fs_crawl (glusterd_conf_t *priv, char *volname, + int type) { pid_t pid; int32_t ret = 0; @@ -178,6 +181,7 @@ glusterd_quota_initiate_fs_crawl (glusterd_conf_t *priv, char *volname) "-s", "localhost", "--volfile-id", volname, "--use-readdirp=no", + "--client-pid", QUOTA_CRAWL_PID, "-l", DEFAULT_LOG_FILE_DIRECTORY"/quota-crawl.log", mountdir, NULL); @@ -210,7 +214,19 @@ glusterd_quota_initiate_fs_crawl (glusterd_conf_t *priv, char *volname) exit (EXIT_FAILURE); } runinit (&runner); - runner_add_args (&runner, "/usr/bin/find", "find", ".", NULL); + + if (type == GF_QUOTA_OPTION_TYPE_ENABLE) + + runner_add_args (&runner, "/usr/bin/find", "find", ".", + NULL); + + else if (type == GF_QUOTA_OPTION_TYPE_DISABLE) + + runner_add_args (&runner, "/usr/bin/find", ".", + "-exec", "/usr/bin/setfattr", "-n", + VIRTUAL_QUOTA_XATTR_CLEANUP_KEY, "-v", + "1", "{}", "\\", ";", NULL); + if (runner_start (&runner) == -1) _exit (EXIT_FAILURE); @@ -325,7 +341,8 @@ out: } int32_t -glusterd_quota_disable (glusterd_volinfo_t *volinfo, char **op_errstr) +glusterd_quota_disable (glusterd_volinfo_t *volinfo, char **op_errstr, + gf_boolean_t *crawl) { int32_t ret = -1; int i = 0; @@ -381,6 +398,8 @@ glusterd_quota_disable (glusterd_volinfo_t *volinfo, char **op_errstr) if (ret) goto out; + *crawl = _gf_true; + (void) glusterd_clean_up_quota_store (volinfo); ret = 0; @@ -1045,7 +1064,8 @@ glusterd_op_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict) break; case GF_QUOTA_OPTION_TYPE_DISABLE: - ret = glusterd_quota_disable (volinfo, op_errstr); + ret = glusterd_quota_disable (volinfo, op_errstr, + &start_crawl); if (ret < 0) goto out; @@ -1129,7 +1149,7 @@ glusterd_op_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict) } if (rsp_dict && start_crawl == _gf_true) - glusterd_quota_initiate_fs_crawl (priv, volname); + glusterd_quota_initiate_fs_crawl (priv, volname, type); if (priv->op_version > GD_OP_VERSION_MIN) { ret = glusterd_quotad_op (type); -- cgit