Commit 621e155a authored by Nick Piggin's avatar Nick Piggin

fs: change d_compare for rcu-walk

Change d_compare so it may be called from lock-free RCU lookups. This
does put significant restrictions on what may be done from the callback,
however there don't seem to have been any problems with in-tree fses.
If some strange use case pops up that _really_ cannot cope with the
rcu-walk rules, we can just add new rcu-unaware callbacks, which would
cause name lookup to drop out of rcu-walk mode.

For in-tree filesystems, this is just a mechanical change.
Signed-off-by: default avatarNick Piggin <npiggin@kernel.dk>
parent fb2d5b86
...@@ -11,7 +11,9 @@ be able to use diff(1). ...@@ -11,7 +11,9 @@ be able to use diff(1).
prototypes: prototypes:
int (*d_revalidate)(struct dentry *, int); int (*d_revalidate)(struct dentry *, int);
int (*d_hash) (struct dentry *, struct qstr *); int (*d_hash) (struct dentry *, struct qstr *);
int (*d_compare) (struct dentry *, struct qstr *, struct qstr *); int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
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 *);
void (*d_iput)(struct dentry *, struct inode *); void (*d_iput)(struct dentry *, struct inode *);
......
...@@ -326,3 +326,10 @@ to it. ...@@ -326,3 +326,10 @@ to it.
unreferenced dentries, and is now only called when the dentry refcount goes to unreferenced dentries, and is now only called when the dentry refcount goes to
0. Even on 0 refcount transition, it must be able to tolerate being called 0, 0. Even on 0 refcount transition, it must be able to tolerate being called 0,
1, or more times (eg. constant, idempotent). 1, or more times (eg. constant, idempotent).
---
[mandatory]
.d_compare() calling convention and locking rules are significantly
changed. Read updated documentation in Documentation/filesystems/vfs.txt (and
look at examples of other filesystems) for guidance.
...@@ -848,7 +848,9 @@ defined: ...@@ -848,7 +848,9 @@ defined:
struct dentry_operations { struct dentry_operations {
int (*d_revalidate)(struct dentry *, struct nameidata *); int (*d_revalidate)(struct dentry *, struct nameidata *);
int (*d_hash)(struct dentry *, struct qstr *); int (*d_hash)(struct dentry *, struct qstr *);
int (*d_compare)(struct dentry *, struct qstr *, struct qstr *); int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
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 *);
void (*d_iput)(struct dentry *, struct inode *); void (*d_iput)(struct dentry *, struct inode *);
...@@ -860,9 +862,27 @@ struct dentry_operations { ...@@ -860,9 +862,27 @@ struct dentry_operations {
dcache. Most filesystems leave this as NULL, because all their dcache. Most filesystems leave this as NULL, because all their
dentries in the dcache are valid dentries in the dcache are valid
d_hash: called when the VFS adds a dentry to the hash table 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
to be hashed into.
d_compare: called when a dentry should be compared with another 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
the parent's inode, then the dentry and inode (may be NULL) of the
child dentry. len and name string are properties of the dentry to be
compared. qstr is the name to compare it with.
Must be constant and idempotent, and should not take locks if
possible, and should not or store into the dentry or inodes.
Should not dereference pointers outside the dentry or inodes without
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
inodes won't disappear, neither will our sb or filesystem module.
->i_sb and ->d_sb may be used.
It is a tricky calling convention because it needs to be called under
"rcu-walk", ie. without any locks or references on things.
d_delete: called when the last reference to a dentry is dropped and the d_delete: called when the last reference to a dentry is dropped and the
dcache is deciding whether or not to cache it. Return 1 to delete dcache is deciding whether or not to cache it. Return 1 to delete
......
...@@ -275,7 +275,10 @@ smb_dir_open(struct inode *dir, struct file *file) ...@@ -275,7 +275,10 @@ smb_dir_open(struct inode *dir, struct file *file)
*/ */
static int smb_lookup_validate(struct dentry *, struct nameidata *); static int smb_lookup_validate(struct dentry *, struct nameidata *);
static int smb_hash_dentry(struct dentry *, struct qstr *); static int smb_hash_dentry(struct dentry *, struct qstr *);
static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *); static int smb_compare_dentry(const struct dentry *,
const struct inode *,
const struct dentry *, const struct inode *,
unsigned int, const char *, const struct qstr *);
static int smb_delete_dentry(const struct dentry *); static int smb_delete_dentry(const struct dentry *);
static const struct dentry_operations smbfs_dentry_operations = static const struct dentry_operations smbfs_dentry_operations =
...@@ -347,14 +350,17 @@ smb_hash_dentry(struct dentry *dir, struct qstr *this) ...@@ -347,14 +350,17 @@ smb_hash_dentry(struct dentry *dir, struct qstr *this)
} }
static int static int
smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b) smb_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)
{ {
int i, result = 1; int i, result = 1;
if (a->len != b->len) if (len != name->len)
goto out; goto out;
for (i=0; i < a->len; i++) { for (i=0; i < len; i++) {
if (tolower(a->name[i]) != tolower(b->name[i])) if (tolower(str[i]) != tolower(name->name[i]))
goto out; goto out;
} }
result = 0; result = 0;
......
...@@ -237,17 +237,19 @@ adfs_hash(struct dentry *parent, struct qstr *qstr) ...@@ -237,17 +237,19 @@ adfs_hash(struct dentry *parent, struct qstr *qstr)
* requirements of the underlying filesystem. * requirements of the underlying filesystem.
*/ */
static int static int
adfs_compare(struct dentry *parent, struct qstr *entry, struct qstr *name) adfs_compare(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)
{ {
int i; int i;
if (entry->len != name->len) if (len != name->len)
return 1; return 1;
for (i = 0; i < name->len; i++) { for (i = 0; i < name->len; i++) {
char a, b; char a, b;
a = entry->name[i]; a = str[i];
b = name->name[i]; b = name->name[i];
if (a >= 'A' && a <= 'Z') if (a >= 'A' && a <= 'Z')
......
...@@ -14,10 +14,16 @@ typedef int (*toupper_t)(int); ...@@ -14,10 +14,16 @@ typedef int (*toupper_t)(int);
static int affs_toupper(int ch); static int affs_toupper(int ch);
static int affs_hash_dentry(struct dentry *, struct qstr *); static int affs_hash_dentry(struct dentry *, struct qstr *);
static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); 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);
static int affs_intl_toupper(int ch); static int affs_intl_toupper(int ch);
static int affs_intl_hash_dentry(struct dentry *, struct qstr *); static int affs_intl_hash_dentry(struct dentry *, struct qstr *);
static int affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *); 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);
const struct dentry_operations affs_dentry_operations = { const struct dentry_operations affs_dentry_operations = {
.d_hash = affs_hash_dentry, .d_hash = affs_hash_dentry,
...@@ -88,29 +94,29 @@ affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr) ...@@ -88,29 +94,29 @@ affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr)
return __affs_hash_dentry(dentry, qstr, affs_intl_toupper); return __affs_hash_dentry(dentry, qstr, affs_intl_toupper);
} }
static inline int static inline int __affs_compare_dentry(unsigned int len,
__affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, toupper_t toupper) const char *str, const struct qstr *name, toupper_t toupper)
{ {
const u8 *aname = a->name; const u8 *aname = str;
const u8 *bname = b->name; const u8 *bname = name->name;
int len;
/* 'a' is the qstr of an already existing dentry, so the name /*
* must be valid. 'b' must be validated first. * 'str' is the name of an already existing dentry, so the name
* must be valid. 'name' must be validated first.
*/ */
if (affs_check_name(b->name,b->len)) if (affs_check_name(name->name, name->len))
return 1; return 1;
/* If the names are longer than the allowed 30 chars, /*
* If the names are longer than the allowed 30 chars,
* the excess is ignored, so their length may differ. * the excess is ignored, so their length may differ.
*/ */
len = a->len;
if (len >= 30) { if (len >= 30) {
if (b->len < 30) if (name->len < 30)
return 1; return 1;
len = 30; len = 30;
} else if (len != b->len) } else if (len != name->len)
return 1; return 1;
for (; len > 0; len--) for (; len > 0; len--)
...@@ -121,14 +127,18 @@ __affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, tou ...@@ -121,14 +127,18 @@ __affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, tou
} }
static int static int
affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) 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)
{ {
return __affs_compare_dentry(dentry, a, b, affs_toupper); return __affs_compare_dentry(len, str, name, affs_toupper);
} }
static int static int
affs_intl_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) 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)
{ {
return __affs_compare_dentry(dentry, a, b, affs_intl_toupper); return __affs_compare_dentry(len, str, name, affs_intl_toupper);
} }
/* /*
......
...@@ -715,13 +715,15 @@ static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) ...@@ -715,13 +715,15 @@ static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
return 0; return 0;
} }
static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, static int cifs_ci_compare(const struct dentry *parent,
struct qstr *b) const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name)
{ {
struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
if ((a->len == b->len) && if ((name->len == len) &&
(nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) (nls_strnicmp(codepage, name->name, str, len) == 0))
return 0; return 0;
return 1; return 1;
} }
......
...@@ -1437,7 +1437,9 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) ...@@ -1437,7 +1437,9 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
*/ */
qstr = &dentry->d_name; qstr = &dentry->d_name;
if (parent->d_op && parent->d_op->d_compare) { if (parent->d_op && parent->d_op->d_compare) {
if (parent->d_op->d_compare(parent, qstr, name)) if (parent->d_op->d_compare(parent, parent->d_inode,
dentry, dentry->d_inode,
qstr->len, qstr->name, name))
goto next; goto next;
} else { } else {
if (qstr->len != len) if (qstr->len != len)
......
...@@ -164,16 +164,18 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr) ...@@ -164,16 +164,18 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
* 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(struct dentry *dentry, struct qstr *a, struct qstr *b) static int msdos_cmp(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)
{ {
struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options;
unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
int error; int error;
error = msdos_format_name(a->name, a->len, a_msdos_name, options); error = msdos_format_name(name->name, name->len, a_msdos_name, options);
if (error) if (error)
goto old_compare; goto old_compare;
error = msdos_format_name(b->name, b->len, b_msdos_name, options); error = msdos_format_name(str, len, b_msdos_name, options);
if (error) if (error)
goto old_compare; goto old_compare;
error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
...@@ -182,8 +184,8 @@ static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) ...@@ -182,8 +184,8 @@ static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
old_compare: old_compare:
error = 1; error = 1;
if (a->len == b->len) if (name->len == len)
error = memcmp(a->name, b->name, a->len); error = memcmp(name->name, str, len);
goto out; goto out;
} }
......
...@@ -85,15 +85,18 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) ...@@ -85,15 +85,18 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
} }
/* returns the length of a struct qstr, ignoring trailing dots */ /* returns the length of a struct qstr, ignoring trailing dots */
static unsigned int vfat_striptail_len(struct qstr *qstr) static unsigned int __vfat_striptail_len(unsigned int len, const char *name)
{ {
unsigned int len = qstr->len; while (len && name[len - 1] == '.')
while (len && qstr->name[len - 1] == '.')
len--; len--;
return len; return len;
} }
static unsigned int vfat_striptail_len(const struct qstr *qstr)
{
return __vfat_striptail_len(qstr->len, qstr->name);
}
/* /*
* Compute the hash for the vfat name corresponding to the dentry. * Compute the hash for the vfat name corresponding to the dentry.
* Note: if the name is invalid, we leave the hash code unchanged so * Note: if the name is invalid, we leave the hash code unchanged so
...@@ -133,16 +136,18 @@ static int vfat_hashi(struct dentry *dentry, struct qstr *qstr) ...@@ -133,16 +136,18 @@ static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
/* /*
* Case insensitive compare of two vfat names. * Case insensitive compare of two vfat names.
*/ */
static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) static int vfat_cmpi(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)
{ {
struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io; struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
unsigned int alen, blen; unsigned int alen, blen;
/* A filename cannot end in '.' or we treat it like it has none */ /* A filename cannot end in '.' or we treat it like it has none */
alen = vfat_striptail_len(a); alen = vfat_striptail_len(name);
blen = vfat_striptail_len(b); blen = __vfat_striptail_len(len, str);
if (alen == blen) { if (alen == blen) {
if (nls_strnicmp(t, a->name, b->name, alen) == 0) if (nls_strnicmp(t, name->name, str, alen) == 0)
return 0; return 0;
} }
return 1; return 1;
...@@ -151,15 +156,17 @@ static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) ...@@ -151,15 +156,17 @@ static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
/* /*
* Case sensitive compare of two vfat names. * Case sensitive compare of two vfat names.
*/ */
static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) static int vfat_cmp(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 alen, blen; unsigned int alen, blen;
/* A filename cannot end in '.' or we treat it like it has none */ /* A filename cannot end in '.' or we treat it like it has none */
alen = vfat_striptail_len(a); alen = vfat_striptail_len(name);
blen = vfat_striptail_len(b); blen = __vfat_striptail_len(len, str);
if (alen == blen) { if (alen == blen) {
if (strncmp(a->name, b->name, alen) == 0) if (strncmp(name->name, str, alen) == 0)
return 0; return 0;
} }
return 1; return 1;
......
...@@ -216,7 +216,10 @@ extern const struct dentry_operations hfs_dentry_operations; ...@@ -216,7 +216,10 @@ extern const struct dentry_operations hfs_dentry_operations;
extern int hfs_hash_dentry(struct dentry *, struct qstr *); extern int hfs_hash_dentry(struct dentry *, 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(struct dentry *, struct qstr *, struct qstr *); extern int hfs_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);
/* trans.c */ /* trans.c */
extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *); extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
......
...@@ -92,21 +92,21 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1, ...@@ -92,21 +92,21 @@ 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(struct dentry *dentry, struct qstr *s1, struct qstr *s2) int hfs_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)
{ {
const unsigned char *n1, *n2; const unsigned char *n1, *n2;
int len;
len = s1->len;
if (len >= HFS_NAMELEN) { if (len >= HFS_NAMELEN) {
if (s2->len < HFS_NAMELEN) if (name->len < HFS_NAMELEN)
return 1; return 1;
len = HFS_NAMELEN; len = HFS_NAMELEN;
} else if (len != s2->len) } else if (len != name->len)
return 1; return 1;
n1 = s1->name; n1 = str;
n2 = s2->name; n2 = name->name;
while (len--) { while (len--) {
if (caseorder[*n1++] != caseorder[*n2++]) if (caseorder[*n1++] != caseorder[*n2++])
return 1; return 1;
......
...@@ -380,7 +380,10 @@ int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *) ...@@ -380,7 +380,10 @@ int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *)
int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str); int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str);
int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2); 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);
/* wrapper.c */ /* wrapper.c */
int hfsplus_read_wrapper(struct super_block *); int hfsplus_read_wrapper(struct super_block *);
......
...@@ -363,9 +363,12 @@ int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str) ...@@ -363,9 +363,12 @@ int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
* 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(struct dentry *dentry, struct qstr *s1, struct qstr *s2) 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)
{ {
struct super_block *sb = dentry->d_sb; struct super_block *sb = parent->d_sb;
int casefold, decompose, size; int casefold, decompose, size;
int dsize1, dsize2, len1, len2; int dsize1, dsize2, len1, len2;
const u16 *dstr1, *dstr2; const u16 *dstr1, *dstr2;
...@@ -375,10 +378,10 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr * ...@@ -375,10 +378,10 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *
casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
astr1 = s1->name; astr1 = str;
len1 = s1->len; len1 = len;
astr2 = s2->name; astr2 = name->name;
len2 = s2->len; len2 = name->len;
dsize1 = dsize2 = 0; dsize1 = dsize2 = 0;
dstr1 = dstr2 = NULL; dstr1 = dstr2 = NULL;
......
...@@ -34,19 +34,25 @@ static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr) ...@@ -34,19 +34,25 @@ static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
return 0; return 0;
} }
static int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) static int hpfs_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 al=a->len; unsigned al = len;
unsigned bl=b->len; unsigned bl = name->len;
hpfs_adjust_length(a->name, &al);
hpfs_adjust_length(str, &al);
/*hpfs_adjust_length(b->name, &bl);*/ /*hpfs_adjust_length(b->name, &bl);*/
/* 'a' is the qstr of an already existing dentry, so the name
* must be valid. 'b' must be validated first. /*
* 'str' is the nane of an already existing dentry, so the name
* must be valid. 'name' must be validated first.
*/ */
if (hpfs_chk_name(b->name, &bl)) if (hpfs_chk_name(name->name, &bl))
return 1; return 1;
if (hpfs_compare_names(dentry->d_sb, a->name, al, b->name, bl, 0)) if (hpfs_compare_names(parent->d_sb, str, al, name->name, bl, 0))
return 1; return 1;
return 0; return 0;
} }
......
...@@ -28,14 +28,26 @@ ...@@ -28,14 +28,26 @@
static int isofs_hashi(struct dentry *parent, struct qstr *qstr); static int isofs_hashi(struct dentry *parent, struct qstr *qstr);
static int isofs_hash(struct dentry *parent, struct qstr *qstr); static int isofs_hash(struct dentry *parent, struct qstr *qstr);
static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); static int isofs_dentry_cmpi(const struct dentry *parent,
static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b); const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name);
static int isofs_dentry_cmp(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);
#ifdef CONFIG_JOLIET #ifdef CONFIG_JOLIET
static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr); static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr);
static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr); static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr);
static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); static int isofs_dentry_cmpi_ms(const struct dentry *parent,
static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name);
static int isofs_dentry_cmp_ms(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);
#endif #endif
static void isofs_put_super(struct super_block *sb) static void isofs_put_super(struct super_block *sb)
...@@ -206,49 +218,31 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms) ...@@ -206,49 +218,31 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
} }
/* /*
* Case insensitive compare of two isofs names. * Compare of two isofs names.
*/ */
static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a, static int isofs_dentry_cmp_common(
struct qstr *b, int ms) unsigned int len, const char *str,
const struct qstr *name, int ms, int ci)
{ {
int alen, blen; int alen, blen;
/* A filename cannot end in '.' or we treat it like it has none */ /* A filename cannot end in '.' or we treat it like it has none */
alen = a->len; alen = name->len;
blen = b->len; blen = len;
if (ms) { if (ms) {
while (alen && a->name[alen-1] == '.') while (alen && name->name[alen-1] == '.')
alen--; alen--;
while (blen && b->name[blen-1] == '.') while (blen && str[blen-1] == '.')
blen--; blen--;
} }
if (alen == blen) { if (alen == blen) {
if (strnicmp(a->name, b->name, alen) == 0) if (ci) {
return 0; if (strnicmp(name->name, str, alen) == 0)
} return 0;
return 1; } else {
} if (strncmp(name->name, str, alen) == 0)
return 0;
/* }
* Case sensitive compare of two isofs names.
*/
static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a,
struct qstr *b, int ms)
{
int alen, blen;
/* A filename cannot end in '.' or we treat it like it has none */
alen = a->len;
blen = b->len;
if (ms) {
while (alen && a->name[alen-1] == '.')
alen--;
while (blen && b->name[blen-1] == '.')
blen--;
}
if (alen == blen) {
if (strncmp(a->name, b->name, alen) == 0)
return 0;
} }
return 1; return 1;
} }
...@@ -266,15 +260,19 @@ isofs_hashi(struct dentry *dentry, struct qstr *qstr) ...@@ -266,15 +260,19 @@ isofs_hashi(struct dentry *dentry, struct qstr *qstr)
} }
static int static int
isofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b) isofs_dentry_cmp(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)
{ {
return isofs_dentry_cmp_common(dentry, a, b, 0); return isofs_dentry_cmp_common(len, str, name, 0, 0);
} }
static int static int
isofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b) isofs_dentry_cmpi(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)
{ {
return isofs_dentry_cmpi_common(dentry, a, b, 0); return isofs_dentry_cmp_common(len, str, name, 0, 1);
} }
#ifdef CONFIG_JOLIET #ifdef CONFIG_JOLIET
...@@ -291,15 +289,19 @@ isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr) ...@@ -291,15 +289,19 @@ isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr)
} }
static int static int
isofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) isofs_dentry_cmp_ms(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)
{ {
return isofs_dentry_cmp_common(dentry, a, b, 1); return isofs_dentry_cmp_common(len, str, name, 1, 0);
} }
static int static int
isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) isofs_dentry_cmpi_ms(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)
{ {
return isofs_dentry_cmpi_common(dentry, a, b, 1); return isofs_dentry_cmp_common(len, str, name, 1, 1);
} }
#endif #endif
......
...@@ -37,7 +37,8 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen) ...@@ -37,7 +37,8 @@ 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(dentry, &dentry->d_name, &qstr); return dentry->d_op->d_compare(NULL, NULL, NULL, NULL,
dentry->d_name.len, dentry->d_name.name, &qstr);
} }
/* /*
......
...@@ -1587,14 +1587,17 @@ static int jfs_ci_hash(struct dentry *dir, struct qstr *this) ...@@ -1587,14 +1587,17 @@ static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
return 0; return 0;
} }
static int jfs_ci_compare(struct dentry *dir, struct qstr *a, struct qstr *b) static int jfs_ci_compare(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)
{ {
int i, result = 1; int i, result = 1;
if (a->len != b->len) if (len != name->len)
goto out; goto out;
for (i=0; i < a->len; i++) { for (i=0; i < len; i++) {
if (tolower(a->name[i]) != tolower(b->name[i])) if (tolower(str[i]) != tolower(name->name[i]))
goto out; goto out;
} }
result = 0; result = 0;
......
...@@ -75,7 +75,9 @@ const struct inode_operations ncp_dir_inode_operations = ...@@ -75,7 +75,9 @@ const struct inode_operations ncp_dir_inode_operations =
*/ */
static int ncp_lookup_validate(struct dentry *, struct nameidata *); static int ncp_lookup_validate(struct dentry *, struct nameidata *);
static int ncp_hash_dentry(struct dentry *, struct qstr *); static int ncp_hash_dentry(struct dentry *, struct qstr *);
static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); static int ncp_compare_dentry(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
unsigned int, const char *, const struct qstr *);
static int ncp_delete_dentry(const struct dentry *); static int ncp_delete_dentry(const struct dentry *);
static const struct dentry_operations ncp_dentry_operations = static const struct dentry_operations ncp_dentry_operations =
...@@ -113,10 +115,10 @@ static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator) ...@@ -113,10 +115,10 @@ static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS) #define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
static inline int ncp_case_sensitive(struct dentry *dentry) static inline int ncp_case_sensitive(const struct inode *i)
{ {
#ifdef CONFIG_NCPFS_NFS_NS #ifdef CONFIG_NCPFS_NFS_NS
return ncp_namespace(dentry->d_inode) == NW_NS_NFS; return ncp_namespace(i) == NW_NS_NFS;
#else #else
return 0; return 0;
#endif /* CONFIG_NCPFS_NFS_NS */ #endif /* CONFIG_NCPFS_NFS_NS */
...@@ -129,12 +131,13 @@ static inline int ncp_case_sensitive(struct dentry *dentry) ...@@ -129,12 +131,13 @@ static inline int ncp_case_sensitive(struct dentry *dentry)
static int static int
ncp_hash_dentry(struct dentry *dentry, struct qstr *this) ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
{ {
if (!ncp_case_sensitive(dentry)) { if (!ncp_case_sensitive(dentry->d_inode)) {
struct super_block *sb = dentry->d_sb;
struct nls_table *t; struct nls_table *t;
unsigned long hash; unsigned long hash;
int i; int i;
t = NCP_IO_TABLE(dentry); t = NCP_IO_TABLE(sb);
hash = init_name_hash(); hash = init_name_hash();
for (i=0; i<this->len ; i++) for (i=0; i<this->len ; i++)
hash = partial_name_hash(ncp_tolower(t, this->name[i]), hash = partial_name_hash(ncp_tolower(t, this->name[i]),
...@@ -145,15 +148,17 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this) ...@@ -145,15 +148,17 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
} }
static int static int
ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) ncp_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)
{ {
if (a->len != b->len) if (len != name->len)
return 1; return 1;
if (ncp_case_sensitive(dentry)) if (ncp_case_sensitive(pinode))
return strncmp(a->name, b->name, a->len); return strncmp(str, name->name, len);
return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
} }
/* /*
......
...@@ -135,7 +135,7 @@ int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *, ...@@ -135,7 +135,7 @@ int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *,
const unsigned char *, unsigned int, int); const unsigned char *, unsigned int, int);
#define NCP_ESC ':' #define NCP_ESC ':'
#define NCP_IO_TABLE(dentry) (NCP_SERVER((dentry)->d_inode)->nls_io) #define NCP_IO_TABLE(sb) (NCP_SBP(sb)->nls_io)
#define ncp_tolower(t, c) nls_tolower(t, c) #define ncp_tolower(t, c) nls_tolower(t, c)
#define ncp_toupper(t, c) nls_toupper(t, c) #define ncp_toupper(t, c) nls_toupper(t, c)
#define ncp_strnicmp(t, s1, s2, len) \ #define ncp_strnicmp(t, s1, s2, len) \
...@@ -150,15 +150,15 @@ int ncp__io2vol(unsigned char *, unsigned int *, ...@@ -150,15 +150,15 @@ int ncp__io2vol(unsigned char *, unsigned int *,
int ncp__vol2io(unsigned char *, unsigned int *, int ncp__vol2io(unsigned char *, unsigned int *,
const unsigned char *, unsigned int, int); const unsigned char *, unsigned int, int);
#define NCP_IO_TABLE(dentry) NULL #define NCP_IO_TABLE(sb) NULL
#define ncp_tolower(t, c) tolower(c) #define ncp_tolower(t, c) tolower(c)
#define ncp_toupper(t, c) toupper(c) #define ncp_toupper(t, c) toupper(c)
#define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U) #define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U)
#define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U) #define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U)
static inline int ncp_strnicmp(struct nls_table *t, const unsigned char *s1, static inline int ncp_strnicmp(const struct nls_table *t,
const unsigned char *s2, int len) const unsigned char *s1, const unsigned char *s2, int len)
{ {
while (len--) { while (len--) {
if (tolower(*s1++) != tolower(*s2++)) if (tolower(*s1++) != tolower(*s2++))
......
...@@ -397,15 +397,16 @@ static int proc_sys_delete(const struct dentry *dentry) ...@@ -397,15 +397,16 @@ static int proc_sys_delete(const struct dentry *dentry)
return !!PROC_I(dentry->d_inode)->sysctl->unregistering; return !!PROC_I(dentry->d_inode)->sysctl->unregistering;
} }
static int proc_sys_compare(struct dentry *dir, struct qstr *qstr, static int proc_sys_compare(const struct dentry *parent,
struct qstr *name) const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name)
{ {
struct dentry *dentry = container_of(qstr, struct dentry, d_name); if (name->len != len)
if (qstr->len != name->len)
return 1; return 1;
if (memcmp(qstr->name, name->name, name->len)) if (memcmp(name->name, str, len))
return 1; return 1;
return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl); return !sysctl_is_seen(PROC_I(inode)->sysctl);
} }
static const struct dentry_operations proc_sys_dentry_operations = { static const struct dentry_operations proc_sys_dentry_operations = {
......
...@@ -134,7 +134,9 @@ enum dentry_d_lock_class ...@@ -134,7 +134,9 @@ enum dentry_d_lock_class
struct dentry_operations { struct dentry_operations {
int (*d_revalidate)(struct dentry *, struct nameidata *); int (*d_revalidate)(struct dentry *, struct nameidata *);
int (*d_hash)(struct dentry *, struct qstr *); int (*d_hash)(struct dentry *, struct qstr *);
int (*d_compare)(struct dentry *, struct qstr *, struct qstr *); int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
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 *);
void (*d_iput)(struct dentry *, struct inode *); void (*d_iput)(struct dentry *, struct inode *);
...@@ -145,12 +147,8 @@ struct dentry_operations { ...@@ -145,12 +147,8 @@ struct dentry_operations {
* Locking rules for dentry_operations callbacks are to be found in * Locking rules for dentry_operations callbacks are to be found in
* Documentation/filesystems/Locking. Keep it updated! * Documentation/filesystems/Locking. Keep it updated!
* *
* the dentry parameter passed to d_hash and d_compare is the parent * FUrther descriptions are found in Documentation/filesystems/vfs.txt.
* directory of the entries to be compared. It is used in case these * Keep it updated too!
* functions need any directory specific information for determining
* equivalency classes. Using the dentry itself might not work, as it
* might be a negative dentry which has no information associated with
* it.
*/ */
/* d_flags entries */ /* d_flags entries */
......
...@@ -184,13 +184,13 @@ struct ncp_entry_info { ...@@ -184,13 +184,13 @@ struct ncp_entry_info {
__u8 file_handle[6]; __u8 file_handle[6];
}; };
static inline struct ncp_server *NCP_SBP(struct super_block *sb) static inline struct ncp_server *NCP_SBP(const struct super_block *sb)
{ {
return sb->s_fs_info; return sb->s_fs_info;
} }
#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb) #define NCP_SERVER(inode) NCP_SBP((inode)->i_sb)
static inline struct ncp_inode_info *NCP_FINFO(struct inode *inode) static inline struct ncp_inode_info *NCP_FINFO(const struct inode *inode)
{ {
return container_of(inode, struct ncp_inode_info, vfs_inode); return container_of(inode, struct ncp_inode_info, vfs_inode);
} }
......
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