diff options
-rw-r--r-- | xlators/cluster/ec/src/ec-heal.c | 8 | ||||
-rw-r--r-- | xlators/cluster/ec/src/ec-helpers.c | 29 | ||||
-rw-r--r-- | xlators/cluster/ec/src/ec-helpers.h | 108 | ||||
-rw-r--r-- | xlators/cluster/ec/src/ec-inode-read.c | 10 | ||||
-rw-r--r-- | xlators/cluster/ec/src/ec-inode-write.c | 13 | ||||
-rw-r--r-- | xlators/cluster/ec/src/ec-locks.c | 8 |
6 files changed, 129 insertions, 47 deletions
diff --git a/xlators/cluster/ec/src/ec-heal.c b/xlators/cluster/ec/src/ec-heal.c index a6de3eee439..bc25015498a 100644 --- a/xlators/cluster/ec/src/ec-heal.c +++ b/xlators/cluster/ec/src/ec-heal.c @@ -1670,7 +1670,8 @@ ec_heal_data_find_direction (ec_t *ec, default_args_cbk_t *replies, * well*/ if (check_ondisksize) { - source_size = ec_adjust_size (ec, size[source], 1); + source_size = size[source]; + ec_adjust_size_up (ec, &source_size, _gf_true); for (i = 0; i < ec->nodes; i++) { if (sources[i]) { @@ -1983,7 +1984,7 @@ ec_rebuild_data (call_frame_t *frame, ec_t *ec, fd_t *fd, uint64_t size, heal->fd = fd_ref (fd); heal->xl = ec->xl; heal->data = &barrier; - size = ec_adjust_size (ec, size, 0); + ec_adjust_size_up (ec, &size, _gf_false); heal->total_size = size; heal->size = (128 * GF_UNIT_KB * (ec->self_heal_window_size)); /* We need to adjust the size to a multiple of the stripe size of the @@ -2038,7 +2039,8 @@ __ec_heal_trim_sinks (call_frame_t *frame, ec_t *ec, ret = 0; goto out; } - trim_offset = ec_adjust_size (ec, size, 1); + trim_offset = size; + ec_adjust_offset_up (ec, &trim_offset, _gf_true); ret = cluster_ftruncate (ec->xl_list, trim, ec->nodes, replies, output, frame, ec->xl, fd, trim_offset, NULL); for (i = 0; i < ec->nodes; i++) { diff --git a/xlators/cluster/ec/src/ec-helpers.c b/xlators/cluster/ec/src/ec-helpers.c index c998462655f..122fe24b5d3 100644 --- a/xlators/cluster/ec/src/ec-helpers.c +++ b/xlators/cluster/ec/src/ec-helpers.c @@ -799,35 +799,6 @@ ec_fd_t * ec_fd_get(fd_t * fd, xlator_t * xl) return ctx; } -uint32_t ec_adjust_offset(ec_t * ec, off_t * offset, int32_t scale) -{ - off_t head, tmp; - - tmp = *offset; - head = tmp % ec->stripe_size; - tmp -= head; - if (scale) - { - tmp /= ec->fragments; - } - - *offset = tmp; - - return head; -} - -uint64_t ec_adjust_size(ec_t * ec, uint64_t size, int32_t scale) -{ - size += ec->stripe_size - 1; - size -= size % ec->stripe_size; - if (scale) - { - size /= ec->fragments; - } - - return size; -} - gf_boolean_t ec_is_internal_xattr (dict_t *dict, char *key, data_t *value, void *data) { diff --git a/xlators/cluster/ec/src/ec-helpers.h b/xlators/cluster/ec/src/ec-helpers.h index 4d2145c8317..cfd7daaa5c2 100644 --- a/xlators/cluster/ec/src/ec-helpers.h +++ b/xlators/cluster/ec/src/ec-helpers.h @@ -55,8 +55,112 @@ ec_inode_t * ec_inode_get(inode_t * inode, xlator_t * xl); ec_fd_t * __ec_fd_get(fd_t * fd, xlator_t * xl); ec_fd_t * ec_fd_get(fd_t * fd, xlator_t * xl); -uint32_t ec_adjust_offset(ec_t * ec, off_t * offset, int32_t scale); -uint64_t ec_adjust_size(ec_t * ec, uint64_t size, int32_t scale); +static inline uint32_t +ec_adjust_size_down(ec_t *ec, uint64_t *value, gf_boolean_t scale) +{ + uint64_t head, tmp; + + tmp = *value; + head = tmp % ec->stripe_size; + tmp -= head; + + if (scale) { + tmp /= ec->fragments; + } + + *value = tmp; + + return (uint32_t)head; +} + +/* This function can cause an overflow if the passed value is too near to the + * uint64_t limit. If this happens, it returns the tail in negative form and + * the value is set to UINT64_MAX. */ +static inline int32_t +ec_adjust_size_up(ec_t *ec, uint64_t *value, gf_boolean_t scale) +{ + uint64_t tmp; + int32_t tail; + + tmp = *value; + /* We first adjust the value down. This never causes overflow. */ + tail = ec_adjust_size_down(ec, &tmp, scale); + + /* If the value was already aligned, tail will be 0 and nothing else + * needs to be done. */ + if (tail != 0) { + /* Otherwise, we need to compute the real tail and adjust the + * returned value to the next stripe. */ + tail = ec->stripe_size - tail; + if (scale) { + tmp += ec->fragment_size; + } else { + tmp += ec->stripe_size; + /* If no scaling is requested there's a posibility of + * overflow. */ + if (tmp < ec->stripe_size) { + tmp = UINT64_MAX; + tail = -tail; + } + } + } + + *value = tmp; + + return tail; +} + +/* This function is equivalent to ec_adjust_size_down() but with a potentially + * different parameter size (off_t vs uint64_t). */ +static inline uint32_t +ec_adjust_offset_down(ec_t *ec, off_t *value, gf_boolean_t scale) +{ + off_t head, tmp; + + tmp = *value; + head = tmp % ec->stripe_size; + tmp -= head; + + if (scale) { + tmp /= ec->fragments; + } + + *value = tmp; + + return (uint32_t)head; +} + +/* This function is equivalent to ec_adjust_size_up() but with a potentially + * different parameter size (off_t vs uint64_t). */ +static inline int32_t +ec_adjust_offset_up(ec_t *ec, off_t *value, gf_boolean_t scale) +{ + uint64_t tail, tmp; + + /* An offset is a signed type that can only have positive values, so + * we take advantage of this to avoid overflows. We simply convert it + * to an unsigned integer and operate normally. This won't cause an + * overflow. Overflow is only checked when converting back to an + * off_t. */ + tmp = *value; + tail = ec->stripe_size; + tail -= (tmp + tail - 1) % tail + 1; + tmp += tail; + if (scale) { + /* If we are scaling, we'll never get an overflow. */ + tmp /= ec->fragments; + } else { + /* Check if there has been an overflow. */ + if ((off_t)tmp < 0) { + tmp = (1ULL << (sizeof(off_t) * 8 - 1)) - 1ULL; + tail = -tail; + } + } + + *value = (off_t)tmp; + + return (int32_t)tail; +} static inline int32_t ec_is_power_of_2(uint32_t value) { diff --git a/xlators/cluster/ec/src/ec-inode-read.c b/xlators/cluster/ec/src/ec-inode-read.c index d925e82ba36..829f47f76aa 100644 --- a/xlators/cluster/ec/src/ec-inode-read.c +++ b/xlators/cluster/ec/src/ec-inode-read.c @@ -1356,9 +1356,10 @@ int32_t ec_manager_readv(ec_fop_data_t * fop, int32_t state) { case EC_STATE_INIT: fop->user_size = fop->size; - fop->head = ec_adjust_offset(fop->xl->private, &fop->offset, 1); - fop->size = ec_adjust_size(fop->xl->private, fop->size + fop->head, - 1); + fop->head = ec_adjust_offset_down(fop->xl->private, &fop->offset, + _gf_true); + fop->size += fop->head; + ec_adjust_size_up(fop->xl->private, &fop->size, _gf_true); /* Fall through */ @@ -1561,7 +1562,8 @@ int32_t ec_manager_seek(ec_fop_data_t *fop, int32_t state) switch (state) { case EC_STATE_INIT: fop->user_size = fop->offset; - fop->head = ec_adjust_offset(fop->xl->private, &fop->offset, 1); + fop->head = ec_adjust_offset_down(fop->xl->private, &fop->offset, + _gf_true); /* Fall through */ diff --git a/xlators/cluster/ec/src/ec-inode-write.c b/xlators/cluster/ec/src/ec-inode-write.c index 68bea1ae55b..3ed9b2a1ba4 100644 --- a/xlators/cluster/ec/src/ec-inode-write.c +++ b/xlators/cluster/ec/src/ec-inode-write.c @@ -870,8 +870,10 @@ int32_t ec_manager_fallocate(ec_fop_data_t *fop, int32_t state) return EC_STATE_REPORT; } fop->user_size = fop->offset + fop->size; - fop->head = ec_adjust_offset (fop->xl->private, &fop->offset, 1); - fop->size = ec_adjust_size (fop->xl->private, fop->head + fop->size, 1); + fop->head = ec_adjust_offset_down (fop->xl->private, &fop->offset, + _gf_true); + fop->size += fop->head; + ec_adjust_size_up (fop->xl->private, &fop->size, _gf_true); /* Fall through */ @@ -1145,7 +1147,7 @@ int32_t ec_manager_truncate(ec_fop_data_t * fop, int32_t state) { case EC_STATE_INIT: fop->user_size = fop->offset; - fop->offset = ec_adjust_size(fop->xl->private, fop->offset, 1); + ec_adjust_offset_up(fop->xl->private, &fop->offset, _gf_true); /* Fall through */ @@ -1508,8 +1510,9 @@ ec_writev_prepare_buffers(ec_t *ec, ec_fop_data_t *fop) int32_t err; fop->user_size = iov_length(fop->vector, fop->int32); - fop->head = ec_adjust_offset(ec, &fop->offset, 0); - fop->size = ec_adjust_size(ec, fop->user_size + fop->head, 0); + fop->head = ec_adjust_offset_down(ec, &fop->offset, _gf_false); + fop->size = fop->user_size + fop->head; + ec_adjust_size_up(ec, &fop->size, _gf_false); if ((fop->int32 != 1) || (fop->head != 0) || (fop->size > fop->user_size) || diff --git a/xlators/cluster/ec/src/ec-locks.c b/xlators/cluster/ec/src/ec-locks.c index ff098522f18..996035de90b 100644 --- a/xlators/cluster/ec/src/ec-locks.c +++ b/xlators/cluster/ec/src/ec-locks.c @@ -572,10 +572,10 @@ int32_t ec_manager_inodelk(ec_fop_data_t * fop, int32_t state) switch (state) { case EC_STATE_INIT: - fop->flock.l_len += ec_adjust_offset(fop->xl->private, - &fop->flock.l_start, 1); - fop->flock.l_len = ec_adjust_size(fop->xl->private, - fop->flock.l_len, 1); + fop->flock.l_len += ec_adjust_offset_down(fop->xl->private, + &fop->flock.l_start, + _gf_true); + ec_adjust_offset_up(fop->xl->private, &fop->flock.l_len, _gf_true); if ((fop->int32 == F_SETLKW) && (fop->flock.l_type != F_UNLCK)) { fop->uint32 = EC_LOCK_MODE_ALL; |