* Future: need to be in "struct repository"
  * when doing a full libification.
  */
-static struct files_ref_store {
-       struct files_ref_store *next;
+struct files_ref_store {
+       struct ref_store base;
        struct ref_entry *loose;
        struct packed_ref_cache *packed;
-       /*
-        * The submodule name, or "" for the main repo. We allocate
-        * length 1 rather than FLEX_ARRAY so that the main
-        * files_ref_store is initialized correctly.
-        */
-       char name[1];
-} ref_store, *submodule_ref_stores;
+};
 
 /* Lock used for the main packed-refs file: */
 static struct lock_file packlock;
  * Create a new submodule ref cache and add it to the internal
  * set of caches.
  */
-static struct files_ref_store *create_ref_store(const char *submodule)
+static struct ref_store *files_ref_store_create(const char *submodule)
 {
-       struct files_ref_store *refs;
-       if (!submodule)
-               submodule = "";
-       FLEX_ALLOC_STR(refs, name, submodule);
-       refs->next = submodule_ref_stores;
-       submodule_ref_stores = refs;
-       return refs;
+       struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
+       struct ref_store *ref_store = (struct ref_store *)refs;
+
+       base_ref_store_init(ref_store, &refs_be_files, submodule);
+
+       return ref_store;
 }
 
-static struct files_ref_store *lookup_ref_store(const char *submodule)
+/*
+ * Downcast ref_store to files_ref_store. Die if ref_store is not a
+ * files_ref_store. If submodule_allowed is not true, then also die if
+ * files_ref_store is for a submodule (i.e., not for the main
+ * repository). caller is used in any necessary error messages.
+ */
+static struct files_ref_store *files_downcast(
+               struct ref_store *ref_store, int submodule_allowed,
+               const char *caller)
 {
-       struct files_ref_store *refs;
+       if (ref_store->be != &refs_be_files)
+               die("BUG: ref_store is type \"%s\" not \"files\" in %s",
+                   ref_store->be->name, caller);
 
-       if (!submodule || !*submodule)
-               return &ref_store;
+       if (!submodule_allowed)
+               assert_main_repository(ref_store, caller);
 
-       for (refs = submodule_ref_stores; refs; refs = refs->next)
-               if (!strcmp(submodule, refs->name))
-                       return refs;
-       return NULL;
+       return (struct files_ref_store *)ref_store;
 }
 
 /*
- * Return a pointer to a files_ref_store for the specified submodule. For
- * the main repository, use submodule==NULL; such a call cannot fail.
- * For a submodule, the submodule must exist and be a nonbare
- * repository, otherwise return NULL.
- *
- * The returned structure will be allocated and initialized but not
- * necessarily populated; it should not be freed.
+ * Return a pointer to the reference store for the specified
+ * submodule. For the main repository, use submodule==NULL; such a
+ * call cannot fail. For a submodule, the submodule must exist and be
+ * a nonbare repository, otherwise return NULL. Verify that the
+ * reference store is a files_ref_store, and cast it to that type
+ * before returning it.
  */
