fs: change d_hash for rcu-walk
authorNick Piggin <npiggin@kernel.dk>
Fri, 7 Jan 2011 06:49:28 +0000 (17:49 +1100)
committerNick Piggin <npiggin@kernel.dk>
Fri, 7 Jan 2011 06:50:20 +0000 (17:50 +1100)
Change d_hash so it may be called from lock-free RCU lookups. See similar
patch for d_compare for details.

For in-tree filesystems, this is just a mechanical change.

Signed-off-by: Nick Piggin <npiggin@kernel.dk>
25 files changed:
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
drivers/staging/smbfs/cache.c
drivers/staging/smbfs/dir.c
fs/adfs/dir.c
fs/affs/namei.c
fs/cifs/dir.c
fs/cifs/readdir.c
fs/dcache.c
fs/ecryptfs/inode.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/gfs2/dentry.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/jfs/namei.c
fs/namei.c
fs/ncpfs/dir.c
fs/sysv/namei.c
include/linux/dcache.h

index 9a76f8d..a15ee20 100644 (file)
@@ -10,7 +10,8 @@ be able to use diff(1).
 --------------------------- dentry_operations --------------------------
 prototypes:
        int (*d_revalidate)(struct dentry *, int);
-       int (*d_hash) (struct dentry *, struct qstr *);
+       int (*d_hash)(const struct dentry *, const struct inode *,
+                       struct qstr *);
        int (*d_compare)(const struct dentry *, const struct inode *,
                        const struct dentry *, const struct inode *,
                        unsigned int, const char *, const struct qstr *);
@@ -22,7 +23,7 @@ prototypes:
 locking rules:
                dcache_lock     rename_lock     ->d_lock        may block
 d_revalidate:  no              no              no              yes
-d_hash         no              no              no              yes
+d_hash         no              no              no              no
 d_compare:     no              yes             no              no 
 d_delete:      yes             no              yes             no
 d_release:     no              no              no              yes
index d44511e..9fd3194 100644 (file)
@@ -333,3 +333,10 @@ unreferenced dentries, and is now only called when the dentry refcount goes to
        .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.
