};
 
 /* attr_hashmap comparison function */
-static int attr_hash_entry_cmp(const struct attr_hash_entry *a,
+static int attr_hash_entry_cmp(void *unused_cmp_data,
+                              const struct attr_hash_entry *a,
                               const struct attr_hash_entry *b,
-                              void *unused)
+                              void *unused_keydata)
 {
        return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);
 }
 /* Initialize an 'attr_hashmap' object */
 static void attr_hashmap_init(struct attr_hashmap *map)
 {
-       hashmap_init(&map->map, (hashmap_cmp_fn) attr_hash_entry_cmp, 0);
+       hashmap_init(&map->map, (hashmap_cmp_fn) attr_hash_entry_cmp, NULL, 0);
 }
 
 /*
 
        N_("head"), N_("lightweight"), N_("annotated"),
 };
 
-static int commit_name_cmp(const struct commit_name *cn1,
-               const struct commit_name *cn2, const void *peeled)
+static int commit_name_cmp(const void *unused_cmp_data,
+                          const struct commit_name *cn1,
+                          const struct commit_name *cn2,
+                          const void *peeled)
 {
        return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled);
 }
                return cmd_name_rev(args.argc, args.argv, prefix);
        }
 
-       hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, 0);
+       hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, NULL, 0);
        for_each_rawref(get_name, NULL);
        if (!names.size && !always)
                die(_("No names found, cannot describe anything."));
 
        char path[FLEX_ARRAY];
 };
 
-static int working_tree_entry_cmp(struct working_tree_entry *a,
-                                 struct working_tree_entry *b, void *keydata)
+static int working_tree_entry_cmp(const void *unused_cmp_data,
+                                 struct working_tree_entry *a,
+                                 struct working_tree_entry *b,
+                                 void *unused_keydata)
 {
        return strcmp(a->path, b->path);
 }
        const char path[FLEX_ARRAY];
 };
 
-static int pair_cmp(struct pair_entry *a, struct pair_entry *b, void *keydata)
+static int pair_cmp(const void *unused_cmp_data,
+                   struct pair_entry *a, struct pair_entry *b,
+                   void *unused_keydata)
 {
        return strcmp(a->path, b->path);
 }
        char path[FLEX_ARRAY];
 };
 
-static int path_entry_cmp(struct path_entry *a, struct path_entry *b, void *key)
+static int path_entry_cmp(const void *unused_cmp_data,
+                         struct path_entry *a, struct path_entry *b,
+                         void *key)
 {
        return strcmp(a->path, key ? key : b->path);
 }
        wtdir_len = wtdir.len;
 
        hashmap_init(&working_tree_dups,
-                    (hashmap_cmp_fn)working_tree_entry_cmp, 0);
-       hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, 0);
-       hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, 0);
+                    (hashmap_cmp_fn)working_tree_entry_cmp, NULL, 0);
+       hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, NULL, 0);
+       hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, NULL, 0);
 
        child.no_stdin = 1;
        child.git_cmd = 1;
         * files through the symlink.
         */
        hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp,
-                    wtindex.cache_nr);
+                    NULL, wtindex.cache_nr);
        hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp,
-                    wtindex.cache_nr);
+                    NULL, wtindex.cache_nr);
 
        for (i = 0; i < wtindex.cache_nr; i++) {
                struct hashmap_entry dummy;
 
        size_t anon_len;
 };
 
-static int anonymized_entry_cmp(const void *va, const void *vb,
-                               const void *data)
+static int anonymized_entry_cmp(const void *unused_cmp_data,
+                               const void *va, const void *vb,
+                               const void *unused_keydata)
 {
        const struct anonymized_entry *a = va, *b = vb;
        return a->orig_len != b->orig_len ||
        struct anonymized_entry key, *ret;
 
        if (!map->cmpfn)
-               hashmap_init(map, anonymized_entry_cmp, 0);
+               hashmap_init(map, anonymized_entry_cmp, NULL, 0);
 
        hashmap_entry_init(&key, memhash(orig, *len));
        key.orig = orig;
 
        return 0;
 }
 