-static struct files_ref_store *get_ref_store(const char *submodule)
+static struct files_ref_store *get_files_ref_store(const char *submodule,
+                                                  const char *caller)
 {
-       struct files_ref_store *refs = lookup_ref_store(submodule);
+       struct ref_store *refs = get_ref_store(submodule);
 
-       if (!refs) {
-               struct strbuf submodule_sb = STRBUF_INIT;
-
-               strbuf_addstr(&submodule_sb, submodule);
-               if (is_nonbare_repository_dir(&submodule_sb))
-                       refs = create_ref_store(submodule);
-               strbuf_release(&submodule_sb);
-       }
-
-       return refs;
+       return refs ? files_downcast(refs, 1, caller) : NULL;
 }
 
 /* The length of a peeled reference line in packed-refs, including EOL: */
 {
        char *packed_refs_file;
 
-       if (*refs->name)
-               packed_refs_file = git_pathdup_submodule(refs->name, "packed-refs");
+       if (*refs->base.submodule)
+               packed_refs_file = git_pathdup_submodule(refs->base.submodule,
+                                                        "packed-refs");
        else
                packed_refs_file = git_pathdup("packed-refs");
 
  */
 static void add_packed_ref(const char *refname, const unsigned char *sha1)
 {
-       struct packed_ref_cache *packed_ref_cache =
-               get_packed_ref_cache(&ref_store);
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "add_packed_ref");
+       struct packed_ref_cache *packed_ref_cache = get_packed_ref_cache(refs);
 
        if (!packed_ref_cache->lock)
                die("internal error: packed refs not locked");
        struct strbuf path = STRBUF_INIT;
        size_t path_baselen;
 
-       if (*refs->name)
-               strbuf_git_path_submodule(&path, refs->name, "%s", dirname);
+       if (*refs->base.submodule)
+               strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname);
        else
                strbuf_git_path(&path, "%s", dirname);
        path_baselen = path.len;
                } else {
                        int read_ok;
 
-                       if (*refs->name) {
+                       if (*refs->base.submodule) {
                                hashclr(sha1);
                                flag = 0;
-                               read_ok = !resolve_gitlink_ref(refs->name,
+                               read_ok = !resolve_gitlink_ref(refs->base.submodule,
                                                               refname.buf, sha1);
                        } else {
                                read_ok = !read_ref_full(refname.buf,
 
        if (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)
                return -1;
-       path = *refs->name
-               ? git_pathdup_submodule(refs->name, "%s", refname)
+       path = *refs->base.submodule
+               ? git_pathdup_submodule(refs->base.submodule, "%s", refname)
                : git_pathdup("%s", refname);
        fd = open(path, O_RDONLY);
        free(path);
                return -1;
 
        strbuf_add(&submodule, path, len);
-       refs = get_ref_store(submodule.buf);
+       refs = get_files_ref_store(submodule.buf, "resolve_gitlink_ref");
        if (!refs) {
                strbuf_release(&submodule);
                return -1;
  */
 static struct ref_entry *get_packed_ref(const char *refname)
 {
-       return find_ref(get_packed_refs(&ref_store), refname);
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "get_packed_ref");
+
+       return find_ref(get_packed_refs(refs), refname);
 }
 
 /*
                        unsigned int *type,
                        struct strbuf *err)
 {
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "lock_raw_ref");
        struct ref_lock *lock;
        struct strbuf ref_file = STRBUF_INIT;
        int attempts_remaining = 3;
                                                          REMOVE_DIR_EMPTY_ONLY)) {
                                if (verify_refname_available_dir(
                                                    refname, extras, skip,
-                                                   get_loose_refs(&ref_store),
+                                                   get_loose_refs(refs),
                                                    err)) {
                                        /*
                                         * The error message set by
                 */
                if (verify_refname_available_dir(
                                    refname, extras, skip,
-                                   get_packed_refs(&ref_store),
+                                   get_packed_refs(refs),
                                    err)) {
                        goto error_return;
                }
                const char *submodule,
                const char *prefix, unsigned int flags)
 {
-       struct files_ref_store *refs = get_ref_store(submodule);
+       struct files_ref_store *refs =
+               get_files_ref_store(submodule, "ref_iterator_begin");
        struct ref_dir *loose_dir, *packed_dir;
        struct ref_iterator *loose_iter, *packed_iter;
        struct files_ref_iterator *iter;
                                            unsigned int flags, int *type,
                                            struct strbuf *err)
 {
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "lock_ref_sha1_basic");
        struct strbuf ref_file = STRBUF_INIT;
        struct ref_lock *lock;
        int last_errno = 0;
                 */
                if (remove_empty_directories(&ref_file)) {
                        last_errno = errno;
-                       if (!verify_refname_available_dir(refname, extras, skip,
-                                                         get_loose_refs(&ref_store), err))
+                       if (!verify_refname_available_dir(
+                                           refname, extras, skip,
+                                           get_loose_refs(refs), err))
                                strbuf_addf(err, "there are still refs under '%s'",
                                            refname);
                        goto error_return;
        if (!resolved) {
                last_errno = errno;
                if (last_errno != ENOTDIR ||
-                   !verify_refname_available_dir(refname, extras, skip,
-                                                 get_loose_refs(&ref_store), err))
+                   !verify_refname_available_dir(
+                                   refname, extras, skip,
+                                   get_loose_refs(refs), err))
                        strbuf_addf(err, "unable to resolve reference '%s': %s",
                                    refname, strerror(last_errno));
 
         */
        if (is_null_oid(&lock->old_oid) &&
            verify_refname_available_dir(refname, extras, skip,
-                                        get_packed_refs(&ref_store), err)) {
+                                        get_packed_refs(refs),
+                                        err)) {
                last_errno = ENOTDIR;
                goto error_return;
        }
  */
 static int lock_packed_refs(int flags)
 {
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "lock_packed_refs");
        static int timeout_configured = 0;
        static int timeout_value = 1000;
-
        struct packed_ref_cache *packed_ref_cache;
 
        if (!timeout_configured) {
         * this will automatically invalidate the cache and re-read
         * the packed-refs file.
         */
-       packed_ref_cache = get_packed_ref_cache(&ref_store);
+       packed_ref_cache = get_packed_ref_cache(refs);
        packed_ref_cache->lock = &packlock;
        /* Increment the reference count to prevent it from being freed: */
        acquire_packed_ref_cache(packed_ref_cache);
  */
 static int commit_packed_refs(void)
 {
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "commit_packed_refs");
        struct packed_ref_cache *packed_ref_cache =
-               get_packed_ref_cache(&ref_store);
+               get_packed_ref_cache(refs);
        int error = 0;
        int save_errno = 0;
        FILE *out;
  */
 static void rollback_packed_refs(void)
 {
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "rollback_packed_refs");
        struct packed_ref_cache *packed_ref_cache =
-               get_packed_ref_cache(&ref_store);
+               get_packed_ref_cache(refs);
 
        if (!packed_ref_cache->lock)
                die("internal error: packed-refs not locked");
        rollback_lock_file(packed_ref_cache->lock);
        packed_ref_cache->lock = NULL;
        release_packed_ref_cache(packed_ref_cache);
-       clear_packed_ref_cache(&ref_store);
+       clear_packed_ref_cache(refs);
 }
 
 struct ref_to_prune {
 
 int pack_refs(unsigned int flags)
 {
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "pack_refs");
        struct pack_refs_cb_data cbdata;
 
        memset(&cbdata, 0, sizeof(cbdata));
        cbdata.flags = flags;
 
        lock_packed_refs(LOCK_DIE_ON_ERROR);
-       cbdata.packed_refs = get_packed_refs(&ref_store);
+       cbdata.packed_refs = get_packed_refs(refs);
 
-       do_for_each_entry_in_dir(get_loose_refs(&ref_store), 0,
+       do_for_each_entry_in_dir(get_loose_refs(refs), 0,
                                 pack_if_possible_fn, &cbdata);
 
        if (commit_packed_refs())
  */
 static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
 {
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "repack_without_refs");
        struct ref_dir *packed;
        struct string_list_item *refname;
        int ret, needs_repacking = 0, removed = 0;
                unable_to_lock_message(git_path("packed-refs"), errno, err);
                return -1;
        }
-       packed = get_packed_refs(&ref_store);
+       packed = get_packed_refs(refs);
 
        /* Remove refnames from the cache */
        for_each_string_list_item(refname, refnames)
                             const struct string_list *skip,
                             struct strbuf *err)
 {
-       struct ref_dir *packed_refs = get_packed_refs(&ref_store);
-       struct ref_dir *loose_refs = get_loose_refs(&ref_store);
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "verify_refname_available");
+       struct ref_dir *packed_refs = get_packed_refs(refs);
+       struct ref_dir *loose_refs = get_loose_refs(refs);
 
        if (verify_refname_available_dir(newname, extras, skip,
                                         packed_refs, err) ||
                             const unsigned char *sha1, const char *logmsg,
                             struct strbuf *err)
 {
-       clear_loose_ref_cache(&ref_store);
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "commit_ref_update");
+
+       clear_loose_ref_cache(refs);
        if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, 0, err)) {
                char *old_msg = strbuf_detach(err, NULL);
                strbuf_addf(err, "cannot update the ref '%s': %s",
 int ref_transaction_commit(struct ref_transaction *transaction,
                           struct strbuf *err)
 {
+       struct files_ref_store *refs =
+               get_files_ref_store(NULL, "ref_transaction_commit");
        int ret = 0, i;
        struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
        struct string_list_item *ref_to_delete;
                        }
                }
                if (update->flags & REF_NEEDS_COMMIT) {
-                       clear_loose_ref_cache(&ref_store);
+                       clear_loose_ref_cache(refs);
                        if (commit_ref(lock)) {
                                strbuf_addf(err, "couldn't set '%s'", lock->ref_name);
                                unlock_ref(lock);
        }
        for_each_string_list_item(ref_to_delete, &refs_to_delete)
                unlink_or_warn(git_path("logs/%s", ref_to_delete->string));
-       clear_loose_ref_cache(&ref_store);
+       clear_loose_ref_cache(refs);
 
 cleanup:
        transaction->state = REF_TRANSACTION_CLOSED;
 
 struct ref_storage_be refs_be_files = {
        NULL,
-       "files"
+       "files",
+       files_ref_store_create
 };