vfs: make the string hashes salt the hash
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 10 Jun 2016 14:51:30 +0000 (07:51 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 11 Jun 2016 03:21:46 +0000 (20:21 -0700)
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>
38 files changed:
drivers/staging/lustre/lustre/llite/statahead.c
fs/adfs/dir.c
fs/affs/namei.c
fs/autofs4/waitq.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/cifs/dir.c
fs/dcache.c
fs/efivarfs/super.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/hfs/string.c
fs/hfsplus/unicode.c
fs/hpfs/dentry.c
fs/isofs/inode.c
fs/jffs2/dir.c
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/summary.c
fs/jffs2/write.c
fs/jfs/namei.c
fs/kernfs/dir.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfs/dir.c
fs/ntfs/namei.c
fs/ocfs2/dlm/dlmcommon.h
fs/proc/proc_sysctl.c
fs/sysv/namei.c
include/linux/stringhash.h
include/linux/sunrpc/svcauth.h
lib/test_hash.c
net/core/dev.c
security/smack/smack_access.c
security/tomoyo/memory.c
security/tomoyo/util.c

index 6322f88661e8c536c7a45ebfd6e03346590bd005..79d9830b2997982b910c9d73f3ad037694395084 100644 (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.
  */
 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)
 {
        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);
        memcpy(dname, name, len);
        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.name = dname;
 
@@ -902,7 +904,7 @@ static void ll_statahead_one(struct dentry *parent, const char *entry_name,
        int                    rc;
        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);
        if (IS_ERR(entry))
                return;
index fd4cf2c48e48e3d16b3fc525373a65ecb5cad6cc..bec25f7017c0baa95444edbef2a886d7a3467bf3 100644 (file)
@@ -207,7 +207,7 @@ adfs_hash(const struct dentry *parent, struct qstr *qstr)
         */
        qstr->len = i = name_len;
        name = qstr->name;
-       hash = init_name_hash();
+       hash = init_name_hash(parent);
        while (i--) {
                char c;
 
index 00d3002a6780b339cf456417b742bf5c9f991ec8..eb32029bc776b5060eb7f1c38ec8d1f6a38bdba7 100644 (file)
@@ -61,7 +61,7 @@ affs_get_toupper(struct super_block *sb)
  * Note: the dentry argument is the parent dentry.
  */
 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;
        unsigned long hash;
@@ -72,7 +72,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
        if (retval)
                return retval;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        len = min(qstr->len, AFFSNAMEMAX);
        for (; len > 0; name++, len--)
                hash = partial_name_hash(toupper(*name), hash);
@@ -84,7 +84,7 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
 static int
 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));
 
 }
@@ -92,7 +92,7 @@ affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 static int
 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));
 
 }
index 0146d911f468ca46d5fe7c946851c500b624ccb9..f620160ceb6cee3ef0bc57264e6d06b06f15427f 100644 (file)
@@ -397,7 +397,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
                }
        }
        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)) {
                kfree(qstr.name);
index f059b5997072c399fcf6cdccbfcc806d4605a581..99bdef66213a662a64dc8b14823c72e3d361a0ca 100644 (file)
@@ -1164,7 +1164,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
 
                        dname.name = rinfo->dname;
                        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.snap = le64_to_cpu(rinfo->targeti.in->snapid);
 retry_lookup:
@@ -1508,7 +1508,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req,
 
                dname.name = rde->name;
                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.snap = le64_to_cpu(rde->inode.in->snapid);
index 2103b823bec0786aa60e48fa3957f252d5010017..4e8678a612b6ffc4465ff90fc8bc12e9f93f465d 100644 (file)
@@ -3204,7 +3204,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                WARN_ON(1);
                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);
        dput(parent);
        if (!dentry)
