fs: change d_compare for rcu-walk
authorNick Piggin <npiggin@kernel.dk>
Fri, 7 Jan 2011 06:49:27 +0000 (17:49 +1100)
committerNick Piggin <npiggin@kernel.dk>
Fri, 7 Jan 2011 06:50:19 +0000 (17:50 +1100)
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>
23 files changed:
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
drivers/staging/smbfs/dir.c
fs/adfs/dir.c
fs/affs/namei.c
fs/cifs/dir.c
fs/dcache.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/hfs/hfs_fs.h
fs/hfs/string.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/unicode.c
fs/hpfs/dentry.c
fs/isofs/inode.c
fs/isofs/namei.c
fs/jfs/namei.c
fs/ncpfs/dir.c
fs/ncpfs/ncplib_kernel.h
fs/proc/proc_sysctl.c
include/linux/dcache.h
include/linux/ncp_fs.h

index 33fa3e5..9a76f8d 100644 (file)
@@ -11,7 +11,9 @@ be able to use diff(1).
 prototypes:
        int (*d_revalidate)(struct dentry *, int);
        int (*d_hash) (struct dentry *, struct qstr *);
 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 *);
        int (*d_delete)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
index 9e71c9a..d44511e 100644 (file)
@@ -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).
 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.
index 95c0a93..250681b 100644 (file)
@@ -848,7 +848,9 @@ defined:
 struct dentry_operations {
        int (*d_revalidate)(struct dentry *, struct nameidata *);
        int (*d_hash)(struct dentry *, struct qstr *);
 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 *);
        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
 
        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
 
   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
index 2270d48..bd63229 100644 (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_hash_dentry(struct dentry *, struct qstr *);
  */
 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 =
 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
 }
 
 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++) {
-               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;
                        goto out;
        }
        result = 0;
index f4287e4..c8ed661 100644 (file)
@@ -237,17 +237,19 @@ adfs_hash(struct dentry *parent, struct qstr *qstr)
  * requirements of the underlying filesystem.
  */
 static int
  * 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;
 
 {
        int i;
 
-       if (entry->len != name->len)
+       if (len != name->len)
                return 1;
 
        for (i = 0; i < name->len; i++) {
                char a, b;
 
                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')
                b = name->name[i];
 
                if (a >= 'A' && a <= 'Z')
index 914d1c0..547d5de 100644 (file)
@@ -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_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_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,
 
 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);
 }
 
        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;
 
                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;
                len = 30;
                        return 1;
                len = 30;
-       } else if (len != b->len)
+       } else if (len != name->len)
                return 1;
 
        for (; len > 0; 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
 }
 
 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);
 }
 
 /*
 }
 
 /*
index 521d841..c60133f 100644 (file)
@@ -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,
-                          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;
 }
                return 0;
        return 1;
 }
index 814e5f4..7075555 100644 (file)
@@ -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) {
                 */
                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)
                                goto next;
                } else {
                        if (qstr->len != len)
index 3345aab..99d3c7a 100644 (file)
@@ -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.
  */
  * 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;
 
        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;
        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);
        if (error)
                goto old_compare;
        error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
@@ -182,8 +184,8 @@ out:
 
 old_compare:
        error = 1;
 
 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;
 }
 
        goto out;
 }
 
index b936703..95e00ab 100644 (file)
@@ -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 && qstr->name[len - 1] == '.')
+       while (len && name[len - 1] == '.')
                len--;
        return len;
 }
 
                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
 /*
  * 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.
  */
 /*
  * 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 */
        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 (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;
                        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.
  */
 /*
  * 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 */
 {
        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 (alen == blen) {
-               if (strncmp(a->name, b->name, alen) == 0)
+               if (strncmp(name->name, str, alen) == 0)
                        return 0;
        }
        return 1;
                        return 0;
        }
        return 1;
index c8cffb8..8cd876f 100644 (file)
@@ -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_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 *);
 
 /* trans.c */
 extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
index 927a5af..aaf90d0 100644 (file)
@@ -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
  */
  * 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;
 {
        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;
                len = HFS_NAMELEN;
                        return 1;
                len = HFS_NAMELEN;
-       } else if (len != s2->len)
+       } else if (len != name->len)
                return 1;
 
                return 1;
 
-       n1 = s1->name;
-       n2 = s2->name;
+       n1 = str;
+       n2 = name->name;
        while (len--) {
                if (caseorder[*n1++] != caseorder[*n2++])
                        return 1;
        while (len--) {
                if (caseorder[*n1++] != caseorder[*n2++])
                        return 1;
index cb3653e..7aa96ee 100644 (file)
@@ -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_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 *);
 
 /* wrapper.c */
 int hfsplus_read_wrapper(struct super_block *);
index b66d67d..b178c99 100644 (file)
@@ -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.
  */
  * 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;
        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);
 
        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;
 
        dsize1 = dsize2 = 0;
        dstr1 = dstr2 = NULL;
 
index 67d9d36..dd9b1e7 100644 (file)
@@ -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 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);*/
        /*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 0;
 }
                return 1;
        return 0;
 }
index bfdeb82..7b0fbc6 100644 (file)
 
 static int isofs_hashi(struct dentry *parent, struct qstr *qstr);
 static int isofs_hash(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_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);
 
 #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)
 #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 */
 {
        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) {
        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--;
        }
        if (alen == blen) {
                        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;
 }
        }
        return 1;
 }
@@ -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)
 }
 
 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
 
index 0d23abf..715f7d3 100644 (file)
@@ -37,7 +37,8 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
 
        qstr.name = compare;
        qstr.len = 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);
 }
 
 /*
 }
 
 /*
index 2da1546..9212901 100644 (file)
@@ -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++) {
-               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;
                        goto out;
        }
        result = 0;
index e80ea4e..3bcc68a 100644 (file)
@@ -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_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 =
 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)
 
 
 #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
        return 0;
 #endif /* CONFIG_NCPFS_NFS_NS */
 #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)
 {
 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;
 
                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]),
                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
 }
 
 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))
-               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);
 }
 
 /*
 }
 
 /*
index 3c57eca..244d1b7 100644 (file)
@@ -135,7 +135,7 @@ int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *,
                                const unsigned char *, unsigned int, int);
 
 #define NCP_ESC                        ':'
                                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) \
 #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);
 
 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)
 
 
 #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++))
 {
        while (len--) {
                if (tolower(*s1++) != tolower(*s2++))
index a256d77..ae4b0fd 100644 (file)
@@ -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,
-                           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;
                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 = {
index 6cdf499..75a072b 100644 (file)
@@ -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 *);
 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 *);
        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!
  *
  * 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 */
  */
 
 /* d_flags entries */
index ef66306..1c27f20 100644 (file)
@@ -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;
 }
 
 #define NCP_SERVER(inode)      NCP_SBP((inode)->i_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);
 }
 {
        return container_of(inode, struct ncp_inode_info, vfs_inode);
 }