Commit da53be12 authored by Linus Torvalds's avatar Linus Torvalds Committed by Al Viro

Don't pass inode to ->d_hash() and ->d_compare()

Instances either don't look at it at all (the majority of cases) or
only want it to find the superblock (which can be had as dentry->d_sb).
A few cases that want more are actually safe with dentry->d_inode -
the only precaution needed is the check that it hadn't been replaced with
NULL by rmdir() or by overwriting rename(), which case should be simply
treated as cache miss.
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 642b704c
...@@ -11,10 +11,8 @@ be able to use diff(1). ...@@ -11,10 +11,8 @@ be able to use diff(1).
prototypes: prototypes:
int (*d_revalidate)(struct dentry *, unsigned int); int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int); int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, const struct inode *, int (*d_hash)(const struct dentry *, struct qstr *);
struct qstr *); int (*d_compare)(const struct dentry *, const struct dentry *,
int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
unsigned int, const char *, const struct qstr *); unsigned int, const char *, const struct qstr *);
int (*d_delete)(struct dentry *); int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *); void (*d_release)(struct dentry *);
......
...@@ -901,10 +901,8 @@ defined: ...@@ -901,10 +901,8 @@ defined:
struct dentry_operations { struct dentry_operations {
int (*d_revalidate)(struct dentry *, unsigned int); int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int); int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, const struct inode *, int (*d_hash)(const struct dentry *, struct qstr *);
struct qstr *); int (*d_compare)(const struct dentry *, const struct dentry *,
int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
unsigned int, const char *, const struct qstr *); unsigned int, const char *, const struct qstr *);
int (*d_delete)(const struct dentry *); int (*d_delete)(const struct dentry *);
void (*d_release)(struct dentry *); void (*d_release)(struct dentry *);
...@@ -949,25 +947,24 @@ struct dentry_operations { ...@@ -949,25 +947,24 @@ struct dentry_operations {
d_hash: called when the VFS adds a dentry to the hash table. The first d_hash: called when the VFS adds a dentry to the hash table. The first
dentry passed to d_hash is the parent directory that the name is dentry passed to d_hash is the parent directory that the name is
to be hashed into. The inode is the dentry's inode. to be hashed into.
Same locking and synchronisation rules as d_compare regarding Same locking and synchronisation rules as d_compare regarding
what is safe to dereference etc. what is safe to dereference etc.
d_compare: called to compare a dentry name with a given name. The first d_compare: called to compare a dentry name with a given name. The first
dentry is the parent of the dentry to be compared, the second is dentry is the parent of the dentry to be compared, the second is
the parent's inode, then the dentry and inode (may be NULL) of the the child dentry. len and name string are properties of the dentry
child dentry. len and name string are properties of the dentry to be to be compared. qstr is the name to compare it with.
compared. qstr is the name to compare it with.
Must be constant and idempotent, and should not take locks if Must be constant and idempotent, and should not take locks if
possible, and should not or store into the dentry or inodes. possible, and should not or store into the dentry.
Should not dereference pointers outside the dentry or inodes without Should not dereference pointers outside the dentry without
lots of care (eg. d_parent, d_inode, d_name should not be used). lots of care (eg. d_parent, d_inode, d_name should not be used).
However, our vfsmount is pinned, and RCU held, so the dentries and However, our vfsmount is pinned, and RCU held, so the dentries and
inodes won't disappear, neither will our sb or filesystem module. inodes won't disappear, neither will our sb or filesystem module.
->i_sb and ->d_sb may be used. ->d_sb may be used.
It is a tricky calling convention because it needs to be called under It is a tricky calling convention because it needs to be called under
"rcu-walk", ie. without any locks or references on things. "rcu-walk", ie. without any locks or references on things.
......
...@@ -191,8 +191,7 @@ const struct file_operations adfs_dir_operations = { ...@@ -191,8 +191,7 @@ const struct file_operations adfs_dir_operations = {
}; };
static int static int
adfs_hash(const struct dentry *parent, const struct inode *inode, adfs_hash(const struct dentry *parent, struct qstr *qstr)
struct qstr *qstr)
{ {
const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen; const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen;
const unsigned char *name; const unsigned char *name;
...@@ -228,8 +227,7 @@ adfs_hash(const struct dentry *parent, const struct inode *inode, ...@@ -228,8 +227,7 @@ adfs_hash(const struct dentry *parent, const struct inode *inode,
* requirements of the underlying filesystem. * requirements of the underlying filesystem.
*/ */
static int static int
adfs_compare(const struct dentry *parent, const struct inode *pinode, adfs_compare(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
int i; int i;
......
...@@ -13,18 +13,12 @@ ...@@ -13,18 +13,12 @@
typedef int (*toupper_t)(int); typedef int (*toupper_t)(int);
static int affs_toupper(int ch); static int affs_toupper(int ch);
static int affs_hash_dentry(const struct dentry *, static int affs_hash_dentry(const struct dentry *, struct qstr *);
const struct inode *, struct qstr *); static int affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
static int affs_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name); unsigned int len, const char *str, const struct qstr *name);
static int affs_intl_toupper(int ch); static int affs_intl_toupper(int ch);
static int affs_intl_hash_dentry(const struct dentry *, static int affs_intl_hash_dentry(const struct dentry *, struct qstr *);
const struct inode *, struct qstr *); static int affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
static int affs_intl_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name); unsigned int len, const char *str, const struct qstr *name);
const struct dentry_operations affs_dentry_operations = { const struct dentry_operations affs_dentry_operations = {
...@@ -86,14 +80,12 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper) ...@@ -86,14 +80,12 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper)
} }
static int static int
affs_hash_dentry(const struct dentry *dentry, const struct inode *inode, affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
return __affs_hash_dentry(qstr, affs_toupper); return __affs_hash_dentry(qstr, affs_toupper);
} }
static int static int
affs_intl_hash_dentry(const struct dentry *dentry, const struct inode *inode, affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
return __affs_hash_dentry(qstr, affs_intl_toupper); return __affs_hash_dentry(qstr, affs_intl_toupper);
} }
...@@ -131,15 +123,13 @@ static inline int __affs_compare_dentry(unsigned int len, ...@@ -131,15 +123,13 @@ static inline int __affs_compare_dentry(unsigned int len,
} }
static int static int
affs_compare_dentry(const struct dentry *parent, const struct inode *pinode, affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
return __affs_compare_dentry(len, str, name, affs_toupper); return __affs_compare_dentry(len, str, name, affs_toupper);
} }
static int static int
affs_intl_compare_dentry(const struct dentry *parent,const struct inode *pinode, affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
return __affs_compare_dentry(len, str, name, affs_intl_toupper); return __affs_compare_dentry(len, str, name, affs_intl_toupper);
......
...@@ -822,8 +822,7 @@ const struct dentry_operations cifs_dentry_ops = { ...@@ -822,8 +822,7 @@ const struct dentry_operations cifs_dentry_ops = {
/* d_delete: cifs_d_delete, */ /* not needed except for debugging */ /* d_delete: cifs_d_delete, */ /* not needed except for debugging */
}; };
static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode, static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
struct qstr *q)
{ {
struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
unsigned long hash; unsigned long hash;
...@@ -838,12 +837,10 @@ static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode, ...@@ -838,12 +837,10 @@ static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
return 0; return 0;
} }
static int cifs_ci_compare(const struct dentry *parent, static int cifs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls; struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls;
if ((name->len == len) && if ((name->len == len) &&
(nls_strnicmp(codepage, name->name, str, len) == 0)) (nls_strnicmp(codepage, name->name, str, len) == 0))
......
...@@ -1723,7 +1723,7 @@ EXPORT_SYMBOL(d_add_ci); ...@@ -1723,7 +1723,7 @@ EXPORT_SYMBOL(d_add_ci);
* Do the slow-case of the dentry name compare. * Do the slow-case of the dentry name compare.
* *
* Unlike the dentry_cmp() function, we need to atomically * Unlike the dentry_cmp() function, we need to atomically
* load the name, length and inode information, so that the * load the name and length information, so that the
* filesystem can rely on them, and can use the 'name' and * filesystem can rely on them, and can use the 'name' and
* 'len' information without worrying about walking off the * 'len' information without worrying about walking off the
* end of memory etc. * end of memory etc.
...@@ -1741,22 +1741,18 @@ enum slow_d_compare { ...@@ -1741,22 +1741,18 @@ enum slow_d_compare {
static noinline enum slow_d_compare slow_dentry_cmp( static noinline enum slow_d_compare slow_dentry_cmp(
const struct dentry *parent, const struct dentry *parent,
struct inode *inode,
struct dentry *dentry, struct dentry *dentry,
unsigned int seq, unsigned int seq,
const struct qstr *name) const struct qstr *name)
{ {
int tlen = dentry->d_name.len; int tlen = dentry->d_name.len;
const char *tname = dentry->d_name.name; const char *tname = dentry->d_name.name;
struct inode *i = dentry->d_inode;
if (read_seqcount_retry(&dentry->d_seq, seq)) { if (read_seqcount_retry(&dentry->d_seq, seq)) {
cpu_relax(); cpu_relax();
return D_COMP_SEQRETRY; return D_COMP_SEQRETRY;
} }
if (parent->d_op->d_compare(parent, inode, if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
dentry, i,
tlen, tname, name))
return D_COMP_NOMATCH; return D_COMP_NOMATCH;
return D_COMP_OK; return D_COMP_OK;
} }
...@@ -1766,7 +1762,6 @@ static noinline enum slow_d_compare slow_dentry_cmp( ...@@ -1766,7 +1762,6 @@ static noinline enum slow_d_compare slow_dentry_cmp(
* @parent: parent dentry * @parent: parent dentry
* @name: qstr of name we wish to find * @name: qstr of name we wish to find
* @seqp: returns d_seq value at the point where the dentry was found * @seqp: returns d_seq value at the point where the dentry was found
* @inode: returns dentry->d_inode when the inode was found valid.
* Returns: dentry, or NULL * Returns: dentry, or NULL
* *
* __d_lookup_rcu is the dcache lookup function for rcu-walk name * __d_lookup_rcu is the dcache lookup function for rcu-walk name
...@@ -1793,7 +1788,7 @@ static noinline enum slow_d_compare slow_dentry_cmp( ...@@ -1793,7 +1788,7 @@ static noinline enum slow_d_compare slow_dentry_cmp(
*/ */
struct dentry *__d_lookup_rcu(const struct dentry *parent, struct dentry *__d_lookup_rcu(const struct dentry *parent,
const struct qstr *name, const struct qstr *name,
unsigned *seqp, struct inode *inode) unsigned *seqp)
{ {
u64 hashlen = name->hash_len; u64 hashlen = name->hash_len;
const unsigned char *str = name->name; const unsigned char *str = name->name;
...@@ -1827,11 +1822,10 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent, ...@@ -1827,11 +1822,10 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
seqretry: seqretry:
/* /*
* The dentry sequence count protects us from concurrent * The dentry sequence count protects us from concurrent
* renames, and thus protects inode, parent and name fields. * renames, and thus protects parent and name fields.
* *
* The caller must perform a seqcount check in order * The caller must perform a seqcount check in order
* to do anything useful with the returned dentry, * to do anything useful with the returned dentry.
* including using the 'd_inode' pointer.
* *
* NOTE! We do a "raw" seqcount_begin here. That means that * NOTE! We do a "raw" seqcount_begin here. That means that
* we don't wait for the sequence count to stabilize if it * we don't wait for the sequence count to stabilize if it
...@@ -1845,12 +1839,12 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent, ...@@ -1845,12 +1839,12 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
continue; continue;
if (d_unhashed(dentry)) if (d_unhashed(dentry))
continue; continue;
*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)) if (dentry->d_name.hash != hashlen_hash(hashlen))
continue; continue;
switch (slow_dentry_cmp(parent, inode, dentry, seq, name)) { *seqp = seq;
switch (slow_dentry_cmp(parent, dentry, seq, name)) {
case D_COMP_OK: case D_COMP_OK:
return dentry; return dentry;
case D_COMP_NOMATCH: case D_COMP_NOMATCH:
...@@ -1862,6 +1856,7 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent, ...@@ -1862,6 +1856,7 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
if (dentry->d_name.hash_len != hashlen) if (dentry->d_name.hash_len != hashlen)
continue; continue;
*seqp = seq;
if (!dentry_cmp(dentry, str, hashlen_len(hashlen))) if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
return dentry; return dentry;
} }
...@@ -1959,9 +1954,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) ...@@ -1959,9 +1954,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
if (parent->d_flags & DCACHE_OP_COMPARE) { if (parent->d_flags & DCACHE_OP_COMPARE) {
int tlen = dentry->d_name.len; int tlen = dentry->d_name.len;
const char *tname = dentry->d_name.name; const char *tname = dentry->d_name.name;
if (parent->d_op->d_compare(parent, parent->d_inode, if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
dentry, dentry->d_inode,
tlen, tname, name))
goto next; goto next;
} else { } else {
if (dentry->d_name.len != len) if (dentry->d_name.len != len)
...@@ -1998,7 +1991,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) ...@@ -1998,7 +1991,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
*/ */
name->hash = full_name_hash(name->name, name->len); name->hash = full_name_hash(name->name, name->len);
if (dir->d_flags & DCACHE_OP_HASH) { if (dir->d_flags & DCACHE_OP_HASH) {
int err = dir->d_op->d_hash(dir, dir->d_inode, name); int err = dir->d_op->d_hash(dir, name);
if (unlikely(err < 0)) if (unlikely(err < 0))
return ERR_PTR(err); return ERR_PTR(err);
} }
......
...@@ -45,8 +45,8 @@ static struct super_block *efivarfs_sb; ...@@ -45,8 +45,8 @@ static struct super_block *efivarfs_sb;
* So we need to perform a case-sensitive match on part 1 and a * So we need to perform a case-sensitive match on part 1 and a
* case-insensitive match on part 2. * case-insensitive match on part 2.
*/ */
static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode, static int efivarfs_d_compare(const struct dentry *parent,
const struct dentry *dentry, const struct inode *inode, const struct dentry *dentry,
unsigned int len, const char *str, unsigned int len, const char *str,
const struct qstr *name) const struct qstr *name)
{ {
...@@ -63,8 +63,7 @@ static int efivarfs_d_compare(const struct dentry *parent, const struct inode *p ...@@ -63,8 +63,7 @@ static int efivarfs_d_compare(const struct dentry *parent, const struct inode *p
return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN); return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN);
} }
static int efivarfs_d_hash(const struct dentry *dentry, static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
const struct inode *inode, struct qstr *qstr)
{ {
unsigned long hash = init_name_hash(); unsigned long hash = init_name_hash();
const unsigned char *s = qstr->name; const unsigned char *s = qstr->name;
...@@ -108,7 +107,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) ...@@ -108,7 +107,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
q.name = name; q.name = name;
q.len = strlen(name); q.len = strlen(name);
err = efivarfs_d_hash(NULL, NULL, &q); err = efivarfs_d_hash(NULL, &q);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
......
...@@ -148,8 +148,7 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len, ...@@ -148,8 +148,7 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len,
* that the existing dentry can be used. The msdos fs routines will * that the existing dentry can be used. The msdos fs routines will
* return ENOENT or EINVAL as appropriate. * return ENOENT or EINVAL as appropriate.
*/ */
static int msdos_hash(const struct dentry *dentry, const struct inode *inode, static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
unsigned char msdos_name[MSDOS_NAME]; unsigned char msdos_name[MSDOS_NAME];
...@@ -165,8 +164,7 @@ static int msdos_hash(const struct dentry *dentry, const struct inode *inode, ...@@ -165,8 +164,7 @@ static int msdos_hash(const struct dentry *dentry, const struct inode *inode,
* Compare two msdos names. If either of the names are invalid, * Compare two msdos names. If either of the names are invalid,
* we fall back to doing the standard name comparison. * we fall back to doing the standard name comparison.
*/ */
static int msdos_cmp(const struct dentry *parent, const struct inode *pinode, static int msdos_cmp(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options; struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options;
......
...@@ -107,8 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr) ...@@ -107,8 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr)
* that the existing dentry can be used. The vfat fs routines will * that the existing dentry can be used. The vfat fs routines will
* return ENOENT or EINVAL as appropriate. * return ENOENT or EINVAL as appropriate.
*/ */
static int vfat_hash(const struct dentry *dentry, const struct inode *inode, static int vfat_hash(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr)); qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
return 0; return 0;
...@@ -120,8 +119,7 @@ static int vfat_hash(const struct dentry *dentry, const struct inode *inode, ...@@ -120,8 +119,7 @@ static int vfat_hash(const struct dentry *dentry, const struct inode *inode,
* that the existing dentry can be used. The vfat fs routines will * that the existing dentry can be used. The vfat fs routines will
* return ENOENT or EINVAL as appropriate. * return ENOENT or EINVAL as appropriate.
*/ */
static int vfat_hashi(const struct dentry *dentry, const struct inode *inode, static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io; struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
const unsigned char *name; const unsigned char *name;
...@@ -142,8 +140,7 @@ static int vfat_hashi(const struct dentry *dentry, const struct inode *inode, ...@@ -142,8 +140,7 @@ static int vfat_hashi(const struct dentry *dentry, const struct inode *inode,
/* /*
* Case insensitive compare of two vfat names. * Case insensitive compare of two vfat names.
*/ */
static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode, static int vfat_cmpi(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io; struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
...@@ -162,8 +159,7 @@ static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode, ...@@ -162,8 +159,7 @@ static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode,
/* /*
* Case sensitive compare of two vfat names. * Case sensitive compare of two vfat names.
*/ */
static int vfat_cmp(const struct dentry *parent, const struct inode *pinode, static int vfat_cmp(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
unsigned int alen, blen; unsigned int alen, blen;
......
...@@ -109,8 +109,7 @@ static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags) ...@@ -109,8 +109,7 @@ static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
return 0; return 0;
} }
static int gfs2_dhash(const struct dentry *dentry, const struct inode *inode, static int gfs2_dhash(const struct dentry *dentry, struct qstr *str)
struct qstr *str)
{ {
str->hash = gfs2_disk_hash(str->name, str->len); str->hash = gfs2_disk_hash(str->name, str->len);
return 0; return 0;
......
...@@ -229,13 +229,10 @@ extern int hfs_part_find(struct super_block *, sector_t *, sector_t *); ...@@ -229,13 +229,10 @@ extern int hfs_part_find(struct super_block *, sector_t *, sector_t *);
/* string.c */ /* string.c */
extern const struct dentry_operations hfs_dentry_operations; extern const struct dentry_operations hfs_dentry_operations;
extern int hfs_hash_dentry(const struct dentry *, const struct inode *, extern int hfs_hash_dentry(const struct dentry *, struct qstr *);
struct qstr *);
extern int hfs_strcmp(const unsigned char *, unsigned int, extern int hfs_strcmp(const unsigned char *, unsigned int,
const unsigned char *, unsigned int); const unsigned char *, unsigned int);
extern int hfs_compare_dentry(const struct dentry *parent, extern int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name); unsigned int len, const char *str, const struct qstr *name);
/* trans.c */ /* trans.c */
......
...@@ -51,8 +51,7 @@ static unsigned char caseorder[256] = { ...@@ -51,8 +51,7 @@ static unsigned char caseorder[256] = {
/* /*
* Hash a string to an integer in a case-independent way * Hash a string to an integer in a case-independent way
*/ */
int hfs_hash_dentry(const struct dentry *dentry, const struct inode *inode, int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
struct qstr *this)
{ {
const unsigned char *name = this->name; const unsigned char *name = this->name;
unsigned int hash, len = this->len; unsigned int hash, len = this->len;
...@@ -93,8 +92,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1, ...@@ -93,8 +92,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1,
* Test for equality of two strings in the HFS filename character ordering. * Test for equality of two strings in the HFS filename character ordering.
* return 1 on failure and 0 on success * return 1 on failure and 0 on success
*/ */
int hfs_compare_dentry(const struct dentry *parent, const struct inode *pinode, int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
const unsigned char *n1, *n2; const unsigned char *n1, *n2;
......
...@@ -495,11 +495,8 @@ int hfsplus_uni2asc(struct super_block *, ...@@ -495,11 +495,8 @@ int hfsplus_uni2asc(struct super_block *,
const struct hfsplus_unistr *, char *, int *); const struct hfsplus_unistr *, char *, int *);
int hfsplus_asc2uni(struct super_block *, int hfsplus_asc2uni(struct super_block *,
struct hfsplus_unistr *, int, const char *, int); struct hfsplus_unistr *, int, const char *, int);
int hfsplus_hash_dentry(const struct dentry *dentry, int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str);
const struct inode *inode, struct qstr *str); int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
int hfsplus_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name); unsigned int len, const char *str, const struct qstr *name);
/* wrapper.c */ /* wrapper.c */
......
...@@ -334,8 +334,7 @@ int hfsplus_asc2uni(struct super_block *sb, ...@@ -334,8 +334,7 @@ int hfsplus_asc2uni(struct super_block *sb,
* Composed unicode characters are decomposed and case-folding is performed * Composed unicode characters are decomposed and case-folding is performed
* if the appropriate bits are (un)set on the superblock. * if the appropriate bits are (un)set on the superblock.
*/ */
int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode, int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
struct qstr *str)
{ {
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
const char *astr; const char *astr;
...@@ -386,9 +385,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode, ...@@ -386,9 +385,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
* Composed unicode characters are decomposed and case-folding is performed * Composed unicode characters are decomposed and case-folding is performed
* if the appropriate bits are (un)set on the superblock. * if the appropriate bits are (un)set on the superblock.
*/ */
int hfsplus_compare_dentry(const struct dentry *parent, int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
struct super_block *sb = parent->d_sb; struct super_block *sb = parent->d_sb;
......
...@@ -12,8 +12,7 @@ ...@@ -12,8 +12,7 @@
* Note: the dentry argument is the parent dentry. * Note: the dentry argument is the parent dentry.
*/ */
static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *inode, static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
unsigned long hash; unsigned long hash;
int i; int i;
...@@ -35,9 +34,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *ino ...@@ -35,9 +34,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *ino
return 0; return 0;
} }
static int hpfs_compare_dentry(const struct dentry *parent, static int hpfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
unsigned al = len; unsigned al = len;
......
...@@ -28,31 +28,23 @@ ...@@ -28,31 +28,23 @@
#define BEQUIET #define BEQUIET
static int isofs_hashi(const struct dentry *parent, const struct inode *inode, static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
struct qstr *qstr); static int isofs_hash(const struct dentry *parent, struct qstr *qstr);
static int isofs_hash(const struct dentry *parent, const struct inode *inode,
struct qstr *qstr);
static int isofs_dentry_cmpi(const struct dentry *parent, static int isofs_dentry_cmpi(const struct dentry *parent,
const struct inode *pinode, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name); unsigned int len, const char *str, const struct qstr *name);
static int isofs_dentry_cmp(const struct dentry *parent, static int isofs_dentry_cmp(const struct dentry *parent,
const struct inode *pinode, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name); unsigned int len, const char *str, const struct qstr *name);
#ifdef CONFIG_JOLIET #ifdef CONFIG_JOLIET
static int isofs_hashi_ms(const struct dentry *parent, const struct inode *inode, static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr);
struct qstr *qstr); static int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr);
static int isofs_hash_ms(const struct dentry *parent, const struct inode *inode,
struct qstr *qstr);
static int isofs_dentry_cmpi_ms(const struct dentry *parent, static int isofs_dentry_cmpi_ms(const struct dentry *parent,
const struct inode *pinode, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name); unsigned int len, const char *str, const struct qstr *name);
static int isofs_dentry_cmp_ms(const struct dentry *parent, static int isofs_dentry_cmp_ms(const struct dentry *parent,
const struct inode *pinode, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name); unsigned int len, const char *str, const struct qstr *name);
#endif #endif
...@@ -265,30 +257,26 @@ static int isofs_dentry_cmp_common( ...@@ -265,30 +257,26 @@ static int isofs_dentry_cmp_common(
} }
static int static int
isofs_hash(const struct dentry *dentry, const struct inode *inode, isofs_hash(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
return isofs_hash_common(dentry, qstr, 0); return isofs_hash_common(dentry, qstr, 0);
} }
static int static int
isofs_hashi(const struct dentry *dentry, const struct inode *inode, isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
return isofs_hashi_common(dentry, qstr, 0); return isofs_hashi_common(dentry, qstr, 0);
} }
static int static int
isofs_dentry_cmp(const struct dentry *parent, const struct inode *pinode, isofs_dentry_cmp(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
return isofs_dentry_cmp_common(len, str, name, 0, 0); return isofs_dentry_cmp_common(len, str, name, 0, 0);
} }
static int static int
isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode, isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
return isofs_dentry_cmp_common(len, str, name, 0, 1); return isofs_dentry_cmp_common(len, str, name, 0, 1);
...@@ -296,30 +284,26 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode, ...@@ -296,30 +284,26 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
#ifdef CONFIG_JOLIET #ifdef CONFIG_JOLIET
static int static int
isofs_hash_ms(const struct dentry *dentry, const struct inode *inode, isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
return isofs_hash_common(dentry, qstr, 1); return isofs_hash_common(dentry, qstr, 1);
} }
static int static int
isofs_hashi_ms(const struct dentry *dentry, const struct inode *inode, isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
return isofs_hashi_common(dentry, qstr, 1); return isofs_hashi_common(dentry, qstr, 1);
} }
static int static int
isofs_dentry_cmp_ms(const struct dentry *parent, const struct inode *pinode, isofs_dentry_cmp_ms(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
return isofs_dentry_cmp_common(len, str, name, 1, 0); return isofs_dentry_cmp_common(len, str, name, 1, 0);
} }
static int static int
isofs_dentry_cmpi_ms(const struct dentry *parent, const struct inode *pinode, isofs_dentry_cmpi_ms(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
return isofs_dentry_cmp_common(len, str, name, 1, 1); return isofs_dentry_cmp_common(len, str, name, 1, 1);
......
...@@ -37,8 +37,7 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen) ...@@ -37,8 +37,7 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
qstr.name = compare; qstr.name = compare;
qstr.len = dlen; qstr.len = dlen;
return dentry->d_op->d_compare(NULL, NULL, NULL, NULL, return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
dentry->d_name.len, dentry->d_name.name, &qstr);
} }
/* /*
......
...@@ -1538,8 +1538,7 @@ const struct file_operations jfs_dir_operations = { ...@@ -1538,8 +1538,7 @@ const struct file_operations jfs_dir_operations = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
}; };
static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode, static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
struct qstr *this)
{ {
unsigned long hash; unsigned long hash;
int i; int i;
...@@ -1552,9 +1551,7 @@ static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode, ...@@ -1552,9 +1551,7 @@ static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
return 0; return 0;
} }
static int jfs_ci_compare(const struct dentry *parent, static int jfs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
int i, result = 1; int i, result = 1;
......
...@@ -1352,7 +1352,7 @@ static int lookup_fast(struct nameidata *nd, ...@@ -1352,7 +1352,7 @@ static int lookup_fast(struct nameidata *nd,
*/ */
if (nd->flags & LOOKUP_RCU) { if (nd->flags & LOOKUP_RCU) {
unsigned seq; unsigned seq;
dentry = __d_lookup_rcu(parent, &nd->last, &seq, nd->inode); dentry = __d_lookup_rcu(parent, &nd->last, &seq);
if (!dentry) if (!dentry)
goto unlazy; goto unlazy;
...@@ -1787,8 +1787,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) ...@@ -1787,8 +1787,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
struct dentry *parent = nd->path.dentry; struct dentry *parent = nd->path.dentry;
nd->flags &= ~LOOKUP_JUMPED; nd->flags &= ~LOOKUP_JUMPED;
if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
err = parent->d_op->d_hash(parent, nd->inode, err = parent->d_op->d_hash(parent, &this);
&this);
if (err < 0) if (err < 0)
break; break;
} }
...@@ -2121,7 +2120,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) ...@@ -2121,7 +2120,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
* to use its own hash.. * to use its own hash..
*/ */
if (base->d_flags & DCACHE_OP_HASH) { if (base->d_flags & DCACHE_OP_HASH) {
int err = base->d_op->d_hash(base, base->d_inode, &this); int err = base->d_op->d_hash(base, &this);
if (err < 0) if (err < 0)
return ERR_PTR(err); return ERR_PTR(err);
} }
......
...@@ -73,10 +73,8 @@ const struct inode_operations ncp_dir_inode_operations = ...@@ -73,10 +73,8 @@ const struct inode_operations ncp_dir_inode_operations =
* Dentry operations routines * Dentry operations routines
*/ */
static int ncp_lookup_validate(struct dentry *, unsigned int); static int ncp_lookup_validate(struct dentry *, unsigned int);
static int ncp_hash_dentry(const struct dentry *, const struct inode *, static int ncp_hash_dentry(const struct dentry *, struct qstr *);
struct qstr *); static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
static int ncp_compare_dentry(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
unsigned int, const char *, const struct qstr *); unsigned int, const char *, const struct qstr *);
static int ncp_delete_dentry(const struct dentry *); static int ncp_delete_dentry(const struct dentry *);
...@@ -119,11 +117,19 @@ static inline int ncp_case_sensitive(const struct inode *i) ...@@ -119,11 +117,19 @@ static inline int ncp_case_sensitive(const struct inode *i)
/* /*
* Note: leave the hash unchanged if the directory * Note: leave the hash unchanged if the directory
* is case-sensitive. * is case-sensitive.
*
* Accessing the parent inode can be racy under RCU pathwalking.
* Use ACCESS_ONCE() to make sure we use _one_ particular inode,
* the callers will handle races.
*/ */
static int static int
ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
struct qstr *this)
{ {
struct inode *inode = ACCESS_ONCE(dentry->d_inode);
if (!inode)
return 0;
if (!ncp_case_sensitive(inode)) { if (!ncp_case_sensitive(inode)) {
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
struct nls_table *t; struct nls_table *t;
...@@ -140,14 +146,24 @@ ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, ...@@ -140,14 +146,24 @@ ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
return 0; return 0;
} }
/*
* Accessing the parent inode can be racy under RCU pathwalking.
* Use ACCESS_ONCE() to make sure we use _one_ particular inode,
* the callers will handle races.
*/
static int static int
ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode, ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
struct inode *pinode;
if (len != name->len) if (len != name->len)
return 1; return 1;
pinode = ACCESS_ONCE(parent->d_inode);
if (!pinode)
return 1;
if (ncp_case_sensitive(pinode)) if (ncp_case_sensitive(pinode))
return strncmp(str, name->name, len); return strncmp(str, name->name, len);
......
...@@ -796,15 +796,16 @@ static int sysctl_is_seen(struct ctl_table_header *p) ...@@ -796,15 +796,16 @@ static int sysctl_is_seen(struct ctl_table_header *p)
return res; return res;
} }
static int proc_sys_compare(const struct dentry *parent, static int proc_sys_compare(const struct dentry *parent, const struct dentry *dentry,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name) unsigned int len, const char *str, const struct qstr *name)
{ {
struct ctl_table_header *head; struct ctl_table_header *head;
struct inode *inode;
/* Although proc doesn't have negative dentries, rcu-walk means /* Although proc doesn't have negative dentries, rcu-walk means
* that inode here can be NULL */ * that inode here can be NULL */
/* AV: can it, indeed? */ /* AV: can it, indeed? */
inode = ACCESS_ONCE(dentry->d_inode);
if (!inode) if (!inode)
return 1; return 1;
if (name->len != len) if (name->len != len)
......
...@@ -27,8 +27,7 @@ static int add_nondir(struct dentry *dentry, struct inode *inode) ...@@ -27,8 +27,7 @@ static int add_nondir(struct dentry *dentry, struct inode *inode)
return err; return err;
} }
static int sysv_hash(const struct dentry *dentry, const struct inode *inode, static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
struct qstr *qstr)
{ {
/* Truncate the name in place, avoids having to define a compare /* Truncate the name in place, avoids having to define a compare
function. */ function. */
......
...@@ -146,10 +146,8 @@ enum dentry_d_lock_class ...@@ -146,10 +146,8 @@ enum dentry_d_lock_class
struct dentry_operations { struct dentry_operations {
int (*d_revalidate)(struct dentry *, unsigned int); int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int); int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, const struct inode *, int (*d_hash)(const struct dentry *, struct qstr *);
struct qstr *); int (*d_compare)(const struct dentry *, const struct dentry *,
int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
unsigned int, const char *, const struct qstr *); unsigned int, const char *, const struct qstr *);
int (*d_delete)(const struct dentry *); int (*d_delete)(const struct dentry *);
void (*d_release)(struct dentry *); void (*d_release)(struct dentry *);
...@@ -302,8 +300,7 @@ extern struct dentry *d_lookup(const struct dentry *, const struct qstr *); ...@@ -302,8 +300,7 @@ extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *); extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *); extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
extern struct dentry *__d_lookup_rcu(const struct dentry *parent, extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
const struct qstr *name, const struct qstr *name, unsigned *seq);
unsigned *seq, struct inode *inode);
/** /**
* __d_rcu_to_refcount - take a refcount on dentry if sequence check is ok * __d_rcu_to_refcount - take a refcount on dentry if sequence check is ok
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment