diff options
| author | Krutika Dhananjay <kdhananj@redhat.com> | 2013-11-25 15:16:23 +0530 | 
|---|---|---|
| committer | Vijay Bellur <vbellur@redhat.com> | 2013-11-30 10:15:05 -0800 | 
| commit | 182bad8bfd099da5e742da28c4820936eb1f3867 (patch) | |
| tree | 50cbf409e303d5bef128c5da08809aef75dc62b4 | |
| parent | 72f733a64abeffee23fb87a3cb397baea1dc22a4 (diff) | |
cli, glusterd: More quota fixes ...
... which may be grouped under the following categories:
1. Fix incorrect cli exit status for 'quota list' cmd
2. Print appropriate error message on quota parse errors in cli
        Authored by: Anuradha Talur <atalur@redhat.com>
3. glusterd: Improve quota validation during stage-op
4. Fix peer probe issues resulting from quota conf checksum mismatches
5. Enhancements to CLI output in the event of quota command failures
        Authored by: Kaushal Madappa <kmadappa@redhat.com>
7. Move aux mount location from /tmp to /var/run/gluster
        Authored by: Krishnan Parthasarathi <kparthas@redhat.com>
8. Fix performance issues in quota limit-usage
        Authored by: Krutika Dhananjay <kdhananj@redhat.com>
Note: Some functions that were used in earlier version of quota,
      that aren't called anymore have been removed.
