@@ -288,19 +288,37 @@ dir_hash_done(
free(hashtab);
}
+/*
+ * Create a directory hash index structure based on the size of the directory we
+ * are about to try to repair. The size passed in is the size of the data
+ * segment of the directory in bytes, so we don't really know exactly how many
+ * entries are in it. Hence assume an entry size of around 64 bytes - that's a
+ * name length of 40+ bytes so should cover a most situations with really large
+ * directories.
+ */
static struct dir_hash_tab *
dir_hash_init(
xfs_fsize_t size)
{
- struct dir_hash_tab *hashtab;
+ struct dir_hash_tab *hashtab = NULL;
int hsize;
- hsize = size / (16 * 4);
- if (hsize > 65536)
- hsize = 63336;
- else if (hsize < 16)
+ hsize = size / 64;
+ if (hsize < 16)
hsize = 16;
- if ((hashtab = calloc(DIR_HASH_TAB_SIZE(hsize), 1)) == NULL)
+
+ /*
+ * Try to allocate as large a hash table as possible. Failure to
+ * allocate isn't fatal, it will just result in slower performance as we
+ * reduce the size of the table.
+ */
+ while (hsize >= 16) {
+ hashtab = calloc(DIR_HASH_TAB_SIZE(hsize), 1);
+ if (hashtab)
+ break;
+ hsize /= 2;
+ }
+ if (!hashtab)
do_error(_("calloc failed in dir_hash_init\n"));
hashtab->size = hsize;
hashtab->byhash = (struct dir_hash_ent **)((char *)hashtab +