mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:02:20 +00:00
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: Nick Piggin <npiggin@kernel.dk>
This commit is contained in:
parent
fb2d5b86af
commit
621e155a35
@ -11,7 +11,9 @@ be able to use diff(1).
|
||||
prototypes:
|
||||
int (*d_revalidate)(struct dentry *, int);
|
||||
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 *);
|
||||
void (*d_release)(struct dentry *);
|
||||
void (*d_iput)(struct dentry *, struct inode *);
|
||||
|
@ -326,3 +326,10 @@ to it.
|
||||
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,
|
||||
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:
|
||||
struct dentry_operations {
|
||||
int (*d_revalidate)(struct dentry *, struct nameidata *);
|
||||
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 *);
|
||||
void (*d_release)(struct dentry *);
|
||||
void (*d_iput)(struct dentry *, struct inode *);
|
||||
@ -860,9 +862,27 @@ struct dentry_operations {
|
||||
dcache. Most filesystems leave this as NULL, because all their
|
||||
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
|
||||
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)
|
||||
*/
|
||||
static int smb_lookup_validate(struct dentry *, struct nameidata *);
|
||||
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 const struct dentry_operations smbfs_dentry_operations =
|
||||
@ -347,14 +350,17 @@ smb_hash_dentry(struct dentry *dir, struct qstr *this)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (a->len != b->len)
|
||||
if (len != name->len)
|
||||
goto out;
|
||||
for (i=0; i < a->len; i++) {
|
||||
if (tolower(a->name[i]) != tolower(b->name[i]))
|
||||
for (i=0; i < len; i++) {
|
||||
if (tolower(str[i]) != tolower(name->name[i]))
|
||||
goto out;
|
||||
}
|
||||
result = 0;
|
||||
|
@ -237,17 +237,19 @@ adfs_hash(struct dentry *parent, struct qstr *qstr)
|
||||
* requirements of the underlying filesystem.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (entry->len != name->len)
|
||||
if (len != name->len)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < name->len; i++) {
|
||||
char a, b;
|
||||
|
||||
a = entry->name[i];
|
||||
a = str[i];
|
||||
b = name->name[i];
|
||||
|
||||
if (a >= 'A' && a <= 'Z')
|
||||
|
@ -14,10 +14,16 @@ typedef int (*toupper_t)(int);
|
||||
|
||||
static int affs_toupper(int ch);
|
||||
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_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 = {
|
||||
.d_hash = affs_hash_dentry,
|
||||
@ -88,29 +94,29 @@ affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr)
|
||||
return __affs_hash_dentry(dentry, qstr, affs_intl_toupper);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, toupper_t toupper)
|
||||
static inline int __affs_compare_dentry(unsigned int len,
|
||||
const char *str, const struct qstr *name, toupper_t toupper)
|
||||
{
|
||||
const u8 *aname = a->name;
|
||||
const u8 *bname = b->name;
|
||||
int len;
|
||||
const u8 *aname = str;
|
||||
const u8 *bname = name->name;
|
||||
|
||||
/* '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;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
len = a->len;
|
||||
if (len >= 30) {
|
||||
if (b->len < 30)
|
||||
if (name->len < 30)
|
||||
return 1;
|
||||
len = 30;
|
||||
} else if (len != b->len)
|
||||
} else if (len != name->len)
|
||||
return 1;
|
||||
|
||||
for (; len > 0; len--)
|
||||
@ -121,14 +127,18 @@ __affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, tou
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
|
||||
struct qstr *b)
|
||||
static int cifs_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)
|
||||
{
|
||||
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) &&
|
||||
(nls_strnicmp(codepage, a->name, b->name, a->len) == 0))
|
||||
if ((name->len == len) &&
|
||||
(nls_strnicmp(codepage, name->name, str, len) == 0))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -1437,7 +1437,9 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
|
||||
*/
|
||||
qstr = &dentry->d_name;
|
||||
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;
|
||||
} else {
|
||||
if (qstr->len != len)
|
||||
|
@ -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,
|
||||
* 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];
|
||||
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)
|
||||
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)
|
||||
goto old_compare;
|
||||
error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
|
||||
@ -182,8 +184,8 @@ out:
|
||||
|
||||
old_compare:
|
||||
error = 1;
|
||||
if (a->len == b->len)
|
||||
error = memcmp(a->name, b->name, a->len);
|
||||
if (name->len == len)
|
||||
error = memcmp(name->name, str, len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
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 && qstr->name[len - 1] == '.')
|
||||
while (len && name[len - 1] == '.')
|
||||
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.
|
||||
* 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)
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* A filename cannot end in '.' or we treat it like it has none */
|
||||
alen = vfat_striptail_len(a);
|
||||
blen = vfat_striptail_len(b);
|
||||
alen = vfat_striptail_len(name);
|
||||
blen = __vfat_striptail_len(len, str);
|
||||
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 1;
|
||||
@ -151,15 +156,17 @@ static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* A filename cannot end in '.' or we treat it like it has none */
|
||||
alen = vfat_striptail_len(a);
|
||||
blen = vfat_striptail_len(b);
|
||||
alen = vfat_striptail_len(name);
|
||||
blen = __vfat_striptail_len(len, str);
|
||||
if (alen == blen) {
|
||||
if (strncmp(a->name, b->name, alen) == 0)
|
||||
if (strncmp(name->name, str, alen) == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -216,7 +216,10 @@ extern const struct dentry_operations hfs_dentry_operations;
|
||||
extern int hfs_hash_dentry(struct dentry *, struct qstr *);
|
||||
extern int hfs_strcmp(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 */
|
||||
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,
|
||||
* Test for equality of two strings in the HFS filename character ordering.
|
||||
* 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;
|
||||
int len;
|
||||
|
||||
len = s1->len;
|
||||
if (len >= HFS_NAMELEN) {
|
||||
if (s2->len < HFS_NAMELEN)
|
||||
if (name->len < HFS_NAMELEN)
|
||||
return 1;
|
||||
len = HFS_NAMELEN;
|
||||
} else if (len != s2->len)
|
||||
} else if (len != name->len)
|
||||
return 1;
|
||||
|
||||
n1 = s1->name;
|
||||
n2 = s2->name;
|
||||
n1 = str;
|
||||
n2 = name->name;
|
||||
while (len--) {
|
||||
if (caseorder[*n1++] != caseorder[*n2++])
|
||||
return 1;
|
||||
|
@ -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_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
|
||||
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 */
|
||||
int hfsplus_read_wrapper(struct super_block *);
|
||||
|
@ -363,9 +363,12 @@ int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
|
||||
* Composed unicode characters are decomposed and case-folding is performed
|
||||
* 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 dsize1, dsize2, len1, len2;
|
||||
const u16 *dstr1, *dstr2;
|
||||
@ -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);
|
||||
decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
|
||||
astr1 = s1->name;
|
||||
len1 = s1->len;
|
||||
astr2 = s2->name;
|
||||
len2 = s2->len;
|
||||
astr1 = str;
|
||||
len1 = len;
|
||||
astr2 = name->name;
|
||||
len2 = name->len;
|
||||
dsize1 = dsize2 = 0;
|
||||
dstr1 = dstr2 = NULL;
|
||||
|
||||
|
@ -34,19 +34,25 @@ static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
|
||||
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 bl=b->len;
|
||||
hpfs_adjust_length(a->name, &al);
|
||||
unsigned al = len;
|
||||
unsigned bl = name->len;
|
||||
|
||||
hpfs_adjust_length(str, &al);
|
||||
/*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;
|
||||
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 0;
|
||||
}
|
||||
|
@ -28,14 +28,26 @@
|
||||
|
||||
static int isofs_hashi(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_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
|
||||
static int 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);
|
||||
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
|
||||
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_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
|
||||
static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
|
||||
static int 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);
|
||||
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
|
||||
|
||||
static void isofs_put_super(struct super_block *sb)
|
||||
@ -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,
|
||||
struct qstr *b, int ms)
|
||||
static int isofs_dentry_cmp_common(
|
||||
unsigned int len, const char *str,
|
||||
const struct qstr *name, int ms, int ci)
|
||||
{
|
||||
int alen, blen;
|
||||
|
||||
/* A filename cannot end in '.' or we treat it like it has none */
|
||||
alen = a->len;
|
||||
blen = b->len;
|
||||
alen = name->len;
|
||||
blen = len;
|
||||
if (ms) {
|
||||
while (alen && a->name[alen-1] == '.')
|
||||
while (alen && name->name[alen-1] == '.')
|
||||
alen--;
|
||||
while (blen && b->name[blen-1] == '.')
|
||||
while (blen && str[blen-1] == '.')
|
||||
blen--;
|
||||
}
|
||||
if (alen == blen) {
|
||||
if (strnicmp(a->name, b->name, alen) == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
if (ci) {
|
||||
if (strnicmp(name->name, str, alen) == 0)
|
||||
return 0;
|
||||
} else {
|
||||
if (strncmp(name->name, str, alen) == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -266,15 +260,19 @@ isofs_hashi(struct dentry *dentry, struct qstr *qstr)
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
@ -291,15 +289,19 @@ isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr)
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -37,7 +37,8 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
|
||||
|
||||
qstr.name = compare;
|
||||
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)
|
||||
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;
|
||||
|
||||
if (a->len != b->len)
|
||||
if (len != name->len)
|
||||
goto out;
|
||||
for (i=0; i < a->len; i++) {
|
||||
if (tolower(a->name[i]) != tolower(b->name[i]))
|
||||
for (i=0; i < len; i++) {
|
||||
if (tolower(str[i]) != tolower(name->name[i]))
|
||||
goto out;
|
||||
}
|
||||
result = 0;
|
||||
|
@ -75,7 +75,9 @@ const struct inode_operations ncp_dir_inode_operations =
|
||||
*/
|
||||
static int ncp_lookup_validate(struct dentry *, struct nameidata *);
|
||||
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 const struct dentry_operations ncp_dentry_operations =
|
||||
@ -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)
|
||||
|
||||
static inline int ncp_case_sensitive(struct dentry *dentry)
|
||||
static inline int ncp_case_sensitive(const struct inode *i)
|
||||
{
|
||||
#ifdef CONFIG_NCPFS_NFS_NS
|
||||
return ncp_namespace(dentry->d_inode) == NW_NS_NFS;
|
||||
return ncp_namespace(i) == NW_NS_NFS;
|
||||
#else
|
||||
return 0;
|
||||
#endif /* CONFIG_NCPFS_NFS_NS */
|
||||
@ -129,12 +131,13 @@ static inline int ncp_case_sensitive(struct dentry *dentry)
|
||||
static int
|
||||
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;
|
||||
unsigned long hash;
|
||||
int i;
|
||||
|
||||
t = NCP_IO_TABLE(dentry);
|
||||
t = NCP_IO_TABLE(sb);
|
||||
hash = init_name_hash();
|
||||
for (i=0; i<this->len ; i++)
|
||||
hash = partial_name_hash(ncp_tolower(t, this->name[i]),
|
||||
@ -145,15 +148,17 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (ncp_case_sensitive(dentry))
|
||||
return strncmp(a->name, b->name, a->len);
|
||||
if (ncp_case_sensitive(pinode))
|
||||
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 *,
|
||||
const unsigned char *, unsigned int, int);
|
||||
|
||||
#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_toupper(t, c) nls_toupper(t, c)
|
||||
#define ncp_strnicmp(t, s1, s2, len) \
|
||||
@ -150,15 +150,15 @@ int ncp__io2vol(unsigned char *, unsigned int *,
|
||||
int ncp__vol2io(unsigned char *, unsigned 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_toupper(t, c) toupper(c)
|
||||
#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)
|
||||
|
||||
|
||||
static inline int ncp_strnicmp(struct nls_table *t, const unsigned char *s1,
|
||||
const unsigned char *s2, int len)
|
||||
static inline int ncp_strnicmp(const struct nls_table *t,
|
||||
const unsigned char *s1, const unsigned char *s2, int len)
|
||||
{
|
||||
while (len--) {
|
||||
if (tolower(*s1++) != tolower(*s2++))
|
||||
|
@ -397,15 +397,16 @@ static int proc_sys_delete(const struct dentry *dentry)
|
||||
return !!PROC_I(dentry->d_inode)->sysctl->unregistering;
|
||||
}
|
||||
|
||||
static int proc_sys_compare(struct dentry *dir, struct qstr *qstr,
|
||||
struct qstr *name)
|
||||
static int proc_sys_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)
|
||||
{
|
||||
struct dentry *dentry = container_of(qstr, struct dentry, d_name);
|
||||
if (qstr->len != name->len)
|
||||
if (name->len != len)
|
||||
return 1;
|
||||
if (memcmp(qstr->name, name->name, name->len))
|
||||
if (memcmp(name->name, str, len))
|
||||
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 = {
|
||||
|
@ -134,7 +134,9 @@ enum dentry_d_lock_class
|
||||
struct dentry_operations {
|
||||
int (*d_revalidate)(struct dentry *, struct nameidata *);
|
||||
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 *);
|
||||
void (*d_release)(struct dentry *);
|
||||
void (*d_iput)(struct dentry *, struct inode *);
|
||||
@ -145,12 +147,8 @@ struct dentry_operations {
|
||||
* Locking rules for dentry_operations callbacks are to be found in
|
||||
* Documentation/filesystems/Locking. Keep it updated!
|
||||
*
|
||||
* the dentry parameter passed to d_hash and d_compare is the parent
|
||||
* directory of the entries to be compared. It is used in case these
|
||||
* 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.
|
||||
* FUrther descriptions are found in Documentation/filesystems/vfs.txt.
|
||||
* Keep it updated too!
|
||||
*/
|
||||
|
||||
/* d_flags entries */
|
||||
|
@ -184,13 +184,13 @@ struct ncp_entry_info {
|
||||
__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;
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user