vfs: make it possible to access the dentry hash/len as one 64-bit entry
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 10 May 2012 20:14:12 +0000 (13:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 May 2012 02:54:35 +0000 (19:54 -0700)
This allows comparing hash and len in one operation on 64-bit
architectures.  Right now only __d_lookup_rcu() takes advantage of this,
since that is the case we care most about.

The use of anonymous struct/unions hides the alternate 64-bit approach
from most users, the exception being a few cases where we initialize a
'struct qstr' with a static initializer.  This makes the problematic
cases use a new QSTR_INIT() helper function for that (but initializing
just the name pointer with a "{ .name = xyzzy }" initializer remains
valid, as does just copying another qstr structure).

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
18 files changed:
fs/dcache.c
fs/ext2/namei.c
fs/ext3/namei.c
fs/ext4/namei.c
fs/gfs2/dir.c
fs/libfs.c
fs/nfs/dir.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
fs/nfs/proc.c
fs/nilfs2/namei.c
fs/ubifs/tnc.c
fs/ubifs/xattr.c
fs/udf/namei.c
fs/ufs/super.c
include/linux/dcache.h
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c

index e6707a1f72c6404f76b3aea60e34ee2283cb6fb1..92099f61bc647ca14aef18ac99bbfd852ba152dd 100644 (file)
@@ -1502,7 +1502,7 @@ struct dentry *d_make_root(struct inode *root_inode)
        struct dentry *res = NULL;
 
        if (root_inode) {
-               static const struct qstr name = { .name = "/", .len = 1 };
+               static const struct qstr name = QSTR_INIT("/", 1);
 
                res = __d_alloc(root_inode->i_sb, &name);
                if (res)
@@ -1816,10 +1816,9 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
                                const struct qstr *name,
                                unsigned *seqp, struct inode *inode)
 {
-       unsigned int len = name->len;
-       unsigned int hash = name->hash;
+       u64 hashlen = name->hash_len;
        const unsigned char *str = name->name;
-       struct hlist_bl_head *b = d_hash(parent, hash);
+       struct hlist_bl_head *b = d_hash(parent, hashlen_hash(hashlen));
        struct hlist_bl_node *node;
        struct dentry *dentry;
 
@@ -1846,9 +1845,6 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
        hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
                unsigned seq;
 
-               if (dentry->d_name.hash != hash)
-                       continue;
-
 seqretry:
                /*
                 * The dentry sequence count protects us from concurrent
@@ -1871,6 +1867,8 @@ seqretry:
                *seqp = seq;
 
                if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
+                       if (dentry->d_name.hash != hashlen_hash(hashlen))
+                               continue;
                        switch (slow_dentry_cmp(parent, inode, dentry, seq, name)) {
                        case D_COMP_OK:
                                return dentry;
@@ -1881,9 +1879,9 @@ seqretry:
                        }
                }
 
-               if (dentry->d_name.len != len)
+               if (dentry->d_name.hash_len != hashlen)
                        continue;
-               if (!dentry_cmp(dentry, str, len))
+               if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
                        return dentry;
        }
        return NULL;
index dffb8653628574390589d9332491afdbd92b5a1d..f663a67d7bf0b92503d0ff8561d2886d0e2796e3 100644 (file)
@@ -79,7 +79,7 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
 
 struct dentry *ext2_get_parent(struct dentry *child)
 {
-       struct qstr dotdot = {.name = "..", .len = 2};
+       struct qstr dotdot = QSTR_INIT("..", 2);
        unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot);
        if (!ino)
                return ERR_PTR(-ENOENT);
index d7940b24cf683c3c63a2cf7d27e0f3e81eebd32e..eeb63dfc5d20320b0b7876022b342920294e7754 100644 (file)
@@ -1045,7 +1045,7 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
 struct dentry *ext3_get_parent(struct dentry *child)
 {
        unsigned long ino;
-       struct qstr dotdot = {.name = "..", .len = 2};
+       struct qstr dotdot = QSTR_INIT("..", 2);
        struct ext3_dir_entry_2 * de;
        struct buffer_head *bh;
 
index 349d7b3671c863ce1565a5d2a184c6bbdafbf6e3..e2a3f4b0ff78d6f81fbf2228f12f201e6ab1a024 100644 (file)
@@ -1052,10 +1052,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
 struct dentry *ext4_get_parent(struct dentry *child)
 {
        __u32 ino;
-       static const struct qstr dotdot = {
-               .name = "..",
-               .len = 2,
-       };
+       static const struct qstr dotdot = QSTR_INIT("..", 2);
        struct ext4_dir_entry_2 * de;
        struct buffer_head *bh;
 
index a836056343f077bee81a6f54c7a1e5b0f86cf604..8aaeb07a07b52bdcbfad125fd5ecbb2fcbb21213 100644 (file)
@@ -821,7 +821,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
        struct buffer_head *bh;
        struct gfs2_leaf *leaf;
        struct gfs2_dirent *dent;
-       struct qstr name = { .name = "", .len = 0, .hash = 0 };
+       struct qstr name = { .name = "" };
 
        error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
        if (error)
index 18d08f5db53adb46d832222357df9d81d5058f11..f86ec27a4230a6cd23f6d020c53217cd30a060f1 100644 (file)
@@ -68,7 +68,7 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct na
 
 int dcache_dir_open(struct inode *inode, struct file *file)
 {
-       static struct qstr cursor_name = {.len = 1, .name = "."};
+       static struct qstr cursor_name = QSTR_INIT(".", 1);
 
        file->private_data = d_alloc(file->f_path.dentry, &cursor_name);
 
@@ -225,7 +225,7 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
        struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
        struct dentry *dentry;
        struct inode *root;
-       struct qstr d_name = {.name = name, .len = strlen(name)};
+       struct qstr d_name = QSTR_INIT(name, strlen(name));
 
        if (IS_ERR(s))
                return ERR_CAST(s);
index 8789210c6905a666c86612d9ac080f567ddbd89f..eedd24d0ad2efc6a02e7ff7b552e2e707adadfbd 100644 (file)
@@ -477,10 +477,7 @@ different:
 static
 void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 {
-       struct qstr filename = {
-               .len = entry->len,
-               .name = entry->name,
-       };
+       struct qstr filename = QSTR_INIT(entry->name, entry->len);
        struct dentry *dentry;
        struct dentry *alias;
        struct inode *dir = parent->d_inode;
index 5242eae6711a0b5323b1dcec13d57ecf01c47986..75c68299358e226e805e861e4ac8ffc81d96ab4f 100644 (file)
@@ -398,8 +398,7 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name)
 {
        struct nfs_removeargs arg = {
                .fh = NFS_FH(dir),
-               .name.len = name->len,
-               .name.name = name->name,
+               .name = *name,
        };
        struct nfs_removeres res;
        struct rpc_message msg = {
index 99650aaf8937a28a52f9fca9946771f61379a8c7..ab985f6f0da8d93da67f625ba8027ff851678c55 100644 (file)
@@ -2782,8 +2782,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_removeargs args = {
                .fh = NFS_FH(dir),
-               .name.len = name->len,
-               .name.name = name->name,
+               .name = *name,
                .bitmask = server->attr_bitmask,
        };
        struct nfs_removeres res = {
index b63b6f4d14fbd5f54bdf265461c2a0069cbc5db0..d6408b6437de4f9f0c55f9f211f61df129976b7c 100644 (file)
@@ -335,8 +335,7 @@ nfs_proc_remove(struct inode *dir, struct qstr *name)
 {
        struct nfs_removeargs arg = {
                .fh = NFS_FH(dir),
-               .name.len = name->len,
-               .name.name = name->name,
+               .name = *name,
        };
        struct rpc_message msg = { 
                .rpc_proc = &nfs_procedures[NFSPROC_REMOVE],
index fce2bbee66d43dac909208a3cd0a6a84fff343c6..0bb2c2010b9512ba5fd971fdbdc34eba2abab886 100644 (file)
@@ -441,7 +441,7 @@ static struct dentry *nilfs_get_parent(struct dentry *child)
 {
        unsigned long ino;
        struct inode *inode;
-       struct qstr dotdot = {.name = "..", .len = 2};
+       struct qstr dotdot = QSTR_INIT("..", 2);
        struct nilfs_root *root;
 
        ino = nilfs_inode_by_name(child->d_inode, &dotdot);
index 16ad84d8402f31a5729f86c3b15f20a129f49efd..abd51331345e74070924b3c83665ba73be211acb 100644 (file)
@@ -2361,7 +2361,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
                         * by passing 'ubifs_tnc_remove_nm()' the same key but
                         * an unmatchable name.
                         */
-                       struct qstr noname = { .len = 0, .name = "" };
+                       struct qstr noname = { .name = "" };
 
                        err = dbg_check_tnc(c, 0);
                        mutex_unlock(&c->tnc_mutex);
index 85b2722687545b0e3299d7bdc0275ebe9fb2d2e2..7a8bafa19c9fbe40003643459c7d03bed02bcbfe 100644 (file)
@@ -298,7 +298,7 @@ int ubifs_setxattr(struct dentry *dentry, const char *name,
 {
        struct inode *inode, *host = dentry->d_inode;
        struct ubifs_info *c = host->i_sb->s_fs_info;
-       struct qstr nm = { .name = name, .len = strlen(name) };
+       struct qstr nm = QSTR_INIT(name, strlen(name));
        struct ubifs_dent_node *xent;
        union ubifs_key key;
        int err, type;
@@ -361,7 +361,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
 {
        struct inode *inode, *host = dentry->d_inode;
        struct ubifs_info *c = host->i_sb->s_fs_info;
-       struct qstr nm = { .name = name, .len = strlen(name) };
+       struct qstr nm = QSTR_INIT(name, strlen(name));
        struct ubifs_inode *ui;
        struct ubifs_dent_node *xent;
        union ubifs_key key;
@@ -524,7 +524,7 @@ int ubifs_removexattr(struct dentry *dentry, const char *name)
 {
        struct inode *inode, *host = dentry->d_inode;
        struct ubifs_info *c = host->i_sb->s_fs_info;
-       struct qstr nm = { .name = name, .len = strlen(name) };
+       struct qstr nm = QSTR_INIT(name, strlen(name));
        struct ubifs_dent_node *xent;
        union ubifs_key key;
        int err;
index 38de8f234b94966893eeec21d76f6ce63a7b6477..a165c66e3eef2249379890c60a4c7d4111e8df4d 100644 (file)
@@ -1193,7 +1193,7 @@ static struct dentry *udf_get_parent(struct dentry *child)
 {
        struct kernel_lb_addr tloc;
        struct inode *inode = NULL;
-       struct qstr dotdot = {.name = "..", .len = 2};
+       struct qstr dotdot = QSTR_INIT("..", 2);
        struct fileIdentDesc cfi;
        struct udf_fileident_bh fibh;
 
index ac8e279eccc668dcf1f6cd55c942569b9830e560..302f340d0071280adaef9366b98280b18e5dd32a 100644 (file)
@@ -146,10 +146,7 @@ static struct dentry *ufs_fh_to_parent(struct super_block *sb, struct fid *fid,
 
 static struct dentry *ufs_get_parent(struct dentry *child)
 {
-       struct qstr dot_dot = {
-               .name   = "..",
-               .len    = 2,
-       };
+       struct qstr dot_dot = QSTR_INIT("..", 2);
        ino_t ino;
 
        ino = ufs_inode_by_name(child->d_inode, &dot_dot);
index 8239f64d1c2e104263fad36412f647667cc1662f..094789ff3e9f4e958ab35a90aa001d05997a0fa2 100644 (file)
@@ -25,6 +25,13 @@ struct vfsmount;
 
 #define IS_ROOT(x) ((x) == (x)->d_parent)
 
+/* The hash is always the low bits of hash_len */
+#ifdef __LITTLE_ENDIAN
+ #define HASH_LEN_DECLARE u32 hash; u32 len;
+#else
+ #define HASH_LEN_DECLARE u32 len; u32 hash;
+#endif
+
 /*
  * "quick string" -- eases parameter passing, but more importantly
  * saves "metadata" about the string (ie length and the hash).
@@ -33,11 +40,19 @@ struct vfsmount;
  * dentry.
  */
 struct qstr {
-       unsigned int hash;
-       unsigned int len;
+       union {
+               struct {
+                       HASH_LEN_DECLARE;
+               };
+               u64 hash_len;
+       };
        const unsigned char *name;
 };
 
+#define QSTR_INIT(n,l) { { { .len = l } }, .name = n }
+#define hashlen_hash(hashlen) ((u32) (hashlen))
+#define hashlen_len(hashlen)  ((u32)((hashlen) >> 32))
+
 struct dentry_stat_t {
        int nr_dentry;
        int nr_unused;
index adf2990acebfd2ff7513f2344f0a143c326eb6ef..7fee13b331d193e1a46831c257ffd6fcf6a4fde8 100644 (file)
@@ -127,9 +127,7 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
 {
        static uint32_t clntid;
        char name[15];
-       struct qstr q = {
-               .name = name,
-       };
+       struct qstr q = { .name = name };
        struct dentry *dir, *dentry;
        int error;
 
index 3b62cf2880316bfb9942960e1fc34e39c64f92bf..fd2423991c2d4dc473223b128d9a761b3da5beea 100644 (file)
@@ -1059,12 +1059,9 @@ static const struct rpc_filelist files[] = {
 struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
                               const unsigned char *dir_name)
 {
-       struct qstr dir = {
-               .name = dir_name,
-               .len = strlen(dir_name),
-               .hash = full_name_hash(dir_name, strlen(dir_name)),
-       };
+       struct qstr dir = QSTR_INIT(dir_name, strlen(dir_name));
 
+       dir.hash = full_name_hash(dir.name, dir.len);
        return d_lookup(sb->s_root, &dir);
 }
 EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);