fs: change d_compare for rcu-walk
Nick Piggin [Fri, 7 Jan 2011 06:49:27 +0000 (17:49 +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 *);
-       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 *);
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).
+
+---
+[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 *);
-       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
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_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;
index f4287e4..c8ed661 100644 (file)
@@ -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')
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_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);
 }
 
 /*
index 521d841..c60133f 100644 (file)
@@ -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;
 }
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) {
-                       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)
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.
  */
-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;
 }
 
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 */
-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;
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_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 *);
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
  */
-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;
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_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 *);
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.
  */
-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;
 
index 67d9d36..dd9b1e7 100644 (file)
@@ -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;
 }
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_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
 
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;
-       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;
 }
 
-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;
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_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);
 }
 
 /*
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                        ':'
-#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++))
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;
 }
 
-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 = {
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 *);
-       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 */
index ef66306..1c27f20 100644 (file)
@@ -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);
 }