Change-Id: I9d874f839ae5fdcfbe6d4f2d727eac091f27ac57
BUG: 969461
Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
Reviewed-on: http://review.gluster.org/6366
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
| -rw-r--r-- | cli/src/cli-cmd-parser.c | 6 | ||||
| -rw-r--r-- | cli/src/cli-cmd-volume.c | 103 | ||||
| -rw-r--r-- | cli/src/cli-cmd.h | 6 | ||||
| -rw-r--r-- | cli/src/cli-rpc-ops.c | 64 | ||||
| -rw-r--r-- | cli/src/cli.h | 4 | ||||
| -rw-r--r-- | libglusterfs/src/common-utils.c | 70 | ||||
| -rw-r--r-- | libglusterfs/src/common-utils.h | 3 | ||||
| -rw-r--r-- | xlators/features/quota/src/quota.c | 2 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-quota.c | 587 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.c | 3 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd.h | 4 | 
11 files changed, 439 insertions, 413 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index dd7b11bccd4..88fbf96ff9c 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -535,6 +535,7 @@ cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options)          w = str_getunamb (words[3], opwords);          if (!w) { +                cli_out ("Invalid quota option : %s", words[3]);                  ret = - 1;                  goto out;          } @@ -587,7 +588,10 @@ cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options)                  ret = gf_string2bytesize (words[5], &value);                  if (ret != 0) { -                        cli_err ("Please enter a correct value"); +                        if (errno == ERANGE) +                                cli_err ("Value too large: %s", words[5]); +                        else +                                cli_err ("Please enter a correct value");                          goto out;                  } diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 9bc11d2dbb4..22bf66b4fb5 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -28,6 +28,7 @@  #include "cli-mem-types.h"  #include "cli1-xdr.h"  #include "run.h" +#include "syscall.h"  extern struct rpc_clnt *global_rpc;  extern struct rpc_clnt *global_quotad_rpc; @@ -1026,7 +1027,7 @@ gf_cli_create_auxiliary_mount (char *volname)                  goto out;          } -        snprintf (mountdir, sizeof (mountdir)-1, "/tmp/%s", volname); +        GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (mountdir, volname, "/");          ret = mkdir (mountdir, 0777);          if (ret && errno != EEXIST) {                  gf_log ("cli", GF_LOG_ERROR, "Failed to create auxiliary mount " @@ -1071,8 +1072,11 @@ cli_stage_quota_op (char *volname, int op_code)                  case GF_QUOTA_OPTION_TYPE_REMOVE:                  case GF_QUOTA_OPTION_TYPE_LIST:                          ret = gf_cli_create_auxiliary_mount (volname); -                        if (ret) +                        if (ret) { +                                cli_err ("quota: Could not start quota " +                                         "auxiliary mount");                                  goto out; +                        }                          ret = 0;                          break; @@ -1153,6 +1157,77 @@ cli_cmd_quota_conf_skip_header (int fd)          return gf_skip_header_section (fd, strlen (buf));  } +/* Checks if at least one limit has been set on the volume + * + * Returns true if at least one limit is set. Returns false otherwise. + */ +gf_boolean_t +_limits_set_on_volume (char *volname) { +        gf_boolean_t    limits_set = _gf_false; +        int             ret = -1; +        char            quota_conf_file[PATH_MAX] = {0,}; +        int             fd = -1; +        char            buf[16] = {0,}; + +        /* TODO: fix hardcoding; Need to perform an RPC call to glusterd +         * to fetch working directory +         */ +        sprintf (quota_conf_file, "/var/lib/glusterd/vols/%s/quota.conf", +                 volname); +        fd = open (quota_conf_file, O_RDONLY); +        if (fd == -1) +                goto out; + +        ret = cli_cmd_quota_conf_skip_header (fd); +        if (ret) +                goto out; + +        /* Try to read atleast one gfid */ +        ret = read (fd, (void *)buf, 16); +        if (ret == 16) +                limits_set = _gf_true; +out: +        if (fd != -1) +                close (fd); +        return limits_set; +} + +/* Checks if the mount is connected to the bricks + * + * Returns true if connected and false if not + */ +gf_boolean_t +_quota_aux_mount_online (char *volname) +{ +        int         ret = 0; +        char        mount_path[PATH_MAX + 1] = {0,}; +        struct stat buf = {0,}; + +        GF_ASSERT (volname); + +        /* Try to create the aux mount before checking if bricks are online */ +        ret = gf_cli_create_auxiliary_mount (volname); +        if (ret) { +                cli_err ("quota: Could not start quota auxiliary mount"); +                return _gf_false; +        } + +        GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (mount_path, volname, "/"); + +        ret = sys_stat (mount_path, &buf); +        if (ret) { +                if (ENOTCONN == errno) { +                        cli_err ("quota: Cannot connect to bricks. Check if " +                                 "bricks are online."); +                } else { +                        cli_err ("quota: Error on quota auxiliary mount (%s).", +                                 strerror (errno)); +                } +                return _gf_false; +        } +        return _gf_true; +} +  int  cli_cmd_quota_handle_list_all (const char **words, dict_t *options)  { @@ -1189,6 +1264,21 @@ cli_cmd_quota_handle_list_all (const char **words, dict_t *options)                  goto out;          } +        /* Check if at least one limit is set on volume. No need to check for +         * quota enabled as cli_get_soft_limit() handles that +         */ +        if (!_limits_set_on_volume (volname)) { +                cli_out ("quota: No quota configured on volume %s", volname); +                ret = 0; +                goto out; +        } + +        /* Check if the mount is online before doing any listing */ +        if (!_quota_aux_mount_online (volname)) { +                ret = -1; +                goto out; +        } +          frame = create_frame (THIS, THIS->ctx->pool);          if (!frame) {                  ret = -1; @@ -1265,22 +1355,19 @@ cli_cmd_quota_handle_list_all (const char **words, dict_t *options)          }          if (count > 0) { -                ret = all_failed? 0: -1; +                ret = all_failed? -1: 0;          } else {                  ret = 0;          }  out: -        if (count == 0) { -                cli_out ("quota: No quota configured on volume %s", volname); -        }          if (fd != -1) {                  close (fd);          }          GF_FREE (gfid_str);          if (ret) { -                gf_log ("cli", GF_LOG_ERROR, "Couldn't fetch quota limits " -                        "for even one of the directories configured"); +                gf_log ("cli", GF_LOG_ERROR, "Could not fetch and display quota" +                        " limits");          }          CLI_STACK_DESTROY (frame);          return ret; diff --git a/cli/src/cli-cmd.h b/cli/src/cli-cmd.h index 52396bbf755..541b4ff7332 100644 --- a/cli/src/cli-cmd.h +++ b/cli/src/cli-cmd.h @@ -119,4 +119,10 @@ gf_answer_t  cli_cmd_get_confirmation (struct cli_state *state, const char *question);  int cli_cmd_sent_status_get (int *status); +gf_boolean_t +_limits_set_on_volume (char *volname); + +gf_boolean_t +_quota_aux_mount_online (char *volname); +  #endif /* __CLI_CMD_H__ */ diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 07c081affcc..d125a928469 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -2288,8 +2288,8 @@ out:  static int  print_quota_list_output (char *mountdir, char *default_sl, char *path)  { -        uint64_t used_space       = 0; -        uint64_t avail            = 0; +        int64_t used_space       = 0; +        int64_t avail            = 0;          char    *used_str         = NULL;          char    *avail_str        = NULL;          int     ret               = -1; @@ -2309,6 +2309,20 @@ print_quota_list_output (char *mountdir, char *default_sl, char *path)                  gf_log ("cli", GF_LOG_ERROR, "Failed to get the xattr "                          "trusted.glusterfs.quota.limit-set on %s. Reason : %s",                          mountdir, strerror (errno)); +                switch (errno) { +#if defined(ENODATA) +                case ENODATA: +#endif +#if defined(ENOATTR) && (ENOATTR != ENODATA) +                case ENOATTR: +#endif +                        cli_err ("%-40s %s", path, "Limit not set"); +                        break; +                default: +                        cli_err ("%-40s %s", path, strerror (errno)); +                        break; +                } +                  goto out;          } @@ -2371,10 +2385,20 @@ gf_cli_print_limit_list_from_dict (char *volname, dict_t *dict,          if (!dict|| count <= 0)                  goto out; -        /*To-Do: -         * Proper error reporting to handle the case where none of the given -         * path arguments are present or have their limits set. +        /* Need to check if any quota limits are set on the volume before trying +         * to list them           */ +        if (!_limits_set_on_volume (volname)) { +                ret = 0; +                cli_out ("quota: No quota configured on volume %s", volname); +                goto out; +        } + +        /* Check if the mount is online before doing any listing */ +        if (!_quota_aux_mount_online (volname)) { +                ret = -1; +                goto out; +        }          cli_out ("                  Path                   Hard-limit "                   "Soft-limit   Used  Available"); @@ -2394,9 +2418,7 @@ gf_cli_print_limit_list_from_dict (char *volname, dict_t *dict,                  ret = gf_canonicalize_path (path);                  if (ret)                          goto out; -                snprintf (mountdir, sizeof (mountdir), "/tmp/%s%s", volname, -                          path); - +                GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (mountdir, volname, path);                  ret = print_quota_list_output (mountdir, default_sl, path);          } @@ -2520,12 +2542,14 @@ cli_quotad_getlimit_cbk (struct rpc_req *req, struct iovec *iov,                  goto out;          } -        if (rsp.op_ret && strcmp (rsp.op_errstr, "") == 0) { -                cli_err ("quota command : failed"); -                goto out; - -        } else if (strcmp (rsp.op_errstr, "")) +        if (rsp.op_ret) { +                ret = -1; +                if (strcmp (rsp.op_errstr, ""))                          cli_err ("quota command failed : %s", rsp.op_errstr); +                else +                        cli_err ("quota command : failed"); +                goto out; +        }          if (rsp.dict.dict_len) {                  /* Unserialize the dictionary */ @@ -2633,14 +2657,18 @@ gf_cli_quota_cbk (struct rpc_req *req, struct iovec *iov,                  goto out;          } -        if (rsp.op_ret && strcmp (rsp.op_errstr, "") == 0) { -                cli_err ("quota command : failed"); - +        if (rsp.op_ret) { +                ret = -1;                  if (global_state->mode & GLUSTER_MODE_XML)                          goto xml_output; -                goto out; -        } else if (strcmp (rsp.op_errstr, "")) + +                if (strcmp (rsp.op_errstr, ""))                          cli_err ("quota command failed : %s", rsp.op_errstr); +                else +                        cli_err ("quota command : failed"); + +                goto out; +        }          if (rsp.dict.dict_len) {                  /* Unserialize the dictionary */ diff --git a/cli/src/cli.h b/cli/src/cli.h index b71140a810b..1fe8ffff7fb 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -47,6 +47,10 @@ enum argp_option_keys {  #define GLUSTER_MODE_XML       (1 << 2) +#define GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH(abspath, volname, path)      \ +        snprintf (abspath, sizeof (abspath)-1,                          \ +                  DEFAULT_VAR_RUN_DIRECTORY"/%s%s", volname, path); +  #define GLUSTERFS_GET_AUX_MOUNT_PIDFILE(pidfile,volname) {               \                  snprintf (pidfile, PATH_MAX-1,                             \                            DEFAULT_VAR_RUN_DIRECTORY"/%s.pid", volname);  \ diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 08efb5c9f03..7862f6aa01b 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -2994,76 +2994,6 @@ backtrace_symbols(void *const *trace, size_t len)  #undef BELOW  #endif /* __NetBSD__ */ -/* TODO: extract common code from gf_get_soft_limit and gf_get_hard_limit into a - * function - */ -int -gf_get_soft_limit (char *limit, char **soft_limit) -{ -        int   colon_count   = 0; -        int   i             = 0; -        int   len           = 0; -        char *sl            = NULL; - -        len = strlen (limit); -        for (i = 0; i < len; i++) { -                if (limit[i] == ':') -                        colon_count++; -                if (colon_count == 2) -                        break; -        } - -        if (colon_count != 2) { -                gf_log ("common-utils", GF_LOG_DEBUG, "Soft-limit absent"); -                return 0; -        } - -        sl = GF_CALLOC (len - i, sizeof (char), gf_common_mt_char); -        if (!sl) -                return -1; -        strncpy (sl, &limit[i+1], len - i - 1); -        *soft_limit = sl; - -        return 1; -} - -int -gf_get_hard_limit (char *limit, char **hard_limit) -{ -        int    i                 = 0; -        int    hlbegin           = 0; -        int    len               = 0; -        char  *hl                = NULL; - -        len = strlen (limit); - -        for (i = 0; i < len; i++) { -                if (limit[i] == ':') -                        break; -        } - -        if (i == len) { -                gf_log ("common-utils", GF_LOG_ERROR, "Hard limit not found"); -                return -1; -        } - -        hlbegin = i + 1; -        i++; - -        while ((limit[i] != '\0') && (limit[i] != ':')) { -                i++; -        } - -        hl = GF_CALLOC (i - hlbegin + 1, sizeof (char), gf_common_mt_char); -        if (!hl) -                return -1; - -        strncpy (hl, &limit[hlbegin], i - hlbegin); -        *hard_limit = hl; - -        return 0; -} -  int  gf_skip_header_section (int fd, int header_len)  { diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index 500d34237f0..6f8436fcba0 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -615,9 +615,6 @@ size_t backtrace(void **, size_t);  char **backtrace_symbols(void *const *, size_t);  #endif -int gf_get_soft_limit (char *limit, char **soft_limit); -int gf_get_hard_limit (char *limit, char **hard_limit); -  gf_boolean_t  gf_is_service_running (char *pidfile, int *pid);  int diff --git a/xlators/features/quota/src/quota.c b/xlators/features/quota/src/quota.c index 3c6c31def42..7156edcad1c 100644 --- a/xlators/features/quota/src/quota.c +++ b/xlators/features/quota/src/quota.c @@ -4222,8 +4222,6 @@ struct volume_options options[] = {          {.key = {"default-soft-limit"},           .type = GF_OPTION_TYPE_PERCENT,           .default_value = "80%", -         .min = 0, -         .max = LONG_MAX,          },          {.key = {"soft-timeout"},           .type = GF_OPTION_TYPE_TIME, diff --git a/xlators/mgmt/glusterd/src/glusterd-quota.c b/xlators/mgmt/glusterd/src/glusterd-quota.c index 56a24c74306..f46f08787ab 100644 --- a/xlators/mgmt/glusterd/src/glusterd-quota.c +++ b/xlators/mgmt/glusterd/src/glusterd-quota.c @@ -26,6 +26,7 @@  #include "compat-errno.h"  #include <sys/wait.h> +#include <dlfcn.h>  const char *gd_quota_op_list[GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT+1] = { @@ -43,6 +44,9 @@ const char *gd_quota_op_list[GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT+1] = {  };  int +glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path, +                             char *gfid_str, int opcode, char **op_errstr); +int  __glusterd_handle_quota (rpcsvc_request_t *req)  {          int32_t                         ret = -1; @@ -153,108 +157,6 @@ out:          return ret;  } -/* At the end of the function, the variable @found will be set - * to true if the path to be removed was present in the limit-list, - * else will be false. - * - * In addition, the function does the following things: - * - * a. places the path to be removed, if found, in @removed_path, - * b. places the new limit list formed after removing @path's entry, in - *    @new_list. If @path is not found, the input limit string @quota_limits is - *    dup'd as is and placed in @new_list. - */ -int32_t -_glusterd_quota_remove_limits (char *quota_limits, char *path, -                               gf_boolean_t *found, char **new_list, -                               char **removed_path) -{ -        int      ret      = 0; -        int      i        = 0; -        int      size     = 0; -        int      len      = 0; -        int      pathlen  = 0; -        int      skiplen  = 0; -        int      flag     = 0; -        char    *limits   = NULL; -        char    *qlimits  = NULL; -        char    *rp       = NULL; - -        if (found != NULL) -                *found = _gf_false; - -        if (quota_limits == NULL) -                return -1; - -        qlimits = quota_limits; - -        pathlen = strlen (path); - -        len = strlen (qlimits); - -        limits = GF_CALLOC (len + 1, sizeof (char), gf_gld_mt_char); -        if (!limits) -                return -1; - -        while (i < len) { -                if (!memcmp ((void *) &qlimits [i], (void *)path, pathlen)) -                        if (qlimits [i + pathlen] == ':') { -                                flag = 1; -                                if (found != NULL) -                                        *found = _gf_true; -                        } - -                while (qlimits [i + size] != ',' && -                       qlimits [i + size] != '\0') -                        size++; - -                if (!flag) { -                        memcpy ((void *) &limits [i], (void *) &qlimits [i], size + 1); -                } else { -                        skiplen = size + 1; -                        size = len - i - size; -                        if (removed_path) { -                                rp = GF_CALLOC (skiplen, sizeof (char), gf_gld_mt_char); -                                if (!rp) { -                                        ret = -1; -                                        goto out; -                                } -                                strncpy (rp, &qlimits[i], skiplen - 1); -                                *removed_path = rp; -                        } -                        memcpy ((void *) &limits [i], (void *) &qlimits [i + skiplen], size); -                        break; -                } - -                i += size + 1; -                size = 0; -        } - -        len = strlen (limits); -        if (len == 0) -                goto out; - -        if (limits[len - 1] == ',') { -                limits[len - 1] = '\0'; -                len --; -        } - -        *new_list = GF_CALLOC (len + 1, sizeof (char), gf_gld_mt_char); -        if (!*new_list) { -                ret = -1; -                goto out; -        } - -        memcpy ((void *) *new_list, (void *) limits, len + 1); -        ret = 0; -out: -        GF_FREE (limits); -        if (ret != -1) -                ret = flag ? 0 : 1; - -        return ret; -} -  int32_t  glusterd_quota_initiate_fs_crawl (glusterd_conf_t *priv, char *volname)  { @@ -328,73 +230,6 @@ out:          return ret;  } -char * -glusterd_quota_get_limit_value (char *quota_limits, char *path) -{ -        int32_t i, j, k, l, len; -        int32_t pat_len, diff; -        char   *ret_str = NULL; - -        len = strlen (quota_limits); -        pat_len = strlen (path); -        i = 0; -        j = 0; - -        while (i < len) { -                j = i; -                k = 0; -                while (path [k] == quota_limits [j]) { -                        j++; -                        k++; -                } - -                l = j; - -                while (quota_limits [j] != ',' && -                       quota_limits [j] != '\0') -                        j++; - -                if (quota_limits [l] == ':' && pat_len == (l - i)) { -                        diff = j - i; -                        ret_str = GF_CALLOC (diff + 1, sizeof (char), -                                             gf_gld_mt_char); - -                        strncpy (ret_str, "a_limits [i], diff); - -                        break; -                } -                i = ++j; //skip ',' -        } - -        return ret_str; -} - -char* -_glusterd_quota_get_limit_usages (glusterd_volinfo_t *volinfo, -                                  char *path, char **op_errstr) -{ -        int32_t  ret          = 0; -        char    *quota_limits = NULL; -        char    *ret_str      = NULL; - -        if (volinfo == NULL) -                return NULL; - -        ret = glusterd_volinfo_get (volinfo, VKEY_FEATURES_LIMIT_USAGE, -                                    "a_limits); -        if (ret) -                return NULL; -        if (quota_limits == NULL) { -                ret_str = NULL; -                *op_errstr = gf_strdup ("Limit not set on any directory"); -        } else if (path == NULL) -                ret_str = gf_strdup (quota_limits); -        else -                ret_str = glusterd_quota_get_limit_value (quota_limits, path); - -        return ret_str; -} -  int32_t  glusterd_quota_get_default_soft_limit (glusterd_volinfo_t *volinfo,                                         dict_t *rsp_dict) @@ -477,6 +312,10 @@ glusterd_quota_enable (glusterd_volinfo_t *volinfo, char **op_errstr,          *crawl = _gf_true; +        ret = glusterd_store_quota_config (volinfo, NULL, NULL, +                                           GF_QUOTA_OPTION_TYPE_ENABLE, +                                           op_errstr); +          ret = 0;  out:          if (ret && op_errstr && !*op_errstr) @@ -552,6 +391,7 @@ out:          return ret;  } +  static int  glusterd_set_quota_limit (char *volname, char *path, char *hard_limit,                            char *soft_limit, char **op_errstr) @@ -575,8 +415,7 @@ glusterd_set_quota_limit (char *volname, char *path, char *hard_limit,          priv = this->private;          GF_ASSERT (priv); -        snprintf (abspath, sizeof (abspath)-1, "/tmp/%s%s", volname, path); - +        GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (abspath, volname, path);          ret = gf_lstat_dir (abspath, NULL);          if (ret) {                  gf_asprintf (op_errstr, "Failed to find the directory %s. " @@ -643,30 +482,117 @@ glusterd_update_quota_conf_version (glusterd_volinfo_t *volinfo)          return 0;  } +/*The function glusterd_find_gfid_match () does the following: + * Given a buffer of gfids, the number of bytes read and the key gfid that needs + * to be found, the function compares 16 bytes at a time from @buf against + * @gfid. + * + * What happens when the match is found: + * i. If the function was called as part of 'limit-usage' operation, the call + *    returns with write_byte_count = bytes_read + *ii. If the function as called as part of 'quota remove' operation, @buf + *    is modified in memory such that the match is deleted from the buffer, and + *    also @write_byte_count is set to original buf size minus the sixteen bytes + *    that was deleted as part of 'remove'. + * + * What happens when the match is not found in the current buffer: + * The function returns with write_byte_count = bytes_read, which means to say + * that the caller of this function must write the entire buffer to the tmp file + * and continue the search. + */ +static gf_boolean_t +glusterd_find_gfid_match (uuid_t gfid, unsigned char *buf, size_t bytes_read, +                          int opcode, size_t *write_byte_count) +{ +        int           gfid_index  = 0; +        int           shift_count = 0; +        unsigned char tmp_buf[17] = {0,}; + +        while (gfid_index != bytes_read) { +                memcpy ((void *)tmp_buf, (void *)&buf[gfid_index], 16); +                if (!uuid_compare (gfid, tmp_buf)) { +                        if (opcode == GF_QUOTA_OPTION_TYPE_REMOVE) { +                                shift_count = bytes_read - (gfid_index + 16); +                                memmove ((void *)&buf[gfid_index], +                                         (void *)&buf[gfid_index+16], +                                         shift_count); +                                *write_byte_count = bytes_read - 16; +                        } else { +                                *write_byte_count = bytes_read; +                        } +                        return _gf_true; +                } else { +                        gfid_index+=16; +                } +        } +        if (gfid_index == bytes_read) +                *write_byte_count = bytes_read; + +        return _gf_false; +} + +/* The function glusterd_copy_to_tmp_file() reads the "remaining" bytes from + * the source fd and writes them to destination fd, at the rate of 128K bytes + * of read+write at a time. + */ +  static int +glusterd_copy_to_tmp_file (int src_fd, int dst_fd) +{ +        int            ret         = 0; +        size_t         entry_sz    = 131072; +        ssize_t        bytes_read  = 0; +        unsigned char  buf[131072] = {0,}; +        xlator_t      *this        = NULL; + +        this = THIS; +        GF_ASSERT (this); + +        while ((bytes_read = read (src_fd, (void *)&buf, entry_sz)) > 0) { +                if (bytes_read % 16 != 0) { +                        gf_log (this->name, GF_LOG_ERROR, "quota.conf " +                                "corrupted"); +                        ret = -1; +                        goto out; +                } +                ret = write (dst_fd, (void *) buf, bytes_read); +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "write into quota.conf failed. Reason : %s", +                                strerror (errno)); +                        goto out; +                } +        } +        ret = 0; + +out: +        return ret; +} + +int  glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path,                               char *gfid_str, int opcode, char **op_errstr)  {          int                ret                   = -1; -        int                count                 = 0; -        xlator_t          *this                  = NULL; -        glusterd_conf_t   *conf                  = NULL; -        unsigned char      buf[16]               = {0,};          int                fd                    = -1;          int                conf_fd               = -1; -        size_t             entry_sz              = 16; +        size_t             entry_sz              = 131072; +        ssize_t            bytes_read            = 0; +        size_t            bytes_to_write         = 0; +        unsigned char      buf[131072]           = {0,};          uuid_t             gfid                  = {0,}; +        xlator_t          *this                  = NULL;          gf_boolean_t       found                 = _gf_false;          gf_boolean_t       modified              = _gf_false; - +        gf_boolean_t       is_file_empty         = _gf_false; +        gf_boolean_t       is_first_read         = _gf_true; +        glusterd_conf_t   *conf                  = NULL;          this = THIS;          GF_ASSERT (this);          conf = this->private;          GF_ASSERT (conf); -        uuid_parse (gfid_str, gfid); -          glusterd_store_create_quota_conf_sh_on_absence (volinfo);          fd = gf_store_mkstemp (volinfo->quota_conf_shandle); @@ -681,7 +607,6 @@ glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path,                  goto out;          } -          ret = glusterd_store_quota_conf_skip_header (this, conf_fd);          if (ret) {                  goto out; @@ -693,87 +618,82 @@ glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path,                          "file.");                  goto out;          } -        //gfid is stored as 16 bytes of 'raw' data -        entry_sz = 16; + +        /* Just create empty quota.conf file if create */ +        if (GF_QUOTA_OPTION_TYPE_ENABLE == opcode) { +                modified = _gf_true; +                goto out; +        } + +        /* Check if gfid_str is given for opts other than ENABLE */ +        if (!gfid_str) { +                ret = -1; +                goto out; +        } +        uuid_parse (gfid_str, gfid); +          for (;;) { -                ret = read (conf_fd, (void*)&buf, entry_sz) ; -                if (ret <= 0) { -                        //Finished reading all entries in the conf file +                bytes_read = read (conf_fd, (void*)&buf, entry_sz); +                if (bytes_read <= 0) { +                        /*The flag @is_first_read is TRUE when the loop is +                         * entered, and is set to false if the first read +                         * reads non-zero bytes of data. The flag is used to +                         * detect if quota.conf is an empty file, but for the +                         * header. This is done to log appropriate error message +                         * when 'quota remove' is attempted when there are no +                         * limits set on the given volume. +                         */ +                        if (is_first_read) +                                is_file_empty = _gf_true;                          break;                  } -                if (ret != 16) { -                        //This should never happen. We must have a multiple of -                        //entry_sz bytes in our configuration file. -                        gf_log (this->name, GF_LOG_CRITICAL, "Quota " -                                "configuration store may be corrupt."); +                if ((bytes_read % 16) != 0) { +                        gf_log (this->name, GF_LOG_ERROR, "quota.conf " +                                "corrupted");                          ret = -1;                          goto out;                  } -                count++; -                if (uuid_compare (gfid, buf)) { -                        /*If the gfids don't match, write @buf into tmp file. */ -                        ret = write (fd, (void*) buf, entry_sz); -                        if (ret == -1) { -                                gf_log (this->name, GF_LOG_ERROR, "Failed to " -                                        "write %s into quota configuration.", -                                        uuid_utoa (buf)); +                found = glusterd_find_gfid_match (gfid, buf, bytes_read, opcode, +                                                  &bytes_to_write); + +                ret = write (fd, (void *) buf, bytes_to_write); +                if (ret == -1) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "write into quota.conf failed. Reason : %s", +                                strerror (errno)); +                        goto out; +                } + +                /*If the match is found in this iteration, copy the rest of +                 * quota.conf into quota.conf.tmp and break. +                 * Else continue with the search. +                 */ +                if (found) { +                        ret = glusterd_copy_to_tmp_file (conf_fd, fd); +                        if (ret)                                  goto out; -                        } -                } else { -                        /*If a match is found, write @buf into tmp file for -                         * limit-usage only. -                         */ -                        if (opcode == GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) { -                                ret = write (fd, (void *) buf, entry_sz); -                                if (ret == -1) { -                                        gf_log (this->name, GF_LOG_ERROR, -                                                "Failed to write %s into quota " -                                                "configuration.", -                                                uuid_utoa (buf)); -                                        goto out; -                                } -                        } -                        found = _gf_true; +                        break;                  } +                is_first_read = _gf_false;          }          switch (opcode) {                  case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE: -                        /* -                         * count = 0 implies that the conf file is empty. -                         * In this case, we directly go ahead and write gfid_str -                         * into the tmp file. -                         * If count is non-zero and found is false, limit is -                         * being set on a gfid for the first time. So -                         * append gfid_str to the end of the file. -                         */ -                        if ((count == 0) || -                            ((count > 0) && (found == _gf_false))) { -                                memcpy (buf, gfid, 16); -                                ret = write (fd, (void *) buf, entry_sz); +                        if (!found) { +                                ret = write (fd, gfid, 16);                                  if (ret == -1) {                                          gf_log (this->name, GF_LOG_ERROR, -                                                "Failed to write %s into quota " -                                                "configuration.", -                                                uuid_utoa (buf)); +                                                "write into quota.conf failed. " +                                                "Reason : %s", +                                                strerror (errno));                                          goto out;                                  }                                  modified = _gf_true;                          } -                          break;                  case GF_QUOTA_OPTION_TYPE_REMOVE: -                        /* -                         * count = 0 is not a valid scenario and must be treated -                         * as error. -                         * If count is non-zero and found is false, then it is -                         * an error. -                         * If count is non-zero and found is true, take no -                         * action, by virtue of which the gfid is as good as -                         * deleted from the store. -                         */ -                        if (count == 0) { +                        if (is_file_empty) {                                  gf_asprintf (op_errstr, "Cannot remove limit on"                                               " %s. The quota configuration file"                                               " for volume %s is empty.", path, @@ -790,7 +710,6 @@ glusterd_store_quota_config (glusterd_volinfo_t *volinfo, char *path,                                  } else {                                          modified = _gf_true;                                  } -                          }                          break; @@ -928,8 +847,7 @@ glusterd_remove_quota_limit (char *volname, char *path, char **op_errstr)          priv = this->private;          GF_ASSERT (priv); -        snprintf (abspath, sizeof (abspath)-1, "/tmp/%s%s", volname, path); - +        GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (abspath, volname, path);          ret = gf_lstat_dir (abspath, NULL);          if (ret) {                  gf_asprintf (op_errstr, "Failed to find the directory %s. " @@ -1318,31 +1236,70 @@ out:          return ret;  } +static int +_glusterd_validate_quota_opts (dict_t *dict, int type, char **errstr) +{ +        int                     ret = -1; +        xlator_t                *this = THIS; +        void                    *quota_xl = NULL; +        volume_opt_list_t       opt_list = {{0},}; +        volume_option_t         *opt = NULL; +        char                    *key = NULL; +        char                    *value = NULL; + +        GF_ASSERT (dict); +        GF_ASSERT (this); + +        ret = xlator_volopt_dynload ("features/quota", "a_xl, &opt_list); +        if (ret) +                goto out; + +        switch (type) { +        case GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT: +        case GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT: +        case GF_QUOTA_OPTION_TYPE_ALERT_TIME: +        case GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT: +                key = (char *)gd_quota_op_list[type]; +                break; +        default: +                ret = -1; +                goto out; +        } + +        opt = xlator_volume_option_get_list (&opt_list, key); +        if (!opt) { +                ret = -1; +                gf_log (this->name, GF_LOG_ERROR, "Unknown option: %s", key); +                goto out; +        } +        ret = dict_get_str (dict, "value", &value); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Value not found for key %s", +                        key); +                goto out; +        } + +        ret = xlator_option_validate (this, key, value, opt, errstr); + +out: +        if (quota_xl) { +                dlclose (quota_xl); +                quota_xl = NULL; +        } +        return ret; +}  int  glusterd_op_stage_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict)  { -        int                 ret           = 0; -        int                 type          = 0; -        int                 i             = 0; -        char               *volname       = NULL; -        char               *value         = NULL; -        gf_boolean_t        exists        = _gf_false; -        dict_t             *ctx           = NULL; -        dict_t             *tmp_dict      = NULL; -        xlator_t           *this          = NULL; -        glusterd_conf_t    *priv          = NULL; -        glusterd_volinfo_t *volinfo       = NULL; - -        struct { -                int opcode; -                char *key; -        } optable[] = { -                {GF_QUOTA_OPTION_TYPE_ALERT_TIME, -                                                "features.alert-time"}, -                {GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT, "features.soft-timeout"}, -                {GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT, "features.hard-timeout"}, -                {GF_QUOTA_OPTION_TYPE_NONE, NULL} -        }; +        int                 ret            = 0; +        char               *volname        = NULL; +        gf_boolean_t        exists         = _gf_false; +        int                 type           = 0; +        xlator_t           *this           = NULL; +        glusterd_conf_t    *priv           = NULL; +        glusterd_volinfo_t *volinfo        = NULL; +        char               *hard_limit_str = NULL; +        uint64_t           hard_limit      = 0;          this = THIS;          GF_ASSERT (this); @@ -1352,10 +1309,6 @@ glusterd_op_stage_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict)          GF_ASSERT (dict);          GF_ASSERT (op_errstr); -        tmp_dict = dict_new (); -        if (!tmp_dict) -                goto out; -          ret = dict_get_str (dict, "volname", &volname);          if (ret) {                  gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name"); @@ -1407,57 +1360,73 @@ glusterd_op_stage_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict)                  goto out;          } -         ctx = glusterd_op_get_ctx(); -         if (ctx && (type == GF_QUOTA_OPTION_TYPE_ENABLE -                     || type == GF_QUOTA_OPTION_TYPE_LIST)) { -                 /* Fuse mount req. only for enable & list-usage options*/ -                 if (!glusterd_is_fuse_available ()) { -                         *op_errstr = gf_strdup ("Fuse unavailable"); -                         ret = -1; -                         goto out; -                 } -         } +        if ((GF_QUOTA_OPTION_TYPE_ENABLE != type) && +            (glusterd_check_if_quota_trans_enabled (volinfo) != 0)) { +                ret = -1; +                gf_asprintf (op_errstr, "Quota is not enabled on volume %s", +                             volname); +                goto out; +        }          switch (type) { -                case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE: -                case GF_QUOTA_OPTION_TYPE_REMOVE: -                        ret = glusterd_get_gfid_from_brick (dict, volinfo, -                                                            rsp_dict, -                                                            op_errstr); -                        if (ret) -                                goto out; -                        break; +        case GF_QUOTA_OPTION_TYPE_ENABLE: +        case GF_QUOTA_OPTION_TYPE_LIST: +                /* Fuse mount req. only for enable & list-usage options*/ +                if (is_origin_glusterd () && +                    !glusterd_is_fuse_available ()) { +                        *op_errstr = gf_strdup ("Fuse unavailable"); +                        ret = -1; +                        goto out; +                } +                break; -                case GF_QUOTA_OPTION_TYPE_ALERT_TIME: -                case GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT: -                case GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT: -                        ret = dict_get_str (dict, "value", &value); -                        if (ret) -                                goto out; +        case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE: +                ret = dict_get_str (dict, "hard-limit", &hard_limit_str); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "Faild to get hard-limit from dict"); +                        goto out; +                } +                ret = gf_string2bytesize (hard_limit_str, &hard_limit); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, +                                "Failed to convert hard-limit string to value"); +                        goto out; +                } +                if (hard_limit > INT64_MAX) { +                        ret = -1; +                        ret = gf_asprintf (op_errstr, "Hard-limit %s is greater" +                                           " than %"PRId64"bytes. Please set a " +                                           "smaller limit.", hard_limit_str, +                                           INT64_MAX); +                        gf_log (this->name, GF_LOG_ERROR, "hard-limit %s " +                                "greater than INT64_MAX", hard_limit_str); +                        goto out; +                } -                        for (i = 0; optable[i].key; i++) { -                                if (type == optable[i].opcode) -                                        break; -                        } -                        ret = dict_set_str (tmp_dict, optable[i].key, value); -                        if (ret) -                                goto out; +        case GF_QUOTA_OPTION_TYPE_REMOVE: +                ret = glusterd_get_gfid_from_brick (dict, volinfo, rsp_dict, +                                                    op_errstr); +                if (ret) +                        goto out; +                break; -                        ret = glusterd_validate_reconfopts (volinfo, tmp_dict, -                                                                    op_errstr); -                        if (ret) -                                goto out; -                        break; +        case GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT: +        case GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT: +        case GF_QUOTA_OPTION_TYPE_ALERT_TIME: +        case GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT: +                ret = _glusterd_validate_quota_opts (dict, type, op_errstr); +                if (ret) +                        goto out; +                break; -                default: -                        ret = 0; +        default: +                break;          }          ret = 0;   out: -        if (tmp_dict) -                dict_unref (tmp_dict);          if (ret && op_errstr && *op_errstr)                  gf_log (this->name, GF_LOG_ERROR, "%s", *op_errstr);          gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index c45f2445c34..2b45289406e 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -8829,8 +8829,7 @@ glusterd_remove_auxiliary_mount (char *volname)                  return 0;          } -        snprintf (mountdir, sizeof (mountdir)-1, "/tmp/%s", volname); - +        GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (mountdir, volname, "/");          runinit (&runner);          runner_add_args (&runner, "umount", diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index 52f8f26b4b6..d1c03d37b3b 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -394,6 +394,10 @@ typedef ssize_t (*gd_serialize_t) (struct iovec outmsg, void *args);  #define GLUSTERD_GET_QUOTAD_DIR(path, priv) \          snprintf (path, PATH_MAX, "%s/quotad", priv->workdir); +#define GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH(abspath, volname, path)      \ +        snprintf (abspath, sizeof (abspath)-1,                          \ +                  DEFAULT_VAR_RUN_DIRECTORY"/%s%s", volname, path); +  #define GLUSTERD_REMOVE_SLASH_FROM_PATH(path,string) do {               \                  int i = 0;                                              \                  for (i = 1; i < strlen (path); i++) {                   \  | 