-static int config_set_element_cmp(const struct config_set_element *e1,
-                                const struct config_set_element *e2, const void *unused)
+static int config_set_element_cmp(const void *unused_cmp_data,
+                                 const struct config_set_element *e1,
+                                 const struct config_set_element *e2,
+                                 const void *unused_keydata)
 {
        return strcmp(e1->key, e2->key);
 }
 
 void git_configset_init(struct config_set *cs)
 {
-       hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, 0);
+       hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp,
+                    NULL, 0);
        cs->hash_initialized = 1;
        cs->list.nr = 0;
        cs->list.alloc = 0;
 
 
        if (!subprocess_map_initialized) {
                subprocess_map_initialized = 1;
-               hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp, 0);
+               hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp,
+                            NULL, 0);
                entry = NULL;
        } else {
                entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
 
        /* Add all sources to the hash table in reverse order, because
         * later on they will be retrieved in LIFO order.
         */
-       hashmap_init(&file_table, NULL, rename_src_nr);
+       hashmap_init(&file_table, NULL, NULL, rename_src_nr);
        for (i = rename_src_nr-1; i >= 0; i--)
                insert_file_table(&file_table, i, rename_src[i].p->one);
 
 
                const struct hashmap_entry *e1, const struct hashmap_entry *e2,
                const void *keydata)
 {
-       return (e1 == e2) || (e1->hash == e2->hash && !map->cmpfn(e1, e2, keydata));
+       return (e1 == e2) ||
+              (e1->hash == e2->hash &&
+               !map->cmpfn(map->cmpfn_data, e1, e2, keydata));
 }
 
 static inline unsigned int bucket(const struct hashmap *map,
        return e;
 }
 
-static int always_equal(const void *unused1, const void *unused2, const void *unused3)
+static int always_equal(const void *unused_cmp_data,
+                       const void *unused1,
+                       const void *unused2,
+                       const void *unused_keydata)
 {
        return 0;
 }
 
 void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function,
-               size_t initial_size)
+               const void *cmpfn_data, size_t initial_size)
 {
        unsigned int size = HASHMAP_INITIAL_SIZE;
 
        memset(map, 0, sizeof(*map));
 
        map->cmpfn = equals_function ? equals_function : always_equal;
+       map->cmpfn_data = cmpfn_data;
 
        /* calculate initial table size and allocate the table */
        initial_size = (unsigned int) ((uint64_t) initial_size * 100
        unsigned char data[FLEX_ARRAY];
 };
 
-static int pool_entry_cmp(const struct pool_entry *e1,
+static int pool_entry_cmp(const void *unused_cmp_data,
+                         const struct pool_entry *e1,
                          const struct pool_entry *e2,
                          const unsigned char *keydata)
 {
 
        /* initialize string pool hashmap */
        if (!map.tablesize)
-               hashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, 0);
+               hashmap_init(&map, (hashmap_cmp_fn) pool_entry_cmp, NULL, 0);
 
        /* lookup interned string in pool */
        hashmap_entry_init(&key, memhash(data, len));
 
        unsigned int hash;
 };
 
-typedef int (*hashmap_cmp_fn)(const void *entry, const void *entry_or_key,
-               const void *keydata);
+typedef int (*hashmap_cmp_fn)(const void *hashmap_cmp_fn_data,
+                             const void *entry, const void *entry_or_key,
+                             const void *keydata);
 
 struct hashmap {
        struct hashmap_entry **table;
        hashmap_cmp_fn cmpfn;
+       const void *cmpfn_data;
        unsigned int size, tablesize, grow_at, shrink_at;
        unsigned disallow_rehash : 1;
 };
 
 /* hashmap functions */
 
-extern void hashmap_init(struct hashmap *map, hashmap_cmp_fn equals_function,
-               size_t initial_size);
+extern void hashmap_init(struct hashmap *map,
+                        hashmap_cmp_fn equals_function,
+                        const void *equals_function_data,
+                        size_t initial_size);
 extern void hashmap_free(struct hashmap *map, int free_entries);
 
 /* hashmap_entry functions */
 
        char name[FLEX_ARRAY];
 };
 