+
+---
+[mandatory]
+
+       .d_hash() 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 250681b..69b10ff 100644 (file)
@@ -847,7 +847,8 @@ defined:
 
 struct dentry_operations {
        int (*d_revalidate)(struct dentry *, struct nameidata *);
-       int (*d_hash)(struct dentry *, struct qstr *);
+       int (*d_hash)(const struct dentry *, const struct inode *,
+                       struct qstr *);
        int (*d_compare)(const struct dentry *, const struct inode *,
                        const struct dentry *, const struct inode *,
                        unsigned int, const char *, const struct qstr *);
@@ -864,7 +865,10 @@ struct dentry_operations {
 
   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.
+       to be hashed into. The inode is the dentry's inode.
+
+       Same locking and synchronisation rules as d_compare regarding
+       what is safe to dereference etc.
 
   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
index dbd2e1d..0beded2 100644 (file)
@@ -134,7 +134,7 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
        qname->hash = full_name_hash(qname->name, qname->len);
 
        if (dentry->d_op && dentry->d_op->d_hash)
-               if (dentry->d_op->d_hash(dentry, qname) != 0)
+               if (dentry->d_op->d_hash(dentry, inode, qname) != 0)
                        goto end_advance;
 
        newdent = d_lookup(dentry, qname);
index bd63229..5f79799 100644 (file)
@@ -274,7 +274,8 @@ smb_dir_open(struct inode *dir, struct file *file)
  * Dentry operations routines
  */
 static int smb_lookup_validate(struct dentry *, struct nameidata *);
-static int smb_hash_dentry(struct dentry *, struct qstr *);
+static int smb_hash_dentry(const struct dentry *, const struct inode *,
+               struct qstr *);
 static int smb_compare_dentry(const struct dentry *,
                const struct inode *,
                const struct dentry *, const struct inode *,
@@ -336,7 +337,8 @@ smb_lookup_validate(struct dentry * dentry, struct nameidata *nd)
 }
 
 static int 
-smb_hash_dentry(struct dentry *dir, struct qstr *this)
+smb_hash_dentry(const struct dentry *dir, const struct inode *inode,
+               struct qstr *this)
 {
        unsigned long hash;
        int i;
index c8ed661..a11e5e1 100644 (file)
@@ -201,7 +201,8 @@ const struct file_operations adfs_dir_operations = {
 };
 
 static int
-adfs_hash(struct dentry *parent, struct qstr *qstr)
+adfs_hash(const struct dentry *parent, const struct inode *inode,
+               struct qstr *qstr)
 {
        const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen;
        const unsigned char *name;
index 547d5de..5aca08c 100644 (file)
 typedef int (*toupper_t)(int);
 
 static int      affs_toupper(int ch);
-static int      affs_hash_dentry(struct dentry *, struct qstr *);
+static int      affs_hash_dentry(const struct dentry *,
+               const struct inode *, 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_hash_dentry(const struct dentry *,
+               const struct inode *, struct qstr *);
 static int       affs_intl_compare_dentry(const struct dentry *parent,
                const struct inode *pinode,
                const struct dentry *dentry, const struct inode *inode,
@@ -64,13 +66,13 @@ affs_get_toupper(struct super_block *sb)
  * Note: the dentry argument is the parent dentry.
  */
 static inline int
-__affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper)
+__affs_hash_dentry(struct qstr *qstr, toupper_t toupper)
 {
        const u8 *name = qstr->name;
        unsigned long hash;
        int i;
 
-       i = affs_check_name(qstr->name,qstr->len);
+       i = affs_check_name(qstr->name, qstr->len);
        if (i)
                return i;
 
@@ -84,14 +86,16 @@ __affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper)
 }
 
 static int
-affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+affs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
-       return __affs_hash_dentry(dentry, qstr, affs_toupper);
+       return __affs_hash_dentry(qstr, affs_toupper);
 }
 static int
-affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+affs_intl_hash_dentry(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
-       return __affs_hash_dentry(dentry, qstr, affs_intl_toupper);
+       return __affs_hash_dentry(qstr, affs_intl_toupper);
 }
 
 static inline int __affs_compare_dentry(unsigned int len,
index c60133f..88bfe68 100644 (file)
@@ -700,9 +700,10 @@ const struct dentry_operations cifs_dentry_ops = {
 /* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
 };
 
-static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
+static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *q)
 {
-       struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+       struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
        unsigned long hash;
        int i;
 
index a73eb9f..ee463ae 100644 (file)
@@ -79,7 +79,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
        cFYI(1, "For %s", name->name);
 
        if (parent->d_op && parent->d_op->d_hash)
-               parent->d_op->d_hash(parent, name);
+               parent->d_op->d_hash(parent, parent->d_inode, name);
        else
                name->hash = full_name_hash(name->name, name->len);
 
index 7075555..6f59f37 100644 (file)
@@ -1478,7 +1478,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
         */
        name->hash = full_name_hash(name->name, name->len);
        if (dir->d_op && dir->d_op->d_hash) {
-               if (dir->d_op->d_hash(dir, name) < 0)
+               if (dir->d_op->d_hash(dir, dir->d_inode, name) < 0)
                        goto out;
        }
        dentry = d_lookup(dir, name);
index 9d1a22d..a1ed7a7 100644 (file)
@@ -454,7 +454,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
        lower_name.hash = ecryptfs_dentry->d_name.hash;
        if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) {
                rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry,
-                                                   &lower_name);
+                               lower_dir_dentry->d_inode, &lower_name);
                if (rc < 0)
                        goto out_d_drop;
        }
@@ -489,7 +489,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
        lower_name.hash = full_name_hash(lower_name.name, lower_name.len);
        if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) {
                rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry,
-                                                   &lower_name);
+                               lower_dir_dentry->d_inode, &lower_name);
                if (rc < 0)
                        goto out_d_drop;
        }
index 99d3c7a..3b3e072 100644 (file)
@@ -148,7 +148,8 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len,
  * that the existing dentry can be used. The msdos fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
+static int msdos_hash(const struct dentry *dentry, const struct inode *inode,
+              struct qstr *qstr)
 {
        struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
        unsigned char msdos_name[MSDOS_NAME];
index 95e00ab..4fc0627 100644 (file)
@@ -103,7 +103,8 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr)
  * that the existing dentry can be used. The vfat fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
