vfs: make the string hashes salt the hash

We always mixed in the parent pointer into the dentry name hash, but we
did it late at lookup time.  It turns out that we can simplify that
lookup-time action by salting the hash with the parent pointer early
instead of late.

A few other users of our string hashes also wanted to mix in their own
pointers into the hash, and those are updated to use the same mechanism.

Hash users that don't have any particular initial salt can just use the
NULL pointer as a no-salt.

Cc: Vegard Nossum <vegard.nossum@oracle.com>
Cc: George Spelvin <linux@sciencehorizons.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2016-06-10 07:51:30 -07:00
parent 147d9e7bca
commit 8387ff2577
38 changed files with 99 additions and 89 deletions

View File

@ -174,7 +174,8 @@ static inline int is_omitted_entry(struct ll_statahead_info *sai, __u64 index)
* Insert it into sai_entries tail when init. * Insert it into sai_entries tail when init.
*/ */
static struct ll_sa_entry * static struct ll_sa_entry *
ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index, ll_sa_entry_alloc(struct dentry *parent,
struct ll_statahead_info *sai, __u64 index,
const char *name, int len) const char *name, int len)
{ {
struct ll_inode_info *lli; struct ll_inode_info *lli;
@ -221,7 +222,8 @@ ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
dname = (char *)entry + sizeof(struct ll_sa_entry); dname = (char *)entry + sizeof(struct ll_sa_entry);
memcpy(dname, name, len); memcpy(dname, name, len);
dname[len] = 0; dname[len] = 0;
entry->se_qstr.hash = full_name_hash(name, len);
entry->se_qstr.hash = full_name_hash(parent, name, len);
entry->se_qstr.len = len; entry->se_qstr.len = len;
entry->se_qstr.name = dname; entry->se_qstr.name = dname;
@ -902,7 +904,7 @@ static void ll_statahead_one(struct dentry *parent, const char *entry_name,
int rc; int rc;
int rc1; int rc1;
entry = ll_sa_entry_alloc(sai, sai->sai_index, entry_name, entry = ll_sa_entry_alloc(parent, sai, sai->sai_index, entry_name,
entry_name_len); entry_name_len);
if (IS_ERR(entry)) if (IS_ERR(entry))
return; return;

View File

@ -207,7 +207,7 @@ adfs_hash(const struct dentry *parent, struct qstr *qstr)
*/ */
qstr->len = i = name_len; qstr->len = i = name_len;
name = qstr->name; name = qstr->name;
hash = init_name_hash(); hash = init_name_hash(parent);
while (i--) { while (i--) {
char c; char c;

View File

@ -61,7 +61,7 @@ affs_get_toupper(struct super_block *sb)
* Note: the dentry argument is the parent dentry. * Note: the dentry argument is the parent dentry.
*/ */
static inline int static inline int
__affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate) __affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr, toupper_t toupper, bool notruncate)
{ {
const u8 *name = qstr->name; const u8 *name = qstr->name;
unsigned long hash; unsigned long hash;
@ -72,7 +72,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
if (retval) if (retval)
return retval; return retval;
hash = init_name_hash(); hash = init_name_hash(dentry);
len = min(qstr->len, AFFSNAMEMAX); len = min(qstr->len, AFFSNAMEMAX);
for (; len > 0; name++, len--) for (; len > 0; name++, len--)
hash = partial_name_hash(toupper(*name), hash); hash = partial_name_hash(toupper(*name), hash);
@ -84,7 +84,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
static int static int
affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr) affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
{ {
return __affs_hash_dentry(qstr, affs_toupper, return __affs_hash_dentry(dentry, qstr, affs_toupper,
affs_nofilenametruncate(dentry)); affs_nofilenametruncate(dentry));
} }
@ -92,7 +92,7 @@ affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
static int static int
affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr) affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
{ {
return __affs_hash_dentry(qstr, affs_intl_toupper, return __affs_hash_dentry(dentry, qstr, affs_intl_toupper,
affs_nofilenametruncate(dentry)); affs_nofilenametruncate(dentry));
} }

View File

@ -397,7 +397,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
} }
} }
qstr.name = name; qstr.name = name;
qstr.hash = full_name_hash(name, qstr.len); qstr.hash = full_name_hash(dentry, name, qstr.len);
if (mutex_lock_interruptible(&sbi->wq_mutex)) { if (mutex_lock_interruptible(&sbi->wq_mutex)) {
kfree(qstr.name); kfree(qstr.name);

View File

@ -1164,7 +1164,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
dname.name = rinfo->dname; dname.name = rinfo->dname;
dname.len = rinfo->dname_len; dname.len = rinfo->dname_len;
dname.hash = full_name_hash(dname.name, dname.len); dname.hash = full_name_hash(parent, dname.name, dname.len);
vino.ino = le64_to_cpu(rinfo->targeti.in->ino); vino.ino = le64_to_cpu(rinfo->targeti.in->ino);
vino.snap = le64_to_cpu(rinfo->targeti.in->snapid); vino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
retry_lookup: retry_lookup:
@ -1508,7 +1508,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
dname.name = rde->name; dname.name = rde->name;
dname.len = rde->name_len; dname.len = rde->name_len;
dname.hash = full_name_hash(dname.name, dname.len); dname.hash = full_name_hash(parent, dname.name, dname.len);
vino.ino = le64_to_cpu(rde->inode.in->ino); vino.ino = le64_to_cpu(rde->inode.in->ino);
vino.snap = le64_to_cpu(rde->inode.in->snapid); vino.snap = le64_to_cpu(rde->inode.in->snapid);

View File

@ -3204,7 +3204,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
WARN_ON(1); WARN_ON(1);
goto release; /* hrm... */ goto release; /* hrm... */
} }
dname.hash = full_name_hash(dname.name, dname.len); dname.hash = full_name_hash(parent, dname.name, dname.len);
dentry = d_lookup(parent, &dname); dentry = d_lookup(parent, &dname);
dput(parent); dput(parent);
if (!dentry) if (!dentry)