-static int dir_entry_cmp(const struct dir_entry *e1,
-               const struct dir_entry *e2, const char *name)
+static int dir_entry_cmp(const void *unused_cmp_data,
+                        const struct dir_entry *e1,
+                        const struct dir_entry *e2,
+                        const char *name)
 {
        return e1->namelen != e2->namelen || strncasecmp(e1->name,
                        name ? name : e2->name, e1->namelen);
                add_dir_entry(istate, ce);
 }
 
-static int cache_entry_cmp(const struct cache_entry *ce1,
-               const struct cache_entry *ce2, const void *remove)
+static int cache_entry_cmp(const void *unused_cmp_data,
+                          const struct cache_entry *ce1,
+                          const struct cache_entry *ce2,
+                          const void *remove)
 {
        /*
         * For remove_name_hash, find the exact entry (pointer equality); for
        if (istate->name_hash_initialized)
                return;
        hashmap_init(&istate->name_hash, (hashmap_cmp_fn) cache_entry_cmp,
-                       istate->cache_nr);
+                       NULL, istate->cache_nr);
        hashmap_init(&istate->dir_hash, (hashmap_cmp_fn) dir_entry_cmp,
-                       istate->cache_nr);
+                       NULL, istate->cache_nr);
 
        if (lookup_lazy_params(istate)) {
                hashmap_disallow_rehash(&istate->dir_hash, 1);
 
        struct object_id oid;
 };
 
-static int oidset_hashcmp(const void *va, const void *vb,
+static int oidset_hashcmp(const void *unused_cmp_data,
+                         const void *va, const void *vb,
                          const void *vkey)
 {
        const struct oidset_entry *a = va, *b = vb;
        struct oidset_entry *entry;
 
        if (!set->map.cmpfn)
-               hashmap_init(&set->map, oidset_hashcmp, 0);
+               hashmap_init(&set->map, oidset_hashcmp, NULL, 0);
 
        if (oidset_contains(set, oid))
                return 1;
 
  * the side of safety.  The actual value being negative does not have
  * any significance; only that it is non-zero matters.
  */
-static int patch_id_cmp(struct patch_id *a,
+static int patch_id_cmp(const void *unused_cmp_data,
+                       struct patch_id *a,
                        struct patch_id *b,
                        struct diff_options *opt)
 {
        ids->diffopts.detect_rename = 0;
        DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
        diff_setup_done(&ids->diffopts);
-       hashmap_init(&ids->patches, (hashmap_cmp_fn)patch_id_cmp, 256);
+       hashmap_init(&ids->patches, (hashmap_cmp_fn)patch_id_cmp,
+                    NULL, 256);
        return 0;
 }
 
 
        char name[FLEX_ARRAY];
 };
 
-static int ref_store_hash_cmp(const void *entry, const void *entry_or_key,
+static int ref_store_hash_cmp(const void *unused_cmp_data,
+                             const void *entry, const void *entry_or_key,
                              const void *keydata)
 {
        const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key;
                                   const char *name)
 {
        if (!map->tablesize)
-               hashmap_init(map, ref_store_hash_cmp, 0);
+               hashmap_init(map, ref_store_hash_cmp, NULL, 0);
 
        if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))
                die("BUG: %s ref_store '%s' initialized twice", type, name);
 
        int len;
 };
 
-static int remotes_hash_cmp(const struct remote *a, const struct remote *b, const struct remotes_hash_key *key)
+static int remotes_hash_cmp(const void *unused_cmp_data,
+                           const struct remote *a,
+                           const struct remote *b,
+                           const struct remotes_hash_key *key)
 {
        if (key)
                return strncmp(a->name, key->str, key->len) || a->name[key->len];
 static inline void init_remotes_hash(void)
 {
        if (!remotes_hash.cmpfn)
-               hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, 0);
+               hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, NULL, 0);
 }
 
 static struct remote *make_remote(const char *name, int len)
 
        return a->p == b->p && a->base_offset == b->base_offset;
 }
 
