Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26fe5750 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

vfs: make it possible to access the dentry hash/len as one 64-bit entry



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: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ee983e89
Loading
Loading
Loading
Loading
+7 −9
Original line number Original line Diff line number Diff line
@@ -1502,7 +1502,7 @@ struct dentry *d_make_root(struct inode *root_inode)
	struct dentry *res = NULL;
	struct dentry *res = NULL;


	if (root_inode) {
	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);
		res = __d_alloc(root_inode->i_sb, &name);
		if (res)
		if (res)
@@ -1816,10 +1816,9 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
				const struct qstr *name,
				const struct qstr *name,
				unsigned *seqp, struct inode *inode)
				unsigned *seqp, struct inode *inode)
{
{
	unsigned int len = name->len;
	u64 hashlen = name->hash_len;
	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(parent, hashlen_hash(hashlen));
	struct hlist_bl_node *node;
	struct hlist_bl_node *node;
	struct dentry *dentry;
	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) {
	hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) {
		unsigned seq;
		unsigned seq;


		if (dentry->d_name.hash != hash)
			continue;

seqretry:
seqretry:
		/*
		/*
		 * The dentry sequence count protects us from concurrent
		 * The dentry sequence count protects us from concurrent
@@ -1871,6 +1867,8 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
		*seqp = seq;
		*seqp = seq;


		if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
		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)) {
			switch (slow_dentry_cmp(parent, inode, dentry, seq, name)) {
			case D_COMP_OK:
			case D_COMP_OK:
				return dentry;
				return dentry;
@@ -1881,9 +1879,9 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
			}
			}
		}
		}


		if (dentry->d_name.len != len)
		if (dentry->d_name.hash_len != hashlen)
			continue;
			continue;
		if (!dentry_cmp(dentry, str, len))
		if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
			return dentry;
			return dentry;
	}
	}
	return NULL;
	return NULL;
+1 −1
Original line number Original line Diff line number Diff line
@@ -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 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);
	unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot);
	if (!ino)
	if (!ino)
		return ERR_PTR(-ENOENT);
		return ERR_PTR(-ENOENT);
+1 −1
Original line number Original line Diff line number Diff line
@@ -1045,7 +1045,7 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
struct dentry *ext3_get_parent(struct dentry *child)
struct dentry *ext3_get_parent(struct dentry *child)
{
{
	unsigned long ino;
	unsigned long ino;
	struct qstr dotdot = {.name = "..", .len = 2};
	struct qstr dotdot = QSTR_INIT("..", 2);
	struct ext3_dir_entry_2 * de;
	struct ext3_dir_entry_2 * de;
	struct buffer_head *bh;
	struct buffer_head *bh;


+1 −4
Original line number Original line Diff line number Diff line
@@ -1052,10 +1052,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
struct dentry *ext4_get_parent(struct dentry *child)
struct dentry *ext4_get_parent(struct dentry *child)
{
{
	__u32 ino;
	__u32 ino;
	static const struct qstr dotdot = {
	static const struct qstr dotdot = QSTR_INIT("..", 2);
		.name = "..",
		.len = 2,
	};
	struct ext4_dir_entry_2 * de;
	struct ext4_dir_entry_2 * de;
	struct buffer_head *bh;
	struct buffer_head *bh;


+1 −1
Original line number Original line Diff line number Diff line
@@ -821,7 +821,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh,
	struct buffer_head *bh;
	struct buffer_head *bh;
	struct gfs2_leaf *leaf;
	struct gfs2_leaf *leaf;
	struct gfs2_dirent *dent;
	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);
	error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
	if (error)
	if (error)
Loading