diff options
| author | Raghavendra G <rgowdapp@redhat.com> | 2013-11-14 17:05:26 +0530 | 
|---|---|---|
| committer | Anand Avati <avati@redhat.com> | 2013-11-26 10:25:27 -0800 | 
| commit | 0d5cd92f51c02b8d664000b5a2d22a2ddbbc23b6 (patch) | |
| tree | 3410752aa6e3389f33fcb43679318eb159ab2c94 /xlators/mgmt/glusterd/src | |
| parent | ab3ab1978a4768e9eed8e23b47e72b25046e607a (diff) | |
cli/glusterd: Changes to quota command Quota feature
 re-work.
Following are the cli commands that are new/re-worked:
======================================================
volume quota <VOLNAME> {enable|disable|list [<path> ...]|remove <path>| default-soft-limit <percent>} |
volume quota <VOLNAME> {limit-usage <path> <size> [<percent>]} |
volume quota <VOLNAME> {alert-time|soft-timeout|hard-timeout} {<time>}
volume status [all | <VOLNAME> [nfs|shd|<BRICK>|quotad]] [detail|clients|mem|inode|fd|callpool]
volume statedump <VOLNAME> [nfs|quotad] [all|mem|iobuf|callpool|priv|fd|inode|history]
glusterd changes:
=================
* Quota limits are now set as extended attributes by glusterd from
  the aux mount created by the cli.
* The gfids of the directories on which quota limits are set
  for a given volume are stored in
  /var/lib/glusterd/vols/<volname>/quota.conf file in binary format,
  and whose cksum and version is stored in
  /var/lib/glusterd/vols/<volname>/quota.cksum.
