NFS is the most complicated of the lot. It uses ->d_fsdata to 1) store devname in the root dentry, and 2) store nfs_unlinkdata for sillyrenames. In addition it stores a verifier in ->d_time. Introduce nfs_dentry structure that to store all of the above and make d_fsdata point to it. Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx> Cc: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx> --- fs/nfs/dir.c | 18 ++++++++++++++---- fs/nfs/getroot.c | 4 ++-- fs/nfs/namespace.c | 2 +- fs/nfs/unlink.c | 16 ++++++++-------- include/linux/nfs_fs.h | 18 +++++++++++++++++- 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index aaf7bd0cbae2..ebb536c23b19 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1022,7 +1022,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry, return 1; if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) return 0; - if (!nfs_verify_change_attribute(dir, dentry->d_time)) + if (!nfs_verify_change_attribute(dir, NFS_D(dentry)->verf)) return 0; /* Revalidate nfsi->cache_change_attribute before we declare a match */ if (rcu_walk) @@ -1031,7 +1031,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry, ret = nfs_revalidate_inode(NFS_SERVER(dir), dir); if (ret < 0) return 0; - if (!nfs_verify_change_attribute(dir, dentry->d_time)) + if (!nfs_verify_change_attribute(dir, NFS_D(dentry)->verf)) return 0; return 1; } @@ -1339,15 +1339,23 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) iput(inode); } +static int nfs_d_allocate(struct dentry *dentry) +{ + dentry->d_fsdata = kzalloc(sizeof(struct nfs_dentry), GFP_KERNEL); + + return dentry->d_fsdata ? 0 : -ENOMEM; +} + static void nfs_d_release(struct dentry *dentry) { /* free cached devname value, if it survived that far */ - if (unlikely(dentry->d_fsdata)) { + if (unlikely(NFS_D(dentry)->devname)) { if (dentry->d_flags & DCACHE_NFSFS_RENAMED) WARN_ON(1); else - kfree(dentry->d_fsdata); + kfree(NFS_D(dentry)->devname); } + kfree(dentry->d_fsdata); } const struct dentry_operations nfs_dentry_operations = { @@ -1356,6 +1364,7 @@ const struct dentry_operations nfs_dentry_operations = { .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, .d_automount = nfs_d_automount, + .d_allocate = nfs_d_allocate, .d_release = nfs_d_release, }; EXPORT_SYMBOL_GPL(nfs_dentry_operations); @@ -1437,6 +1446,7 @@ const struct dentry_operations nfs4_dentry_operations = { .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, .d_automount = nfs_d_automount, + .d_allocate = nfs_d_allocate, .d_release = nfs_d_release, }; EXPORT_SYMBOL_GPL(nfs4_dentry_operations); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index a608ffd28acc..84482c656e05 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -120,9 +120,9 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, security_d_instantiate(ret, inode); spin_lock(&ret->d_lock); - if (IS_ROOT(ret) && !ret->d_fsdata && + if (IS_ROOT(ret) && !NFS_D(ret)->devname && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { - ret->d_fsdata = name; + NFS_D(ret)->devname = name; name = NULL; } spin_unlock(&ret->d_lock); diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index c8162c660c44..0060806d047b 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -90,7 +90,7 @@ rename_retry: *--end = '/'; } *p = end; - base = dentry->d_fsdata; + base = NFS_D(dentry)->devname; if (!base) { spin_unlock(&dentry->d_lock); rcu_read_unlock(); diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 1868246f56e6..d4c442a5f56a 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -134,8 +134,8 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data) spin_lock(&alias->d_lock); if (d_really_is_positive(alias) && !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { - devname_garbage = alias->d_fsdata; - alias->d_fsdata = data; + devname_garbage = NFS_D(alias)->devname; + NFS_D(alias)->data = data; alias->d_flags |= DCACHE_NFSFS_RENAMED; ret = 1; } else @@ -189,8 +189,8 @@ nfs_async_unlink(struct dentry *dentry, struct qstr *name) if (dentry->d_flags & DCACHE_NFSFS_RENAMED) goto out_unlock; dentry->d_flags |= DCACHE_NFSFS_RENAMED; - devname_garbage = dentry->d_fsdata; - dentry->d_fsdata = data; + devname_garbage = NFS_D(dentry)->devname; + NFS_D(dentry)->data = data; spin_unlock(&dentry->d_lock); /* * If we'd displaced old cached devname, free it. At that @@ -226,8 +226,8 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode) spin_lock(&dentry->d_lock); dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; - data = dentry->d_fsdata; - dentry->d_fsdata = NULL; + data = NFS_D(dentry)->data; + NFS_D(dentry)->data = NULL; spin_unlock(&dentry->d_lock); if (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)) @@ -240,10 +240,10 @@ nfs_cancel_async_unlink(struct dentry *dentry) { spin_lock(&dentry->d_lock); if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { - struct nfs_unlinkdata *data = dentry->d_fsdata; + struct nfs_unlinkdata *data = NFS_D(dentry)->data; dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; - dentry->d_fsdata = NULL; + NFS_D(dentry)->data = NULL; spin_unlock(&dentry->d_lock); nfs_free_unlinkdata(data); return; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index d71278c3c5bd..a33fb67ddd1c 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -187,6 +187,17 @@ struct nfs_inode { }; /* + * NFS specific dentry data + */ +struct nfs_dentry { + union { + char *devname; + struct nfs_unlinkdata *data; + }; + unsigned long verf; +}; + +/* * Cache validity bit flags */ #define NFS_INO_INVALID_ATTR 0x0001 /* cached attrs are invalid */ @@ -217,6 +228,11 @@ static inline struct nfs_inode *NFS_I(const struct inode *inode) return container_of(inode, struct nfs_inode, vfs_inode); } +static inline struct nfs_dentry *NFS_D(struct dentry *dentry) +{ + return (struct nfs_dentry *) dentry->d_fsdata; +} + static inline struct nfs_server *NFS_SB(const struct super_block *s) { return (struct nfs_server *)(s->s_fs_info); @@ -299,7 +315,7 @@ static inline int nfs_server_capable(struct inode *inode, int cap) static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) { - dentry->d_time = verf; + NFS_D(dentry)->verf = verf; } /** -- 2.5.5 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html