-static int delta_base_cache_hash_cmp(const void *va, const void *vb,
+static int delta_base_cache_hash_cmp(const void *unused_cmp_data,
+                                    const void *va, const void *vb,
                                     const void *vkey)
 {
        const struct delta_base_cache_entry *a = va, *b = vb;
        list_add_tail(&ent->lru, &delta_base_cache_lru);
 
        if (!delta_base_cache.cmpfn)
-               hashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, 0);
+               hashmap_init(&delta_base_cache, delta_base_cache_hash_cmp, NULL, 0);
        hashmap_entry_init(ent, pack_entry_hash(p, base_offset));
        hashmap_add(&delta_base_cache, ent);
 }
 
 #include "sigchain.h"
 #include "pkt-line.h"
 
-int cmd2process_cmp(const struct subprocess_entry *e1,
-                          const struct subprocess_entry *e2,
-                          const void *unused)
+int cmd2process_cmp(const void *unused_cmp_data,
+                   const struct subprocess_entry *e1,
+                   const struct subprocess_entry *e2,
+                   const void *unused_keydata)
 {
        return strcmp(e1->cmd, e2->cmd);
 }
 
 
 /* subprocess functions */
 
-int cmd2process_cmp(const struct subprocess_entry *e1,
-       const struct subprocess_entry *e2, const void *unused);
+extern int cmd2process_cmp(const void *unused_cmp_data,
+                          const struct subprocess_entry *e1,
+                          const struct subprocess_entry *e2,
+                          const void *unused_keydata);
 
 typedef int(*subprocess_start_fn)(struct subprocess_entry *entry);
 int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
 
 static struct submodule_cache the_submodule_cache;
 static int is_cache_init;
 
-static int config_path_cmp(const struct submodule_entry *a,
+static int config_path_cmp(const void *unused_cmp_data,
+                          const struct submodule_entry *a,
                           const struct submodule_entry *b,
-                          const void *unused)
+                          const void *unused_keydata)
 {
        return strcmp(a->config->path, b->config->path) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
 }
 
-static int config_name_cmp(const struct submodule_entry *a,
+static int config_name_cmp(const void *unused_cmp_data,
+                          const struct submodule_entry *a,
                           const struct submodule_entry *b,
-                          const void *unused)
+                          const void *unused_keydata)
 {
        return strcmp(a->config->name, b->config->name) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
 
 static void cache_init(struct submodule_cache *cache)
 {
-       hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);
-       hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);
+       hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, NULL, 0);
+       hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, NULL, 0);
 }
 
 static void free_one_config(struct submodule_entry *entry)
 
        return e->key + strlen(e->key) + 1;
 }
 
-static int test_entry_cmp(const struct test_entry *e1,
-               const struct test_entry *e2, const char* key)
+static int test_entry_cmp(const void *unused_cmp_data,
+                         const struct test_entry *e1,
+                         const struct test_entry *e2,
+                         const char* key)
 {
        return strcmp(e1->key, key ? key : e2->key);
 }
 
-static int test_entry_cmp_icase(const struct test_entry *e1,
-               const struct test_entry *e2, const char* key)
+static int test_entry_cmp_icase(const void *unused_cmp_data,
+                               const struct test_entry *e1,
+                               const struct test_entry *e2,
+                               const char* key)
 {
        return strcasecmp(e1->key, key ? key : e2->key);
 }
        if (method & TEST_ADD) {
                /* test adding to the map */
                for (j = 0; j < rounds; j++) {
-                       hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, 0);
+                       hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp,
+                                    NULL, 0);
 
                        /* add entries */
                        for (i = 0; i < TEST_SIZE; i++) {
                }
        } else {
                /* test map lookups */
-               hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, 0);
+               hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, NULL, 0);
 
                /* fill the map (sparsely if specified) */
                j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;
        /* init hash map */
        icase = argc > 1 && !strcmp("ignorecase", argv[1]);
        hashmap_init(&map, (hashmap_cmp_fn) (icase ? test_entry_cmp_icase
-                       : test_entry_cmp), 0);
+                       : test_entry_cmp), NULL, 0);
 
        /* process commands from stdin */
        while (fgets(line, sizeof(line), stdin)) {