index c3eb998a99bd18a2ed9b7b843c99be15fedab9df..916b2d7d3a9b23688a8e4e15fda0b03b5cd5100d 100644 (file)
@@ -856,7 +856,7 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
        wchar_t c;
        int i, charlen;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (i = 0; i < q->len; i += charlen) {
                charlen = codepage->char2uni(&q->name[i], q->len - i, &c);
                /* error out if we can't convert the character */
index 817c243c1ff114d5a0e5243a4269fdac925994e7..9522b8b638714ff65b73e6b8ee0acb03f6d3cc61 100644 (file)
@@ -104,10 +104,8 @@ static unsigned int d_hash_shift __read_mostly;
 
 static struct hlist_bl_head *dentry_hashtable __read_mostly;
 
-static inline struct hlist_bl_head *d_hash(const struct dentry *parent,
-                                       unsigned int hash)
+static inline struct hlist_bl_head *d_hash(unsigned int hash)
 {
-       hash += (unsigned long) parent / L1_CACHE_BYTES;
        return dentry_hashtable + hash_32(hash, d_hash_shift);
 }
 
@@ -488,7 +486,7 @@ void __d_drop(struct dentry *dentry)
                if (unlikely(IS_ROOT(dentry)))
                        b = &dentry->d_sb->s_anon;
                else
-                       b = d_hash(dentry->d_parent, dentry->d_name.hash);
+                       b = d_hash(dentry->d_name.hash);
 
                hlist_bl_lock(b);
                __hlist_bl_del(&dentry->d_hash);
@@ -1670,7 +1668,7 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name)
        struct qstr q;
 
        q.name = name;
-       q.hash_len = hashlen_string(name);
+       q.hash_len = hashlen_string(parent, name);
        return d_alloc(parent, &q);
 }
 EXPORT_SYMBOL(d_alloc_name);
@@ -2094,7 +2092,7 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
 {
        u64 hashlen = name->hash_len;
        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 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 hash = name->hash;
        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 dentry *found = NULL;
        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()
         * 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) {
                int err = dir->d_op->d_hash(dir, name);
                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)
 {
-       __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.
         */
        __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
@@ -2829,8 +2827,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
         */
        __d_drop(target);
        if (exchange) {
-               __d_rehash(target,
-                          d_hash(dentry->d_parent, dentry->d_name.hash));
+               __d_rehash(target, d_hash(dentry->d_name.hash));
        }
 
        /* Switch the names.. */
index 9cb54a38832de664b3ced0c4b876ececb7c907dd..a5e607e8f056dc7c1cac815573c01d6a2601caf1 100644 (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)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(dentry);
        const unsigned char *s = qstr->name;
        unsigned int len = qstr->len;
 
@@ -98,7 +98,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
        q.name = name;
        q.len = strlen(name);
 
-       err = efivarfs_d_hash(NULL, &q);
+       err = efivarfs_d_hash(parent, &q);
        if (err)
                return ERR_PTR(err);
 
index b7e2b33aa79356b7762512dbe5940b5fca7de1d7..1337c0c7527d543f5d5585bec256ad56b7c32a4e 100644 (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);
        if (!error)
-               qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
+               qstr->hash = full_name_hash(dentry, msdos_name, MSDOS_NAME);
        return 0;
 }
 
index 7092584f424af63e66e43cf8ad365343fc18daa9..6ccdf3f34f90f4789d0f217d74e7a748337e9758 100644 (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)
 {
-       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;
 }
 
@@ -127,7 +127,7 @@ static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
        name = qstr->name;
        len = vfat_striptail_len(qstr);
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        while (len--)
                hash = partial_name_hash(nls_tolower(t, *name++), hash);
        qstr->hash = end_name_hash(hash);
index cbece1221417bb0ad5c60a143c724e6b3a5b06e8..203adf3b75dba448c074e596b81c9966a75f51d4 100644 (file)
@@ -1525,7 +1525,6 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
                goto err;
        fuse_copy_finish(cs);
        buf[outarg.namelen] = 0;
-       name.hash = full_name_hash(name.name, name.len);
 
        down_read(&fc->killsb);
        err = -ENOENT;
@@ -1576,7 +1575,6 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
                goto err;
        fuse_copy_finish(cs);
        buf[outarg.namelen] = 0;
-       name.hash = full_name_hash(name.name, name.len);
 
        down_read(&fc->killsb);
        err = -ENOENT;
index ccd4971cc6c1ac787ede8998d73f3e68f3a1294a..112ab40681152c4cba968a62e5d95052c79b9609 100644 (file)
@@ -953,6 +953,7 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
        if (!dir)
                goto unlock;
 
+       name->hash = full_name_hash(dir, name->name, name->len);
        entry = d_lookup(dir, name);
        dput(dir);
        if (!entry)