Original-author: Krutika Dhananjay <kdhananj@redhat.com>
Original-author: Krishnan Parthasarathi <kparthas@redhat.com>
BUG: 969461
Change-Id: If32bba36c67f9c2a30417af9c6389045b2b7c13b
Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
Signed-off-by: Raghavendra G <rgowdapp@redhat.com>
Reviewed-on: http://review.gluster.org/6003
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'xlators/mgmt/glusterd/src')
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-handler.c | 34 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-op-sm.c | 77 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-quota.c | 1182 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-rebalance.c | 2 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-replace-brick.c | 2 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 11 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-store.c | 162 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-store.h | 10 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-syncop.c | 83 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.c | 997 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.h | 51 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.c | 262 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.h | 2 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volume-ops.c | 56 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volume-set.c | 68 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd.c | 19 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd.h | 102 | 
17 files changed, 2536 insertions, 584 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index 740d04aa1e4..3aafa122b6a 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -54,6 +54,8 @@  #include <lvm2app.h>  #endif +extern glusterd_op_info_t opinfo; +  int glusterd_big_locked_notify (struct rpc_clnt *rpc, void *mydata,                                  rpc_clnt_event_t event,                                  void *data, rpc_clnt_notify_t notify_fn) @@ -307,10 +309,23 @@ _build_option_key (dict_t *d, char *k, data_t *v, void *tmp)          char                    reconfig_key[256] = {0, };          struct args_pack        *pack             = NULL;          int                     ret               = -1; +        xlator_t                *this             = NULL; +        glusterd_conf_t         *priv             = NULL; + +        this = THIS; +        GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv);          pack = tmp;          if (strcmp (k, GLUSTERD_GLOBAL_OPT_VERSION) == 0)                  return 0; + +        if (priv->op_version > GD_OP_VERSION_MIN) { +                if ((strcmp (k, "features.limit-usage") == 0) || +                    (strcmp (k, "features.soft-limit") == 0)) +                        return 0; +        }          snprintf (reconfig_key, 256, "volume%d.option.%s",                    pack->vol_count, k);          ret = dict_set_str (pack->dict, reconfig_key, v->data); @@ -3468,10 +3483,13 @@ __glusterd_handle_status_volume (rpcsvc_request_t *req)          glusterd_op_t                   cli_op  = GD_OP_STATUS_VOLUME;          char                            err_str[2048] = {0,};          xlator_t                       *this = NULL; +        glusterd_conf_t                *conf = NULL;          GF_ASSERT (req);          this = THIS;          GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf);          ret = xdr_to_generic (req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req);          if (ret < 0) { @@ -3512,6 +3530,14 @@ __glusterd_handle_status_volume (rpcsvc_request_t *req)                          "Received status volume req for volume %s", volname);          } +        if ((cmd & GF_CLI_STATUS_QUOTAD) && +            (conf->op_version == GD_OP_VERSION_MIN)) { +                snprintf (err_str, sizeof (err_str), "The cluster is operating " +                          "at version 1. Getting the status of quotad is not " +                          "allowed in this state."); +                ret = -1; +                goto out; +        }          ret = glusterd_op_begin_synctask (req, GD_OP_STATUS_VOLUME, dict); @@ -3810,6 +3836,7 @@ __glusterd_peer_rpc_notify (struct rpc_clnt *rpc, void *mydata,          glusterd_peerinfo_t  *peerinfo    = NULL;          glusterd_peerctx_t   *peerctx     = NULL;          gf_boolean_t         quorum_action = _gf_false; +        uuid_t               uuid;          peerctx = mydata;          if (!peerctx) @@ -3851,6 +3878,13 @@ __glusterd_peer_rpc_notify (struct rpc_clnt *rpc, void *mydata,                          glusterd_friend_remove_notify (peerctx);                          goto out;                  } +                glusterd_get_lock_owner (&uuid); +                if (!uuid_is_null (uuid) && +                    !uuid_compare (peerinfo->uuid, uuid)) { +                        glusterd_unlock (peerinfo->uuid); +                        if (opinfo.state.state != GD_OP_STATE_DEFAULT) +                                opinfo.state.state = GD_OP_STATE_DEFAULT; +                }                  peerinfo->connected = 0;                  break; diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c index 14f03a9a56a..501be66f826 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c @@ -888,18 +888,24 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr)          if (cmd & GF_CLI_STATUS_ALL)                  goto out; +        if ((cmd & GF_CLI_STATUS_QUOTAD) && +            (priv->op_version == GD_OP_VERSION_MIN)) { +                snprintf (msg, sizeof (msg), "The cluster is operating at " +                          "version 1. Getting the status of quotad is not " +                          "allowed in this state."); +                ret = -1; +                goto out; +        } +          ret = dict_get_str (dict, "volname", &volname);          if (ret) { -                gf_log (THIS->name, GF_LOG_ERROR, -                        "Unable to get volume name"); +                gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name");                  goto out;          }          ret = glusterd_volinfo_find (volname, &volinfo);          if (ret) { -                snprintf (msg, sizeof(msg), "Volume %s does not exist", -                          volname); -                gf_log (THIS->name, GF_LOG_ERROR, "%s", msg); +                snprintf (msg, sizeof(msg), FMTSTR_CHECK_VOL_EXISTS, volname);                  ret = -1;                  goto out;          } @@ -912,7 +918,6 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr)          if (!ret) {                  snprintf (msg, sizeof (msg), "Volume %s is not started",                            volname); -                gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);                  ret = -1;                  goto out;          } @@ -927,7 +932,6 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr)                          snprintf (msg, sizeof (msg),                                    "NFS server is disabled for volume %s",                                    volname); -                        gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);                          goto out;                  }          } else if ((cmd & GF_CLI_STATUS_SHD) != 0) { @@ -936,7 +940,6 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr)                          snprintf (msg, sizeof (msg),                                    "Volume %s is not of type replicate",                                    volname); -                        gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);                          goto out;                  } @@ -948,10 +951,15 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr)                          snprintf (msg, sizeof (msg),                                    "Self-heal Daemon is disabled for volume %s",                                    volname); -                        gf_log (THIS->name, GF_LOG_ERROR, "%s", msg);                          goto out;                  } - +        } else if ((cmd & GF_CLI_STATUS_QUOTAD) != 0) { +                if (!glusterd_is_volume_quota_enabled (volinfo)) { +                        ret = -1; +                        snprintf (msg, sizeof (msg), "Volume %s does not have " +                                  "quota enabled", volname); +                        goto out; +                }          } else if ((cmd & GF_CLI_STATUS_BRICK) != 0) {                  ret = dict_get_str (dict, "brick", &brick);                  if (ret) @@ -962,8 +970,6 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr)                  if (ret) {                          snprintf (msg, sizeof(msg), "No brick %s in"                                    " volume %s", brick, volname); -                        gf_log (THIS->name, GF_LOG_ERROR, "%s", msg); -                          ret = -1;                          goto out;                  } @@ -979,7 +985,7 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr)                          *op_errstr = gf_strdup ("Validation Failed for Status");          } -        gf_log (THIS->name, GF_LOG_DEBUG, "Returning: %d", ret); +        gf_log (this->name, GF_LOG_DEBUG, "Returning: %d", ret);          return ret;  } @@ -2216,6 +2222,14 @@ glusterd_op_status_volume (dict_t *dict, char **op_errstr,                  other_count++;                  node_count++; +        } else if ((cmd & GF_CLI_STATUS_QUOTAD) != 0) { +                ret = glusterd_add_node_to_dict ("quotad", rsp_dict, 0, +                                                 vol_opts); +                if (ret) +                        goto out; +                other_count++; +                node_count++; +          } else if ((cmd & GF_CLI_STATUS_BRICK) != 0) {                  ret = dict_get_str (dict, "brick", &brick);                  if (ret) @@ -2291,6 +2305,17 @@ glusterd_op_status_volume (dict_t *dict, char **op_errstr,                                          goto out;                                  other_count++;                                  node_count++; +                                other_index++; +                        } +                        if (glusterd_is_volume_quota_enabled (volinfo)) { +                                ret = glusterd_add_node_to_dict ("quotad", +                                                                 rsp_dict, +                                                                 other_index, +                                                                 vol_opts); +                                if (ret) +                                        goto out; +                                other_count++; +                                node_count++;                          }                  }          } @@ -4069,7 +4094,8 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr,                          break;                  case GD_OP_QUOTA: -                        ret = glusterd_op_stage_quota (dict, op_errstr); +                        ret = glusterd_op_stage_quota (dict, op_errstr, +                                                       rsp_dict);                          break;                  case GD_OP_STATUS_VOLUME: @@ -4942,9 +4968,6 @@ out:          return ret;  } - - -  static int  glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr,                                        struct list_head *selected) @@ -4984,6 +5007,7 @@ glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr,          case GF_CLI_STATUS_CALLPOOL:          case GF_CLI_STATUS_NFS:          case GF_CLI_STATUS_SHD: +        case GF_CLI_STATUS_QUOTAD:                  break;          default:                  goto out; @@ -5065,6 +5089,25 @@ glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr,                  list_add_tail (&pending_node->list, selected);                  ret = 0; +        } else if ((cmd & GF_CLI_STATUS_QUOTAD) != 0) { +                if (!glusterd_is_nodesvc_online ("quotad")) { +                        gf_log (this->name, GF_LOG_ERROR, "Quotad is not " +                                "running"); +                        ret = -1; +                        goto out; +                } +                pending_node = GF_CALLOC (1, sizeof (*pending_node), +                                          gf_gld_mt_pending_node_t); +                if (!pending_node) { +                        ret = -1; +                        goto out; +                } +                pending_node->node = priv->quotad; +                pending_node->type = GD_NODE_QUOTAD; +                pending_node->index = 0; +                list_add_tail (&pending_node->list, selected); + +                ret = 0;          } else {                  list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {                          brick_index++; diff --git a/xlators/mgmt/glusterd/src/glusterd-quota.c b/xlators/mgmt/glusterd/src/glusterd-quota.c index cef2baf599c..56a24c74306 100644 --- a/xlators/mgmt/glusterd/src/glusterd-quota.c +++ b/xlators/mgmt/glusterd/src/glusterd-quota.c @@ -21,9 +21,27 @@  #include "glusterd-utils.h"  #include "glusterd-volgen.h"  #include "run.h" +#include "syscall.h" +#include "byte-order.h" +#include "compat-errno.h"  #include <sys/wait.h> + +const char *gd_quota_op_list[GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT+1] = { +        [GF_QUOTA_OPTION_TYPE_NONE]               = "none", +        [GF_QUOTA_OPTION_TYPE_ENABLE]             = "enable", +        [GF_QUOTA_OPTION_TYPE_DISABLE]            = "disable", +        [GF_QUOTA_OPTION_TYPE_LIMIT_USAGE]        = "limit-usage", +        [GF_QUOTA_OPTION_TYPE_REMOVE]             = "remove", +        [GF_QUOTA_OPTION_TYPE_LIST]               = "list", +        [GF_QUOTA_OPTION_TYPE_VERSION]            = "version", +        [GF_QUOTA_OPTION_TYPE_ALERT_TIME]         = "alert-time", +        [GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT]       = "soft-timeout", +        [GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT]       = "hard-timeout", +        [GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT] = "default-soft-limit", +}; +  int  __glusterd_handle_quota (rpcsvc_request_t *req)  { @@ -31,15 +49,17 @@ __glusterd_handle_quota (rpcsvc_request_t *req)          gf_cli_req                      cli_req = {{0,}};          dict_t                         *dict = NULL;          glusterd_op_t                   cli_op = GD_OP_QUOTA; -        char                            operation[256] = {0, };          char                           *volname = NULL;          int32_t                         type = 0;          char                            msg[2048] = {0,};          xlator_t                       *this = NULL; +        glusterd_conf_t                *conf = NULL;          GF_ASSERT (req);          this = THIS;          GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf);          ret = xdr_to_generic (req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req);          if (ret < 0) { @@ -82,23 +102,16 @@ __glusterd_handle_quota (rpcsvc_request_t *req)                 goto out;          } -        switch (type) { -        case GF_QUOTA_OPTION_TYPE_ENABLE: -                strncpy (operation, "enable", sizeof (operation)); -                break; - -        case GF_QUOTA_OPTION_TYPE_DISABLE: -                strncpy (operation, "disable", sizeof (operation)); -                break; - -        case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE: -                strncpy (operation, "limit-usage", sizeof (operation)); -                break; +        if ((conf->op_version == GD_OP_VERSION_MIN) && +            (type > GF_QUOTA_OPTION_TYPE_VERSION)) { +                snprintf (msg, sizeof (msg), "Cannot execute command. The " +                         "cluster is operating at version %d. Quota command %s " +                         "is unavailable in this version", conf->op_version, +                         gd_quota_op_list[type]); +                ret = -1; +                goto out; +       } -        case GF_QUOTA_OPTION_TYPE_REMOVE: -                strncpy (operation, "remove", sizeof (operation)); -                break; -        }          ret = glusterd_op_begin_synctask (req, GD_OP_QUOTA, dict);  out: @@ -132,7 +145,6 @@ glusterd_check_if_quota_trans_enabled (glusterd_volinfo_t *volinfo)          }          if (flag == _gf_false) { -                gf_log ("", GF_LOG_ERROR, "first enable the quota translator");                  ret = -1;                  goto out;          } @@ -141,13 +153,21 @@ out:          return ret;  } -/* At the end of the function, the variable found will be set +/* 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) +_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; @@ -158,14 +178,15 @@ _glusterd_quota_remove_limits (char **quota_limits, char *path,          int      flag     = 0;          char    *limits   = NULL;          char    *qlimits  = NULL; +        char    *rp       = NULL;          if (found != NULL)                  *found = _gf_false; -        if (*quota_limits == NULL) +        if (quota_limits == NULL)                  return -1; -        qlimits = *quota_limits; +        qlimits = quota_limits;          pathlen = strlen (path); @@ -192,6 +213,15 @@ _glusterd_quota_remove_limits (char **quota_limits, char *path,                  } 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;                  } @@ -200,42 +230,27 @@ _glusterd_quota_remove_limits (char **quota_limits, char *path,                  size = 0;          } -        if (!flag) { -                ret = 1; -        } else { -                len = strlen (limits); - -                if (len == 0) { -                        GF_FREE (qlimits); - -                        *quota_limits = NULL; - -                        goto out; -                } - -                if (limits[len - 1] == ',') { -                        limits[len - 1] = '\0'; -                        len --; -                } - -                GF_FREE (qlimits); - -                qlimits = GF_CALLOC (len + 1, sizeof (char), gf_gld_mt_char); - -                if (!qlimits) { -                        ret = -1; -                        goto out; -                } - -                memcpy ((void *) qlimits, (void *) limits, len + 1); +        len = strlen (limits); +        if (len == 0) +                goto out; -                *quota_limits = qlimits; +        if (limits[len - 1] == ',') { +                limits[len - 1] = '\0'; +                len --; +        } -                ret = 0; +        *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;  } @@ -381,46 +396,38 @@ _glusterd_quota_get_limit_usages (glusterd_volinfo_t *volinfo,  }  int32_t -glusterd_quota_get_limit_usages (glusterd_conf_t *priv, -                                 glusterd_volinfo_t *volinfo, -                                 char *volname, -                                 dict_t *dict, -                                 char **op_errstr, -                                 dict_t *rsp_dict) +glusterd_quota_get_default_soft_limit (glusterd_volinfo_t *volinfo, +                                       dict_t *rsp_dict)  { -        int32_t i               = 0; -        int32_t ret             = 0; -        int32_t count           = 0; -        char    *path           = NULL; -        char    cmd_str [1024]  = {0, }; -        char   *ret_str         = NULL; +        int32_t            ret             = 0; +        xlator_t          *this            = NULL; +        glusterd_conf_t   *conf            = NULL; +        char              *default_limit   = NULL; +        char              *val             = NULL;          if (rsp_dict == NULL) -                return 0; - -        ret = dict_get_int32 (dict, "count", &count); -        if (ret < 0) -                goto out; +                return -1; -        if (count == 0) { -                ret_str = _glusterd_quota_get_limit_usages (volinfo, NULL, -                                                            op_errstr); -        } else { -                i = 0; -                while (count--) { -                        snprintf (cmd_str, 1024, "path%d", i++); +        this = THIS; +        GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf); -                        ret = dict_get_str (dict, cmd_str, &path); -                        if (ret < 0) -                                goto out; +        ret = glusterd_volinfo_get (volinfo, "features.default-soft-limit", +                                    &default_limit); +        if (default_limit) +                val = gf_strdup (default_limit); +        else +                val = gf_strdup ("80%"); -                        ret_str = _glusterd_quota_get_limit_usages (volinfo, path, op_errstr); -                } +        ret = dict_set_dynstr (rsp_dict, "default-soft-limit", val); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to set default " +                        "soft-limit into dict"); +                goto out;          } +        ret = 0; -        if (ret_str) { -                ret = dict_set_dynstr (rsp_dict, "limit_list", ret_str); -        }  out:          return ret;  } @@ -431,54 +438,74 @@ glusterd_quota_enable (glusterd_volinfo_t *volinfo, char **op_errstr,  {          int32_t         ret     = -1;          char            *quota_status = NULL; +        xlator_t        *this         = NULL; -        GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); -        GF_VALIDATE_OR_GOTO ("glusterd", crawl, out); -        GF_VALIDATE_OR_GOTO ("glusterd", op_errstr, out); +        this = THIS; +        GF_ASSERT (this); + +        GF_VALIDATE_OR_GOTO (this->name, volinfo, out); +        GF_VALIDATE_OR_GOTO (this->name, crawl, out); +        GF_VALIDATE_OR_GOTO (this->name, op_errstr, out);          if (glusterd_is_volume_started (volinfo) == 0) {                  *op_errstr = gf_strdup ("Volume is stopped, start volume "                                          "to enable quota."); +                ret = -1;                  goto out;          }          ret = glusterd_check_if_quota_trans_enabled (volinfo);          if (ret == 0) {                  *op_errstr = gf_strdup ("Quota is already enabled"); +                ret = -1;                  goto out;          }          quota_status = gf_strdup ("on");          if (!quota_status) { -                gf_log ("", GF_LOG_ERROR, "memory allocation failed"); -                *op_errstr = gf_strdup ("Enabling quota has been unsuccessful"); +                gf_log (this->name, GF_LOG_ERROR, "memory allocation failed"); +                ret = -1;                  goto out;          } -        ret = dict_set_dynstr (volinfo->dict, VKEY_FEATURES_QUOTA, quota_status); +        ret = dict_set_dynstr (volinfo->dict, VKEY_FEATURES_QUOTA, +                               quota_status);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "dict set failed"); -                *op_errstr = gf_strdup ("Enabling quota has been unsuccessful"); +                gf_log (this->name, GF_LOG_ERROR, "dict set failed");                  goto out;          } -        *op_errstr = gf_strdup ("Enabling quota has been successful"); -          *crawl = _gf_true;          ret = 0;  out: +        if (ret && op_errstr && !*op_errstr) +                gf_asprintf (op_errstr, "Enabling quota on volume %s has been " +                             "unsuccessful", volinfo->volname);          return ret;  }  int32_t  glusterd_quota_disable (glusterd_volinfo_t *volinfo, char **op_errstr)  { -        int32_t  ret            = -1; -        char    *quota_status   = NULL, *quota_limits = NULL; +        int32_t    ret            = -1; +        int        i              =  0; +        char      *quota_status   = NULL; +        char      *value          = NULL; +        xlator_t  *this           = NULL; +        glusterd_conf_t *conf     = NULL; +        char *quota_options[]     = {"features.soft-timeout", +                                     "features.hard-timeout", +                                     "features.alert-time", +                                     "features.default-soft-limit", NULL}; -        GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); -        GF_VALIDATE_OR_GOTO ("glusterd", op_errstr, out); +        this = THIS; +        GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf); + +        GF_VALIDATE_OR_GOTO (this->name, volinfo, out); +        GF_VALIDATE_OR_GOTO (this->name, op_errstr, out);          ret = glusterd_check_if_quota_trans_enabled (volinfo);          if (ret == -1) { @@ -488,47 +515,345 @@ glusterd_quota_disable (glusterd_volinfo_t *volinfo, char **op_errstr)          quota_status = gf_strdup ("off");          if (!quota_status) { -                gf_log ("", GF_LOG_ERROR, "memory allocation failed"); -                *op_errstr = gf_strdup ("Disabling quota has been unsuccessful"); +                gf_log (this->name, GF_LOG_ERROR, "memory allocation failed"); +                ret = -1;                  goto out;          }          ret = dict_set_dynstr (volinfo->dict, VKEY_FEATURES_QUOTA, quota_status);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "dict set failed"); -                *op_errstr = gf_strdup ("Disabling quota has been unsuccessful"); +                gf_log (this->name, GF_LOG_ERROR, "dict set failed");                  goto out;          } -        *op_errstr = gf_strdup ("Disabling quota has been successful"); +        for (i = 0; quota_options [i]; i++) { +                ret = glusterd_volinfo_get (volinfo, quota_options[i], &value); +                if (ret) { +                        gf_log (this->name, GF_LOG_INFO, "failed to get option" +                                                         " %s", +                                                         quota_options[i]); +                } else { +                dict_del (volinfo->dict, quota_options[i]); +                } +        } -        ret = glusterd_volinfo_get (volinfo, VKEY_FEATURES_LIMIT_USAGE, -                                    "a_limits); +        //Remove aux mount of the volume on every node in the cluster +        ret = glusterd_remove_auxiliary_mount (volinfo->volname); +        if (ret) +                goto out; + +        (void) glusterd_clean_up_quota_store (volinfo); + +        ret = 0; +out: +        if (ret && op_errstr && !*op_errstr) +                gf_asprintf (op_errstr, "Disabling quota on volume %s has been " +                             "unsuccessful", volinfo->volname); +        return ret; +} + +static int +glusterd_set_quota_limit (char *volname, char *path, char *hard_limit, +                          char *soft_limit, char **op_errstr) +{ +        int               ret                = -1; +        xlator_t         *this               = NULL; +        char              abspath[PATH_MAX]  = {0,}; +        glusterd_conf_t  *priv               = NULL; +        double           soft_lim            = 0; + +        typedef struct quota_limits { +                int64_t hl; +                int64_t sl; +        } __attribute__ ((__packed__)) quota_limits_t; + +	quota_limits_t existing_limit = {0,}; +	quota_limits_t new_limit = {0,}; + +        this = THIS; +        GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv); + +        snprintf (abspath, sizeof (abspath)-1, "/tmp/%s%s", volname, path); + +        ret = gf_lstat_dir (abspath, NULL);          if (ret) { -                gf_log ("", GF_LOG_WARNING, "failed to get the quota limits"); +                gf_asprintf (op_errstr, "Failed to find the directory %s. " +                             "Reason : %s", abspath, strerror (errno)); +                goto out; +        } + +        if (!soft_limit) { +                ret = sys_lgetxattr (abspath, +                                     "trusted.glusterfs.quota.limit-set", +                                     (void *)&existing_limit, +                                     sizeof (existing_limit)); +                if (ret < 0) { +                        switch (errno) { +                        case ENOATTR: +                                existing_limit.sl = -1; +                            break; +                        default: +                                gf_asprintf (op_errstr, "Failed to get the xattr " +                                             "'trusted.glusterfs.quota.limit-set' from " +                                             "%s. Reason : %s", abspath, +                                             strerror (errno)); +                                goto out; +                        } +                } else { +                        existing_limit.hl = ntoh64 (existing_limit.hl); +                        existing_limit.sl = ntoh64 (existing_limit.sl); +                } +                new_limit.sl = existing_limit.sl; +          } else { -                GF_FREE (quota_limits); +                ret = gf_string2percent (soft_limit, &soft_lim); +                if (ret) +                        goto out; +                new_limit.sl = soft_lim;          } -        dict_del (volinfo->dict, VKEY_FEATURES_LIMIT_USAGE); +        new_limit.sl = hton64 (new_limit.sl); + +        ret = gf_string2bytesize (hard_limit, (uint64_t*)&new_limit.hl); +        if (ret) +                goto out; + +        new_limit.hl = hton64 (new_limit.hl); + +        ret = sys_lsetxattr (abspath, "trusted.glusterfs.quota.limit-set", +                             (char *)(void *)&new_limit, sizeof (new_limit), 0); +        if (ret) { +                gf_asprintf (op_errstr, "setxattr of " +                             "'trusted.glusterfs.quota.limit-set' failed on %s." +                             " Reason : %s", abspath, strerror (errno)); +                goto out; +        } +        ret = 0;  out:          return ret;  } +static int +glusterd_update_quota_conf_version (glusterd_volinfo_t *volinfo) +{ +        volinfo->quota_conf_version++; +        return 0; +} + +static 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; +        uuid_t             gfid                  = {0,}; +        gf_boolean_t       found                 = _gf_false; +        gf_boolean_t       modified              = _gf_false; + + +        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); +        if (fd < 0) { +                ret = -1; +                goto out; +        } + +        conf_fd = open (volinfo->quota_conf_shandle->path, O_RDONLY); +        if (conf_fd == -1) { +                ret = -1; +                goto out; +        } + + +        ret = glusterd_store_quota_conf_skip_header (this, conf_fd); +        if (ret) { +                goto out; +        } + +        ret = glusterd_store_quota_conf_stamp_header (this, fd); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to add header to tmp " +                        "file."); +                goto out; +        } +        //gfid is stored as 16 bytes of 'raw' data +        entry_sz = 16; +        for (;;) { +                ret = read (conf_fd, (void*)&buf, entry_sz) ; +                if (ret <= 0) { +                        //Finished reading all entries in the conf file +                        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."); +                        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)); +                                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; +                } +        } + +        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 (ret == -1) { +                                        gf_log (this->name, GF_LOG_ERROR, +                                                "Failed to write %s into quota " +                                                "configuration.", +                                                uuid_utoa (buf)); +                                        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) { +                                gf_asprintf (op_errstr, "Cannot remove limit on" +                                             " %s. The quota configuration file" +                                             " for volume %s is empty.", path, +                                             volinfo->volname); +                                ret = -1; +                                goto out; +                        } else { +                                if (!found) { +                                        gf_asprintf (op_errstr, "Error. gfid %s" +                                                     " for path %s not found in" +                                                     " store", gfid_str, path); +                                        ret = -1; +                                        goto out; +                                } else { +                                        modified = _gf_true; +                                } + +                        } +                        break; + +                default: +                        ret = 0; +                        break; +        } + +        if (modified) +                glusterd_update_quota_conf_version (volinfo); + +        ret = 0; +out: +        if (conf_fd != -1) { +                close (conf_fd); +        } + +        if (fd != -1) { +                close (fd); +        } + +        if (ret && (fd > 0)) { +                gf_store_unlink_tmppath (volinfo->quota_conf_shandle); +        } else if (!ret) { +                ret = gf_store_rename_tmppath (volinfo->quota_conf_shandle); +                if (modified) { +                        ret = glusterd_compute_cksum (volinfo, _gf_true); +                        if (ret) { +                                gf_log (this->name, GF_LOG_ERROR, "Failed to " +                                        "compute cksum for quota conf file"); +                                goto out; +                        } + +                        ret = glusterd_store_save_quota_version_and_cksum +                                                                      (volinfo); +                        if (ret) { +                                gf_log (this->name, GF_LOG_ERROR, "Failed to " +                                        "store quota version and cksum"); +                                goto out; +                        } +                } +        } + +        return ret; +} +  int32_t -glusterd_quota_limit_usage (glusterd_volinfo_t *volinfo, dict_t *dict, char **op_errstr) +glusterd_quota_limit_usage (glusterd_volinfo_t *volinfo, dict_t *dict, +                            int opcode, char **op_errstr)  { -        int32_t          ret    = -1; -        char            *path   = NULL; -        char            *limit  = NULL; -        char            *value  = NULL; -        char             msg [1024] = {0,}; -        char            *quota_limits = NULL; +        int32_t          ret                = -1; +        char            *path               = NULL; +        char            *hard_limit         = NULL; +        char            *soft_limit         = NULL; +        char            *gfid_str           = NULL; +        xlator_t        *this               = NULL; -        GF_VALIDATE_OR_GOTO ("glusterd", dict, out); -        GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); -        GF_VALIDATE_OR_GOTO ("glusterd", op_errstr, out); +        this = THIS; +        GF_ASSERT (this); + +        GF_VALIDATE_OR_GOTO (this->name, dict, out); +        GF_VALIDATE_OR_GOTO (this->name, volinfo, out); +        GF_VALIDATE_OR_GOTO (this->name, op_errstr, out);          ret = glusterd_check_if_quota_trans_enabled (volinfo);          if (ret == -1) { @@ -537,141 +862,217 @@ glusterd_quota_limit_usage (glusterd_volinfo_t *volinfo, dict_t *dict, char **op                  goto out;          } -        ret = glusterd_volinfo_get (volinfo, VKEY_FEATURES_LIMIT_USAGE, -                                    "a_limits); -        if (ret) { -                gf_log ("", GF_LOG_ERROR, "failed to get the quota limits"); -                *op_errstr = gf_strdup ("failed to set limit"); -                goto out; -        } -          ret = dict_get_str (dict, "path", &path);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "Unable to fetch quota limits" ); -                *op_errstr = gf_strdup ("failed to set limit"); +                gf_log (this->name, GF_LOG_ERROR, "Unable to fetch path");                  goto out;          } +        ret = gf_canonicalize_path (path); +        if (ret) +                goto out; -        ret = dict_get_str (dict, "limit", &limit); +        ret = dict_get_str (dict, "hard-limit", &hard_limit);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "Unable to fetch quota limits" ); -                *op_errstr = gf_strdup ("failed to set limit"); +                gf_log (this->name, GF_LOG_ERROR, "Unable to fetch hard limit");                  goto out;          } -        if (quota_limits) { -                ret = _glusterd_quota_remove_limits ("a_limits, path, NULL); -                if (ret == -1) { -                        gf_log ("", GF_LOG_ERROR, "Unable to allocate memory"); -                        *op_errstr = gf_strdup ("failed to set limit"); +        if (dict_get (dict, "soft-limit")) { +                ret = dict_get_str (dict, "soft-limit", &soft_limit); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, "Unable to fetch " +                                "soft limit");                          goto out;                  }          } -        if (quota_limits == NULL) { -                ret = gf_asprintf (&value, "%s:%s", path, limit); -                if (ret == -1) { -                        gf_log ("", GF_LOG_ERROR, "Unable to allocate memory"); -                        *op_errstr = gf_strdup ("failed to set limit"); -                        goto out; -                } -        } else { -                ret = gf_asprintf (&value, "%s,%s:%s", -                                   quota_limits, path, limit); -                if (ret == -1) { -                        gf_log ("", GF_LOG_ERROR, "Unable to allocate memory"); -                        *op_errstr = gf_strdup ("failed to set limit"); +        if (is_origin_glusterd ()) { +                ret = glusterd_set_quota_limit (volinfo->volname, path, +                                                hard_limit, soft_limit, +                                                op_errstr); +                if (ret)                          goto out; -                } +        } -                GF_FREE (quota_limits); +        ret = dict_get_str (dict, "gfid", &gfid_str); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get gfid of path " +                        "%s", path); +                goto out;          } -        quota_limits = value; +        ret = glusterd_store_quota_config (volinfo, path, gfid_str, opcode, +                                           op_errstr); +        if (ret) +                goto out; + +        ret = 0; +out: -        ret = dict_set_str (volinfo->dict, VKEY_FEATURES_LIMIT_USAGE, -                            quota_limits); +        if (ret && op_errstr && !*op_errstr) +                gf_asprintf (op_errstr, "Failed to set hard limit on path %s " +                             "for volume %s", path, volinfo->volname); +        return ret; +} + +static int +glusterd_remove_quota_limit (char *volname, char *path, char **op_errstr) +{ +        int               ret                = -1; +        xlator_t         *this               = NULL; +        char              abspath[PATH_MAX]  = {0,}; +        glusterd_conf_t  *priv               = NULL; + +        this = THIS; +        GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv); + +        snprintf (abspath, sizeof (abspath)-1, "/tmp/%s%s", volname, path); + +        ret = gf_lstat_dir (abspath, NULL);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "Unable to set quota limits" ); -                *op_errstr = gf_strdup ("failed to set limit"); +                gf_asprintf (op_errstr, "Failed to find the directory %s. " +                             "Reason : %s", abspath, strerror (errno));                  goto out;          } -        snprintf (msg, 1024, "limit set on %s", path); -        *op_errstr = gf_strdup (msg); +        ret = sys_lremovexattr (abspath, "trusted.glusterfs.quota.limit-set"); +        if (ret) { +                gf_asprintf (op_errstr, "removexattr failed on %s. Reason : %s", +                             abspath, strerror (errno)); +                goto out; +        }          ret = 0; +  out:          return ret;  }  int32_t -glusterd_quota_remove_limits (glusterd_volinfo_t *volinfo, dict_t *dict, char **op_errstr) +glusterd_quota_remove_limits (glusterd_volinfo_t *volinfo, dict_t *dict, +                              int opcode, char **op_errstr)  {          int32_t         ret                   = -1; -        char            str [PATH_MAX + 1024] = {0,}; -        char            *quota_limits         = NULL;          char            *path                 = NULL; -        gf_boolean_t     flag                 = _gf_false; +        char            *gfid_str             = NULL; +        xlator_t        *this                 = NULL; -        GF_VALIDATE_OR_GOTO ("glusterd", dict, out); -        GF_VALIDATE_OR_GOTO ("glusterd", volinfo, out); -        GF_VALIDATE_OR_GOTO ("glusterd", op_errstr, out); +        this = THIS; +        GF_ASSERT (this); + +        GF_VALIDATE_OR_GOTO (this->name, dict, out); +        GF_VALIDATE_OR_GOTO (this->name, volinfo, out); +        GF_VALIDATE_OR_GOTO (this->name, op_errstr, out);          ret = glusterd_check_if_quota_trans_enabled (volinfo);          if (ret == -1) { -                *op_errstr = gf_strdup ("Quota is disabled, please enable quota"); +                *op_errstr = gf_strdup ("Quota is disabled, please enable " +                                        "quota");                  goto out;          } -        ret = glusterd_volinfo_get (volinfo, VKEY_FEATURES_LIMIT_USAGE, -                                    "a_limits); +        ret = dict_get_str (dict, "path", &path);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "failed to get the quota limits"); +                gf_log (this->name, GF_LOG_ERROR, "Unable to fetch path");                  goto out;          } -        ret = dict_get_str (dict, "path", &path); -        if (ret) { -                gf_log ("", GF_LOG_ERROR, "Unable to fetch quota limits" ); +        ret = gf_canonicalize_path (path); +        if (ret)                  goto out; + +        if (is_origin_glusterd ()) { +                ret = glusterd_remove_quota_limit (volinfo->volname, path, +                                                   op_errstr); +                if (ret) +                        goto out;          } -        ret = _glusterd_quota_remove_limits ("a_limits, path, &flag); -        if (ret == -1) { -                if (flag == _gf_true) -                        snprintf (str, sizeof (str), "Removing limit on %s has " -                                  "been unsuccessful", path); -                else -                        snprintf (str, sizeof (str), "%s has no limit set", path); -                *op_errstr = gf_strdup (str); +        ret = dict_get_str (dict, "gfid", &gfid_str); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get gfid of path " +                        "%s", path);                  goto out; -        } else { -                if (flag == _gf_true) -                        snprintf (str, sizeof (str), "Removed quota limit on " -                                  "%s", path); -                else -                        snprintf (str, sizeof (str), "no limit set on %s", -                                  path); -                *op_errstr = gf_strdup (str); -        } - -        if (quota_limits) { -                ret = dict_set_str (volinfo->dict, VKEY_FEATURES_LIMIT_USAGE, -                                    quota_limits); -                if (ret) { -                        gf_log ("", GF_LOG_ERROR, "Unable to set quota limits" ); -                        goto out; -                } -        } else { -               dict_del (volinfo->dict, VKEY_FEATURES_LIMIT_USAGE);          } +        ret = glusterd_store_quota_config (volinfo, path, gfid_str, opcode, +                                           op_errstr); +        if (ret) +                goto out; + +          ret = 0;  out:          return ret;  } +int +glusterd_set_quota_option (glusterd_volinfo_t *volinfo, dict_t *dict, +                           char *key, char **op_errstr) +{ +        int        ret    = 0; +        char      *value  = NULL; +        xlator_t  *this   = NULL; +        char      *option = NULL; + +        this = THIS; +        GF_ASSERT (this); + +        ret = glusterd_check_if_quota_trans_enabled (volinfo); +        if (ret == -1) { +                gf_asprintf (op_errstr, "Cannot set %s. Quota on volume %s is " +                                        "disabled", key, volinfo->volname); +                return -1; +        } + +        ret = dict_get_str (dict, "value", &value); +        if(ret) { +                gf_log (this->name, GF_LOG_ERROR, "Option value absent."); +                return -1; +        } + +        option = gf_strdup (value); +        ret = dict_set_dynstr (volinfo->dict, key, option); +        if(ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to set option %s", +                        key); +                return -1; +        } + +        return 0; +} + +static int +glusterd_quotad_op (int opcode) +{ +        int ret = -1; + +        switch (opcode) { +                case GF_QUOTA_OPTION_TYPE_ENABLE: +                case GF_QUOTA_OPTION_TYPE_DISABLE: + +                        if (glusterd_all_volumes_with_quota_stopped ()) +                                ret = glusterd_quotad_stop (); +                        else +                                ret = glusterd_check_generate_start_quotad (); +                        break; + +                case GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT: +                case GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT: +                case GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT: +                case GF_QUOTA_OPTION_TYPE_ALERT_TIME: + +                        ret = glusterd_reconfigure_quotad (); +                        break; + +                default: +                        ret = 0; +                        break; +        } +        return ret; +}  int  glusterd_op_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict) @@ -682,76 +1083,120 @@ glusterd_op_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict)          int                     type         = -1;          gf_boolean_t            start_crawl  = _gf_false;          glusterd_conf_t        *priv         = NULL; +        xlator_t               *this         = NULL;          GF_ASSERT (dict);          GF_ASSERT (op_errstr); -        priv = THIS->private; +        this = THIS; +        GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv);          ret = dict_get_str (dict, "volname", &volname);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "Unable to get volume name " ); +                gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name");                  goto out;          }          ret = glusterd_volinfo_find (volname, &volinfo);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "Unable to allocate memory"); +                gf_asprintf (op_errstr, FMTSTR_CHECK_VOL_EXISTS, volname);                  goto out;          }          ret = dict_get_int32 (dict, "type", &type); -        if (type == GF_QUOTA_OPTION_TYPE_ENABLE) { -                ret = glusterd_quota_enable (volinfo, op_errstr, &start_crawl); -                if (ret < 0) -                        goto out; - -                goto create_vol; +        if ((priv->op_version == GD_OP_VERSION_MIN) && +            (type > GF_QUOTA_OPTION_TYPE_VERSION)) { +                gf_asprintf (op_errstr, "Volume quota failed. The cluster is " +                                        "operating at version %d. Quota command" +                                        " %s is unavailable in this version.", +                                        priv->op_version, +                                        gd_quota_op_list[type]); +                ret = -1; +                goto out;          } -        if (type == GF_QUOTA_OPTION_TYPE_DISABLE) { -                ret = glusterd_quota_disable (volinfo, op_errstr); -                if (ret < 0) -                        goto out; +        switch (type) { +                case GF_QUOTA_OPTION_TYPE_ENABLE: +                        ret = glusterd_quota_enable (volinfo, op_errstr, +                                                     &start_crawl); +                        if (ret < 0) +                                goto out; +                        break; -                goto create_vol; -        } +                case GF_QUOTA_OPTION_TYPE_DISABLE: +                        ret = glusterd_quota_disable (volinfo, op_errstr); +                        if (ret < 0) +                                goto out; -        if (type == GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) { -                ret = glusterd_quota_limit_usage (volinfo, dict, op_errstr); -                if (ret < 0) +                        break; + +                case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE: +                        ret = glusterd_quota_limit_usage (volinfo, dict, type, +                                                          op_errstr);                          goto out; -                goto create_vol; -        } +                case GF_QUOTA_OPTION_TYPE_REMOVE: +                        ret = glusterd_quota_remove_limits (volinfo, dict, type, +                                                            op_errstr); +                        goto out; -        if (type == GF_QUOTA_OPTION_TYPE_REMOVE) { -                ret = glusterd_quota_remove_limits (volinfo, dict, op_errstr); -                if (ret < 0) +                case GF_QUOTA_OPTION_TYPE_LIST: +                        ret = glusterd_check_if_quota_trans_enabled (volinfo); +                        if (ret == -1) { +                                *op_errstr = gf_strdup ("Cannot list limits, " +                                                        "quota is disabled"); +                                goto out; +                        } +                        ret = glusterd_quota_get_default_soft_limit (volinfo, +                                                               rsp_dict);                          goto out; -                goto create_vol; -        } +                case GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT: +                        ret = glusterd_set_quota_option (volinfo, dict, +                                                        "features.soft-timeout", +                                                         op_errstr); +                        if (ret) +                                goto out; +                        break; -        if (type == GF_QUOTA_OPTION_TYPE_LIST) { -                ret = glusterd_check_if_quota_trans_enabled (volinfo); -                if (ret == -1) { -                        *op_errstr = gf_strdup ("cannot list the limits, " -                                                "quota is disabled"); -                        goto out; -                } +                case GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT: +                        ret = glusterd_set_quota_option (volinfo, dict, +                                                        "features.hard-timeout", +                                                         op_errstr); +                        if (ret) +                                goto out; +                        break; -                ret = glusterd_quota_get_limit_usages (priv, volinfo, volname, -                                                       dict, op_errstr, rsp_dict); +                case GF_QUOTA_OPTION_TYPE_ALERT_TIME: +                        ret = glusterd_set_quota_option (volinfo, dict, +                                                         "features.alert-time", +                                                         op_errstr); +                        if (ret) +                                goto out; +                        break; -                goto out; +                case GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT: +                        ret = glusterd_set_quota_option (volinfo, dict, +                                                  "features.default-soft-limit", +                                                  op_errstr); +                        if (ret) +                                goto out; +                        break; + +                default: +                        gf_asprintf (op_errstr, "Quota command failed. Invalid " +                                     "opcode"); +                        ret = -1; +                        goto out;          } -create_vol: +          ret = glusterd_create_volfiles_and_notify_services (volinfo);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "Unable to re-create volfile for" -                                          " 'quota'"); +                gf_log (this->name, GF_LOG_ERROR, "Unable to re-create " +                                                  "volfiles");                  ret = -1;                  goto out;          } @@ -760,81 +1205,262 @@ create_vol:          if (ret)                  goto out; -        if (GLUSTERD_STATUS_STARTED == volinfo->status) -                ret = glusterd_check_generate_start_nfs (); - -        ret = 0; +        if (GLUSTERD_STATUS_STARTED == volinfo->status) { +                if (priv->op_version == GD_OP_VERSION_MIN) +                        ret = glusterd_check_generate_start_nfs (); +        } -out:          if (rsp_dict && start_crawl == _gf_true)                  glusterd_quota_initiate_fs_crawl (priv, volname); -        if (rsp_dict && *op_errstr) { -                ret = dict_set_dynstr (rsp_dict, "errstr", *op_errstr); +        if (priv->op_version > GD_OP_VERSION_MIN) { +                ret = glusterd_quotad_op (type); +                if (ret) +                        goto out; +        } +        ret = 0; +out: +        return ret; +} + +/* + * glusterd_get_gfid_from_brick() fetches the 'trusted.gfid' attribute of @path + * from each brick in the backend and places the same in the rsp_dict with the + * keys being gfid0, gfid1, gfid2 and so on. The absence of @path in the backend + * is not treated as error. + */ +static int +glusterd_get_gfid_from_brick (dict_t *dict, glusterd_volinfo_t *volinfo, +                              dict_t *rsp_dict, char **op_errstr) +{ +        int                    ret                    = -1; +        int                    count                  = 0; +        char                  *path                   = NULL; +        char                   backend_path[PATH_MAX] = {0,}; +        xlator_t              *this                   = NULL; +        glusterd_conf_t       *priv                   = NULL; +        glusterd_brickinfo_t  *brickinfo              = NULL; +        char                   key[256]               = {0,}; +        char                  *gfid_str               = NULL; +        uuid_t                 gfid; + +        this = THIS; +        GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv); + +        ret = dict_get_str (dict, "path", &path); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get path"); +                goto out; +        } + +        list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { +                ret = glusterd_resolve_brick (brickinfo); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, FMTSTR_RESOLVE_BRICK, +                                brickinfo->hostname, brickinfo->path); +                        goto out; +                } + +                if (uuid_compare (brickinfo->uuid, MY_UUID)) +                        continue; + +                if (brickinfo->vg[0]) +                        continue; + +                snprintf (backend_path, sizeof (backend_path), "%s%s", +                          brickinfo->path, path); + +                ret = gf_lstat_dir (backend_path, NULL); +                if (ret) { +                        gf_log (this->name, GF_LOG_INFO, "Failed to find " +                                "directory %s. Reason : %s", backend_path, +                                strerror (errno)); +                        ret = 0; +                        continue; +                } +                ret = sys_lgetxattr (backend_path, GFID_XATTR_KEY, gfid, 16); +                if (ret < 0) { +                        gf_log (this->name, GF_LOG_INFO, "Failed to get " +                                "extended attribute %s for directory %s. " +                                "Reason : %s", GFID_XATTR_KEY, backend_path, +                                     strerror (errno)); +                        ret = 0; +                        continue; +                } +                snprintf (key, sizeof (key), "gfid%d", count); + +                gfid_str = gf_strdup (uuid_utoa (gfid)); +                if (!gfid_str) { +                        ret = -1; +                        goto out; +                } + +                ret = dict_set_dynstr (rsp_dict, key, gfid_str);                  if (ret) { -                        GF_FREE (*op_errstr); -                        gf_log ("", GF_LOG_DEBUG, -                                "failed to set error message in ctx"); +                        gf_log (this->name, GF_LOG_ERROR, "Failed to place " +                                "gfid of %s in dict", backend_path); +                        GF_FREE (gfid_str); +                        goto out;                  } -                *op_errstr = NULL; +                count++; +        } + +        ret = dict_set_int32 (rsp_dict, "count", count); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to set count"); +                goto out;          } +        ret = 0; +out:          return ret;  }  int -glusterd_op_stage_quota (dict_t *dict, char **op_errstr) +glusterd_op_stage_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict)  { -        int                ret           = 0; -        char              *volname       = NULL; -        gf_boolean_t       exists        = _gf_false; -        int                type          = 0; -        dict_t            *ctx           = NULL; +        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} +        }; + +        this = THIS; +        GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv);          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 ("", GF_LOG_ERROR, "Unable to get volume name"); +                gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name");                  goto out;          }          exists = glusterd_check_volume_exists (volname);          if (!exists) { -                gf_log ("", GF_LOG_ERROR, "Volume with name: %s " -                                "does not exist", -                                volname); -                *op_errstr = gf_strdup ("Invalid volume name"); +                gf_asprintf (op_errstr, FMTSTR_CHECK_VOL_EXISTS, volname); +                ret = -1; +                goto out; +        } +        ret = glusterd_volinfo_find (volname, &volinfo); +        if (ret) { +                gf_asprintf (op_errstr, FMTSTR_CHECK_VOL_EXISTS, volname); +                goto out; +        } + +        if (!glusterd_is_volume_started (volinfo)) { +                *op_errstr = gf_strdup ("Volume is stopped, start volume " +                                        "before executing quota command.");                  ret = -1;                  goto out;          }          ret = dict_get_int32 (dict, "type", &type);          if (ret) { -                gf_log ("", GF_LOG_ERROR, "Unable to get 'type' for quota op"); -                *op_errstr = gf_strdup ("Volume quota failed, internal error " -                                        ", unable to get type of operation"); +                *op_errstr = gf_strdup ("Volume quota failed, internal error, " +                                        "unable to get type of operation");                  goto out;          } +        if ((!glusterd_is_volume_quota_enabled (volinfo)) && +            (type != GF_QUOTA_OPTION_TYPE_ENABLE)) { +                *op_errstr = gf_strdup ("Quota is disabled, please enable " +                                        "quota"); +                ret = -1; +                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 ()) { -                        gf_log ("glusterd", GF_LOG_ERROR, "Unable to open /dev/" -                                "fuse (%s), quota command failed", -                                strerror (errno)); -                        *op_errstr = gf_strdup ("Fuse unavailable"); -                        ret = -1; -                        goto out; -                } +        if ((priv->op_version == GD_OP_VERSION_MIN) && +            (type > GF_QUOTA_OPTION_TYPE_VERSION)) { +                gf_asprintf (op_errstr, "Volume quota failed. The cluster is " +                                        "operating at version %d. Quota command" +                                        " %s is unavailable in this version.", +                                         priv->op_version, +                                         gd_quota_op_list[type]); +                ret = -1; +                goto out;          } -out: -        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); +         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; +                 } +         } -        return ret; +        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_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; + +                        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; + +                        ret = glusterd_validate_reconfopts (volinfo, tmp_dict, +                                                                    op_errstr); +                        if (ret) +                                goto out; +                        break; + +                default: +                        ret = 0; +        } + +        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); + +         return ret;  } diff --git a/xlators/mgmt/glusterd/src/glusterd-rebalance.c b/xlators/mgmt/glusterd/src/glusterd-rebalance.c index 214f40c668a..1b6ee293ae3 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rebalance.c +++ b/xlators/mgmt/glusterd/src/glusterd-rebalance.c @@ -141,7 +141,7 @@ __glusterd_defrag_notify (struct rpc_clnt *rpc, void *mydata,                  }                  UNLOCK (&defrag->lock); -                if (!glusterd_is_service_running (pidfile, NULL)) { +                if (!gf_is_service_running (pidfile, NULL)) {                          if (volinfo->rebal.defrag_status ==                                                  GF_DEFRAG_STATUS_STARTED) {                                  volinfo->rebal.defrag_status = diff --git a/xlators/mgmt/glusterd/src/glusterd-replace-brick.c b/xlators/mgmt/glusterd/src/glusterd-replace-brick.c index 29f6a0e0f7c..94b0383fec4 100644 --- a/xlators/mgmt/glusterd/src/glusterd-replace-brick.c +++ b/xlators/mgmt/glusterd/src/glusterd-replace-brick.c @@ -450,7 +450,7 @@ glusterd_op_stage_replace_brick (dict_t *dict, char **op_errstr,                  GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, src_brickinfo,                                              priv);                  if ((replace_op != GF_REPLACE_OP_COMMIT_FORCE) && -                    !glusterd_is_service_running (pidfile, NULL)) { +                    !gf_is_service_running (pidfile, NULL)) {                          snprintf(msg, sizeof(msg), "Source brick %s:%s "                                   "is not online.", src_brickinfo->hostname,                                   src_brickinfo->path); diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c index 38714a5ebf9..cd81383e921 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c @@ -96,13 +96,6 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret,                 break;          } -        case GD_OP_QUOTA: -        { -                if (ctx && !op_errstr) { -                        ret = dict_get_str (ctx, "errstr", &errstr); -                } -                break; -        }          case GD_OP_PROFILE_VOLUME:          {                  if (ctx && dict_get_int32 (ctx, "count", &count)) { @@ -142,6 +135,7 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret,          case GD_OP_LIST_VOLUME:          case GD_OP_CLEARLOCKS_VOLUME:          case GD_OP_HEAL_VOLUME: +        case GD_OP_QUOTA:          {                  /*nothing specific to be done*/                  break; @@ -1521,8 +1515,9 @@ glusterd_brick_op (call_frame_t *frame, xlator_t *this,                          continue;                  if ((pending_node->type == GD_NODE_NFS) || +                    (pending_node->type == GD_NODE_QUOTAD) ||                      ((pending_node->type == GD_NODE_SHD) && -                    (req_ctx->op == GD_OP_STATUS_VOLUME))) +                     (req_ctx->op == GD_OP_STATUS_VOLUME)))                          ret = glusterd_node_op_build_payload                                  (req_ctx->op,                                   (gd1_mgmt_brick_op_req **)&req, diff --git a/xlators/mgmt/glusterd/src/glusterd-store.c b/xlators/mgmt/glusterd/src/glusterd-store.c index 5902589f4b6..5b51aabaddb 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.c +++ b/xlators/mgmt/glusterd/src/glusterd-store.c @@ -698,6 +698,21 @@ glusterd_store_node_state_path_set (glusterd_volinfo_t *volinfo,                    GLUSTERD_NODE_STATE_FILE);  } +static void +glusterd_store_quota_conf_path_set (glusterd_volinfo_t *volinfo, +                                    char *quota_conf_path, size_t len) +{ +        char    voldirpath[PATH_MAX] = {0,}; +        GF_ASSERT (volinfo); +        GF_ASSERT (quota_conf_path); +        GF_ASSERT (len <= PATH_MAX); + +        glusterd_store_voldirpath_set (volinfo, voldirpath, +                                       sizeof (voldirpath)); +        snprintf (quota_conf_path, len, "%s/%s", voldirpath, +                  GLUSTERD_VOLUME_QUOTA_CONFIG); +} +  int32_t  glusterd_store_create_rbstate_shandle_on_absence (glusterd_volinfo_t *volinfo)  { @@ -743,6 +758,22 @@ glusterd_store_create_nodestate_sh_on_absence (glusterd_volinfo_t *volinfo)  }  int32_t +glusterd_store_create_quota_conf_sh_on_absence (glusterd_volinfo_t *volinfo) +{ +        char            quota_conf_path[PATH_MAX] = {0}; +        int32_t         ret                       = 0; + +        GF_ASSERT (volinfo); + +        glusterd_store_quota_conf_path_set (volinfo, quota_conf_path, +                                            sizeof (quota_conf_path)); +        ret = +          gf_store_handle_create_on_absence (&volinfo->quota_conf_shandle, +                                             quota_conf_path); + +        return ret; +} +int32_t  glusterd_store_brickinfos (glusterd_volinfo_t *volinfo, int vol_fd)  {          int32_t                 ret = 0; @@ -1083,7 +1114,7 @@ glusterd_store_volinfo (glusterd_volinfo_t *volinfo, glusterd_volinfo_ver_ac_t a                  goto out;          //checksum should be computed at the end -        ret = glusterd_volume_compute_cksum (volinfo); +        ret = glusterd_compute_cksum (volinfo, _gf_false);          if (ret)                  goto out; @@ -1897,6 +1928,14 @@ glusterd_store_retrieve_volume (char    *volname)                                  break;                          case 1: +                                /*The following strcmp check is to ensure that +                                 * glusterd does not restore the quota limits +                                 * into volinfo->dict post upgradation from 3.3 +                                 * to 3.4 as the same limits will now be stored +                                 * in xattrs on the respective directories. +                                 */ +                                if (!strcmp (key, "features.limit-usage")) +                                        break;                                  ret = dict_set_str(volinfo->dict, key,                                                     gf_strdup (value));                                  if (ret) { @@ -1971,7 +2010,23 @@ glusterd_store_retrieve_volume (char    *volname)          if (ret)                  goto out; -        ret = glusterd_volume_compute_cksum (volinfo); +        ret = glusterd_compute_cksum (volinfo, _gf_false); +        if (ret) +                goto out; + +        ret = glusterd_store_retrieve_quota_version (volinfo); +        if (ret) +                goto out; + +        ret = glusterd_store_create_quota_conf_sh_on_absence (volinfo); +        if (ret) +                goto out; + +        ret = glusterd_compute_cksum (volinfo, _gf_true); +        if (ret) +                goto out; + +        ret = glusterd_store_save_quota_version_and_cksum (volinfo);          if (ret)                  goto out; @@ -2565,3 +2620,106 @@ out:          gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);          return ret;  } + +int +glusterd_store_retrieve_quota_version (glusterd_volinfo_t *volinfo) +{ +        int                 ret                  = -1; +        uint32_t            version              = 0; +        char                cksum_path[PATH_MAX] = {0,}; +        char                path[PATH_MAX]       = {0,}; +        char               *version_str          = NULL; +        char               *tmp                  = NULL; +        xlator_t           *this                 = NULL; +        glusterd_conf_t    *conf                 = NULL; +        gf_store_handle_t  *handle               = NULL; + +        this = THIS; +        GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf); + +        GLUSTERD_GET_VOLUME_DIR (path, volinfo, conf); +        snprintf (cksum_path, sizeof (cksum_path), "%s/%s", path, +                  GLUSTERD_VOL_QUOTA_CKSUM_FILE); + +        ret = gf_store_handle_new (cksum_path, &handle); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Unable to get store handle " +                        "for %s", cksum_path); +                goto out; +        } + +        ret = gf_store_retrieve_value (handle, "version", &version_str); +        if (ret) { +                gf_log (this->name, GF_LOG_DEBUG, "Version absent"); +                ret = 0; +                goto out; +        } + +        version = strtoul (version_str, &tmp, 10); +         if (version < 0) { +                 gf_log (this->name, GF_LOG_DEBUG, "Invalid version number"); +                 goto out; +        } +        volinfo->quota_conf_version = version; +        ret = 0; + +out: +        if (version_str) +                GF_FREE (version_str); +        gf_store_handle_destroy (handle); +        return ret; +} + +int +glusterd_store_save_quota_version_and_cksum (glusterd_volinfo_t *volinfo) +{ +        int                 ret                  = -1; +        char                cksum_path[PATH_MAX] = {0,}; +        char                path[PATH_MAX]       = {0,}; +        xlator_t           *this                 = NULL; +        glusterd_conf_t    *conf                 = NULL; +        char                buf[256]             = {0,}; +        int                 fd                   = -1; + +        this = THIS; +        GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf); + +        GLUSTERD_GET_VOLUME_DIR (path, volinfo, conf); +        snprintf (cksum_path, sizeof (cksum_path), "%s/%s", path, +                  GLUSTERD_VOL_QUOTA_CKSUM_FILE); + +        fd = open (cksum_path, O_RDWR | O_APPEND | O_CREAT| O_TRUNC, 0600); + +        if (-1 == fd) { +                gf_log (this->name, GF_LOG_ERROR, "Unable to open %s," +                        "Reason: %s", cksum_path, strerror (errno)); +                ret = -1; +                goto out; +        } + +        snprintf (buf, sizeof (buf)-1, "%u", volinfo->quota_conf_cksum); +        ret = gf_store_save_value (fd, "cksum", buf); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to store cksum"); +                goto out; +        } + +        memset (buf, 0, sizeof (buf)); +        snprintf (buf, sizeof (buf)-1, "%u", volinfo->quota_conf_version); +        ret = gf_store_save_value (fd, "version", buf); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to store version"); +                goto out; +        } + +        ret = 0; + +out: +        if (fd != -1) +                close (fd); +        return ret; +} diff --git a/xlators/mgmt/glusterd/src/glusterd-store.h b/xlators/mgmt/glusterd/src/glusterd-store.h index ce1f766b1de..fadea8b2f14 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.h +++ b/xlators/mgmt/glusterd/src/glusterd-store.h @@ -128,4 +128,14 @@ glusterd_store_retrieve_options (xlator_t *this);  int32_t  glusterd_store_options (xlator_t *this, dict_t *opts); + +int32_t +glusterd_store_create_quota_conf_sh_on_absence (glusterd_volinfo_t *volinfo); + +int +glusterd_store_retrieve_quota_version (glusterd_volinfo_t *volinfo); + +int +glusterd_store_save_quota_version_and_cksum (glusterd_volinfo_t *volinfo); +  #endif diff --git a/xlators/mgmt/glusterd/src/glusterd-syncop.c b/xlators/mgmt/glusterd/src/glusterd-syncop.c index b3bab6fdcdd..33a865209fd 100644 --- a/xlators/mgmt/glusterd/src/glusterd-syncop.c +++ b/xlators/mgmt/glusterd/src/glusterd-syncop.c @@ -261,14 +261,18 @@ glusterd_syncop_aggr_rsp_dict (glusterd_op_t op, dict_t *aggr, dict_t *rsp)          break; -        case GD_OP_QUOTA:          case GD_OP_CLEARLOCKS_VOLUME:                  ret = glusterd_use_rsp_dict (aggr, rsp);                  if (ret)                          goto out; -          break; +        case GD_OP_QUOTA: +                ret = glusterd_volume_quota_copy_to_op_ctx_dict (aggr, rsp); +                if (ret) +                        goto out; +                break; +          case GD_OP_SYS_EXEC:                  ret = glusterd_sys_exec_output_rsp_dict (aggr, rsp);                  if (ret) @@ -474,7 +478,7 @@ _gd_syncop_stage_op_cbk (struct rpc_req *req, struct iovec *iov,          }          uuid_copy (args->uuid, rsp.uuid); -        if (rsp.op == GD_OP_REPLACE_BRICK) { +        if (rsp.op == GD_OP_REPLACE_BRICK || rsp.op == GD_OP_QUOTA) {                  pthread_mutex_lock (&args->lock_dict);                  {                          ret = glusterd_syncop_aggr_rsp_dict (rsp.op, args->dict, @@ -624,8 +628,8 @@ gd_syncop_mgmt_brick_op (struct rpc_clnt *rpc, glusterd_pending_node_t *pnode,          args.op_errno = ENOTCONN;          if ((pnode->type == GD_NODE_NFS) || -            ((pnode->type == GD_NODE_SHD) && -            (op == GD_OP_STATUS_VOLUME))) { +            (pnode->type == GD_NODE_QUOTAD) || +            ((pnode->type == GD_NODE_SHD) && (op == GD_OP_STATUS_VOLUME))) {                  ret = glusterd_node_op_build_payload                          (op, &req, dict_out); @@ -683,6 +687,7 @@ _gd_syncop_commit_op_cbk (struct rpc_req *req, struct iovec *iov,          glusterd_peerinfo_t         *peerinfo      = NULL;          int                          op_ret        = -1;          int                          op_errno      = -1; +        int                          type          = GF_QUOTA_OPTION_TYPE_NONE;          this  = THIS;          frame = myframe; @@ -725,16 +730,27 @@ _gd_syncop_commit_op_cbk (struct rpc_req *req, struct iovec *iov,          }          uuid_copy (args->uuid, rsp.uuid); -        pthread_mutex_lock (&args->lock_dict); -        { -                ret = glusterd_syncop_aggr_rsp_dict (rsp.op, args->dict, -                                                     rsp_dict); -                if (ret) -                        gf_log (this->name, GF_LOG_ERROR, "%s", -                                "Failed to aggregate response from " -                                " node/brick"); +        if (rsp.op == GD_OP_QUOTA) { +                ret = dict_get_int32 (args->dict, "type", &type); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, "Failed to get " +                                "opcode"); +                        goto out; +                } +        } + +        if ((rsp.op != GD_OP_QUOTA) || (type == GF_QUOTA_OPTION_TYPE_LIST)) { +                pthread_mutex_lock (&args->lock_dict); +                { +                        ret = glusterd_syncop_aggr_rsp_dict (rsp.op, args->dict, +                                                             rsp_dict); +                        if (ret) +                                gf_log (this->name, GF_LOG_ERROR, "%s", +                                        "Failed to aggregate response from " +                                        " node/brick"); +                } +                pthread_mutex_unlock (&args->lock_dict);          } -        pthread_mutex_unlock (&args->lock_dict);          op_ret = rsp.op_ret;          op_errno = rsp.op_errno; @@ -878,7 +894,7 @@ gd_stage_op_phase (struct list_head *peers, glusterd_op_t op, dict_t *op_ctx,                  goto stage_done;          } -        if ((op == GD_OP_REPLACE_BRICK)) { +        if ((op == GD_OP_REPLACE_BRICK || op == GD_OP_QUOTA)) {                  ret = glusterd_syncop_aggr_rsp_dict (op, op_ctx, rsp_dict);                  if (ret) {                          gf_log (this->name, GF_LOG_ERROR, "%s", @@ -913,6 +929,10 @@ stage_done:                                                 op, req_dict, op_ctx);                  peer_cnt++;          } + +        gf_log (this->name, GF_LOG_DEBUG, "Sent stage op req for 'Volume %s' " +                "to %d peers", gd_op_list[op], peer_cnt); +          gd_synctask_barrier_wait((&args), peer_cnt);          if (args.errstr) @@ -922,9 +942,14 @@ stage_done:          ret = args.op_ret; -        gf_log (this->name, GF_LOG_DEBUG, "Sent stage op req for 'Volume %s' " -                "to %d peers", gd_op_list[op], peer_cnt);  out: +        if ((ret == 0) && (op == GD_OP_QUOTA)) { +                ret = glusterd_validate_and_set_gfid (op_ctx, req_dict, +                                                      op_errstr); +                if (ret) +                        goto out; +        } +          if (rsp_dict)                  dict_unref (rsp_dict);          return ret; @@ -943,6 +968,7 @@ gd_commit_op_phase (struct list_head *peers, glusterd_op_t op, dict_t *op_ctx,          uuid_t              tmp_uuid        = {0};          char                *errstr         = NULL;          struct syncargs     args            = {0}; +        int                 type            = GF_QUOTA_OPTION_TYPE_NONE;          this = THIS;          rsp_dict = dict_new (); @@ -956,15 +982,28 @@ gd_commit_op_phase (struct list_head *peers, glusterd_op_t op, dict_t *op_ctx,                  hostname = "localhost";                  goto commit_done;          } -        if (op != GD_OP_SYNC_VOLUME) { -                ret =  glusterd_syncop_aggr_rsp_dict (op, op_ctx, rsp_dict); + +        if (op == GD_OP_QUOTA) { +                ret = dict_get_int32 (op_ctx, "type", &type);                  if (ret) { -                        gf_log (this->name, GF_LOG_ERROR, "%s", -                                "Failed to aggregate response " -                                "from node/brick"); +                        gf_log (this->name, GF_LOG_ERROR, "Failed to get " +                                "opcode");                          goto out;                  }          } + +        if (((op == GD_OP_QUOTA) && (type == GF_QUOTA_OPTION_TYPE_LIST)) || +            ((op != GD_OP_SYNC_VOLUME) && (op != GD_OP_QUOTA))) { + +                ret =  glusterd_syncop_aggr_rsp_dict (op, op_ctx, +                                                      rsp_dict); +                if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "%s", "Failed to aggregate " +                        "response from node/brick"); +                goto out; +                } +        } +          dict_unref (rsp_dict);          rsp_dict = NULL; diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index e093a566b09..c45f2445c34 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -565,6 +565,8 @@ glusterd_volinfo_delete (glusterd_volinfo_t *volinfo)                  dict_unref (volinfo->gsync_slaves);          GF_FREE (volinfo->logdir); +        gf_store_handle_destroy (volinfo->quota_conf_shandle); +          glusterd_auth_cleanup (volinfo);          GF_FREE (volinfo); @@ -1105,7 +1107,7 @@ glusterd_service_stop (const char *service, char *pidfile, int sig,          this = THIS;          GF_ASSERT (this); -        if (!glusterd_is_service_running (pidfile, &pid)) { +        if (!gf_is_service_running (pidfile, &pid)) {                  ret = 0;                  gf_log (this->name, GF_LOG_INFO, "%s already stopped", service);                  goto out; @@ -1118,7 +1120,7 @@ glusterd_service_stop (const char *service, char *pidfile, int sig,                  goto out;          sleep (1); -        if (glusterd_is_service_running (pidfile, NULL)) { +        if (gf_is_service_running (pidfile, NULL)) {                  ret = kill (pid, SIGKILL);                  if (ret) {                          gf_log (this->name, GF_LOG_ERROR, "Unable to " @@ -1284,7 +1286,7 @@ glusterd_volume_start_glusterfs (glusterd_volinfo_t  *volinfo,          if (ret)                  goto out;          GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, brickinfo, priv); -        if (glusterd_is_service_running (pidfile, NULL)) +        if (gf_is_service_running (pidfile, NULL))                  goto connect;          _reap_brick_process (pidfile, brickinfo->path); @@ -1617,89 +1619,85 @@ glusterd_sort_and_redirect (const char *src_filepath, int dest_fd)  }  int -glusterd_volume_compute_cksum (glusterd_volinfo_t  *volinfo) -{ -        int32_t                 ret = -1; -        glusterd_conf_t         *priv = NULL; -        char                    path[PATH_MAX] = {0,}; -        char                    cksum_path[PATH_MAX] = {0,}; -        char                    filepath[PATH_MAX] = {0,}; -        int                     fd = -1; -        uint32_t                cksum = 0; -        char                    buf[4096] = {0,}; +glusterd_volume_compute_cksum (glusterd_volinfo_t  *volinfo, char *cksum_path, +                               char *filepath, gf_boolean_t is_quota_conf, +                               uint32_t *cs) +{ +        int32_t                 ret                     = -1; +        uint32_t                cksum                   = 0; +        int                     fd                      = -1; +        int                     sort_fd                 = 0;          char                    sort_filepath[PATH_MAX] = {0}; -        gf_boolean_t            unlink_sortfile = _gf_false; -        int                     sort_fd = 0; -        xlator_t               *this = NULL; +        char                   *cksum_path_final        = NULL; +        char                    buf[4096]               = {0,}; +        gf_boolean_t            unlink_sortfile         = _gf_false; +        glusterd_conf_t        *priv                    = NULL; +        xlator_t               *this                    = NULL;          GF_ASSERT (volinfo);          this = THIS;          priv = THIS->private;          GF_ASSERT (priv); -        GLUSTERD_GET_VOLUME_DIR (path, volinfo, priv); - -        snprintf (cksum_path, sizeof (cksum_path), "%s/%s", -                  path, GLUSTERD_CKSUM_FILE); -          fd = open (cksum_path, O_RDWR | O_APPEND | O_CREAT| O_TRUNC, 0600);          if (-1 == fd) { -                gf_log (this->name, GF_LOG_ERROR, "Unable to open %s, errno: %d", -                        cksum_path, errno); +                gf_log (this->name, GF_LOG_ERROR, "Unable to open %s," +                        " errno: %d", cksum_path, errno);                  ret = -1;                  goto out;          } -        snprintf (filepath, sizeof (filepath), "%s/%s", path, -                  GLUSTERD_VOLUME_INFO_FILE); -        snprintf (sort_filepath, sizeof (sort_filepath), "/tmp/%s.XXXXXX", -                  volinfo->volname); +        if (!is_quota_conf) { +                snprintf (sort_filepath, sizeof (sort_filepath), +                          "/tmp/%s.XXXXXX", volinfo->volname); -        sort_fd = mkstemp (sort_filepath); -        if (sort_fd < 0) { -                gf_log (this->name, GF_LOG_ERROR, "Could not generate temp " -                        "file, reason: %s for volume: %s", strerror (errno), -                        volinfo->volname); -                goto out; -        } else { -                unlink_sortfile = _gf_true; -        } +                sort_fd = mkstemp (sort_filepath); +                if (sort_fd < 0) { +                        gf_log (this->name, GF_LOG_ERROR, "Could not generate " +                                "temp file, reason: %s for volume: %s", +                                strerror (errno), volinfo->volname); +                        goto out; +                } else { +                        unlink_sortfile = _gf_true; +                } -        /* sort the info file, result in sort_filepath */ +                /* sort the info file, result in sort_filepath */ -        ret = glusterd_sort_and_redirect (filepath, sort_fd); -        if (ret) { -                gf_log (this->name, GF_LOG_ERROR, "sorting info file failed"); -                goto out; -        } +                ret = glusterd_sort_and_redirect (filepath, sort_fd); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, "sorting info file " +                                "failed"); +                        goto out; +                } -        ret = close (sort_fd); -        if (ret) -                goto out; +                ret = close (sort_fd); +                if (ret) +                        goto out; +        } -        ret = get_checksum_for_path (sort_filepath, &cksum); +        cksum_path_final = is_quota_conf ? filepath : sort_filepath; +        ret = get_checksum_for_path (cksum_path_final, &cksum);          if (ret) { -                gf_log (this->name, GF_LOG_ERROR, "Unable to get checksum" -                        " for path: %s", sort_filepath); +                gf_log (this->name, GF_LOG_ERROR, "unable to get " +                        "checksum for path: %s", cksum_path_final);                  goto out;          } - -        snprintf (buf, sizeof (buf), "%s=%u\n", "info", cksum); -        ret = write (fd, buf, strlen (buf)); - -        if (ret <= 0) { -                ret = -1; -                goto out; +        if (!is_quota_conf) { +                snprintf (buf, sizeof (buf), "%s=%u\n", "info", cksum); +                ret = write (fd, buf, strlen (buf)); +                if (ret <= 0) { +                        ret = -1; +                        goto out; +                }          }          ret = get_checksum_for_file (fd, &cksum); -          if (ret)                  goto out; -        volinfo->cksum = cksum; +        *cs = cksum;  out:          if (fd > 0) @@ -1711,6 +1709,54 @@ out:          return ret;  } +int glusterd_compute_cksum (glusterd_volinfo_t *volinfo, +                               gf_boolean_t is_quota_conf) +{ +        int               ret                  = -1; +        uint32_t          cs                   = 0; +        char              cksum_path[PATH_MAX] = {0,}; +        char              path[PATH_MAX]       = {0,}; +        char              filepath[PATH_MAX]   = {0,}; +        glusterd_conf_t  *conf                 = NULL; +        xlator_t         *this                 = NULL; + +        this = THIS; +        GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf); + +        GLUSTERD_GET_VOLUME_DIR (path, volinfo, conf); + +        if (is_quota_conf) { +                snprintf (cksum_path, sizeof (cksum_path), "%s/%s", path, +                          GLUSTERD_VOL_QUOTA_CKSUM_FILE); +                snprintf (filepath, sizeof (filepath), "%s/%s", path, +                          GLUSTERD_VOLUME_QUOTA_CONFIG); +        } else { +                snprintf (cksum_path, sizeof (cksum_path), "%s/%s", path, +                          GLUSTERD_CKSUM_FILE); +                snprintf (filepath, sizeof (filepath), "%s/%s", path, +                          GLUSTERD_VOLUME_INFO_FILE); +        } + +        ret = glusterd_volume_compute_cksum (volinfo, cksum_path, filepath, +                                             is_quota_conf, &cs); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to compute checksum " +                        "for volume %s", volinfo->volname); +                goto out; +        } + +        if (is_quota_conf) +                volinfo->quota_conf_cksum = cs; +        else +                volinfo->cksum = cs; + +        ret = 0; +out: +        return ret; +} +  int  _add_dict_to_prdict (dict_t *this, char *key, data_t *value, void *data)  { @@ -2019,6 +2065,93 @@ out:          return ret;  } +int +glusterd_vol_add_quota_conf_to_dict (glusterd_volinfo_t *volinfo, dict_t* load, +                                     int vol_idx) +{ +        int   fd                    = -1; +        char  *gfid_str             = NULL; +        unsigned char  buf[16]      = {0}; +        char  key[PATH_MAX]         = {0}; +        int   gfid_idx              = 0; +        int   ret                   = -1; +        xlator_t *this              = NULL; + +        this = THIS; +        GF_ASSERT (this); + +        ret = glusterd_store_create_quota_conf_sh_on_absence (volinfo); +        if (ret) +                goto out; + +        fd = open (volinfo->quota_conf_shandle->path, O_RDONLY); +        if (fd == -1) { +                ret = -1; +                goto out; +        } + +        ret = glusterd_store_quota_conf_skip_header (this, fd); +        if (ret) +                goto out; + +        for (gfid_idx=0; ; gfid_idx++) { + +                ret = read (fd, (void*)&buf, 16) ; +                if (ret <= 0) { +                        //Finished reading all entries in the conf file +                        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."); +                        goto out; +                } + +                gfid_str = gf_strdup (uuid_utoa (buf)); +                if (!gfid_str) { +                        ret = -1; +                        goto out; +                } + +                snprintf (key, sizeof(key)-1, "volume%d.gfid%d", vol_idx, +                          gfid_idx); +                key[sizeof(key)-1] = '\0'; +                ret = dict_set_dynstr (load, key, gfid_str); +                if (ret) { +                        goto out; +                } + +                gfid_str = NULL; +        } + +        snprintf (key, sizeof(key)-1, "volume%d.gfid-count", vol_idx); +        key[sizeof(key)-1] = '\0'; +        ret = dict_set_int32 (load, key, gfid_idx); +        if (ret) +                goto out; + +        snprintf (key, sizeof(key)-1, "volume%d.quota-cksum", vol_idx); +        key[sizeof(key)-1] = '\0'; +        ret = dict_set_uint32 (load, key, volinfo->quota_conf_cksum); +        if (ret) +                goto out; + +        snprintf (key, sizeof(key)-1, "volume%d.quota-version", vol_idx); +        key[sizeof(key)-1] = '\0'; +        ret = dict_set_uint32 (load, key, volinfo->quota_conf_version); +        if (ret) +                goto out; + +        ret = 0; +out: +        if (fd != -1) +                close (fd); +        GF_FREE (gfid_str); +        return ret; +} +  int32_t  glusterd_build_volume_dict (dict_t **vols)  { @@ -2041,6 +2174,11 @@ glusterd_build_volume_dict (dict_t **vols)                  ret = glusterd_add_volume_to_dict (volinfo, dict, count);                  if (ret)                          goto out; +                if (!glusterd_is_volume_quota_enabled (volinfo)) +                        continue; +                ret = glusterd_vol_add_quota_conf_to_dict (volinfo, dict, count); +                if (ret) +                        goto out;          } @@ -2078,11 +2216,17 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status,          glusterd_volinfo_t      *volinfo = NULL;          char                    *volname = NULL;          uint32_t                cksum = 0; +        uint32_t                quota_cksum = 0; +        uint32_t                quota_version = 0;          int32_t                 version = 0; +        xlator_t                *this = NULL;          GF_ASSERT (vols);          GF_ASSERT (status); +        this = THIS; +        GF_ASSERT (this); +          snprintf (key, sizeof (key), "volume%d.name", count);          ret = dict_get_str (vols, key, &volname);          if (ret) @@ -2105,7 +2249,7 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status,          if (version > volinfo->version) {                  //Mismatch detected                  ret = 0; -                gf_log ("", GF_LOG_ERROR, "Version of volume %s differ." +                gf_log (this->name, GF_LOG_ERROR, "Version of volume %s differ."                          "local version = %d, remote version = %d on peer %s",                          volinfo->volname, volinfo->version, version, hostname);                  *status = GLUSTERD_VOL_COMP_UPDATE_REQ; @@ -2125,17 +2269,66 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status,          if (cksum != volinfo->cksum) {                  ret = 0; -                gf_log ("", GF_LOG_ERROR, "Cksums of volume %s differ." +                gf_log (this->name, GF_LOG_ERROR, "Cksums of volume %s differ."                          " local cksum = %u, remote cksum = %u on peer %s",                          volinfo->volname, volinfo->cksum, cksum, hostname);                  *status = GLUSTERD_VOL_COMP_RJT;                  goto out;          } +        memset (key, 0, sizeof (key)); +        snprintf (key, sizeof (key), "volume%d.quota-version", count); +        ret = dict_get_uint32 (vols, key, "a_version); +        if (ret) { +                gf_log (this->name, GF_LOG_DEBUG, "quota-version key absent for" +                        " volume %s in peer %s's response", volinfo->volname, +                        hostname); +                ret = 0; +        } else { +                if (quota_version > volinfo->quota_conf_version) { +                        //Mismatch detected +                        ret = 0; +                        gf_log (this->name, GF_LOG_ERROR, "Quota configuration " +                                "versions of volume %s differ. " +                                "local version = %d, remote version = %d " +                                "on peer %s", volinfo->volname, +                                volinfo->quota_conf_version, quota_version, +                                hostname); +                        *status = GLUSTERD_VOL_COMP_UPDATE_REQ; +                        goto out; +                } else if (quota_version < volinfo->quota_conf_version) { +                        *status = GLUSTERD_VOL_COMP_SCS; +                        goto out; +                } +        } + +        //Now, versions are same, compare cksums. +        // +        memset (key, 0, sizeof (key)); +        snprintf (key, sizeof (key), "volume%d.quota-cksum", count); +        ret = dict_get_uint32 (vols, key, "a_cksum); +        if (ret) { +                gf_log (this->name, GF_LOG_DEBUG, "quota checksum absent for " +                        "volume %s in peer %s's response", volinfo->volname, +                        hostname); +                ret = 0; +        } else { +                if (quota_cksum != volinfo->quota_conf_cksum) { +                        ret = 0; +                        gf_log (this->name, GF_LOG_ERROR, "Cksums of quota " +                                "configurations of volume %s differ. " +                                "local cksum = %u, remote cksum = %u on " +                                "peer %s", volinfo->volname, +                                volinfo->quota_conf_cksum, quota_cksum, +                                hostname); +                        *status = GLUSTERD_VOL_COMP_RJT; +                        goto out; +                } +        }          *status = GLUSTERD_VOL_COMP_SCS;  out: -        gf_log ("", GF_LOG_DEBUG, "Returning with ret: %d, status: %d", +        gf_log (this->name, GF_LOG_DEBUG, "Returning with ret: %d, status: %d",                  ret, *status);          return ret;  } @@ -2582,6 +2775,113 @@ out:          return ret;  } +static int +glusterd_import_quota_conf (dict_t *vols, int vol_idx, +                            glusterd_volinfo_t *new_volinfo) +{ +        int     gfid_idx         = 0; +        int     gfid_count       = 0; +        int     ret              = -1; +        int     fd               = -1; +        char    key[PATH_MAX]    = {0}; +        char    *gfid_str        = NULL; +        uuid_t   gfid            = {0,}; +        xlator_t *this           = NULL; + +        this = THIS; +        GF_ASSERT (this); + +        if (!glusterd_is_volume_quota_enabled (new_volinfo)) { +                (void) glusterd_clean_up_quota_store (new_volinfo); +                return 0; +        } + +        ret = glusterd_store_create_quota_conf_sh_on_absence (new_volinfo); +        if (ret) +                goto out; + +        fd = gf_store_mkstemp (new_volinfo->quota_conf_shandle); +        if (fd < 0) { +                ret = -1; +                goto out; +        } + +        snprintf (key, sizeof (key)-1, "volume%d.quota-cksum", vol_idx); +        key[sizeof(key)-1] = '\0'; +        ret = dict_get_uint32 (vols, key, &new_volinfo->quota_conf_cksum); +        if (ret) +                gf_log (this->name, GF_LOG_DEBUG, "Failed to get quota cksum"); + +        snprintf (key, sizeof (key)-1, "volume%d.quota-version", vol_idx); +        key[sizeof(key)-1] = '\0'; +        ret = dict_get_uint32 (vols, key, &new_volinfo->quota_conf_version); +        if (ret) +                gf_log (this->name, GF_LOG_DEBUG, "Failed to get quota " +                                                  "version"); + +        snprintf (key, sizeof (key)-1, "volume%d.gfid-count", vol_idx); +        key[sizeof(key)-1] = '\0'; +        ret = dict_get_int32 (vols, key, &gfid_count); +        if (ret) +                goto out; + +        ret = glusterd_store_quota_conf_stamp_header (this, fd); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to add header to tmp " +                        "file"); +                goto out; +        } + +        gfid_idx = 0; +        for (gfid_idx = 0; gfid_idx < gfid_count; gfid_idx++) { + +                snprintf (key, sizeof (key)-1, "volume%d.gfid%d", +                          vol_idx, gfid_idx); +                key[sizeof(key)-1] = '\0'; +                ret = dict_get_str (vols, key, &gfid_str); +                if (ret) +                        goto out; + +                uuid_parse (gfid_str, gfid); +                ret = write (fd, (void*)gfid, 16); +                if (ret != 16) { +                        gf_log (this->name, GF_LOG_CRITICAL, "Unable to write " +                                "gfid %s into quota.conf for %s", gfid_str, +                                new_volinfo->volname); +                        ret = -1; +                        goto out; +                } + +        } + +        ret = gf_store_rename_tmppath (new_volinfo->quota_conf_shandle); + +        ret = 0; + +out: +        if (fd != -1) +                close (fd); + +        if (!ret) { +                ret = glusterd_compute_cksum (new_volinfo, _gf_true); +                if (ret) +                        goto out; + +                ret = glusterd_store_save_quota_version_and_cksum (new_volinfo); +                if (ret) +                        goto out; +        } + +        if (ret && (fd > 0)) { +                gf_store_unlink_tmppath (new_volinfo->quota_conf_shandle); +                (void) gf_store_handle_destroy +                                              (new_volinfo->quota_conf_shandle); +                new_volinfo->quota_conf_shandle = NULL; +        } + +        return ret; +} +  int32_t  glusterd_import_volinfo (dict_t *vols, int count,                           glusterd_volinfo_t **volinfo) @@ -2863,6 +3163,7 @@ glusterd_import_volinfo (dict_t *vols, int count,          ret = glusterd_import_bricks (vols, count, new_volinfo);          if (ret)                  goto out; +          *volinfo = new_volinfo;  out:          if (msg[0]) @@ -3032,6 +3333,10 @@ glusterd_import_friend_volume (dict_t *vols, size_t count)          if (ret)                  goto out; +        ret = glusterd_import_quota_conf (vols, count, new_volinfo); +        if (ret) +                goto out; +          list_add_tail (&new_volinfo->vol_list, &priv->volumes);  out:          gf_log ("", GF_LOG_DEBUG, "Returning with ret: %d", ret); @@ -3161,6 +3466,7 @@ glusterd_compare_friend_data (dict_t  *vols, int32_t *status, char *hostname)          gf_boolean_t            update = _gf_false;          gf_boolean_t            stale_nfs = _gf_false;          gf_boolean_t            stale_shd = _gf_false; +        gf_boolean_t            stale_qd  = _gf_false;          GF_ASSERT (vols);          GF_ASSERT (status); @@ -3190,6 +3496,8 @@ glusterd_compare_friend_data (dict_t  *vols, int32_t *status, char *hostname)                          stale_nfs = _gf_true;                  if (glusterd_is_nodesvc_running ("glustershd"))                          stale_shd = _gf_true; +                if (glusterd_is_nodesvc_running ("quotad")) +                        stale_qd  = _gf_true;                  ret = glusterd_import_global_opts (vols);                  if (ret)                          goto out; @@ -3203,6 +3511,8 @@ glusterd_compare_friend_data (dict_t  *vols, int32_t *status, char *hostname)                                  glusterd_nfs_server_stop ();                          if (stale_shd)                                  glusterd_shd_stop (); +                        if (stale_qd) +                                glusterd_quotad_stop ();                  }          } @@ -3213,40 +3523,6 @@ out:          return ret;  } -/* Valid only in if service is 'local' to glusterd. - * pid can be -1, if reading pidfile failed */ -gf_boolean_t -glusterd_is_service_running (char *pidfile, int *pid) -{ -        FILE            *file = NULL; -        gf_boolean_t    running = _gf_false; -        int             ret = 0; -        int             fno = 0; - -        file = fopen (pidfile, "r+"); -        if (!file) -                goto out; - -        fno = fileno (file); -        ret = lockf (fno, F_TEST, 0); -        if (ret == -1) -                running = _gf_true; -        if (!pid) -                goto out; - -        ret = fscanf (file, "%d", pid); -        if (ret <= 0) { -                gf_log ("", GF_LOG_ERROR, "Unable to read pidfile: %s, %s", -                        pidfile, strerror (errno)); -                *pid = -1; -        } - -out: -        if (file) -                fclose (file); -        return running; -} -  void  glusterd_get_nodesvc_dir (char *server, char *workdir,                                  char *path, size_t len) @@ -3285,7 +3561,10 @@ glusterd_get_nodesvc_volfile (char *server, char *workdir,          GF_ASSERT (len == PATH_MAX);          glusterd_get_nodesvc_dir (server, workdir, dir, sizeof (dir)); -        snprintf (volfile, len, "%s/%s-server.vol", dir, server); +        if (strcmp ("quotad", server) != 0) +                snprintf (volfile, len, "%s/%s-server.vol", dir, server); +        else +                snprintf (volfile, len, "%s/%s.vol", dir, server);  }  void @@ -3298,11 +3577,14 @@ glusterd_nodesvc_set_online_status (char *server, gf_boolean_t status)          GF_ASSERT (priv);          GF_ASSERT (priv->shd);          GF_ASSERT (priv->nfs); +        GF_ASSERT (priv->quotad);          if (!strcmp("glustershd", server))                  priv->shd->online = status;          else if (!strcmp ("nfs", server))                  priv->nfs->online = status; +        else if (!strcmp ("quotad", server)) +                priv->quotad->online = status;  }  gf_boolean_t @@ -3316,11 +3598,14 @@ glusterd_is_nodesvc_online (char *server)          GF_ASSERT (conf);          GF_ASSERT (conf->shd);          GF_ASSERT (conf->nfs); +        GF_ASSERT (conf->quotad);          if (!strcmp (server, "glustershd"))                  online = conf->shd->online;          else if (!strcmp (server, "nfs"))                  online = conf->nfs->online; +        else if (!strcmp (server, "quotad")) +                online = conf->quotad->online;          return online;  } @@ -3346,6 +3631,7 @@ glusterd_pending_node_get_rpc (glusterd_pending_node_t *pending_node)          nodesrv_t               *shd       = NULL;          glusterd_volinfo_t      *volinfo   = NULL;          nodesrv_t               *nfs       = NULL; +        nodesrv_t               *quotad    = NULL;          GF_VALIDATE_OR_GOTO (THIS->name, pending_node, out);          GF_VALIDATE_OR_GOTO (THIS->name, pending_node->node, out); @@ -3367,6 +3653,10 @@ glusterd_pending_node_get_rpc (glusterd_pending_node_t *pending_node)                  nfs = pending_node->node;                  rpc = nfs->rpc; +        } else if (pending_node->type == GD_NODE_QUOTAD) { +                quotad = pending_node->node; +                rpc = quotad->rpc; +          } else {                  GF_ASSERT (0);          } @@ -3386,11 +3676,14 @@ glusterd_nodesvc_get_rpc (char *server)          GF_ASSERT (priv);          GF_ASSERT (priv->shd);          GF_ASSERT (priv->nfs); +        GF_ASSERT (priv->quotad);          if (!strcmp (server, "glustershd"))                  rpc = priv->shd->rpc;          else if (!strcmp (server, "nfs"))                  rpc = priv->nfs->rpc; +        else if (!strcmp (server, "quotad")) +                rpc = priv->quotad->rpc;          return rpc;  } @@ -3408,11 +3701,14 @@ glusterd_nodesvc_set_rpc (char *server, struct rpc_clnt *rpc)          GF_ASSERT (priv);          GF_ASSERT (priv->shd);          GF_ASSERT (priv->nfs); +        GF_ASSERT (priv->quotad);          if (!strcmp ("glustershd", server))                  priv->shd->rpc = rpc;          else if (!strcmp ("nfs", server))                  priv->nfs->rpc = rpc; +        else if (!strcmp ("quotad", server)) +                priv->quotad->rpc = rpc;          return ret;  } @@ -3539,6 +3835,14 @@ glusterd_nodesvc_start (char *server)                  runner_add_args (&runner, "--xlator-option",                                   glusterd_uuid_option, NULL);          } +        if (!strcmp (server, "quotad")) { +                runner_add_args (&runner, "--xlator-option", +                                 "*replicate*.data-self-heal=off", +                                 "--xlator-option", +                                 "*replicate*.metadata-self-heal=off", +                                 "--xlator-option", +                                 "*replicate*.entry-self-heal=off", NULL); +        }          runner_log (&runner, "", GF_LOG_DEBUG,                      "Starting the nfs/glustershd services"); @@ -3562,6 +3866,12 @@ glusterd_shd_start ()          return glusterd_nodesvc_start ("glustershd");  } +int +glusterd_quotad_start () +{ +        return glusterd_nodesvc_start ("quotad"); +} +  gf_boolean_t  glusterd_is_nodesvc_running (char *server)  { @@ -3570,7 +3880,7 @@ glusterd_is_nodesvc_running (char *server)          glusterd_get_nodesvc_pidfile (server, priv->workdir,                                              pidfile, sizeof (pidfile)); -        return glusterd_is_service_running (pidfile, NULL); +        return gf_is_service_running (pidfile, NULL);  }  int32_t @@ -3680,6 +3990,12 @@ glusterd_shd_stop ()  }  int +glusterd_quotad_stop () +{ +        return glusterd_nodesvc_stop ("quotad", SIGTERM); +} + +int  glusterd_add_node_to_dict (char *server, dict_t *dict, int count,                             dict_t *vol_opts)  { @@ -3695,7 +4011,7 @@ glusterd_add_node_to_dict (char *server, dict_t *dict, int count,                                        sizeof (pidfile));          //Consider service to be running only when glusterd sees it Online          if (glusterd_is_nodesvc_online (server)) -                running = glusterd_is_service_running (pidfile, &pid); +                running = gf_is_service_running (pidfile, &pid);          /* For nfs-servers/self-heal-daemon setting           * brick<n>.hostname = "NFS Server" / "Self-heal Daemon" @@ -3711,6 +4027,8 @@ glusterd_add_node_to_dict (char *server, dict_t *dict, int count,                  ret = dict_set_str (dict, key, "NFS Server");          else if (!strcmp (server, "glustershd"))                  ret = dict_set_str (dict, key, "Self-heal Daemon"); +        else if (!strcmp (server, "quotad")) +                ret = dict_set_str (dict, key, "Quota Daemon");          if (ret)                  goto out; @@ -3829,6 +4147,12 @@ glusterd_reconfigure_shd ()  }  int +glusterd_reconfigure_quotad () +{ +        return glusterd_reconfigure_nodesvc (glusterd_create_quotad_volfile); +} + +int  glusterd_reconfigure_nfs ()  {          int             ret             = -1; @@ -3905,21 +4229,52 @@ glusterd_check_generate_start_shd ()  }  int -glusterd_nodesvcs_batch_op (glusterd_volinfo_t *volinfo, -                             int (*nfs_op) (), int (*shd_op) ()) +glusterd_check_generate_start_quotad ()  { +        int ret = 0; + +        ret = glusterd_check_generate_start_service (glusterd_create_quotad_volfile, +                                                     glusterd_quotad_stop, +                                                     glusterd_quotad_start); +        if (ret == -EINVAL) +                ret = 0; +        return ret; +} + +int +glusterd_nodesvcs_batch_op (glusterd_volinfo_t *volinfo, int (*nfs_op) (), +                            int (*shd_op) (), int (*qd_op) ()) + {          int     ret = 0; +        xlator_t *this = THIS; +        glusterd_conf_t *conf = NULL; + +        GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf);          ret = nfs_op ();          if (ret)                  goto out; -        if (volinfo && !glusterd_is_volume_replicate (volinfo)) +        if (volinfo && !glusterd_is_volume_replicate (volinfo)) { +                ; //do nothing +        } else { +                ret = shd_op (); +                if (ret) +                        goto out; +        } + +        if (conf->op_version == GD_OP_VERSION_MIN)                  goto out; -        ret = shd_op (); +        if (volinfo && !glusterd_is_volume_quota_enabled (volinfo)) +                goto out; + +        ret = qd_op ();          if (ret)                  goto out; +  out:          return ret;  } @@ -3929,7 +4284,8 @@ glusterd_nodesvcs_start (glusterd_volinfo_t *volinfo)  {          return glusterd_nodesvcs_batch_op (volinfo,                                             glusterd_nfs_server_start, -                                           glusterd_shd_start); +                                           glusterd_shd_start, +                                           glusterd_quotad_start);  }  int @@ -3937,7 +4293,8 @@ glusterd_nodesvcs_stop (glusterd_volinfo_t *volinfo)  {          return glusterd_nodesvcs_batch_op (volinfo,                                              glusterd_nfs_server_stop, -                                            glusterd_shd_stop); +                                            glusterd_shd_stop, +                                            glusterd_quotad_stop);  }  gf_boolean_t @@ -3983,21 +4340,53 @@ glusterd_all_replicate_volumes_stopped ()          return _gf_true;  } +gf_boolean_t +glusterd_all_volumes_with_quota_stopped () +{ +        glusterd_conf_t                   *priv     = NULL; +        xlator_t                          *this     = NULL; +        glusterd_volinfo_t                *voliter  = NULL; + +        this = THIS; +        GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv); + +        list_for_each_entry (voliter, &priv->volumes, vol_list) { +                if (!glusterd_is_volume_quota_enabled (voliter)) +                        continue; +                if (voliter->status == GLUSTERD_STATUS_STARTED) +                        return _gf_false; +        } + +        return _gf_true; +} + +  int  glusterd_nodesvcs_handle_graph_change (glusterd_volinfo_t *volinfo)  {          int (*shd_op) () = NULL;          int (*nfs_op) () = NULL; +        int (*qd_op)  () = NULL;          shd_op = glusterd_check_generate_start_shd;          nfs_op = glusterd_check_generate_start_nfs; +        qd_op  = glusterd_check_generate_start_quotad;          if (glusterd_are_all_volumes_stopped ()) {                  shd_op = glusterd_shd_stop;                  nfs_op = glusterd_nfs_server_stop; -        } else if (glusterd_all_replicate_volumes_stopped()) { -                shd_op = glusterd_shd_stop; +                qd_op  = glusterd_quotad_stop; +        } else { +                if (glusterd_all_replicate_volumes_stopped()) { +                        shd_op = glusterd_shd_stop; +                } +                if (glusterd_all_volumes_with_quota_stopped ()) { +                        qd_op = glusterd_quotad_stop; +                }          } -        return glusterd_nodesvcs_batch_op (volinfo, nfs_op, shd_op); + +        return glusterd_nodesvcs_batch_op (volinfo, nfs_op, shd_op, qd_op);  }  int @@ -4005,7 +4394,8 @@ glusterd_nodesvcs_handle_reconfigure (glusterd_volinfo_t *volinfo)  {          return glusterd_nodesvcs_batch_op (volinfo,                                             glusterd_reconfigure_nfs, -                                           glusterd_reconfigure_shd); +                                           glusterd_reconfigure_shd, +                                           glusterd_reconfigure_quotad);  }  int @@ -4671,7 +5061,7 @@ glusterd_add_brick_to_dict (glusterd_volinfo_t *volinfo,          GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, brickinfo, priv); -        brick_online = glusterd_is_service_running (pidfile, &pid); +        brick_online = gf_is_service_running (pidfile, &pid);          memset (key, 0, sizeof (key));          snprintf (key, sizeof (key), "%s.pid", base_key); @@ -6073,6 +6463,82 @@ out:          return ret;  } +int +glusterd_quotad_statedump (char *options, int option_cnt, char **op_errstr) +{ +        int                     ret = -1; +        xlator_t                *this = NULL; +        glusterd_conf_t         *conf = NULL; +        char                    pidfile_path[PATH_MAX] = {0,}; +        char                    path[PATH_MAX] = {0,}; +        FILE                    *pidfile = NULL; +        pid_t                   pid = -1; +        char                    dumpoptions_path[PATH_MAX] = {0,}; +        char                    *option = NULL; +        char                    *tmpptr = NULL; +        char                    *dup_options = NULL; +        char                    msg[256] = {0,}; + +        this = THIS; +        GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf); + +        dup_options = gf_strdup (options); +        option = strtok_r (dup_options, " ", &tmpptr); +        if (strcmp (option, "quotad")) { +                snprintf (msg, sizeof (msg), "for quotad statedump, options " +                          "should be after the key 'quotad'"); +                *op_errstr = gf_strdup (msg); +                ret = -1; +                goto out; +        } + +        GLUSTERD_GET_QUOTAD_DIR (path, conf); +        GLUSTERD_GET_QUOTAD_PIDFILE (pidfile_path, path); + +        pidfile = fopen (pidfile_path, "r"); +        if (!pidfile) { +                gf_log (this->name, GF_LOG_ERROR, "Unable to open pidfile: %s", +                        pidfile_path); +                ret = -1; +                goto out; +        } + +        ret = fscanf (pidfile, "%d", &pid); +        if (ret <= 0) { +                gf_log (this->name, GF_LOG_ERROR, "Unable to get pid of quotad " +                        "process"); +                ret = -1; +                goto out; +        } + +        snprintf (dumpoptions_path, sizeof (dumpoptions_path), +                  DEFAULT_VAR_RUN_DIRECTORY"/glusterdump.%d.options", pid); +        ret = glusterd_set_dump_options (dumpoptions_path, options, option_cnt); +        if (ret < 0) { +                gf_log (this->name, GF_LOG_ERROR, "error while parsing " +                        "statedump options"); +                ret = -1; +                goto out; +        } + +        gf_log (this->name, GF_LOG_INFO, "Performing statedump on quotad with " +                "pid %d", pid); + +        kill (pid, SIGUSR1); + +        sleep (1); + +        ret = 0; +out: +        if (pidfile) +                fclose (pidfile); +        unlink (dumpoptions_path); +        GF_FREE (dup_options); +        return ret; +} +  /* Checks if the given peer contains all the bricks belonging to the   * given volume. Returns true if it does else returns false   */ @@ -6215,7 +6681,7 @@ glusterd_volume_defrag_restart (glusterd_volinfo_t *volinfo, char *op_errstr,          GLUSTERD_GET_DEFRAG_PID_FILE(pidfile, volinfo, priv); -        if (!glusterd_is_service_running (pidfile, &pid)) { +        if (!gf_is_service_running (pidfile, &pid)) {                  glusterd_handle_defrag_start (volinfo, op_errstr, len, cmd,                                                cbk, volinfo->rebal.op);          } else { @@ -7363,6 +7829,90 @@ _profile_volume_add_brick_rsp (dict_t *this, char *key, data_t *value,  }  int +glusterd_volume_quota_copy_to_op_ctx_dict (dict_t *dict, dict_t *rsp_dict) +{ +        int        ret            = -1; +        int        i              = 0; +        int        count          = 0; +        int        rsp_dict_count = 0; +        char      *uuid_str       = NULL; +        char      *uuid_str_dup   = NULL; +        char       key[256]       = {0,}; +        xlator_t  *this           = NULL; +        int        type           = GF_QUOTA_OPTION_TYPE_NONE; + +        this = THIS; +        GF_ASSERT (this); + +        ret = dict_get_int32 (dict, "type", &type); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get quota opcode"); +                goto out; +        } + +        if ((type != GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) && +            (type != GF_QUOTA_OPTION_TYPE_REMOVE)) { +                dict_copy (rsp_dict, dict); +                ret = 0; +                goto out; +        } + +        ret = dict_get_int32 (rsp_dict, "count", &rsp_dict_count); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get the count of " +                        "gfids from the rsp dict"); +                goto out; +        } + +        ret = dict_get_int32 (dict, "count", &count); +        if (ret) +                /* The key "count" is absent in op_ctx when this function is +                 * called after self-staging on the originator. This must not +                 * be treated as error. +                 */ +                gf_log (this->name, GF_LOG_DEBUG, "Failed to get count of gfids" +                        " from req dict. This could be because count is not yet" +                        " copied from rsp_dict into op_ctx"); + +        for (i = 0; i < rsp_dict_count; i++) { +                snprintf (key, sizeof(key)-1, "gfid%d", i); + +                ret = dict_get_str (rsp_dict, key, &uuid_str); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, "Failed to get gfid " +                                "from rsp dict"); +                        goto out; +                } + +                snprintf (key, sizeof (key)-1, "gfid%d", i + count); + +                uuid_str_dup = gf_strdup (uuid_str); +                if (!uuid_str_dup) { +                        ret = -1; +                        goto out; +                } + +                ret = dict_set_dynstr (dict, key, uuid_str_dup); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, "Failed to set gfid " +                                "from rsp dict into req dict"); +                        GF_FREE (uuid_str_dup); +                        goto out; +                } +        } + +        ret = dict_set_int32 (dict, "count", rsp_dict_count + count); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR,  "Failed to set aggregated " +                        "count in req dict"); +                goto out; +        } + +out: +        return ret; +} + +int  glusterd_profile_volume_brick_rsp (void *pending_entry,                                     dict_t *rsp_dict, dict_t *op_ctx,                                     char **op_errstr, gd_node_type type) @@ -8068,3 +8618,232 @@ gd_should_i_start_rebalance  (glusterd_volinfo_t *volinfo) {  out:          return retval;  } + +int +glusterd_is_volume_quota_enabled (glusterd_volinfo_t *volinfo) +{ +        return (glusterd_volinfo_get_boolean (volinfo, VKEY_FEATURES_QUOTA)); +} + +int +glusterd_validate_and_set_gfid (dict_t *op_ctx, dict_t *req_dict, +                                char **op_errstr) +{ +        int        ret           = -1; +        int        count         = 0; +        int        i             = 0; +        int        op_code       = GF_QUOTA_OPTION_TYPE_NONE; +        uuid_t     uuid1         = {0}; +        uuid_t     uuid2         = {0,}; +        char      *path          = NULL; +        char       key[256]      = {0,}; +        char      *uuid1_str     = NULL; +        char      *uuid1_str_dup = NULL; +        char      *uuid2_str     = NULL; +        xlator_t  *this          = NULL; + +        this = THIS; +        GF_ASSERT (this); + +        ret = dict_get_int32 (op_ctx, "type", &op_code); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get quota opcode"); +                goto out; +        } + +        if ((op_code != GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) && +            (op_code != GF_QUOTA_OPTION_TYPE_REMOVE)) { +                ret = 0; +                goto out; +        } + +        ret = dict_get_str (op_ctx, "path", &path); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get path"); +                goto out; +        } + +        ret = dict_get_int32 (op_ctx, "count", &count); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get count"); +                goto out; +        } + +        /* If count is 0, fail the command with ENOENT. +         * +         * If count is 1, treat gfid0 as the gfid on which the operation +         * is to be performed and resume the command. +         * +         * if count > 1, get the 0th gfid from the op_ctx and, +         * compare it with the remaining 'count -1' gfids. +         * If they are found to be the same, set gfid0 in the op_ctx and +         * resume the operation, else error out. +         */ + +        if (count == 0) { +                gf_asprintf (op_errstr, "Failed to get trusted.gfid attribute " +                             "on path %s. Reason : %s", path, +                             strerror (ENOENT)); +                ret = -1; +                goto out; +        } + +        snprintf (key, sizeof (key) - 1, "gfid%d", 0); + +        ret = dict_get_str (op_ctx, key, &uuid1_str); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to get key '%s'", +                        key); +                goto out; +        } + +        uuid_parse (uuid1_str, uuid1); + +        for (i = 1; i < count; i++) { +                snprintf (key, sizeof (key)-1, "gfid%d", i); + +                ret = dict_get_str (op_ctx, key, &uuid2_str); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, "Failed to get key " +                                "'%s'", key); +                        goto out; +                } + +                uuid_parse (uuid2_str, uuid2); + +                if (uuid_compare (uuid1, uuid2)) { +                        gf_asprintf (op_errstr, "gfid mismatch between %s and " +                                     "%s for path %s", uuid1_str, uuid2_str, +                                     path); +                        ret = -1; +                        goto out; +                } +        } + +        if (i == count) { +                uuid1_str_dup = gf_strdup (uuid1_str); +                if (!uuid1_str_dup) { +                        ret = -1; +                        goto out; +                } + +                ret = dict_set_dynstr (req_dict, "gfid", uuid1_str_dup); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, "Failed to set gfid"); +                        GF_FREE (uuid1_str_dup); +                        goto out; +                } +        } else { +                gf_log (this->name, GF_LOG_ERROR, "Failed to iterate through %d" +                        " entries in the req dict", count); +                ret = -1; +                goto out; +        } + +        ret = 0; +out: +        return ret; +} + +void +glusterd_clean_up_quota_store (glusterd_volinfo_t *volinfo) +{ +        char      voldir[PATH_MAX]         = {0,}; +        char      quota_confpath[PATH_MAX] = {0,}; +        char      cksum_path[PATH_MAX]     = {0,}; +        xlator_t  *this                    = NULL; +        glusterd_conf_t *conf              = NULL; + +        this = THIS; +        GF_ASSERT (this); +        conf = this->private; +        GF_ASSERT (conf); + +        GLUSTERD_GET_VOLUME_DIR (voldir, volinfo, conf); + +        snprintf (quota_confpath, sizeof (quota_confpath), "%s/%s", voldir, +                  GLUSTERD_VOLUME_QUOTA_CONFIG); +        snprintf (cksum_path, sizeof (cksum_path), "%s/%s", voldir, +                  GLUSTERD_VOL_QUOTA_CKSUM_FILE); + +        unlink (quota_confpath); +        unlink (cksum_path); + +        gf_store_handle_destroy (volinfo->quota_conf_shandle); +        volinfo->quota_conf_shandle = NULL; +        volinfo->quota_conf_version = 0; + +} + +#define QUOTA_CONF_HEADER                                                \ +        "GlusterFS Quota conf | version: v%d.%d\n" + +int +glusterd_store_quota_conf_skip_header (xlator_t *this, int fd) +{ +        char buf[PATH_MAX] = {0,}; + +        snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); +        return gf_skip_header_section (fd, strlen (buf)); +} + +int +glusterd_store_quota_conf_stamp_header (xlator_t *this, int fd) +{ +        char buf[PATH_MAX]  = {0,}; +        int  buf_len        = 0; +        ssize_t  ret        = -1; +        ssize_t  written    = 0; + +        snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); +        buf_len = strlen (buf); +        for (written = 0; written != buf_len; written += ret) { +                ret = write (fd, buf + written, buf_len - written); +                if (ret == -1) { +                        goto out; +                } +        } + +        ret = 0; +out: +        return ret; +} + +int +glusterd_remove_auxiliary_mount (char *volname) +{ +        int       ret                = -1; +        runner_t  runner             = {0,}; +        char      mountdir[PATH_MAX] = {0,}; +        char      pidfile[PATH_MAX]  = {0,}; +        xlator_t *this               = NULL; + +        this = THIS; +        GF_ASSERT (this); + +        GLUSTERFS_GET_AUX_MOUNT_PIDFILE (pidfile, volname); + +        if (!gf_is_service_running (pidfile, NULL)) { +                gf_log (this->name, GF_LOG_DEBUG, "Aux mount of volume %s " +                        "absent, hence returning", volname); +                return 0; +        } + +        snprintf (mountdir, sizeof (mountdir)-1, "/tmp/%s", volname); + +        runinit (&runner); +        runner_add_args (&runner, "umount", + +#if GF_LINUX_HOST_OS +                        "-l", +#endif +                        mountdir, NULL); +        ret = runner_run_reuse (&runner); +        if (ret) +                gf_log (this->name, GF_LOG_ERROR, "umount on %s failed, " +                        "reason : %s", mountdir, strerror (errno)); +        runner_end (&runner); + +        rmdir (mountdir); +        return ret; +} diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index 5b0cfca7b55..9907a03d490 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -158,16 +158,14 @@ int32_t  glusterd_compare_friend_data (dict_t  *vols, int32_t *status, char *hostname);  int -glusterd_volume_compute_cksum (glusterd_volinfo_t  *volinfo); +glusterd_compute_cksum (glusterd_volinfo_t  *volinfo, +                        gf_boolean_t is_quota_conf);  void  glusterd_get_nodesvc_volfile (char *server, char *workdir,                                      char *volfile, size_t len);  gf_boolean_t -glusterd_is_service_running (char *pidfile, int *pid); - -gf_boolean_t  glusterd_is_nodesvc_running ();  gf_boolean_t @@ -188,6 +186,12 @@ glusterd_shd_start ();  int32_t  glusterd_shd_stop (); +int32_t +glusterd_quotad_start (); + +int32_t +glusterd_quotad_stop (); +  void  glusterd_set_socket_filepath (char *sock_filepath, char *sockpath, size_t len); @@ -228,6 +232,9 @@ int  glusterd_check_generate_start_shd (void);  int +glusterd_check_generate_start_quotad (void); + +int  glusterd_nodesvcs_handle_graph_change (glusterd_volinfo_t *volinfo);  int @@ -401,8 +408,13 @@ glusterd_brick_statedump (glusterd_volinfo_t *volinfo,                            char *options, int option_cnt, char **op_errstr);  int  glusterd_nfs_statedump (char *options, int option_cnt, char **op_errstr); + +int +glusterd_quotad_statedump (char *options, int option_cnt, char **op_errstr); +  gf_boolean_t  glusterd_is_volume_replicate (glusterd_volinfo_t *volinfo); +  gf_boolean_t  glusterd_is_brick_decommissioned (glusterd_volinfo_t *volinfo, char *hostname,                                    char *path); @@ -493,6 +505,11 @@ int  glusterd_volume_rebalance_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict);  int  glusterd_volume_heal_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict); + +int32_t +glusterd_check_if_quota_trans_enabled (glusterd_volinfo_t *volinfo); +int +glusterd_volume_quota_copy_to_op_ctx_dict (dict_t *aggr, dict_t *rsp);  int  _profile_volume_add_brick_rsp (dict_t *this, char *key, data_t *value,                               void *data); @@ -537,6 +554,10 @@ int  glusterd_generate_and_set_task_id (dict_t *dict, char *key);  int +glusterd_validate_and_set_gfid (dict_t *op_ctx, dict_t *req_dict, +                                char **op_errstr); + +int  glusterd_copy_uuid_to_dict (uuid_t uuid, dict_t *dict, char *key);  gf_boolean_t @@ -576,4 +597,26 @@ glusterd_is_status_tasks_op (glusterd_op_t op, dict_t *dict);  gf_boolean_t  gd_should_i_start_rebalance  (glusterd_volinfo_t *volinfo); + +int +glusterd_is_volume_quota_enabled (glusterd_volinfo_t *volinfo); + +gf_boolean_t +glusterd_all_volumes_with_quota_stopped (); + +int +glusterd_reconfigure_quotad (); + +void +glusterd_clean_up_quota_store (glusterd_volinfo_t *volinfo); + +int +glusterd_store_quota_conf_skip_header (xlator_t *this, int fd); + +int +glusterd_store_quota_conf_stamp_header (xlator_t *this, int fd); + +int +glusterd_remove_auxiliary_mount (char *volname); +  #endif diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index da8ace953cf..dcff8c30517 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -1616,7 +1616,21 @@ server_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,          if (ret)                  return -1; -        if (dict_get_str_boolean (set_dict, "features.read-only", 0) && +        xl = volgen_graph_add (graph, "features/quota", volname); +        if (!xl) +                return -1; +        ret = xlator_set_option (xl, "volume-uuid", volname); +        if (ret) +                return -1; + +        ret = glusterd_volinfo_get (volinfo, VKEY_FEATURES_QUOTA, &value); +        if (value) { +                ret = xlator_set_option (xl, "server-quota", value); +                if (ret) +                        return -1; +        } + +         if (dict_get_str_boolean (set_dict, "features.read-only", 0) &&              dict_get_str_boolean (set_dict, "features.worm",0)) {                  gf_log (THIS->name, GF_LOG_ERROR,                          "read-only and worm cannot be set together"); @@ -2331,13 +2345,15 @@ out:  static int  volgen_graph_build_dht_cluster (volgen_graph_t *graph, -                                glusterd_volinfo_t *volinfo, size_t child_count) +                                glusterd_volinfo_t *volinfo, size_t child_count, +                                gf_boolean_t is_quotad)  {          int32_t                 clusters                 = 0;          int                     ret                      = -1;          char                    *decommissioned_children = NULL;          xlator_t                *dht                     = NULL;          char                    *voltype                 = "cluster/distribute"; +        char                    *name_fmt                = NULL;          /* NUFA and Switch section */          if (dict_get_str_boolean (volinfo->dict, "cluster.nufa", 0) && @@ -2356,9 +2372,14 @@ volgen_graph_build_dht_cluster (volgen_graph_t *graph,          if (dict_get_str_boolean (volinfo->dict, "cluster.switch", 0))                  voltype = "cluster/switch"; +        if (is_quotad) +                name_fmt = "%s"; +        else +                name_fmt = "%s-dht"; +          clusters = volgen_graph_build_clusters (graph,  volinfo,                                                  voltype, -                                                "%s-dht", +                                                name_fmt,                                                  child_count,                                                  child_count);          if (clusters < 0) @@ -2383,7 +2404,8 @@ out:  static int  volume_volgen_graph_build_clusters (volgen_graph_t *graph, -                                    glusterd_volinfo_t *volinfo) +                                    glusterd_volinfo_t *volinfo, +                                    gf_boolean_t is_quotad)  {          char                    *replicate_args[]   = {"cluster/replicate",                                                         "%s-replicate-%d"}; @@ -2456,8 +2478,8 @@ build_distribute:          }          ret = volgen_graph_build_dht_cluster (graph, volinfo, -                                              dist_count); -        if (ret == -1) +                                              dist_count, is_quotad); +        if (ret)                  goto out;          ret = 0; @@ -2492,16 +2514,19 @@ static int  client_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,                        dict_t *set_dict, void *param)  { -        int       ret      = 0; -        xlator_t *xl       = NULL; -        char     *volname  = NULL; +        int              ret     = 0; +        xlator_t        *xl      = NULL; +        char            *volname = NULL; +        glusterd_conf_t *conf    = THIS->private; + +        GF_ASSERT (conf);          volname = volinfo->volname;          ret = volgen_graph_build_clients (graph, volinfo, set_dict, param);          if (ret)                  goto out; -        ret = volume_volgen_graph_build_clusters (graph, volinfo); +        ret = volume_volgen_graph_build_clusters (graph, volinfo, _gf_false);          if (ret == -1)                  goto out; @@ -2530,15 +2555,18 @@ client_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,                  }          } -        ret = glusterd_volinfo_get_boolean (volinfo, VKEY_FEATURES_QUOTA); -        if (ret == -1) -                goto out; -        if (ret) { -                xl = volgen_graph_add (graph, "features/quota", volname); - -                if (!xl) { -                        ret = -1; +        if (conf->op_version == GD_OP_VERSION_MIN) { +                ret = glusterd_volinfo_get_boolean (volinfo, +                                                    VKEY_FEATURES_QUOTA); +                if (ret == -1)                          goto out; +                if (ret) { +                        xl = volgen_graph_add (graph, "features/quota", +                                              volname); +                        if (!xl) { +                                ret = -1; +                                goto out; +                        }                  }          } @@ -3096,9 +3124,6 @@ build_nfs_graph (volgen_graph_t *graph, dict_t *mod_dict)          return ret;  } - - -  /****************************   *   * Volume generation interface @@ -3185,7 +3210,100 @@ glusterd_generate_brick_volfile (glusterd_volinfo_t *volinfo,          return ret;  } +static int +build_quotad_graph (volgen_graph_t *graph, dict_t *mod_dict) +{ +        volgen_graph_t     cgraph         = {0}; +        glusterd_volinfo_t *voliter       = NULL; +        xlator_t           *this          = NULL; +        glusterd_conf_t    *priv          = NULL; +        dict_t             *set_dict      = NULL; +        int                ret            = 0; +        xlator_t           *quotad_xl     = NULL; +	char		   *skey	  = NULL; + +        this = THIS; +        priv = this->private; + +        set_dict = dict_new (); +        if (!set_dict) { +                ret = -ENOMEM; +                goto out; +        } + +        quotad_xl = volgen_graph_add_as (graph, "features/quotad", "quotad"); +        if (!quotad_xl) { +                ret = -1; +                goto out; +        } + +        list_for_each_entry (voliter, &priv->volumes, vol_list) { +                if (voliter->status != GLUSTERD_STATUS_STARTED) +                        continue; + +                if (1 != glusterd_is_volume_quota_enabled (voliter)) +                        continue; + +                ret = dict_set_uint32 (set_dict, "trusted-client", +                                       GF_CLIENT_TRUSTED); +                if (ret) +                        goto out; + +                dict_copy (voliter->dict, set_dict); +                if (mod_dict) +                        dict_copy (mod_dict, set_dict); + +                ret = gf_asprintf(&skey, "%s.volume-id", voliter->volname); +                if (ret == -1) { +                        gf_log("", GF_LOG_ERROR, "Out of memory"); +                        goto out; +                } +                ret = xlator_set_option(quotad_xl, skey, voliter->volname); +                GF_FREE(skey); +                if (ret) +                        goto out; + +                memset (&cgraph, 0, sizeof (cgraph)); +                ret = volgen_graph_build_clients (&cgraph, voliter, set_dict, +                                                  NULL); +                if (ret) +                        goto out; + +                ret = volume_volgen_graph_build_clusters (&cgraph, voliter, +                                                          _gf_true); +                if (ret) { +                        ret = -1; +                        goto out; +                } + +                if (mod_dict) { +                        dict_copy (mod_dict, set_dict); +                        ret = volgen_graph_set_options_generic (&cgraph, set_dict, +                                                        voliter, +                                                        basic_option_handler); +                } else { +                        ret = volgen_graph_set_options_generic (&cgraph, +                                                                voliter->dict, +                                                                voliter, +                                                                basic_option_handler); +                } +                if (ret) +                        goto out; + +                ret = volgen_graph_merge_sub (graph, &cgraph, 1); +                if (ret) +                        goto out; + +                ret = dict_reset (set_dict); +                if (ret) +                        goto out; +        } +out: +        if (set_dict) +                dict_unref (set_dict); +        return ret; +}  static void  get_vol_tstamp_file (char *filename, glusterd_volinfo_t *volinfo) @@ -3453,105 +3571,117 @@ out:  }  int -glusterd_check_nfs_topology_identical (gf_boolean_t *identical) +glusterd_check_nfs_volfile_identical (gf_boolean_t *identical)  {          char            nfsvol[PATH_MAX]        = {0,};          char            tmpnfsvol[PATH_MAX]     = {0,};          glusterd_conf_t *conf                   = NULL; -        xlator_t        *this                   = THIS; +        xlator_t        *this                   = NULL;          int             ret                     = -1; -        int             tmpclean                = 0; -        int             tmpfd                   = -1; +        int             need_unlink             = 0; +        int             tmp_fd                  = -1; -        if ((!identical) || (!this) || (!this->private)) -                goto out; +        this = THIS; -        conf = (glusterd_conf_t *) this->private; +        GF_ASSERT (this); +        GF_ASSERT (identical); +        conf = this->private; -        /* Fetch the original NFS volfile */          glusterd_get_nodesvc_volfile ("nfs", conf->workdir,                                        nfsvol, sizeof (nfsvol)); -        /* Create the temporary NFS volfile */          snprintf (tmpnfsvol, sizeof (tmpnfsvol), "/tmp/gnfs-XXXXXX"); -        tmpfd = mkstemp (tmpnfsvol); -        if (tmpfd < 0) { -                gf_log (this->name, GF_LOG_WARNING, -                                    "Unable to create temp file %s: (%s)", -                                    tmpnfsvol, strerror (errno)); + +        tmp_fd = mkstemp (tmpnfsvol); +        if (tmp_fd < 0) { +                gf_log ("", GF_LOG_WARNING, "Unable to create temp file %s: " +                                "(%s)", tmpnfsvol, strerror (errno));                  goto out;          } -        tmpclean = 1; /* SET the flag to unlink() tmpfile */ +        need_unlink = 1;          ret = glusterd_create_global_volfile (build_nfs_graph,                                                tmpnfsvol, NULL);          if (ret)                  goto out; -        /* Compare the topology of volfiles */ -        ret = glusterd_check_topology_identical (nfsvol, tmpnfsvol, -                                                 identical); +        ret = glusterd_check_files_identical (nfsvol, tmpnfsvol, +                                              identical); +        if (ret) +                goto out; +  out: -        if (tmpfd >= 0) -                close (tmpfd); -        if (tmpclean) +        if (need_unlink)                  unlink (tmpnfsvol); + +        if (tmp_fd >= 0) +                close (tmp_fd); +          return ret;  }  int -glusterd_check_nfs_volfile_identical (gf_boolean_t *identical) +glusterd_check_nfs_topology_identical (gf_boolean_t *identical)  {          char            nfsvol[PATH_MAX]        = {0,};          char            tmpnfsvol[PATH_MAX]     = {0,};          glusterd_conf_t *conf                   = NULL; -        xlator_t        *this                   = NULL; +        xlator_t        *this                   = THIS;          int             ret                     = -1; -        int             need_unlink             = 0; -        int             tmp_fd                  = -1; - -        this = THIS; +        int             tmpclean                = 0; +        int             tmpfd                   = -1; -        GF_ASSERT (this); -        GF_ASSERT (identical); +        if ((!identical) || (!this) || (!this->private)) +                goto out; -        conf = this->private; +        conf = (glusterd_conf_t *) this->private; +        /* Fetch the original NFS volfile */          glusterd_get_nodesvc_volfile ("nfs", conf->workdir,                                        nfsvol, sizeof (nfsvol)); +        /* Create the temporary NFS volfile */          snprintf (tmpnfsvol, sizeof (tmpnfsvol), "/tmp/gnfs-XXXXXX"); - -        tmp_fd = mkstemp (tmpnfsvol); -        if (tmp_fd < 0) { -                gf_log ("", GF_LOG_WARNING, "Unable to create temp file %s: " -                                "(%s)", tmpnfsvol, strerror (errno)); +        tmpfd = mkstemp (tmpnfsvol); +        if (tmpfd < 0) { +                gf_log (this->name, GF_LOG_WARNING, +                                    "Unable to create temp file %s: (%s)", +                                    tmpnfsvol, strerror (errno));                  goto out;          } -        need_unlink = 1; +        tmpclean = 1; /* SET the flag to unlink() tmpfile */          ret = glusterd_create_global_volfile (build_nfs_graph,                                                tmpnfsvol, NULL);          if (ret)                  goto out; -        ret = glusterd_check_files_identical (nfsvol, tmpnfsvol, -                                              identical); -        if (ret) -                goto out; - +        /* Compare the topology of volfiles */ +        ret = glusterd_check_topology_identical (nfsvol, tmpnfsvol, +                                                 identical);  out: -        if (need_unlink) +        if (tmpfd >= 0) +                close (tmpfd); +        if (tmpclean)                  unlink (tmpnfsvol); +        return ret; +} -        if (tmp_fd >= 0) -                close (tmp_fd); +int +glusterd_create_quotad_volfile () +{ +        char             filepath[PATH_MAX] = {0,}; +        glusterd_conf_t *conf               = THIS->private; -        return ret; +        glusterd_get_nodesvc_volfile ("quotad", conf->workdir, +                                            filepath, sizeof (filepath)); +        return glusterd_create_global_volfile (build_quotad_graph, +                                               filepath, NULL);  } +  int  glusterd_delete_volfile (glusterd_volinfo_t *volinfo,                           glusterd_brickinfo_t *brickinfo) diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h index 2d31c4040a4..1683f905022 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.h +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.h @@ -22,6 +22,7 @@  #define VKEY_DIAG_CNT_FOP_HITS    "diagnostics.count-fop-hits"  #define VKEY_DIAG_LAT_MEASUREMENT "diagnostics.latency-measurement"  #define VKEY_FEATURES_LIMIT_USAGE "features.limit-usage" +#define VKEY_FEATURES_SOFT_LIMIT  "features.soft-limit"  #define VKEY_MARKER_XTIME         GEOREP".indexing"  #define VKEY_MARKER_XTIME_FORCE   GEOREP".ignore-pid-check"  #define VKEY_CHANGELOG            "changelog.changelog" @@ -121,6 +122,7 @@ void glusterd_get_shd_filepath (char *filename);  int glusterd_create_nfs_volfile ();  int glusterd_create_shd_volfile (); +int glusterd_create_quotad_volfile ();  int glusterd_delete_volfile (glusterd_volinfo_t *volinfo,                               glusterd_brickinfo_t *brickinfo); diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c index ad33227019c..41555230e92 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c @@ -527,9 +527,12 @@ __glusterd_handle_cli_statedump_volume (rpcsvc_request_t *req)          glusterd_op_t                   cli_op = GD_OP_STATEDUMP_VOLUME;          char                            err_str[2048] = {0,};          xlator_t                        *this = NULL; +        glusterd_conf_t                 *priv = NULL;          this = THIS;          GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv);          GF_ASSERT (req); @@ -578,6 +581,14 @@ __glusterd_handle_cli_statedump_volume (rpcsvc_request_t *req)                  goto out;          } +        if (priv->op_version == GD_OP_VERSION_MIN && +            strstr (options, "quotad")) { +                snprintf (err_str, sizeof (err_str), "The cluster is operating " +                          "at op-version 1. Taking quotad's statedump is " +                          "disallowed in this state"); +                ret = -1; +                goto out; +        }          gf_log (this->name, GF_LOG_INFO, "Received statedump request for "                  "volume %s with options %s", volname, options); @@ -1314,6 +1325,13 @@ glusterd_op_stage_statedump_volume (dict_t *dict, char **op_errstr)          gf_boolean_t            is_running = _gf_false;          glusterd_volinfo_t      *volinfo = NULL;          char                    msg[2408] = {0,}; +        xlator_t                *this     = NULL; +        glusterd_conf_t         *priv     = NULL; + +        this = THIS; +        GF_ASSERT (this); +        priv = this->private; +        GF_ASSERT (priv);          ret = glusterd_op_statedump_volume_args_get (dict, &volname, &options,                                                       &option_cnt); @@ -1322,10 +1340,7 @@ glusterd_op_stage_statedump_volume (dict_t *dict, char **op_errstr)          ret = glusterd_volinfo_find (volname, &volinfo);          if (ret) { -                snprintf (msg, sizeof(msg), "Volume %s does not exist", -                          volname); -                gf_log ("", GF_LOG_ERROR, "%s", msg); -                *op_errstr = gf_strdup (msg); +                snprintf (msg, sizeof(msg), FMTSTR_CHECK_VOL_EXISTS, volname);                  goto out;          } @@ -1335,16 +1350,31 @@ glusterd_op_stage_statedump_volume (dict_t *dict, char **op_errstr)          is_running = glusterd_is_volume_started (volinfo);          if (!is_running) { -                snprintf (msg, sizeof(msg), "Volume %s is not in a started" +                snprintf (msg, sizeof(msg), "Volume %s is not in the started"                            " state", volname); -                gf_log ("", GF_LOG_ERROR, "%s", msg); -                *op_errstr = gf_strdup (msg);                  ret = -1;                  goto out;          } +        if (priv->op_version == GD_OP_VERSION_MIN && +            strstr (options, "quotad")) { +                snprintf (msg, sizeof (msg), "The cluster is operating " +                          "at op-version 1. Taking quotad's statedump is " +                          "disallowed in this state"); +                ret = -1; +                goto out; +        } +        if ((strstr (options, "quotad")) && +            (!glusterd_is_volume_quota_enabled (volinfo))) { +                    snprintf (msg, sizeof (msg), "Quota is not enabled on " +                              "volume %s", volname); +                    ret = -1; +                    goto out; +        }  out: -        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); +        if (ret && msg[0] != '\0') +                *op_errstr = gf_strdup (msg); +        gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret);          return ret;  } @@ -1785,6 +1815,10 @@ glusterd_op_delete_volume (dict_t *dict)                  goto out;          } +        ret = glusterd_remove_auxiliary_mount (volname); +        if (ret) +                goto out; +          ret = glusterd_delete_volume (volinfo);  out:          gf_log (this->name, GF_LOG_DEBUG, "returning %d", ret); @@ -1823,6 +1857,12 @@ glusterd_op_statedump_volume (dict_t *dict, char **op_errstr)                  ret = glusterd_nfs_statedump (options, option_cnt, op_errstr);                  if (ret)                          goto out; + +        } else if (strstr (options, "quotad")) { +                ret = glusterd_quotad_statedump (options, option_cnt, +                                                 op_errstr); +                if (ret) +                        goto out;          } else {                  list_for_each_entry (brickinfo, &volinfo->bricks,                                                          brick_list) { diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c index 665a8b29859..131f96ce667 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c @@ -1043,29 +1043,51 @@ struct volopt_map_entry glusterd_volopt_map[] = {   #endif          /* Quota xlator options */ -        { .key        = VKEY_FEATURES_LIMIT_USAGE, -          .voltype    = "features/quota", -          .option     = "limit-set", -          .type       = NO_DOC, -          .op_version = 1, -          .flags      = OPT_FLAG_CLIENT_OPT -        }, -        { .key         = "features.quota-timeout", -          .voltype     = "features/quota", -          .option      = "timeout", -          .value       = "0", -          .op_version  = 1, -          .validate_fn = validate_quota, -          .flags       = OPT_FLAG_CLIENT_OPT -        }, -        { .key         = "features.quota-deem-statfs", -          .voltype     = "features/quota", -          .option      = "deem-statfs", -          .value       = "off", -          .type        = DOC, -          .op_version  = 3, -          .validate_fn = validate_quota, -          .flags       = OPT_FLAG_CLIENT_OPT +        { .key           = VKEY_FEATURES_LIMIT_USAGE, +          .voltype       = "features/quota", +          .option        = "limit-set", +          .type          = NO_DOC, +          .op_version    = 1, +        }, +        { +          .key           = "features.quota-timeout", +          .voltype       = "features/quota", +          .option        = "timeout", +          .value         = "0", +          .op_version    = 1, +          .validate_fn   = validate_quota, +        }, +        { .key           = "features.default-soft-limit", +          .voltype       = "features/quota", +          .option        = "default-soft-limit", +          .type          = NO_DOC, +          .op_version    = 3, +        }, +        { .key           = "features.soft-timeout", +          .voltype       = "features/quota", +          .option        = "soft-timeout", +          .type          = NO_DOC, +          .op_version    = 3, +        }, +        { .key           = "features.hard-timeout", +          .voltype       = "features/quota", +          .option        = "hard-timeout", +          .type          = NO_DOC, +          .op_version    = 3, +        }, +        { .key           = "features.alert-time", +          .voltype       = "features/quota", +          .option        = "alert-time", +          .type          = NO_DOC, +          .op_version    = 3, +        }, +        { .key           = "features.quota-deem-statfs", +          .voltype       = "features/quota", +          .option        = "deem-statfs", +          .value         = "off", +          .type          = DOC, +          .op_version    = 2, +          .validate_fn   = validate_quota,          },          /* Marker xlator options */ diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c index e4c4caee45c..c2be2c9da59 100644 --- a/xlators/mgmt/glusterd/src/glusterd.c +++ b/xlators/mgmt/glusterd/src/glusterd.c @@ -1189,6 +1189,15 @@ init (xlator_t *this)                  exit (1);          } +        snprintf (storedir, PATH_MAX, "%s/quotad", workdir); +        ret = mkdir (storedir, 0777); +        if ((-1 == ret) && (errno != EEXIST)) { +                gf_log (this->name, GF_LOG_CRITICAL, +                        "Unable to create quotad directory %s" +                        " ,errno = %d", storedir, errno); +                exit (1); +        } +          snprintf (storedir, PATH_MAX, "%s/groups", workdir);          ret = mkdir (storedir, 0777);          if ((-1 == ret) && (errno != EEXIST)) { @@ -1253,12 +1262,14 @@ init (xlator_t *this)          conf = GF_CALLOC (1, sizeof (glusterd_conf_t),                            gf_gld_mt_glusterd_conf_t);          GF_VALIDATE_OR_GOTO(this->name, conf, out); -        conf->shd = GF_CALLOC (1, sizeof (nodesrv_t), -                               gf_gld_mt_nodesrv_t); + +        conf->shd = GF_CALLOC (1, sizeof (nodesrv_t), gf_gld_mt_nodesrv_t);          GF_VALIDATE_OR_GOTO(this->name, conf->shd, out); -        conf->nfs = GF_CALLOC (1, sizeof (nodesrv_t), -                               gf_gld_mt_nodesrv_t); +        conf->nfs = GF_CALLOC (1, sizeof (nodesrv_t), gf_gld_mt_nodesrv_t);          GF_VALIDATE_OR_GOTO(this->name, conf->nfs, out); +        conf->quotad = GF_CALLOC (1, sizeof (nodesrv_t), +                               gf_gld_mt_nodesrv_t); +        GF_VALIDATE_OR_GOTO(this->name, conf->quotad, out);          INIT_LIST_HEAD (&conf->peers);          INIT_LIST_HEAD (&conf->volumes); diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index b081ec32eb4..52f8f26b4b6 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -122,39 +122,41 @@ typedef struct {  } gd_global_opts_t;  typedef struct { -        struct _volfile_ctx      *volfile; -        pthread_mutex_t           mutex; -        struct list_head          peers; -        struct list_head          xaction_peers; -        gf_boolean_t              verify_volfile_checksum; -        gf_boolean_t              trace; -        uuid_t                    uuid; -        char                      workdir[PATH_MAX]; -        rpcsvc_t                 *rpc; -        nodesrv_t                *shd; -        nodesrv_t                *nfs; -        struct pmap_registry     *pmap; -        struct list_head          volumes; -        pthread_mutex_t           xprt_lock; -        struct list_head          xprt_list; -        gf_store_handle_t        *handle; -        gf_timer_t               *timer; -        glusterd_sm_tr_log_t      op_sm_log; -        struct rpc_clnt_program  *gfs_mgmt; - -        struct list_head           mount_specs; -        gf_boolean_t               valgrind; -        pthread_t                  brick_thread; -        void                      *hooks_priv; +        struct _volfile_ctx     *volfile; +        pthread_mutex_t          mutex; +        struct list_head         peers; +        struct list_head         xaction_peers; +        gf_boolean_t             verify_volfile_checksum; +        gf_boolean_t             trace; +        uuid_t                   uuid; +        char                     workdir[PATH_MAX]; +        rpcsvc_t                *rpc; +        nodesrv_t               *shd; +        nodesrv_t               *nfs; +        nodesrv_t               *quotad; +        struct pmap_registry    *pmap; +        struct list_head         volumes; +        pthread_mutex_t          xprt_lock; +        struct list_head         xprt_list; +        gf_store_handle_t       *handle; +        gf_timer_t              *timer; +        glusterd_sm_tr_log_t     op_sm_log; +        struct rpc_clnt_program *gfs_mgmt; + +        struct list_head  mount_specs; +        gf_boolean_t      valgrind; +        pthread_t         brick_thread; +        void             *hooks_priv; +          /* need for proper handshake_t */ -        int                        op_version; /* Starts with 1 for 3.3.0 */ -        xlator_t                  *xl;  /* Should be set to 'THIS' before creating thread */ -        gf_boolean_t               pending_quorum_action; -        dict_t                    *opts; -        synclock_t                 big_lock; -        gf_boolean_t               restart_done; -        rpcsvc_t                  *uds_rpc; /* RPCSVC for the unix domain socket */ -        uint32_t                   base_port; +        int           op_version; /* Starts with 1 for 3.3.0 */ +        xlator_t     *xl;       /* Should be set to 'THIS' before creating thread */ +        gf_boolean_t  pending_quorum_action; +        dict_t       *opts; +        synclock_t    big_lock; +        gf_boolean_t  restart_done; +        rpcsvc_t     *uds_rpc;  /* RPCSVC for the unix domain socket */ +        uint32_t      base_port;  } glusterd_conf_t; @@ -281,10 +283,11 @@ struct glusterd_volinfo_ {                                                   distribute volume */          int                       dist_leaf_count; /* Number of bricks in one                                                      distribute subvolume */ -        int                       port; -        gf_store_handle_t        *shandle; -        gf_store_handle_t        *rb_shandle; -        gf_store_handle_t        *node_state_shandle; +        int                     port; +        gf_store_handle_t *shandle; +        gf_store_handle_t *rb_shandle; +        gf_store_handle_t *node_state_shandle; +        gf_store_handle_t *quota_conf_shandle;          /* Defrag/rebalance related */          glusterd_rebalance_t      rebal; @@ -292,10 +295,12 @@ struct glusterd_volinfo_ {          /* Replace brick status */          glusterd_replace_brick_t  rep_brick; -        int                       version; -        uint32_t                  cksum; -        gf_transport_type         transport_type; -        gf_transport_type         nfs_transport_type; +        int                     version; +        uint32_t                quota_conf_version; +        uint32_t                cksum; +        uint32_t                quota_conf_cksum; +        gf_transport_type       transport_type; +        gf_transport_type   nfs_transport_type;          dict_t                   *dict; @@ -321,6 +326,7 @@ typedef enum gd_node_type_ {          GD_NODE_SHD,          GD_NODE_REBALANCE,          GD_NODE_NFS, +        GD_NODE_QUOTAD,  } gd_node_type;  typedef struct glusterd_pending_node_ { @@ -351,12 +357,14 @@ enum glusterd_vol_comp_status_ {  #define GLUSTERD_DEFAULT_WORKDIR "/var/lib/glusterd"  #define GLUSTERD_DEFAULT_PORT    GF_DEFAULT_BASE_PORT  #define GLUSTERD_INFO_FILE      "glusterd.info" +#define GLUSTERD_VOLUME_QUOTA_CONFIG "quota.conf"  #define GLUSTERD_VOLUME_DIR_PREFIX "vols"  #define GLUSTERD_PEER_DIR_PREFIX "peers"  #define GLUSTERD_VOLUME_INFO_FILE "info"  #define GLUSTERD_VOLUME_RBSTATE_FILE "rbstate"  #define GLUSTERD_BRICK_INFO_DIR "bricks"  #define GLUSTERD_CKSUM_FILE "cksum" +#define GLUSTERD_VOL_QUOTA_CKSUM_FILE "quota.cksum"  #define GLUSTERD_TRASH "trash"  #define GLUSTERD_NODE_STATE_FILE "node_state.info" @@ -383,6 +391,9 @@ typedef ssize_t (*gd_serialize_t) (struct iovec outmsg, void *args);  #define GLUSTERD_GET_NFS_DIR(path, priv) \          snprintf (path, PATH_MAX, "%s/nfs", priv->workdir); +#define GLUSTERD_GET_QUOTAD_DIR(path, priv) \ +        snprintf (path, PATH_MAX, "%s/quotad", priv->workdir); +  #define GLUSTERD_REMOVE_SLASH_FROM_PATH(path,string) do {               \                  int i = 0;                                              \                  for (i = 1; i < strlen (path); i++) {                   \ @@ -406,6 +417,11 @@ typedef ssize_t (*gd_serialize_t) (struct iovec outmsg, void *args);                            nfspath);                                     \          } +#define GLUSTERD_GET_QUOTAD_PIDFILE(pidfile,quotadpath) {                     \ +                snprintf (pidfile, PATH_MAX, "%s/run/quotad.pid",          \ +                          quotadpath);                                     \ +        } +  #define GLUSTERD_STACK_DESTROY(frame) do {\                  frame->local = NULL;                                    \                  STACK_DESTROY (frame->root);                            \ @@ -431,6 +447,10 @@ typedef ssize_t (*gd_serialize_t) (struct iovec outmsg, void *args);                             uuid_utoa(MY_UUID));                         \          } while (0) +#define GLUSTERFS_GET_AUX_MOUNT_PIDFILE(pidfile, volname) {               \ +                snprintf (pidfile, PATH_MAX-1,                            \ +                          DEFAULT_VAR_RUN_DIRECTORY"/%s.pid", volname);   \ +        }  int glusterd_uuid_init(); @@ -720,7 +740,7 @@ int glusterd_op_sys_exec (dict_t *dict, char **op_errstr, dict_t *rsp_dict);  int glusterd_op_stage_gsync_create (dict_t *dict, char **op_errstr);  int glusterd_op_gsync_create (dict_t *dict, char **op_errstr, dict_t *rsp_dict);  int glusterd_op_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict); -int glusterd_op_stage_quota (dict_t *dict, char **op_errstr); +int glusterd_op_stage_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict);  int glusterd_op_stage_replace_brick (dict_t *dict, char **op_errstr,                                       dict_t *rsp_dict);  int glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict);  | 
