diff options
author | Raghavendra G <raghavendra@zresearch.com> | 2009-05-15 03:55:20 -0700 |
---|---|---|
committer | Anand V. Avati <avati@amp.gluster.com> | 2009-05-16 16:40:18 +0530 |
commit | 9669c70c901474dc21ef08e49478b5f5dead8f64 (patch) | |
tree | 9040bceccf4c3aaec5966655900f7fac11de3646 /libglusterfs/src/dict.c | |
parent | dec2674685da30d6cef157748bcf52454ec97208 (diff) |
dict.c: Add dict_allocate_and_serialize
- this procedure atomically allocates a buffer and serializes dict into it.
- this procedure helps avoid memory corruptions due to race conditions where
in new members are added into dict between allocating a buffer for
serializing and actually serializing buffer into it.
Signed-off-by: Anand V. Avati <avati@amp.gluster.com>
Diffstat (limited to 'libglusterfs/src/dict.c')
-rw-r--r-- | libglusterfs/src/dict.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c index 22e350e0e9a..b4c75d79f89 100644 --- a/libglusterfs/src/dict.c +++ b/libglusterfs/src/dict.c @@ -2050,6 +2050,173 @@ err: #define DICT_DATA_HDR_VAL_LEN 4 /** + * _dict_serialized_length - return the length of serialized dict. This + * procedure has to be called with this->lock held. + * + * @this : dict to be serialized + * @return: success: len + * : failure: -errno + */ + +int +_dict_serialized_length (dict_t *this) +{ + int ret = -EINVAL; + int count = 0; + int len = 0; + int i = 0; + data_pair_t * pair = NULL; + + len = DICT_HDR_LEN; + count = this->count; + + if (count < 0) { + gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0!", count); + goto out; + } + + pair = this->members_list; + + while (count) { + if (!pair) { + gf_log ("dict", GF_LOG_ERROR, + "less than count data pairs found!"); + goto out; + } + + len += DICT_DATA_HDR_KEY_LEN + DICT_DATA_HDR_VAL_LEN; + + if (!pair->key) { + gf_log ("dict", GF_LOG_ERROR, "pair->key is null!"); + goto out; + } + + len += strlen (pair->key) + 1 /* for '\0' */; + + if (!pair->value) { + gf_log ("dict", GF_LOG_ERROR, + "pair->value is null!"); + goto out; + } + + if (pair->value->vec) { + for (i = 0; i < pair->value->len; i++) { + if (pair->value->vec[i].iov_len < 0) { + gf_log ("dict", GF_LOG_ERROR, + "iov_len (%"GF_PRI_SIZET") < 0!", + pair->value->vec[i].iov_len); + goto out; + } + + len += pair->value->vec[i].iov_len; + } + } else { + if (pair->value->len < 0) { + gf_log ("dict", GF_LOG_ERROR, + "value->len (%d) < 0", + pair->value->len); + goto out; + } + + len += pair->value->len; + } + + pair = pair->next; + count--; + } + + ret = len; +out: + return ret; +} + +/** + * _dict_serialize - serialize a dictionary into a buffer. This procedure has + * to be called with this->lock held. + * + * @this: dict to serialize + * @buf: buffer to serialize into. This must be + * atleast dict_serialized_length (this) large + * + * @return: success: 0 + * failure: -errno + */ + +int +_dict_serialize (dict_t *this, char *buf) +{ + int ret = -1; + data_pair_t * pair = NULL; + int32_t count = 0; + int32_t keylen = 0; + int32_t vallen = 0; + + if (!buf) { + gf_log ("dict", GF_LOG_ERROR, + "buf is null!"); + goto out; + } + + count = this->count; + if (count < 0) { + gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0!", count); + goto out; + } + + *(int32_t *) buf = hton32 (count); + buf += DICT_HDR_LEN; + pair = this->members_list; + + while (count) { + if (!pair) { + gf_log ("dict", GF_LOG_ERROR, + "less than count data pairs found!"); + goto out; + } + + if (!pair->key) { + gf_log ("dict", GF_LOG_ERROR, + "pair->key is null!"); + goto out; + } + + keylen = strlen (pair->key); + *(int32_t *) buf = hton32 (keylen); + buf += DICT_DATA_HDR_KEY_LEN; + + if (!pair->value) { + gf_log ("dict", GF_LOG_ERROR, + "pair->value is null!"); + goto out; + } + + vallen = pair->value->len; + *(int32_t *) buf = hton32 (vallen); + buf += DICT_DATA_HDR_VAL_LEN; + + memcpy (buf, pair->key, keylen); + buf += keylen; + *buf++ = '\0'; + + if (!pair->value->data) { + gf_log ("dict", GF_LOG_ERROR, + "pair->value->data is null!"); + goto out; + } + memcpy (buf, pair->value->data, vallen); + buf += vallen; + + pair = pair->next; + count--; + } + + ret = 0; +out: + return ret; +} + + +/** * dict_serialized_length - return the length of serialized dict * * @this: dict to be serialized @@ -2337,3 +2504,63 @@ out: return ret; } + +/** + * dict_allocate_and_serialize - serialize a dictionary into an allocated buffer + * + * @this: dict to serialize + * @buf: pointer to pointer to character. The allocated buffer is stored in + * this pointer. The buffer has to be freed by the caller. + * + * @return: success: 0 + * failure: -errno + */ + +int32_t +dict_allocate_and_serialize (dict_t *this, char **buf, size_t *length) +{ + int ret = -EINVAL; + ssize_t len = 0; + + if (!this) { + gf_log ("dict", GF_LOG_DEBUG, + "NULL passed as this pointer"); + goto out; + } + if (!buf) { + gf_log ("dict", GF_LOG_DEBUG, + "NULL passed as buf"); + goto out; + } + + LOCK (&this->lock); + { + len = _dict_serialized_length (this); + if (len < 0) { + ret = len; + goto unlock; + } + + *buf = CALLOC (1, len); + if (*buf == NULL) { + ret = -ENOMEM; + gf_log ("dict", GF_LOG_ERROR, "out of memory"); + goto unlock; + } + + ret = _dict_serialize (this, *buf); + if (ret < 0) { + FREE (*buf); + *buf = NULL; + goto unlock; + } + + if (length != NULL) { + *length = len; + } + } +unlock: + UNLOCK (&this->lock); +out: + return ret; +} |