summaryrefslogtreecommitdiff
path: root/fs/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c82
1 files changed, 33 insertions, 49 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 70580ab1445c..68a896c804b7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1449,9 +1449,8 @@ static int follow_dotdot(struct nameidata *nd)
}
/*
- * This looks up the name in dcache, possibly revalidates the old dentry and
- * allocates a new one if not found or not valid. In the need_lookup argument
- * returns whether i_op->lookup is necessary.
+ * This looks up the name in dcache and possibly revalidates the found dentry.
+ * NULL is returned if the dentry does not exist in the cache.
*/
static struct dentry *lookup_dcache(const struct qstr *name,
struct dentry *dir,
@@ -1890,9 +1889,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 +1910,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 +1938,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 +1966,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 +1976,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 +1995,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 +2037,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)) {
@@ -2389,33 +2396,6 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
EXPORT_SYMBOL(vfs_path_lookup);
/**
- * lookup_hash - lookup single pathname component on already hashed name
- * @name: name and hash to lookup
- * @base: base directory to lookup from
- *
- * The name must have been verified and hashed (see lookup_one_len()). Using
- * this after just full_name_hash() is unsafe.
- *
- * This function also doesn't check for search permission on base directory.
- *
- * Use lookup_one_len_unlocked() instead, unless you really know what you are
- * doing.
- *
- * Do not hold i_mutex; this helper takes i_mutex if necessary.
- */
-struct dentry *lookup_hash(const struct qstr *name, struct dentry *base)
-{
- struct dentry *ret;
-
- ret = lookup_dcache(name, base, 0);
- if (!ret)
- ret = lookup_slow(name, base, 0);
-
- return ret;
-}
-EXPORT_SYMBOL(lookup_hash);
-
-/**
* lookup_one_len - filesystem helper to lookup single pathname component
* @name: pathname component to lookup
* @base: base directory to lookup from
@@ -2436,7 +2416,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);
@@ -2486,10 +2466,11 @@ struct dentry *lookup_one_len_unlocked(const char *name,
struct qstr this;
unsigned int c;
int err;
+ struct dentry *ret;
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);
@@ -2517,7 +2498,10 @@ struct dentry *lookup_one_len_unlocked(const char *name,
if (err)
return ERR_PTR(err);
- return lookup_hash(&this, base);
+ ret = lookup_dcache(&this, base, 0);
+ if (!ret)
+ ret = lookup_slow(&this, base, 0);
+ return ret;
}
EXPORT_SYMBOL(lookup_one_len_unlocked);
@@ -4328,7 +4312,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* Check source == target.
* On overlayfs need to look at underlying inodes.
*/
- if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))
+ if (d_real_inode(old_dentry) == d_real_inode(new_dentry))
return 0;
error = may_delete(old_dir, old_dentry, is_dir);