@@ -1202,7 +1203,7 @@ static int fuse_direntplus_link(struct file *file,
 
        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);
        if (!dentry) {
 retry:
index 85b610c3909fbad5b5da73343f29cd9b2b84b96d..ec9f164c35a585478b97864d3dad94c3596ad9bc 100644 (file)
@@ -59,7 +59,7 @@ int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
        if (len > HFS_NAMELEN)
                len = HFS_NAMELEN;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (; len; len--)
                hash = partial_name_hash(caseorder[*name++], hash);
        this->hash = end_name_hash(hash);
index e8ef121a4d8b5be7ca35bfe18aa4de4b925dfb59..c13c8a240be307a1e1f6151a543b5c485e4c483c 100644 (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);
        decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        astr = str->name;
        len = str->len;
        while (len > 0) {
index fa27980f2229216c47c2378ce7431f18bd5a793e..60e6d334d79abbf2323dcd5e55316ffb8d9f5332 100644 (file)
@@ -26,7 +26,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
                /*return -ENOENT;*/
        x:
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        for (i = 0; i < l; i++)
                hash = partial_name_hash(hpfs_upcase(hpfs_sb(dentry->d_sb)->sb_cp_table,qstr->name[i]), hash);
        qstr->hash = end_name_hash(hash);
index 131dedc920d8db28b00a19b09dd33ca438a7d81d..761fade7680f8c92ffbc31f218578ad1fa04479d 100644 (file)
@@ -174,7 +174,7 @@ struct iso9660_options{
  * Compute the hash for the isofs name corresponding to the dentry.
  */
 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;
        int len;
@@ -188,7 +188,7 @@ isofs_hashi_common(struct qstr *qstr, int ms)
                        len--;
        }
 
-       hash = init_name_hash();
+       hash = init_name_hash(dentry);
        while (len--) {
                c = tolower(*name++);
                hash = partial_name_hash(c, hash);
@@ -231,7 +231,7 @@ static int isofs_dentry_cmp_common(
 static int
 isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
 {
-       return isofs_hashi_common(qstr, 0);
+       return isofs_hashi_common(dentry, qstr, 0);
 }
 
 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.
  */
 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;
        int len;
@@ -258,7 +258,7 @@ isofs_hash_common(struct qstr *qstr, int ms)
                        len--;
        }
 
-       qstr->hash = full_name_hash(name, len);
+       qstr->hash = full_name_hash(dentry, name, len);
 
        return 0;
 }
@@ -266,13 +266,13 @@ isofs_hash_common(struct qstr *qstr, int ms)
 static int
 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
 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
index 84c4bf3631a25b85143856c43b6adcae673b94c4..30eb33ff81892586a227a366669c2a133eaadf4a 100644 (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;
        uint32_t ino = 0;
        struct inode *inode = NULL;
+       unsigned int nhash;
 
        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);
 
+       /* 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);
 
        /* 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) {
-               if (fd_list->nhash == target->d_name.hash &&
+       for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= nhash; fd_list = fd_list->next) {
+               if (fd_list->nhash == nhash &&
                    (!fd || fd_list->version > fd->version) &&
                    strlen(fd_list->name) == target->d_name.len &&
                    !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) {
index bfebbf13698c0e0d255e20f5ebf26de7fd6b5845..06a71dbd4833e3bdf4ea5277bc50e15ee40c45ad 100644 (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->name[rd->nsize] = '\0';
 
index 9ad5ba4b299be2f41cca834e97480a309c4e7b16..90431dd613b8db1bd699c6cc1eaff6a5608fde46 100644 (file)
@@ -1100,7 +1100,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
        fd->next = NULL;
        fd->version = je32_to_cpu(rd->version);
        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;
        jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
 
index bc5385471a6e3f2b1088d93bed109b185f4d8256..be7c8a6a574806fd0d4189695083c15b65e5f492 100644 (file)
@@ -476,7 +476,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
                                fd->next = NULL;
                                fd->version = je32_to_cpu(spd->version);
                                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;
 
                                jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
index 7fb187ab2682ff3433f7f26eebb68dd5e8ad9e21..cda9a361368e8e2c9949e577718691e931bd06bd 100644 (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->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;
        memcpy(fd->name, name, namelen);
        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);
                mutex_unlock(&dir_f->sem);
        } else {
-               uint32_t nhash = full_name_hash(name, namelen);
+               uint32_t nhash = full_name_hash(NULL, name, namelen);
 
                fd = dir_f->dents;
                /* We don't actually want to reserve any space, but we do
index 539deddecbb037618d8944236ced8e730785fba5..04baf0dfc40c0b3d7a61966feeb37e8fc2de5ff1 100644 (file)
@@ -1564,7 +1564,7 @@ static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
        unsigned long hash;
        int i;
 
-       hash = init_name_hash();
+       hash = init_name_hash(dir);
        for (i=0; i < this->len; i++)
                hash = partial_name_hash(tolower(this->name[i]), hash);
        this->hash = end_name_hash(hash);
index 8a652404eef680f77ebc49fad7636e1f950b82df..e57174d436830a4111a1bfdf7c9b7fa11a124908 100644 (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)
 {
-       unsigned long hash = init_name_hash();
+       unsigned long hash = init_name_hash(ns);
        unsigned int len = strlen(name);
        while (len--)
                hash = partial_name_hash(*name++, hash);
-       hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31));
+       hash = end_name_hash(hash);
        hash &= 0x7fffffffU;
        /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
        if (hash < 2)
index 70580ab1445c89f8379756fc16e33223aca4ab0d..7cb9be3e200a97d79ee2e60bf5911bb71ad659a5 100644 (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
  * 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 (;;) {
                if (!len)
@@ -1911,15 +1911,19 @@ done:
 EXPORT_SYMBOL(full_name_hash);
 
 /* 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;
 
-       len = -sizeof(unsigned long);
+       len = 0;
+       goto inside;
+
        do {
                HASH_MIX(x, y, a);
                len += sizeof(unsigned long);
+inside:
                a = load_unaligned_zeropad(name+len);
        } while (!has_zero(a, &adata, &constants));
 
@@ -1935,15 +1939,19 @@ EXPORT_SYMBOL(hashlen_string);
  * Calculate the length and hash of the path component, and
  * 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;
 
-       len = -sizeof(unsigned long);
+       len = 0;
+       goto inside;
+
        do {
                HASH_MIX(x, y, a);
                len += sizeof(unsigned long);
+inside:
                a = load_unaligned_zeropad(name+len);
                b = a ^ REPEAT_BYTE('/');
        } 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 */
 
 /* 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--)
                hash = partial_name_hash((unsigned char)*name++, 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);
 
 /* 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;
 
        c = (unsigned char)*name;
@@ -1988,9 +1996,9 @@ EXPORT_SYMBOL(hashlen_string);
  * We know there's a real path component here of at least
  * 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;
 
        c = (unsigned char)*name;
@@ -2030,7 +2038,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                if (err)
                        return err;
 
-               hash_len = hash_name(name);
+               hash_len = hash_name(nd->path.dentry, name);
 
                type = LAST_NORM;
                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.len = len;
-       this.hash = full_name_hash(name, len);
+       this.hash = full_name_hash(base, name, len);
        if (!len)
                return ERR_PTR(-EACCES);
 
@@ -2489,7 +2497,7 @@ struct dentry *lookup_one_len_unlocked(const char *name,
 
        this.name = name;
        this.len = len;
-       this.hash = full_name_hash(name, len);
+       this.hash = full_name_hash(base, name, len);
        if (!len)
                return ERR_PTR(-EACCES);
 
index bfdad003ee56f69a8eb55dbd5023b384d4b55fdc..9add7ab747a53338f081aa3cc97c8c3d9ebdc4d7 100644 (file)
@@ -139,7 +139,7 @@ ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
                int i;
 
                t = NCP_IO_TABLE(sb);
-               hash = init_name_hash();
+               hash = init_name_hash(dentry);
                for (i=0; i<this->len ; i++)
                        hash = partial_name_hash(ncp_tolower(t, this->name[i]),
                                                                        hash);
index aaf7bd0cbae20216333042c5a082a7560f6af61f..d6935a9e8fddb856d03a97e982b90fb7ce4fa0a3 100644 (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.
         */
        kmemleak_not_leak(string->name);
-       string->hash = full_name_hash(name, len);
+       string->hash = full_name_hash(NULL, name, len);
        return 0;
 }
 
@@ -497,7 +497,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
                if (filename.len == 2 && filename.name[1] == '.')
                        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);
 again:
