summaryrefslogtreecommitdiffstats
path: root/xlators/mgmt/glusterd/src/glusterd-handshake.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-handshake.c')
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-handshake.c178
1 files changed, 103 insertions, 75 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-handshake.c b/xlators/mgmt/glusterd/src/glusterd-handshake.c
index c41a9459870..9124c46ee21 100644
--- a/xlators/mgmt/glusterd/src/glusterd-handshake.c
+++ b/xlators/mgmt/glusterd/src/glusterd-handshake.c
@@ -108,112 +108,140 @@ out:
return ret;
}
-int
-__server_getspec (rpcsvc_request_t *req)
+/* Get and store op-versions of the clients sending the getspec request
+ * Clients of versions <= 3.3, don't send op-versions, their op-versions are
+ * defaulted to 1
+ */
+static int
+_get_client_op_versions (gf_getspec_req *args, peer_info_t *peerinfo)
{
- int32_t ret = -1;
- int32_t op_errno = 0;
- int32_t spec_fd = -1;
- size_t file_len = 0;
- char filename[PATH_MAX] = {0,};
- struct stat stbuf = {0,};
- char *volume = NULL;
- char *tmp = NULL;
- int cookie = 0;
- rpc_transport_t *trans = NULL;
- gf_getspec_req args = {0,};
- gf_getspec_rsp rsp = {0,};
- char addrstr[RPCSVC_PEER_STRLEN] = {0};
- dict_t *dict = NULL;
- xlator_t *this = NULL;
- glusterd_conf_t *conf = NULL;
- int client_min_op_version = 1; // OP-VERSIONs start at 1
- int client_max_op_version = 1;
-
- this = THIS;
- GF_ASSERT (this);
+ int ret = 0;
+ int client_max_op_version = 1;
+ int client_min_op_version = 1;
+ dict_t *dict = NULL;
- conf = this->private;
- GF_ASSERT (conf);
+ GF_ASSERT (args);
+ GF_ASSERT (peerinfo);
- ret = xdr_to_generic (req->msg[0], &args,
- (xdrproc_t)xdr_gf_getspec_req);
- if (ret < 0) {
- //failed to decode msg;
- req->rpc_err = GARBAGE_ARGS;
- goto fail;
- }
-
- if (!args.xdata.xdata_len) {
- // For clients <= 3.3.0, only allow if op_version = 1
- if (1 != conf->op_version) {
- ret = -1;
- op_errno = ENOTSUP;
- gf_log (this->name, GF_LOG_INFO,
- "Client %s doesn't support required op-version. "
- "Rejecting getspec request.",
- req->trans->peerinfo.identifier);
- goto fail;
- }
- } else {
- // For clients > 3.3, only allow if they can support
- // clusters' op_version
+ if (args->xdata.xdata_len) {
dict = dict_new ();
if (!dict) {
ret = -1;
- goto fail;
+ goto out;
}
- ret = dict_unserialize (args.xdata.xdata_val,
- args.xdata.xdata_len, &dict);
+ ret = dict_unserialize (args->xdata.xdata_val,
+ args->xdata.xdata_len, &dict);
if (ret) {
- gf_log (this->name, GF_LOG_ERROR,
+ gf_log ("glusterd", GF_LOG_ERROR,
"Failed to unserialize request dictionary");
- goto fail;
+ goto out;
}
ret = dict_get_int32 (dict, "min-op-version",
&client_min_op_version);
if (ret) {
- gf_log (this->name, GF_LOG_ERROR,
+ gf_log ("glusterd", GF_LOG_ERROR,
"Failed to get client-min-op-version");
- goto fail;
+ goto out;
}
ret = dict_get_int32 (dict, "max-op-version",
&client_max_op_version);
if (ret) {
- gf_log (this->name, GF_LOG_ERROR,
+ gf_log ("glusterd", GF_LOG_ERROR,
"Failed to get client-max-op-version");
- goto fail;
+ goto out;
}
+ }
- if ((client_min_op_version > conf->op_version) ||
- (client_max_op_version < conf->op_version)) {
- ret = -1;
- op_errno = ENOTSUP;
- //TODO: Add client identifier
- gf_log (this->name, GF_LOG_INFO,
- "Client %s doesn't support required op-version. "
- "Rejecting getspec request.",
- req->trans->peerinfo.identifier);
- goto fail;
- }
+ peerinfo->max_op_version = client_max_op_version;
+ peerinfo->min_op_version = client_min_op_version;
+out:
+ return ret;
+}
+
+/* Checks if the client supports the volume, ie. client can understand all the
+ * options in the volfile
+ */
+static gf_boolean_t
+_client_supports_volume (peer_info_t *peerinfo, int32_t *op_errno)
+{
+ gf_boolean_t ret = _gf_true;
+ glusterd_volinfo_t *volinfo = NULL;
+
+ GF_ASSERT (peerinfo);
+ GF_ASSERT (op_errno);
+
+
+ /* Only check when the volfile being requested is a volume. Not finding
+ * a volinfo implies that the volfile requested for is not of a gluster
+ * volume. A non volume volfile is requested by the local gluster
+ * services like shd and nfs-server. These need not be checked as they
+ * will be running at the same op-version as glusterd and will be able
+ * to support all the features
+ */
+ if ((glusterd_volinfo_find (peerinfo->volname, &volinfo) == 0) &&
+ ((peerinfo->min_op_version > volinfo->client_op_version) ||
+ (peerinfo->max_op_version < volinfo->client_op_version))) {
+ ret = _gf_false;
+ *op_errno = ENOTSUP;
+ gf_log ("glusterd", GF_LOG_INFO,
+ "Client %s (%d -> %d) doesn't support required "
+ "op-version (%d). Rejecting volfile request.",
+ peerinfo->identifier, peerinfo->min_op_version,
+ peerinfo->max_op_version, volinfo->client_op_version);
}
- // Store the op-versions supported by the client
- req->trans->peerinfo.max_op_version = client_max_op_version;
- req->trans->peerinfo.min_op_version = client_min_op_version;
+ return ret;
+}
- volume = args.key;
+int
+__server_getspec (rpcsvc_request_t *req)
+{
+ int32_t ret = -1;
+ int32_t op_errno = 0;
+ int32_t spec_fd = -1;
+ size_t file_len = 0;
+ char filename[PATH_MAX] = {0,};
+ struct stat stbuf = {0,};
+ char *volume = NULL;
+ char *tmp = NULL;
+ int cookie = 0;
+ rpc_transport_t *trans = NULL;
+ gf_getspec_req args = {0,};
+ gf_getspec_rsp rsp = {0,};
+ char addrstr[RPCSVC_PEER_STRLEN] = {0};
+ peer_info_t *peerinfo = NULL;
- // Store the name of volume being mounted
+ ret = xdr_to_generic (req->msg[0], &args,
+ (xdrproc_t)xdr_gf_getspec_req);
+ if (ret < 0) {
+ //failed to decode msg;
+ req->rpc_err = GARBAGE_ARGS;
+ goto fail;
+ }
+
+ peerinfo = &req->trans->peerinfo;
+
+ volume = args.key;
+ /* Need to strip leading '/' from volnames. This was introduced to
+ * support nfs style mount parameters for native gluster mount
+ */
if (volume[0] == '/')
- strncpy (req->trans->peerinfo.volname, &volume[1],
- strlen(&volume[1]));
+ strncpy (peerinfo->volname, &volume[1], strlen(&volume[1]));
else
- strncpy (req->trans->peerinfo.volname, volume, strlen(volume));
+ strncpy (peerinfo->volname, volume, strlen(volume));
+
+ ret = _get_client_op_versions (&args, peerinfo);
+ if (ret)
+ goto fail;
+
+ if (!_client_supports_volume (peerinfo, &op_errno)) {
+ ret = -1;
+ goto fail;
+ }
trans = req->trans;
ret = rpcsvc_transport_peername (trans, (char *)&addrstr,