diff options
Diffstat (limited to 'xlators/lib/src/libxlator.c')
| -rw-r--r-- | xlators/lib/src/libxlator.c | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/xlators/lib/src/libxlator.c b/xlators/lib/src/libxlator.c new file mode 100644 index 000000000..9e5357255 --- /dev/null +++ b/xlators/lib/src/libxlator.c @@ -0,0 +1,470 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#include "mem-types.h" +#include "libxlator.h" + + +int marker_xtime_default_gauge[] = { + [MCNT_FOUND] = 1, + [MCNT_NOTFOUND] = -1, + [MCNT_ENODATA] = -1, + [MCNT_ENOTCONN] = -1, + [MCNT_ENOENT] = -1, + [MCNT_EOTHER] = -1, +}; + +int marker_uuid_default_gauge[] = { + [MCNT_FOUND] = 1, + [MCNT_NOTFOUND] = 0, + [MCNT_ENODATA] = 0, + [MCNT_ENOTCONN] = 0, + [MCNT_ENOENT] = 0, + [MCNT_EOTHER] = 0, +}; + +static int marker_idx_errno_map[] = { + [MCNT_FOUND] = EINVAL, + [MCNT_NOTFOUND] = EINVAL, + [MCNT_ENOENT] = ENOENT, + [MCNT_ENOTCONN] = ENOTCONN, + [MCNT_ENODATA] = ENODATA, + [MCNT_EOTHER] = EINVAL, + [MCNT_MAX] = 0, +}; + +/*Copy the contents of oldtimebuf to newtimbuf*/ +static void +update_timebuf (uint32_t *oldtimbuf, uint32_t *newtimebuf) +{ + newtimebuf[0] = (oldtimbuf[0]); + newtimebuf[1] = (oldtimbuf[1]); +} + +/* Convert Timebuf in network order to host order */ +static void +get_hosttime (uint32_t *oldtimbuf, uint32_t *newtimebuf) +{ + newtimebuf[0] = ntohl (oldtimbuf[0]); + newtimebuf[1] = ntohl (oldtimbuf[1]); +} + + + +/* Match the Incoming trusted.glusterfs.<uuid>.xtime against volume uuid */ +int +match_uuid_local (const char *name, char *uuid) +{ + name = strtail ((char *)name, MARKER_XATTR_PREFIX); + if (!name || name++[0] != '.') + return -1; + + name = strtail ((char *)name, uuid); + if (!name || strcmp (name, ".xtime") != 0) + return -1; + + return 0; +} + +static void +marker_local_incr_errcount (xl_marker_local_t *local, int op_errno) +{ + marker_result_idx_t i = -1; + + if (!local) + return; + + switch (op_errno) { + case ENODATA: + i = MCNT_ENODATA; + break; + case ENOENT: + i = MCNT_ENOENT; + break; + case ENOTCONN: + i = MCNT_ENOTCONN; + break; + default: + i = MCNT_EOTHER; + break; + } + + local->count[i]++; +} + +static int +evaluate_marker_results (int *gauge, int *count) +{ + int i = 0; + int op_errno = 0; + gf_boolean_t sane = _gf_true; + + /* check if the policy of the gauge is violated; + * if yes, try to get the best errno, ie. look + * for the first position where there is a more + * specific kind of vioilation than the generic EINVAL + */ + for (i = 0; i < MCNT_MAX; i++) { + if (sane) { + if ((gauge[i] > 0 && count[i] < gauge[i]) || + (gauge[i] < 0 && count[i] >= -gauge[i])) { + sane = _gf_false; + /* generic action: adopt corresponding errno */ + op_errno = marker_idx_errno_map[i]; + } + } else { + /* already insane; trying to get a more informative + * errno by checking subsequent counters + */ + if (count[i] > 0) + op_errno = marker_idx_errno_map[i]; + } + if (op_errno && op_errno != EINVAL) + break; + } + + return op_errno; +} + +/* Aggregate all the <volid>.xtime attrs of the cluster and send the max*/ +int32_t +cluster_markerxtime_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, dict_t *dict, dict_t *xdata) + +{ + + int32_t callcnt = 0; + int ret = -1; + uint32_t *net_timebuf = NULL; + uint32_t host_timebuf[2] = {0,}; + char *marker_xattr = NULL; + xl_marker_local_t *local = NULL; + char *vol_uuid = NULL; + char need_unwind = 0; + + if (!this || !frame || !frame->local || !cookie) { + gf_log ("", GF_LOG_DEBUG, "possible NULL deref"); + need_unwind = 1; + goto out; + } + + local = frame->local; + if (!local || !local->vol_uuid) { + gf_log (this->name, GF_LOG_DEBUG, "possible NULL deref"); + need_unwind = 1; + goto out; + } + + LOCK (&frame->lock); + { + callcnt = --local->call_count; + + vol_uuid = local->vol_uuid; + + if (op_ret) { + marker_local_incr_errcount (local, op_errno); + goto unlock; + } + + if (!gf_asprintf (&marker_xattr, "%s.%s.%s", + MARKER_XATTR_PREFIX, vol_uuid, XTIME)) { + op_errno = ENOMEM; + goto unlock; + } + + + if (dict_get_ptr (dict, marker_xattr, (void **)&net_timebuf)) { + gf_log (this->name, GF_LOG_WARNING, + "Unable to get <uuid>.xtime attr"); + local->count[MCNT_NOTFOUND]++; + goto unlock; + } + + if (local->count[MCNT_FOUND]) { + get_hosttime (net_timebuf, host_timebuf); + if ( (host_timebuf[0]>local->host_timebuf[0]) || + (host_timebuf[0] == local->host_timebuf[0] && + host_timebuf[1] >= local->host_timebuf[1])) { + update_timebuf (net_timebuf, local->net_timebuf); + update_timebuf (host_timebuf, local->host_timebuf); + } + + } else { + get_hosttime (net_timebuf, local->host_timebuf); + update_timebuf (net_timebuf, local->net_timebuf); + local->count[MCNT_FOUND]++; + } + + } +unlock: + UNLOCK (&frame->lock); + + if (!callcnt) { + op_ret = 0; + op_errno = 0; + need_unwind = 1; + + if (local->count[MCNT_FOUND]) { + if (!dict) + dict = dict_new(); + + ret = dict_set_static_bin (dict, marker_xattr, + (void *)local->net_timebuf, 8); + if (ret) { + op_ret = -1; + op_errno = ENOMEM; + goto out; + } + } + + op_errno = evaluate_marker_results (local->gauge, local->count); + if (op_errno) + op_ret = -1; + } + +out: + if (need_unwind && local && local->xl_specf_unwind) { + frame->local = local->xl_local; + local->xl_specf_unwind (frame, op_ret, + op_errno, dict, xdata); + } else if (need_unwind) { + STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, + dict, xdata); + } + + GF_FREE (marker_xattr); + return 0; + +} + +int32_t +cluster_markeruuid_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, dict_t *dict, dict_t *xdata) +{ + int32_t callcnt = 0; + struct volume_mark *volmark = NULL; + xl_marker_local_t *local = NULL; + int32_t ret = -1; + char need_unwind = 0; + char *vol_uuid = NULL; + + if (!this || !frame || !cookie) { + gf_log ("", GF_LOG_DEBUG, "possible NULL deref"); + need_unwind = 1; + goto out; + } + + local = frame->local; + + if (!local) { + gf_log (this->name, GF_LOG_DEBUG, "possible NULL deref"); + need_unwind = 1; + goto out; + } + + LOCK (&frame->lock); + { + callcnt = --local->call_count; + vol_uuid = local->vol_uuid; + + if (op_ret) { + marker_local_incr_errcount (local, op_errno); + goto unlock; + } + + ret = dict_get_bin (dict, GF_XATTR_MARKER_KEY, + (void *)&volmark); + if (ret) + goto unlock; + + if (local->count[MCNT_FOUND]) { + if ((local->volmark->major != volmark->major) || + (local->volmark->minor != volmark->minor)) { + op_ret = -1; + op_errno = EINVAL; + goto unlock; + } + + if (local->retval) + goto unlock; + else if (volmark->retval) { + GF_FREE (local->volmark); + local->volmark = + memdup (volmark, sizeof (*volmark)); + local->retval = volmark->retval; + } else if ((volmark->sec > local->volmark->sec) || + ((volmark->sec == local->volmark->sec) && + (volmark->usec >= local->volmark->usec))) { + GF_FREE (local->volmark); + local->volmark = + memdup (volmark, sizeof (*volmark)); + } + + } else { + local->volmark = memdup (volmark, sizeof (*volmark)); + VALIDATE_OR_GOTO (local->volmark, unlock); + uuid_unparse (volmark->uuid, vol_uuid); + if (volmark->retval) + local->retval = volmark->retval; + local->count[MCNT_FOUND]++; + } + } +unlock: + UNLOCK (&frame->lock); + + if (!callcnt) { + op_ret = 0; + op_errno = 0; + need_unwind = 1; + + if (local->count[MCNT_FOUND]) { + if (!dict) + dict = dict_new(); + + if (dict_set_bin (dict, GF_XATTR_MARKER_KEY, + local->volmark, + sizeof (struct volume_mark))) { + op_ret = -1; + op_errno = ENOMEM; + } + } + op_errno = evaluate_marker_results (local->gauge, local->count); + if (op_errno) + op_ret = -1; + } + + out: + if (need_unwind && local && local->xl_specf_unwind) { + frame->local = local->xl_local; + local->xl_specf_unwind (frame, op_ret, + op_errno, dict, xdata); + return 0; + } else if (need_unwind){ + STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, + dict, xdata); + } + return 0; +} + + +int32_t +cluster_getmarkerattr (call_frame_t *frame,xlator_t *this, loc_t *loc, + const char *name, void *xl_local, + xlator_specf_unwind_t xl_specf_getxattr_unwind, + xlator_t **sub_volumes, int count, int type, + int *gauge, char *vol_uuid) +{ + int i = 0; + xl_marker_local_t *local = NULL; + + VALIDATE_OR_GOTO (frame, err); + VALIDATE_OR_GOTO (this, err); + VALIDATE_OR_GOTO (loc, err); + VALIDATE_OR_GOTO (loc->path, err); + VALIDATE_OR_GOTO (loc->inode, err); + VALIDATE_OR_GOTO (name, err); + VALIDATE_OR_GOTO (xl_specf_getxattr_unwind, err); + + local = GF_CALLOC (sizeof (struct marker_str), 1, + gf_common_mt_libxl_marker_local); + + if (!local) + goto err; + + local->xl_local = xl_local; + local->call_count = count; + local->xl_specf_unwind = xl_specf_getxattr_unwind; + local->vol_uuid = vol_uuid; + memcpy (local->gauge, gauge, sizeof (local->gauge)); + + frame->local = local; + + for (i=0; i < count; i++) { + if (MARKER_UUID_TYPE == type) + STACK_WIND (frame, cluster_markeruuid_cbk, + *(sub_volumes + i), + (*(sub_volumes + i))->fops->getxattr, + loc, name, NULL); + else if (MARKER_XTIME_TYPE == type) + STACK_WIND (frame, cluster_markerxtime_cbk, + *(sub_volumes + i), + (*(sub_volumes + i))->fops->getxattr, + loc, name, NULL); + else { + gf_log (this->name, GF_LOG_WARNING, + "Unrecognized type (%d) of marker attr " + "received", type); + STACK_WIND (frame, default_getxattr_cbk, + *(sub_volumes + i), + (*(sub_volumes + i))->fops->getxattr, + loc, name, NULL); + break; + } + } + + return 0; +err: + return -1; + +} + +int +gf_get_min_stime (xlator_t *this, dict_t *dst, char *key, data_t *value) +{ + int ret = -1; + uint32_t *net_timebuf = NULL; + uint32_t *value_timebuf = NULL; + uint32_t host_timebuf[2] = {0,}; + uint32_t host_value_timebuf[2] = {0,}; + + /* stime should be minimum of all the other nodes */ + ret = dict_get_bin (dst, key, (void **)&net_timebuf); + if (ret < 0) { + net_timebuf = GF_CALLOC (1, sizeof (int64_t), + gf_common_mt_char); + if (!net_timebuf) + goto out; + + ret = dict_set_bin (dst, key, net_timebuf, sizeof (int64_t)); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "key=%s: dict set failed", key); + goto error; + } + } + + value_timebuf = data_to_bin (value); + if (!value_timebuf) { + gf_log (this->name, GF_LOG_WARNING, + "key=%s: getting value of stime failed", key); + ret = -1; + goto out; + } + + get_hosttime (value_timebuf, host_value_timebuf); + get_hosttime (net_timebuf, host_timebuf); + + /* can't use 'min()' macro here as we need to compare two fields + in the array, selectively */ + if ((host_value_timebuf[0] > host_timebuf[0]) || + ((host_value_timebuf[0] == host_timebuf[0]) && + (host_value_timebuf[1] > host_timebuf[1]))) { + update_timebuf (value_timebuf, net_timebuf); + } + + ret = 0; +out: + return ret; +error: + /* To be used only when net_timebuf is not set in the dict */ + if (net_timebuf) + GF_FREE (net_timebuf); + + return ret; +} |