index 443abecf01b7d45cfb19be0ee63032b156ae718b..358258364616cd3c2fee997daca2a192719cb045 100644 (file)
@@ -253,7 +253,7 @@ handle_name:
                err = (signed)nls_name.len;
                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);
        kfree(nls_name.name);
index 004f2cbe8f71e7c4ffb8833f8cc1e249680f99c4..8107d0d0c3f6e8857f4cbbfd8f14f3573b0267c2 100644 (file)
@@ -47,7 +47,7 @@
 #define DLM_HASH_BUCKETS       (DLM_HASH_PAGES * DLM_BUCKETS_PER_PAGE)
 
 /* 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 {
        DLM_MLE_BLOCK = 0,
index 5e57c3e46e1da6d2338cdce05ec0044d5b158797..b59db94d2ff452b8eb3124fbc5785457d7e6d947 100644 (file)
@@ -623,7 +623,7 @@ static bool proc_sys_fill_cache(struct file *file,
 
        qname.name = 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);
        if (!child) {
index 90b60c03b588488cd16b96f2f324f026ee7ee1bf..a42de45ce40dbfea77987cab4a4de00e85c6ae97 100644 (file)
@@ -33,7 +33,7 @@ static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
           function. */
        if (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;
 }
index 451771d9b9c09e2ef8d8317dee9c10008772c7e6..eb7debb280c09cffd83b995e920939fcf2b89344 100644 (file)
@@ -34,7 +34,7 @@
  */
 
 /* 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 */
 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.
  */