View File

@ -856,7 +856,7 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
wchar_t c; wchar_t c;
int i, charlen; int i, charlen;
hash = init_name_hash(); hash = init_name_hash(dentry);
for (i = 0; i < q->len; i += charlen) { for (i = 0; i < q->len; i += charlen) {
charlen = codepage->char2uni(&q->name[i], q->len - i, &c); charlen = codepage->char2uni(&q->name[i], q->len - i, &c);
/* error out if we can't convert the character */ /* error out if we can't convert the character */

View File

@ -104,10 +104,8 @@ static unsigned int d_hash_shift __read_mostly;
static struct hlist_bl_head *dentry_hashtable __read_mostly; static struct hlist_bl_head *dentry_hashtable __read_mostly;
static inline struct hlist_bl_head *d_hash(const struct dentry *parent, static inline struct hlist_bl_head *d_hash(unsigned int hash)
unsigned int hash)
{ {
hash += (unsigned long) parent / L1_CACHE_BYTES;
return dentry_hashtable + hash_32(hash, d_hash_shift); return dentry_hashtable + hash_32(hash, d_hash_shift);
} }
@ -488,7 +486,7 @@ void __d_drop(struct dentry *dentry)
if (unlikely(IS_ROOT(dentry))) if (unlikely(IS_ROOT(dentry)))
b = &dentry->d_sb->s_anon; b = &dentry->d_sb->s_anon;
else else
b = d_hash(dentry->d_parent, dentry->d_name.hash); b = d_hash(dentry->d_name.hash);
hlist_bl_lock(b); hlist_bl_lock(b);
__hlist_bl_del(&dentry->d_hash); __hlist_bl_del(&dentry->d_hash);
@ -1670,7 +1668,7 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
struct qstr q; struct qstr q;
q.name = name; q.name = name;
q.hash_len = hashlen_string(name); q.hash_len = hashlen_string(parent, name);
return d_alloc(parent, &q); return d_alloc(parent, &q);
} }
EXPORT_SYMBOL(d_alloc_name); EXPORT_SYMBOL(d_alloc_name);
@ -2094,7 +2092,7 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
{ {
u64 hashlen = name->hash_len; u64 hashlen = name->hash_len;
const unsigned char *str = name->name; const unsigned char *str = name->name;
struct hlist_bl_head *b = d_hash(parent, hashlen_hash(hashlen)); struct hlist_bl_head *b = d_hash(hashlen_hash(hashlen));
struct hlist_bl_node *node; struct hlist_bl_node *node;
struct dentry *dentry; struct dentry *dentry;
@ -2211,7 +2209,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
unsigned int len = name->len; unsigned int len = name->len;
unsigned int hash = name->hash; unsigned int hash = name->hash;
const unsigned char *str = name->name; const unsigned char *str = name->name;
struct hlist_bl_head *b = d_hash(parent, hash); struct hlist_bl_head *b = d_hash(hash);
struct hlist_bl_node *node; struct hlist_bl_node *node;
struct dentry *found = NULL; struct dentry *found = NULL;
struct dentry *dentry; struct dentry *dentry;
@ -2291,7 +2289,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
* calculate the standard hash first, as the d_op->d_hash() * calculate the standard hash first, as the d_op->d_hash()
* routine may choose to leave the hash value unchanged. * routine may choose to leave the hash value unchanged.
*/ */
name->hash = full_name_hash(name->name, name->len); name->hash = full_name_hash(dir, name->name, name->len);
if (dir->d_flags & DCACHE_OP_HASH) { if (dir->d_flags & DCACHE_OP_HASH) {
int err = dir->d_op->d_hash(dir, name); int err = dir->d_op->d_hash(dir, name);
if (unlikely(err < 0)) if (unlikely(err < 0))
@ -2364,7 +2362,7 @@ static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b)
static void _d_rehash(struct dentry * entry) static void _d_rehash(struct dentry * entry)
{ {
__d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash)); __d_rehash(entry, d_hash(entry->d_name.hash));
} }
/** /**
@ -2821,7 +2819,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
* for the same hash queue because of how unlikely it is. * for the same hash queue because of how unlikely it is.
*/ */
__d_drop(dentry); __d_drop(dentry);
__d_rehash(dentry, d_hash(target->d_parent, target->d_name.hash)); __d_rehash(dentry, d_hash(target->d_name.hash));
/* /*
* Unhash the target (d_delete() is not usable here). If exchanging * Unhash the target (d_delete() is not usable here). If exchanging
@ -2829,8 +2827,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
*/ */
__d_drop(target); __d_drop(target);
if (exchange) { if (exchange) {
__d_rehash(target, __d_rehash(target, d_hash(dentry->d_name.hash));
d_hash(dentry->d_parent, dentry->d_name.hash));
} }
/* Switch the names.. */ /* Switch the names.. */

View File

@ -65,7 +65,7 @@ static int efivarfs_d_compare(const struct dentry *parent,
static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr) static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
{ {
unsigned long hash = init_name_hash(); unsigned long hash = init_name_hash(dentry);
const unsigned char *s = qstr->name; const unsigned char *s = qstr->name;
unsigned int len = qstr->len; unsigned int len = qstr->len;
@ -98,7 +98,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
q.name = name; q.name = name;
q.len = strlen(name); q.len = strlen(name);
err = efivarfs_d_hash(NULL, &q); err = efivarfs_d_hash(parent, &q);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);

View File

@ -154,7 +154,7 @@ static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
error = msdos_format_name(qstr->name, qstr->len, msdos_name, options); error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
if (!error) if (!error)
qstr->hash = full_name_hash(msdos_name, MSDOS_NAME); qstr->hash = full_name_hash(dentry, msdos_name, MSDOS_NAME);
return 0; return 0;
} }

