summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/crc32c_intel_fast.c18
-rw-r--r--src/test/common/test_crc32c.cc9
2 files changed, 26 insertions, 1 deletions
diff --git a/src/common/crc32c_intel_fast.c b/src/common/crc32c_intel_fast.c
index b446fc1ecc5..49305088aff 100644
--- a/src/common/crc32c_intel_fast.c
+++ b/src/common/crc32c_intel_fast.c
@@ -1,5 +1,6 @@
#include <inttypes.h>
#include "acconfig.h"
+#include "common/crc32c_intel_baseline.h"
extern unsigned int crc32_iscsi_00(unsigned char const *buffer, int len, unsigned int crc);
@@ -7,7 +8,22 @@ extern unsigned int crc32_iscsi_00(unsigned char const *buffer, int len, unsigne
uint32_t ceph_crc32c_intel_fast(uint32_t crc, unsigned char const *buffer, unsigned len)
{
- return crc32_iscsi_00(buffer, len, crc);
+ uint32_t v;
+ unsigned left;
+
+ /*
+ * the crc32_iscsi_00 method reads past buffer+len (because it
+ * reads full words) which makes valgrind unhappy. don't do
+ * that.
+ */
+ if (len < 16)
+ return ceph_crc32c_intel_baseline(crc, buffer, len);
+ left = ((unsigned long)buffer + len) & 7;
+ len -= left;
+ v = crc32_iscsi_00(buffer, len, crc);
+ if (left)
+ v = ceph_crc32c_intel_baseline(v, buffer + len, left);
+ return v;
}
int ceph_crc32c_intel_fast_exists(void)
diff --git a/src/test/common/test_crc32c.cc b/src/test/common/test_crc32c.cc
index 19a1dfb7284..5cf88de0a80 100644
--- a/src/test/common/test_crc32c.cc
+++ b/src/test/common/test_crc32c.cc
@@ -23,6 +23,15 @@ TEST(Crc32c, Small) {
ASSERT_EQ(3743019208u, ceph_crc32c(5678, (unsigned char *)b, strlen(b)));
}
+TEST(Crc32c, PartialWord) {
+ const char *a = (const char *)malloc(5);
+ const char *b = (const char *)malloc(35);
+ memset((void *)a, 1, 5);
+ memset((void *)b, 1, 35);
+ ASSERT_EQ(2715569182u, ceph_crc32c(0, (unsigned char *)a, 5));
+ ASSERT_EQ(440531800u, ceph_crc32c(0, (unsigned char *)b, 35));
+}
+
TEST(Crc32c, Big) {
int len = 4096000;
char *a = (char *)malloc(len);