mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
vfs: link_path_walk: simplify name hash flow
This is one of those hot functions in path walking, and it's doing things in just the wrong order that causes slightly unnecessary extra work. Move the name pointer update and the setting of 'nd->last' up a bit, so that the (unlikely) filesystem-specific hashing can run on them in place, instead of having to set up a copy on the stack and copy things back and forth. Because even when the hashing is not run, it causes the stack frame of the function to be bigger to hold the unnecessary temporary copy. This also means that we never then reference the full "hashlen" field after calculating it, and can clarify the code with just using the length part. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
6ba59ff422
commit
7d286849a8
29
fs/namei.c
29
fs/namei.c
@ -2266,7 +2266,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
|
||||
for(;;) {
|
||||
struct mnt_idmap *idmap;
|
||||
const char *link;
|
||||
u64 hash_len;
|
||||
unsigned int len;
|
||||
int type;
|
||||
|
||||
idmap = mnt_idmap(nd->path.mnt);
|
||||
@ -2274,37 +2274,34 @@ static int link_path_walk(const char *name, struct nameidata *nd)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
hash_len = hash_name(nd->path.dentry, name);
|
||||
nd->last.name = name;
|
||||
nd->last.hash_len = hash_name(nd->path.dentry, name);
|
||||
len = hashlen_len(nd->last.hash_len);
|
||||
name += len;
|
||||
|
||||
type = LAST_NORM;
|
||||
if (name[0] == '.') switch (hashlen_len(hash_len)) {
|
||||
case 2:
|
||||
if (name[1] == '.') {
|
||||
/* We know len is at least 1, so compare against 2 */
|
||||
if (len <= 2 && name[-1] == '.') {
|
||||
if (len == 2) {
|
||||
if (name[-2] == '.') {
|
||||
type = LAST_DOTDOT;
|
||||
nd->state |= ND_JUMPED;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
} else {
|
||||
type = LAST_DOT;
|
||||
}
|
||||
}
|
||||
nd->last_type = type;
|
||||
if (likely(type == LAST_NORM)) {
|
||||
struct dentry *parent = nd->path.dentry;
|
||||
nd->state &= ~ND_JUMPED;
|
||||
if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
|
||||
struct qstr this = { { .hash_len = hash_len }, .name = name };
|
||||
err = parent->d_op->d_hash(parent, &this);
|
||||
err = parent->d_op->d_hash(parent, &nd->last);
|
||||
if (err < 0)
|
||||
return err;
|
||||
hash_len = this.hash_len;
|
||||
name = this.name;
|
||||
}
|
||||
}
|
||||
|
||||
nd->last.hash_len = hash_len;
|
||||
nd->last.name = name;
|
||||
nd->last_type = type;
|
||||
|
||||
name += hashlen_len(hash_len);
|
||||
if (!*name)
|
||||
goto OK;
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user