-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
@@ -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))
 
 /* 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 */
index 91d5a5d6f52b0547b4652f4e3f6efbd7de1ff776..d03932055328ccef696dd3008dcddc2d5d1c5d70 100644 (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)
 {
-       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)
 {
-       return full_name_hash(buf, length) >> (32 - bits);
+       return full_name_hash(NULL, buf, length) >> (32 - bits);
 }
 
 #endif /* __KERNEL__ */
index c9549c8b49090d7e3bd7ee1484f31ae313334511..66c5fc8351e84d703373a3572d6afaea84c410da 100644 (file)
@@ -155,8 +155,8 @@ test_hash_init(void)
                buf[j] = '\0';
 
                for (i = 0; i <= j; i++) {
-                       u64 hashlen = hashlen_string(buf+i);
-                       u32 h0 = full_name_hash(buf+i, j-i);
+                       u64 hashlen = hashlen_string(buf+i, buf+i);
+                       u32 h0 = full_name_hash(buf+i, buf+i, j-i);
 
                        /* Check that hashlen_string gets the length right */
                        if (hashlen_len(hashlen) != j-i) {
index 904ff431d570e3cfc0e6255480bd25f3c9dec2f3..7f7d7ef1caa568b99d2d1daca045fa988c696d95 100644 (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)
 {
-       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)];
 }
index a283f9e796c114465dc969a1224e72b328a1c927..23e5808a0970b69bfed64a92d608b05537bbc074 100644 (file)
@@ -413,7 +413,7 @@ void smk_insert_entry(struct smack_known *skp)
        unsigned int hash;
        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)];
 
        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 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)];
 
        hlist_for_each_entry_rcu(skp, head, smk_hashed)
index 0e995716cc258b40353f2e559081b0f55ba51b2b..1598b559ac425863f73825303f64d9ab168847b8 100644 (file)
@@ -154,7 +154,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
        if (!name)
                return NULL;
        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)];
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return NULL;
index b974a6997d7f8b7a81f8d2062c59a810b0a6c2d7..5fe3679137aeb76297305e3e73d7defe3ed4c004 100644 (file)
@@ -666,7 +666,7 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
        ptr->const_len = tomoyo_const_part_length(name);
        ptr->is_dir = len && (name[len - 1] == '/');
        ptr->is_patterned = (ptr->const_len < len);
-       ptr->hash = full_name_hash(name, len);
+       ptr->hash = full_name_hash(NULL, name, len);
 }
 
 /**