View File

@ -107,7 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr)
*/ */
static int vfat_hash(const struct dentry *dentry, struct qstr *qstr) static int vfat_hash(const struct dentry *dentry, struct qstr *qstr)
{ {
qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr)); qstr->hash = full_name_hash(dentry, qstr->name, vfat_striptail_len(qstr));
return 0; return 0;
} }
@ -127,7 +127,7 @@ static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
name = qstr->name; name = qstr->name;
len = vfat_striptail_len(qstr); len = vfat_striptail_len(qstr);
hash = init_name_hash(); hash = init_name_hash(dentry);
while (len--) while (len--)
hash = partial_name_hash(nls_tolower(t, *name++), hash); hash = partial_name_hash(nls_tolower(t, *name++), hash);
qstr->hash = end_name_hash(hash); qstr->hash = end_name_hash(hash);

View File

@ -1525,7 +1525,6 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
goto err; goto err;
fuse_copy_finish(cs); fuse_copy_finish(cs);
buf[outarg.namelen] = 0; buf[outarg.namelen] = 0;
name.hash = full_name_hash(name.name, name.len);
down_read(&fc->killsb); down_read(&fc->killsb);
err = -ENOENT; err = -ENOENT;
@ -1576,7 +1575,6 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
goto err; goto err;
fuse_copy_finish(cs); fuse_copy_finish(cs);
buf[outarg.namelen] = 0; buf[outarg.namelen] = 0;
name.hash = full_name_hash(name.name, name.len);
down_read(&fc->killsb); down_read(&fc->killsb);
err = -ENOENT; err = -ENOENT;

View File

