summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSage Weil2009-11-07 01:44:05 +0100
committerSage Weil2009-11-07 01:44:05 +0100
commitcfbbcd24a6bfd794295ee7ad76dfbff40ad6b934 (patch)
tree26a9640291ae3af1a9f1dd56cd8b3a2e3016b3ff
parentceph: make CRUSH hash functions non-inline (diff)
downloadkernel-qcow2-linux-cfbbcd24a6bfd794295ee7ad76dfbff40ad6b934.tar.gz
kernel-qcow2-linux-cfbbcd24a6bfd794295ee7ad76dfbff40ad6b934.tar.xz
kernel-qcow2-linux-cfbbcd24a6bfd794295ee7ad76dfbff40ad6b934.zip
ceph: use strong hash function for mapping objects to pgs
We were using the (weak) dcache hash function, but it was leaving lower bits consecutive for consecutive (inode) objects. We really want to make the object to pg mapping random and uniform, so use a proper hash function here. This is Robert Jenkin's public domain hash function (with some minor cleanup): http://burtleburtle.net/bob/hash/evahash.html This is a protocol revision. Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r--fs/ceph/ceph_fs.c93
-rw-r--r--fs/ceph/ceph_fs.h2
2 files changed, 71 insertions, 24 deletions
diff --git a/fs/ceph/ceph_fs.c b/fs/ceph/ceph_fs.c
index a950b4083577..b3ecf1b07521 100644
--- a/fs/ceph/ceph_fs.c
+++ b/fs/ceph/ceph_fs.c
@@ -73,32 +73,79 @@ int ceph_caps_for_mode(int mode)
return 0;
}
-/* Name hashing routines. Initial hash value */
-/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
-#define ceph_init_name_hash() 0
-
-/* partial hash update function. Assume roughly 4 bits per character */
-static unsigned long ceph_partial_name_hash(unsigned long c,
- unsigned long prevhash)
-{
- return (prevhash + (c << 4) + (c >> 4)) * 11;
-}
-
/*
- * Finally: cut down the number of bits to a int value (and try to avoid
- * losing bits)
+ * Robert Jenkin's hash function.
+ * http://burtleburtle.net/bob/hash/evahash.html
+ * This is in the public domain.
*/
-static unsigned long ceph_end_name_hash(unsigned long hash)
-{
- return hash & 0xffffffff;
-}
+#define mix(a, b, c) \
+ do { \
+ a = a - b; a = a - c; a = a ^ (c >> 13); \
+ b = b - c; b = b - a; b = b ^ (a << 8); \
+ c = c - a; c = c - b; c = c ^ (b >> 13); \
+ a = a - b; a = a - c; a = a ^ (c >> 12); \
+ b = b - c; b = b - a; b = b ^ (a << 16); \
+ c = c - a; c = c - b; c = c ^ (b >> 5); \
+ a = a - b; a = a - c; a = a ^ (c >> 3); \
+ b = b - c; b = b - a; b = b ^ (a << 10); \
+ c = c - a; c = c - b; c = c ^ (b >> 15); \
+ } while (0)
-/* Compute the hash for a name string. */
-unsigned int ceph_full_name_hash(const char *name, unsigned int len)
+unsigned int ceph_full_name_hash(const char *str, unsigned int length)
{
- unsigned long hash = ceph_init_name_hash();
- while (len--)
- hash = ceph_partial_name_hash(*name++, hash);
- return ceph_end_name_hash(hash);
+ const unsigned char *k = (const unsigned char *)str;
+ __u32 a, b, c; /* the internal state */
+ __u32 len; /* how many key bytes still need mixing */
+
+ /* Set up the internal state */
+ len = length;
+ a = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+ b = a;
+ c = 0; /* variable initialization of internal state */
+
+ /* handle most of the key */
+ while (len >= 12) {
+ a = a + (k[0] + ((__u32)k[1] << 8) + ((__u32)k[2] << 16) +
+ ((__u32)k[3] << 24));
+ b = b + (k[4] + ((__u32)k[5] << 8) + ((__u32)k[6] << 16) +
+ ((__u32)k[7] << 24));
+ c = c + (k[8] + ((__u32)k[9] << 8) + ((__u32)k[10] << 16) +
+ ((__u32)k[11] << 24));
+ mix(a, b, c);
+ k = k + 12;
+ len = len - 12;
+ }
+
+ /* handle the last 11 bytes */
+ c = c + length;
+ switch (len) { /* all the case statements fall through */
+ case 11:
+ c = c + ((__u32)k[10] << 24);
+ case 10:
+ c = c + ((__u32)k[9] << 16);
+ case 9:
+ c = c + ((__u32)k[8] << 8);
+ /* the first byte of c is reserved for the length */
+ case 8:
+ b = b + ((__u32)k[7] << 24);
+ case 7:
+ b = b + ((__u32)k[6] << 16);
+ case 6:
+ b = b + ((__u32)k[5] << 8);
+ case 5:
+ b = b + k[4];
+ case 4:
+ a = a + ((__u32)k[3] << 24);
+ case 3:
+ a = a + ((__u32)k[2] << 16);
+ case 2:
+ a = a + ((__u32)k[1] << 8);
+ case 1:
+ a = a + k[0];
+ /* case 0: nothing left to add */
+ }
+ mix(a, b, c);
+
+ return c;
}
diff --git a/fs/ceph/ceph_fs.h b/fs/ceph/ceph_fs.h
index ae523828c538..25fc537f4140 100644
--- a/fs/ceph/ceph_fs.h
+++ b/fs/ceph/ceph_fs.h
@@ -38,7 +38,7 @@
#define CEPH_OSD_PROTOCOL 7 /* cluster internal */
#define CEPH_MDS_PROTOCOL 9 /* cluster internal */
#define CEPH_MON_PROTOCOL 5 /* cluster internal */
-#define CEPH_OSDC_PROTOCOL 21 /* server/client */
+#define CEPH_OSDC_PROTOCOL 22 /* server/client */
#define CEPH_MDSC_PROTOCOL 29 /* server/client */
#define CEPH_MONC_PROTOCOL 15 /* server/client */