+static int vfat_hash(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
        qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
        return 0;
@@ -115,9 +116,10 @@ static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
  * that the existing dentry can be used. The vfat fs routines will
  * return ENOENT or EINVAL as appropriate.
  */
-static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
+static int vfat_hashi(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
-       struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
+       struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
        const unsigned char *name;
        unsigned int len;
        unsigned long hash;
index e80fea2..50497f6 100644 (file)
@@ -100,7 +100,8 @@ fail:
        return 0;
 }
 
-static int gfs2_dhash(struct dentry *dentry, struct qstr *str)
+static int gfs2_dhash(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *str)
 {
        str->hash = gfs2_disk_hash(str->name, str->len);
        return 0;
index 8cd876f..ad97c2d 100644 (file)
@@ -213,7 +213,8 @@ extern int hfs_part_find(struct super_block *, sector_t *, sector_t *);
 /* string.c */
 extern const struct dentry_operations hfs_dentry_operations;
 
-extern int hfs_hash_dentry(struct dentry *, struct qstr *);
+extern int hfs_hash_dentry(const struct dentry *, const struct inode *,
+               struct qstr *);
 extern int hfs_strcmp(const unsigned char *, unsigned int,
                      const unsigned char *, unsigned int);
 extern int hfs_compare_dentry(const struct dentry *parent,
index aaf90d0..495a976 100644 (file)
@@ -51,7 +51,8 @@ static unsigned char caseorder[256] = {
 /*
  * Hash a string to an integer in a case-independent way
  */
-int hfs_hash_dentry(struct dentry *dentry, struct qstr *this)
+int hfs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *this)
 {
        const unsigned char *name = this->name;
        unsigned int hash, len = this->len;
index 7aa96ee..a5308f4 100644 (file)
@@ -379,7 +379,8 @@ int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unist
 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_hash_dentry(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *str);
 int hfsplus_compare_dentry(const struct dentry *parent,
                const struct inode *pinode,
                const struct dentry *dentry, const struct inode *inode,
index b178c99..d800aa0 100644 (file)
@@ -320,7 +320,8 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
  * Composed unicode characters are decomposed and case-folding is performed
  * if the appropriate bits are (un)set on the superblock.
  */
-int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
+int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *str)
 {
        struct super_block *sb = dentry->d_sb;
        const char *astr;
index dd9b1e7..35526df 100644 (file)
@@ -12,7 +12,8 @@
  * Note: the dentry argument is the parent dentry.
  */
 
-static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
+static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
        unsigned long    hash;
        int              i;
index 7b0fbc6..d204ee4 100644 (file)
 
 #define BEQUIET
 
-static int isofs_hashi(struct dentry *parent, struct qstr *qstr);
-static int isofs_hash(struct dentry *parent, struct qstr *qstr);
+static int isofs_hashi(const struct dentry *parent, const struct inode *inode,
+               struct qstr *qstr);
+static int isofs_hash(const struct dentry *parent, const struct inode *inode,
+               struct qstr *qstr);
 static int isofs_dentry_cmpi(const struct dentry *parent,
                const struct inode *pinode,
                const struct dentry *dentry, const struct inode *inode,
@@ -38,8 +40,10 @@ static int isofs_dentry_cmp(const struct dentry *parent,
                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_hashi_ms(const struct dentry *parent, const struct inode *inode,
+               struct qstr *qstr);
+static int isofs_hash_ms(const struct dentry *parent, const struct inode *inode,
+               struct qstr *qstr);
 static int isofs_dentry_cmpi_ms(const struct dentry *parent,
                const struct inode *pinode,
                const struct dentry *dentry, const struct inode *inode,
@@ -172,7 +176,7 @@ struct iso9660_options{
  * Compute the hash for the isofs name corresponding to the dentry.
  */
 static int
-isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms)
+isofs_hash_common(const struct dentry *dentry, struct qstr *qstr, int ms)
 {
        const char *name;
        int len;
@@ -193,7 +197,7 @@ isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms)
  * Compute the hash for the isofs name corresponding to the dentry.
  */
 static int
-isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
+isofs_hashi_common(const struct dentry *dentry, struct qstr *qstr, int ms)
 {
        const char *name;
        int len;
@@ -248,13 +252,15 @@ static int isofs_dentry_cmp_common(
 }
 
 static int
-isofs_hash(struct dentry *dentry, struct qstr *qstr)
+isofs_hash(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
        return isofs_hash_common(dentry, qstr, 0);
 }
 
 static int
-isofs_hashi(struct dentry *dentry, struct qstr *qstr)
+isofs_hashi(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
        return isofs_hashi_common(dentry, qstr, 0);
 }
@@ -277,13 +283,15 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
 
 #ifdef CONFIG_JOLIET
 static int
-isofs_hash_ms(struct dentry *dentry, struct qstr *qstr)
+isofs_hash_ms(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
        return isofs_hash_common(dentry, qstr, 1);
 }
 
 static int
-isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr)
+isofs_hashi_ms(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
        return isofs_hashi_common(dentry, qstr, 1);
 }
index 9212901..57f90da 100644 (file)
@@ -1574,7 +1574,8 @@ const struct file_operations jfs_dir_operations = {
        .llseek         = generic_file_llseek,
 };
 
-static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
+static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
+               struct qstr *this)
 {
        unsigned long hash;
        int i;
index 4ff7ca5..f3b5ca4 100644 (file)
@@ -731,7 +731,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
         * to use its own hash..
         */
        if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
-               int err = nd->path.dentry->d_op->d_hash(nd->path.dentry, name);
+               int err = nd->path.dentry->d_op->d_hash(nd->path.dentry,
+                               nd->path.dentry->d_inode, name);
                if (err < 0)
                        return err;
        }
@@ -1134,7 +1135,7 @@ static struct dentry *__lookup_hash(struct qstr *name,
         * to use its own hash..
         */
        if (base->d_op && base->d_op->d_hash) {
-               err = base->d_op->d_hash(base, name);
+               err = base->d_op->d_hash(base, inode, name);
                dentry = ERR_PTR(err);
                if (err < 0)
                        goto out;
index 3bcc68a..bbbf792 100644 (file)
@@ -74,7 +74,8 @@ const struct inode_operations ncp_dir_inode_operations =
  * Dentry operations routines
  */
 static int ncp_lookup_validate(struct dentry *, struct nameidata *);
-static int ncp_hash_dentry(struct dentry *, struct qstr *);
+static int ncp_hash_dentry(const struct dentry *, const struct inode *,
+               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 *);
@@ -129,9 +130,10 @@ static inline int ncp_case_sensitive(const struct inode *i)
  * is case-sensitive.
  */
 static int 
-ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
+ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *this)
 {
-       if (!ncp_case_sensitive(dentry->d_inode)) {
+       if (!ncp_case_sensitive(inode)) {
                struct super_block *sb = dentry->d_sb;
                struct nls_table *t;
                unsigned long hash;
@@ -597,7 +599,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
        qname.hash = full_name_hash(qname.name, qname.len);
 
        if (dentry->d_op && dentry->d_op->d_hash)
-               if (dentry->d_op->d_hash(dentry, &qname) != 0)
+               if (dentry->d_op->d_hash(dentry, dentry->d_inode, &qname) != 0)
                        goto end_advance;
 
        newdent = d_lookup(dentry, &qname);
index 11e7f7d..7507aeb 100644 (file)
@@ -27,7 +27,8 @@ static int add_nondir(struct dentry *dentry, struct inode *inode)
        return err;
 }
 
-static int sysv_hash(struct dentry *dentry, struct qstr *qstr)
+static int sysv_hash(const struct dentry *dentry, const struct inode *inode,
+               struct qstr *qstr)
 {
        /* Truncate the name in place, avoids having to define a compare
           function. */
index 75a072b..1149e70 100644 (file)
@@ -133,7 +133,8 @@ enum dentry_d_lock_class
 
 struct dentry_operations {
        int (*d_revalidate)(struct dentry *, struct nameidata *);
-       int (*d_hash)(struct dentry *, struct qstr *);
+       int (*d_hash)(const struct dentry *, const struct inode *,
+                       struct qstr *);
        int (*d_compare)(const struct dentry *, const struct inode *,
                        const struct dentry *, const struct inode *,
                        unsigned int, const char *, const struct qstr *);