@ -953,6 +953,7 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
if (!dir) if (!dir)
goto unlock; goto unlock;
name->hash = full_name_hash(dir, name->name, name->len);
entry = d_lookup(dir, name); entry = d_lookup(dir, name);
dput(dir); dput(dir);
if (!entry) if (!entry)
@ -1202,7 +1203,7 @@ static int fuse_direntplus_link(struct file *file,
fc = get_fuse_conn(dir); fc = get_fuse_conn(dir);
name.hash = full_name_hash(name.name, name.len); name.hash = full_name_hash(parent, name.name, name.len);
dentry = d_lookup(parent, &name); dentry = d_lookup(parent, &name);
if (!dentry) { if (!dentry) {
retry: retry:

View File

@ -59,7 +59,7 @@ int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
if (len > HFS_NAMELEN) if (len > HFS_NAMELEN)
len = HFS_NAMELEN; len = HFS_NAMELEN;
hash = init_name_hash(); hash = init_name_hash(dentry);
for (; len; len--) for (; len; len--)
hash = partial_name_hash(caseorder[*name++], hash); hash = partial_name_hash(caseorder[*name++], hash);
this->hash = end_name_hash(hash); this->hash = end_name_hash(hash);

View File

@ -346,7 +346,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
hash = init_name_hash(); hash = init_name_hash(dentry);
astr = str->name; astr = str->name;
len = str->len; len = str->len;
while (len > 0) { while (len > 0) {

View File

@ -26,7 +26,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
/*return -ENOENT;*/ /*return -ENOENT;*/
x: x:
hash = init_name_hash(); hash = init_name_hash(dentry);
for (i = 0; i < l; i++) for (i = 0; i < l; i++)
hash = partial_name_hash(hpfs_upcase(hpfs_sb(dentry->d_sb)->sb_cp_table,qstr->name[i]), hash); hash = partial_name_hash(hpfs_upcase(hpfs_sb(dentry->d_sb)->sb_cp_table,qstr->name[i]), hash);
qstr->hash = end_name_hash(hash); qstr->hash = end_name_hash(hash);

View File

@ -174,7 +174,7 @@ struct iso9660_options{
* Compute the hash for the isofs name corresponding to the dentry. * Compute the hash for the isofs name corresponding to the dentry.
*/ */
static int static int
isofs_hashi_common(struct qstr *qstr, int ms) isofs_hashi_common(const struct dentry *dentry, struct qstr *qstr, int ms)
{ {
const char *name; const char *name;
int len; int len;
@ -188,7 +188,7 @@ isofs_hashi_common(struct qstr *qstr, int ms)
len--; len--;
} }
hash = init_name_hash(); hash = init_name_hash(dentry);
while (len--) { while (len--) {
c = tolower(*name++); c = tolower(*name++);
hash = partial_name_hash(c, hash); hash = partial_name_hash(c, hash);
@ -231,7 +231,7 @@ static int isofs_dentry_cmp_common(
static int static int
isofs_hashi(const struct dentry *dentry, struct qstr *qstr) isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
{ {
return isofs_hashi_common(qstr, 0); return isofs_hashi_common(dentry, qstr, 0);
} }
static int static int
@ -246,7 +246,7 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
* Compute the hash for the isofs name corresponding to the dentry. * Compute the hash for the isofs name corresponding to the dentry.
*/ */
static int static int
isofs_hash_common(struct qstr *qstr, int ms) isofs_hash_common(const struct dentry *dentry, struct qstr *qstr, int ms)
{ {
const char *name; const char *name;
int len; int len;
@ -258,7 +258,7 @@ isofs_hash_common(struct qstr *qstr, int ms)
len--; len--;
} }
qstr->hash = full_name_hash(name, len); qstr->hash = full_name_hash(dentry, name, len);
return 0; return 0;
} }
@ -266,13 +266,13 @@ isofs_hash_common(struct qstr *qstr, int ms)
static int static int
isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr) isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
{ {
return isofs_hash_common(qstr, 1); return isofs_hash_common(dentry, qstr, 1);
} }
static int static int
isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr) isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
{ {
return isofs_hashi_common(qstr, 1); return isofs_hashi_common(dentry, qstr, 1);
} }
static int static int

View File

@ -81,6 +81,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
struct jffs2_full_dirent *fd = NULL, *fd_list; struct jffs2_full_dirent *fd = NULL, *fd_list;
uint32_t ino = 0; uint32_t ino = 0;
struct inode *inode = NULL; struct inode *inode = NULL;
unsigned int nhash;
jffs2_dbg(1, "jffs2_lookup()\n"); jffs2_dbg(1, "jffs2_lookup()\n");
@ -89,11 +90,14 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
dir_f = JFFS2_INODE_INFO(dir_i); dir_f = JFFS2_INODE_INFO(dir_i);
/* The 'nhash' on the fd_list is not the same as the dentry hash */
nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len);
mutex_lock(&dir_f->sem); mutex_lock(&dir_f->sem);
/* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) {
if (fd_list->nhash == target->d_name.hash && if (fd_list->nhash == nhash &&
(!fd || fd_list->version > fd->version) && (!fd || fd_list->version > fd->version) &&
strlen(fd_list->name) == target->d_name.len && strlen(fd_list->name) == target->d_name.len &&
!strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) {

View File

@ -674,7 +674,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r
} }
} }
fd->nhash = full_name_hash(fd->name, rd->nsize); fd->nhash = full_name_hash(NULL, fd->name, rd->nsize);
fd->next = NULL; fd->next = NULL;
fd->name[rd->nsize] = '\0'; fd->name[rd->nsize] = '\0';

View File

@ -1100,7 +1100,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
fd->next = NULL; fd->next = NULL;
fd->version = je32_to_cpu(rd->version); fd->version = je32_to_cpu(rd->version);
fd->ino = je32_to_cpu(rd->ino); fd->ino = je32_to_cpu(rd->ino);
fd->nhash = full_name_hash(fd->name, checkedlen); fd->nhash = full_name_hash(NULL, fd->name, checkedlen);
fd->type = rd->type; fd->type = rd->type;
jffs2_add_fd_to_list(c, fd, &ic->scan_dents); jffs2_add_fd_to_list(c, fd, &ic->scan_dents);

View File

@ -476,7 +476,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
fd->next = NULL; fd->next = NULL;
fd->version = je32_to_cpu(spd->version); fd->version = je32_to_cpu(spd->version);
fd->ino = je32_to_cpu(spd->ino); fd->ino = je32_to_cpu(spd->ino);
fd->nhash = full_name_hash(fd->name, checkedlen); fd->nhash = full_name_hash(NULL, fd->name, checkedlen);
fd->type = spd->type; fd->type = spd->type;
jffs2_add_fd_to_list(c, fd, &ic->scan_dents); jffs2_add_fd_to_list(c, fd, &ic->scan_dents);

View File

@ -245,7 +245,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
fd->version = je32_to_cpu(rd->version); fd->version = je32_to_cpu(rd->version);
fd->ino = je32_to_cpu(rd->ino); fd->ino = je32_to_cpu(rd->ino);
fd->nhash = full_name_hash(name, namelen); fd->nhash = full_name_hash(NULL, name, namelen);
fd->type = rd->type; fd->type = rd->type;
memcpy(fd->name, name, namelen); memcpy(fd->name, name, namelen);
fd->name[namelen]=0; fd->name[namelen]=0;
@ -598,7 +598,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
jffs2_add_fd_to_list(c, fd, &dir_f->dents); jffs2_add_fd_to_list(c, fd, &dir_f->dents);
mutex_unlock(&dir_f->sem); mutex_unlock(&dir_f->sem);
} else { } else {
uint32_t nhash = full_name_hash(name, namelen); uint32_t nhash = full_name_hash(NULL, name, namelen);
fd = dir_f->dents; fd = dir_f->dents;
/* We don't actually want to reserve any space, but we do /* We don't actually want to reserve any space, but we do

View File

@ -1564,7 +1564,7 @@ static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
unsigned long hash; unsigned long hash;
int i; int i;
hash = init_name_hash(); hash = init_name_hash(dir);
for (i=0; i < this->len; i++) for (i=0; i < this->len; i++)
hash = partial_name_hash(tolower(this->name[i]), hash); hash = partial_name_hash(tolower(this->name[i]), hash);
this->hash = end_name_hash(hash); this->hash = end_name_hash(hash);

View File

@ -336,11 +336,11 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
*/ */
static unsigned int kernfs_name_hash(const char *name, const void *ns) static unsigned int kernfs_name_hash(const char *name, const void *ns)
{ {
unsigned long hash = init_name_hash(); unsigned long hash = init_name_hash(ns);
unsigned int len = strlen(name); unsigned int len = strlen(name);
while (len--) while (len--)
hash = partial_name_hash(*name++, hash); hash = partial_name_hash(*name++, hash);
hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31)); hash = end_name_hash(hash);
hash &= 0x7fffffffU; hash &= 0x7fffffffU;
/* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
if (hash < 2) if (hash < 2)

View File

@ -1890,9 +1890,9 @@ static inline unsigned int fold_hash(unsigned long x, unsigned long y)
* payload bytes, to match the way that hash_name() iterates until it * payload bytes, to match the way that hash_name() iterates until it
* finds the delimiter after the name. * finds the delimiter after the name.
*/ */
unsigned int full_name_hash(const char *name, unsigned int len) unsigned int full_name_hash(const void *salt, const char *name, unsigned int len)
{ {
unsigned long a, x = 0, y = 0; unsigned long a, x = 0, y = (unsigned long)salt;
for (;;) { for (;;) {
if (!len) if (!len)
@ -1911,15 +1911,19 @@ done:
EXPORT_SYMBOL(full_name_hash); EXPORT_SYMBOL(full_name_hash);
/* Return the "hash_len" (hash and length) of a null-terminated string */ /* Return the "hash_len" (hash and length) of a null-terminated string */
u64 hashlen_string(const char *name) u64 hashlen_string(const void *salt, const char *name)
{ {
unsigned long a = 0, x = 0, y = 0, adata, mask, len; unsigned long a = 0, x = 0, y = (unsigned long)salt;
unsigned long adata, mask, len;
const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
len = -sizeof(unsigned long); len = 0;
goto inside;
do { do {
HASH_MIX(x, y, a); HASH_MIX(x, y, a);
len += sizeof(unsigned long); len += sizeof(unsigned long);
inside:
a = load_unaligned_zeropad(name+len); a = load_unaligned_zeropad(name+len);
} while (!has_zero(a, &adata, &constants)); } while (!has_zero(a, &adata, &constants));
@ -1935,15 +1939,19 @@ EXPORT_SYMBOL(hashlen_string);
* Calculate the length and hash of the path component, and * Calculate the length and hash of the path component, and
* return the "hash_len" as the result. * return the "hash_len" as the result.
*/ */
static inline u64 hash_name(const char *name) static inline u64 hash_name(const void *salt, const char *name)
{ {
unsigned long a = 0, b, x = 0, y = 0, adata, bdata, mask, len; unsigned long a = 0, b, x = 0, y = (unsigned long)salt;
unsigned long adata, bdata, mask, len;
const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
len = -sizeof(unsigned long); len = 0;
goto inside;
do { do {
HASH_MIX(x, y, a); HASH_MIX(x, y, a);
len += sizeof(unsigned long); len += sizeof(unsigned long);
inside:
a = load_unaligned_zeropad(name+len); a = load_unaligned_zeropad(name+len);
b = a ^ REPEAT_BYTE('/'); b = a ^ REPEAT_BYTE('/');
} while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants))); } while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants)));
@ -1959,9 +1967,9 @@ static inline u64 hash_name(const char *name)
#else /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */ #else /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */
/* Return the hash of a string of known length */ /* Return the hash of a string of known length */
unsigned int full_name_hash(const char *name, unsigned int len) unsigned int full_name_hash(const void *salt, const char *name, unsigned int len)
{ {
unsigned long hash = init_name_hash(); unsigned long hash = init_name_hash(salt);
while (len--) while (len--)
hash = partial_name_hash((unsigned char)*name++, hash); hash = partial_name_hash((unsigned char)*name++, hash);
return end_name_hash(hash); return end_name_hash(hash);
@ -1969,9 +1977,9 @@ unsigned int full_name_hash(const char *name, unsigned int len)
EXPORT_SYMBOL(full_name_hash); EXPORT_SYMBOL(full_name_hash);
/* Return the "hash_len" (hash and length) of a null-terminated string */ /* Return the "hash_len" (hash and length) of a null-terminated string */
u64 hashlen_string(const char *name) u64 hashlen_string(const void *salt, const char *name)
{ {
unsigned long hash = init_name_hash(); unsigned long hash = init_name_hash(salt);
unsigned long len = 0, c; unsigned long len = 0, c;
c = (unsigned char)*name; c = (unsigned char)*name;
@ -1988,9 +1996,9 @@ EXPORT_SYMBOL(hashlen_string);
* We know there's a real path component here of at least * We know there's a real path component here of at least
* one character. * one character.
*/ */
static inline u64 hash_name(const char *name) static inline u64 hash_name(const void *salt, const char *name)
{ {
unsigned long hash = init_name_hash(); unsigned long hash = init_name_hash(salt);
unsigned long len = 0, c; unsigned long len = 0, c;
c = (unsigned char)*name; c = (unsigned char)*name;
@ -2030,7 +2038,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
if (err) if (err)
return err; return err;
hash_len = hash_name(name); hash_len = hash_name(nd->path.dentry, name);
type = LAST_NORM; type = LAST_NORM;
if (name[0] == '.') switch (hashlen_len(hash_len)) { if (name[0] == '.') switch (hashlen_len(hash_len)) {
@ -2436,7 +2444,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
this.name = name; this.name = name;
this.len = len; this.len = len;
this.hash = full_name_hash(name, len); this.hash = full_name_hash(base, name, len);
if (!len) if (!len)
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
@ -2489,7 +2497,7 @@ struct dentry *lookup_one_len_unlocked(const char *name,
this.name = name; this.name = name;
this.len = len; this.len = len;
this.hash = full_name_hash(name, len); this.hash = full_name_hash(base, name, len);
if (!len) if (!len)
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);

View File

@ -139,7 +139,7 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
int i; int i;
t = NCP_IO_TABLE(sb); t = NCP_IO_TABLE(sb);
hash = init_name_hash(); hash = init_name_hash(dentry);
for (i=0; i<this->len ; i++) for (i=0; i<this->len ; i++)
hash = partial_name_hash(ncp_tolower(t, this->name[i]), hash = partial_name_hash(ncp_tolower(t, this->name[i]),
hash); hash);

View File

@ -232,7 +232,7 @@ int nfs_readdir_make_qstr(struct qstr *string, const char *name, unsigned int le
* in a page cache page which kmemleak does not scan. * in a page cache page which kmemleak does not scan.
*/ */
kmemleak_not_leak(string->name); kmemleak_not_leak(string->name);
string->hash = full_name_hash(name, len); string->hash = full_name_hash(NULL, name, len);
return 0; return 0;
} }
@ -497,7 +497,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
if (filename.len == 2 && filename.name[1] == '.') if (filename.len == 2 && filename.name[1] == '.')
return; return;
} }
filename.hash = full_name_hash(filename.name, filename.len); filename.hash = full_name_hash(parent, filename.name, filename.len);
dentry = d_lookup(parent, &filename); dentry = d_lookup(parent, &filename);
again: again:

View File

@ -253,7 +253,7 @@ handle_name:
err = (signed)nls_name.len; err = (signed)nls_name.len;
goto err_out; goto err_out;
} }
nls_name.hash = full_name_hash(nls_name.name, nls_name.len); nls_name.hash = full_name_hash(dent, nls_name.name, nls_name.len);
dent = d_add_ci(dent, dent_inode, &nls_name); dent = d_add_ci(dent, dent_inode, &nls_name);
kfree(nls_name.name); kfree(nls_name.name);

View File

@ -47,7 +47,7 @@
#define DLM_HASH_BUCKETS (DLM_HASH_PAGES * DLM_BUCKETS_PER_PAGE) #define DLM_HASH_BUCKETS (DLM_HASH_PAGES * DLM_BUCKETS_PER_PAGE)
/* Intended to make it easier for us to switch out hash functions */ /* Intended to make it easier for us to switch out hash functions */
#define dlm_lockid_hash(_n, _l) full_name_hash(_n, _l) #define dlm_lockid_hash(_n, _l) full_name_hash(NULL, _n, _l)
enum dlm_mle_type { enum dlm_mle_type {
DLM_MLE_BLOCK = 0, DLM_MLE_BLOCK = 0,

View File

@ -623,7 +623,7 @@ static bool proc_sys_fill_cache(struct file *file,
qname.name = table->procname; qname.name = table->procname;
qname.len = strlen(table->procname); qname.len = strlen(table->procname);
qname.hash = full_name_hash(qname.name, qname.len); qname.hash = full_name_hash(dir, qname.name, qname.len);
child = d_lookup(dir, &qname); child = d_lookup(dir, &qname);
if (!child) { if (!child) {

View File

@ -33,7 +33,7 @@ static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
function. */ function. */
if (qstr->len > SYSV_NAMELEN) { if (qstr->len > SYSV_NAMELEN) {
qstr->len = SYSV_NAMELEN; qstr->len = SYSV_NAMELEN;
qstr->hash = full_name_hash(qstr->name, qstr->len); qstr->hash = full_name_hash(dentry, qstr->name, qstr->len);
} }
return 0; return 0;
} }

View File

@ -34,7 +34,7 @@
*/ */
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */ /* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
#define init_name_hash() 0 #define init_name_hash(salt) (unsigned long)(salt)
/* partial hash update function. Assume roughly 4 bits per character */ /* partial hash update function. Assume roughly 4 bits per character */
static inline unsigned long static inline unsigned long
@ -60,7 +60,7 @@ static inline unsigned long end_name_hash(unsigned long hash)
* *
* If not set, this falls back to a wrapper around the preceding. * If not set, this falls back to a wrapper around the preceding.
*/ */
extern unsigned int __pure full_name_hash(const char *, unsigned int); extern unsigned int __pure full_name_hash(const void *salt, const char *, unsigned int);
/* /*
* A hash_len is a u64 with the hash of a string in the low * A hash_len is a u64 with the hash of a string in the low
@ -71,6 +71,6 @@ extern unsigned int __pure full_name_hash(const char *, unsigned int);
#define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash)) #define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash))
/* Return the "hash_len" (hash and length) of a null-terminated string */ /* Return the "hash_len" (hash and length) of a null-terminated string */
extern u64 __pure hashlen_string(const char *name); extern u64 __pure hashlen_string(const void *salt, const char *name);
#endif /* __LINUX_STRINGHASH_H */ #endif /* __LINUX_STRINGHASH_H */

View File

@ -172,12 +172,12 @@ extern void unix_gid_cache_destroy(struct net *net);
*/ */
static inline unsigned long hash_str(char const *name, int bits) static inline unsigned long hash_str(char const *name, int bits)
{ {
return hashlen_hash(hashlen_string(name)) >> (32 - bits); return hashlen_hash(hashlen_string(NULL, name)) >> (32 - bits);
} }
static inline unsigned long hash_mem(char const *buf, int length, int bits) static inline unsigned long hash_mem(char const *buf, int length, int bits)
{ {
return full_name_hash(buf, length) >> (32 - bits); return full_name_hash(NULL, buf, length) >> (32 - bits);
} }
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */

View File

@ -155,8 +155,8 @@ test_hash_init(void)
buf[j] = '\0'; buf[j] = '\0';
for (i = 0; i <= j; i++) { for (i = 0; i <= j; i++) {
u64 hashlen = hashlen_string(buf+i); u64 hashlen = hashlen_string(buf+i, buf+i);
u32 h0 = full_name_hash(buf+i, j-i); u32 h0 = full_name_hash(buf+i, buf+i, j-i);
/* Check that hashlen_string gets the length right */ /* Check that hashlen_string gets the length right */
if (hashlen_len(hashlen) != j-i) { if (hashlen_len(hashlen) != j-i) {

View File

@ -196,7 +196,7 @@ static inline void dev_base_seq_inc(struct net *net)
static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
{ {
unsigned int hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); unsigned int hash = full_name_hash(net, name, strnlen(name, IFNAMSIZ));
return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)]; return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)];
} }

View File

@ -413,7 +413,7 @@ void smk_insert_entry(struct smack_known *skp)
unsigned int hash; unsigned int hash;
struct hlist_head *head; struct hlist_head *head;
hash = full_name_hash(skp->smk_known, strlen(skp->smk_known)); hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known));
head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
hlist_add_head_rcu(&skp->smk_hashed, head); hlist_add_head_rcu(&skp->smk_hashed, head);
@ -433,7 +433,7 @@ struct smack_known *smk_find_entry(const char *string)
struct hlist_head *head; struct hlist_head *head;
struct smack_known *skp; struct smack_known *skp;
hash = full_name_hash(string, strlen(string)); hash = full_name_hash(NULL, string, strlen(string));
head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
hlist_for_each_entry_rcu(skp, head, smk_hashed) hlist_for_each_entry_rcu(skp, head, smk_hashed)

View File

@ -154,7 +154,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
if (!name) if (!name)
return NULL; return NULL;
len = strlen(name) + 1; len = strlen(name) + 1;
hash = full_name_hash((const unsigned char *) name, len - 1); hash = full_name_hash(NULL, (const unsigned char *) name, len - 1);
head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
if (mutex_lock_interruptible(&tomoyo_policy_lock)) if (mutex_lock_interruptible(&tomoyo_policy_lock))
return NULL; return NULL;

View File

@ -666,7 +666,7 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
ptr->const_len = tomoyo_const_part_length(name); ptr->const_len = tomoyo_const_part_length(name);
ptr->is_dir = len && (name[len - 1] == '/'); ptr->is_dir = len && (name[len - 1] == '/');
ptr->is_patterned = (ptr->const_len < len); ptr->is_patterned = (ptr->const_len < len);
ptr->hash = full_name_hash(name, len); ptr->hash = full_name_hash(NULL, name, len);
} }
/** /**