All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC/RFT PATCH 0/3] d_time removal
@ 2016-11-07 10:51 Miklos Szeredi
  2016-11-07 10:51 ` [PATCH 1/3] nfs: don't use ->d_time Miklos Szeredi
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Miklos Szeredi @ 2016-11-07 10:51 UTC (permalink / raw)
  To: Al Viro; +Cc: Trond Myklebust, linux-fsdevel, linux-kernel

Only two filesystems remaining: nfs and ncpfs.  Both use d_fsdata as well
as d_time which means we have to allocate a separate structure (RCU freed
in case of NFS).

I still haven't tested these; hoping someone will do it for me.

Thanks,
Miklos

---
Miklos Szeredi (3):
  nfs: don't use ->d_time
  ncpfs: don't use ->d_time
  vfs: remove ->d_time

 fs/ncpfs/dir.c           | 21 ++++++++++++++++++---
 fs/ncpfs/ncplib_kernel.h | 16 +++++++++++++---
 fs/nfs/dir.c             | 18 ++++++++++++++----
 fs/nfs/getroot.c         |  4 ++--
 fs/nfs/namespace.c       |  2 +-
 fs/nfs/unlink.c          | 16 ++++++++--------
 include/linux/dcache.h   |  7 +++----
 include/linux/nfs_fs.h   | 19 ++++++++++++++++++-
 8 files changed, 77 insertions(+), 26 deletions(-)

-- 
2.5.5

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] nfs: don't use ->d_time
  2016-11-07 10:51 [RFC/RFT PATCH 0/3] d_time removal Miklos Szeredi
@ 2016-11-07 10:51 ` Miklos Szeredi
  2016-11-07 10:51 ` [PATCH 2/3] ncpfs: " Miklos Szeredi
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Miklos Szeredi @ 2016-11-07 10:51 UTC (permalink / raw)
  To: Al Viro; +Cc: Trond Myklebust, linux-fsdevel, linux-kernel

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.  Need to use rcu freeing since ->verf is accessed
from dentry revalidation.  And not only read, but changed as well, so
rcu_head must not overlay verf.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Cc: Trond Myklebust <trond.myklebust@primarydata.com>
---
 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 | 19 ++++++++++++++++++-
 5 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 5f1af4cd1a33..5a3f02c4c28a 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1041,7 +1041,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)
@@ -1050,7 +1050,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;
 }
@@ -1358,15 +1358,23 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
 	iput(inode);
 }
 
+static int nfs_d_init(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_rcu(NFS_D(dentry), rcu);
 }
 
 const struct dentry_operations nfs_dentry_operations = {
@@ -1375,6 +1383,7 @@ const struct dentry_operations nfs_dentry_operations = {
 	.d_delete	= nfs_dentry_delete,
 	.d_iput		= nfs_dentry_iput,
 	.d_automount	= nfs_d_automount,
+	.d_init		= nfs_d_init,
 	.d_release	= nfs_d_release,
 };
 EXPORT_SYMBOL_GPL(nfs_dentry_operations);
@@ -1453,6 +1462,7 @@ const struct dentry_operations nfs4_dentry_operations = {
 	.d_delete	= nfs_dentry_delete,
 	.d_iput		= nfs_dentry_iput,
 	.d_automount	= nfs_d_automount,
+	.d_init		= nfs_d_init,
 	.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 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen,
 		*--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 191aa577dd1f..74e708fbd945 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, const 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 810124b33327..20a07688a392 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -187,6 +187,18 @@ struct nfs_inode {
 };
 
 /*
+ * NFS specific dentry data
+ */
+struct nfs_dentry {
+	union {
+		char *devname;
+		struct nfs_unlinkdata *data;
+		struct rcu_head rcu;
+	};
+	unsigned long verf;
+};
+
+/*
  * Cache validity bit flags
  */
 #define NFS_INO_INVALID_ATTR	0x0001		/* cached attrs are invalid */
@@ -217,6 +229,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 +316,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

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] ncpfs: don't use ->d_time
  2016-11-07 10:51 [RFC/RFT PATCH 0/3] d_time removal Miklos Szeredi
  2016-11-07 10:51 ` [PATCH 1/3] nfs: don't use ->d_time Miklos Szeredi
@ 2016-11-07 10:51 ` Miklos Szeredi
  2016-11-07 10:52 ` [PATCH 3/3] vfs: remove ->d_time Miklos Szeredi
  2016-12-07 19:46 ` [RFC/RFT PATCH 0/3] d_time removal Al Viro
  3 siblings, 0 replies; 5+ messages in thread
From: Miklos Szeredi @ 2016-11-07 10:51 UTC (permalink / raw)
  To: Al Viro; +Cc: Trond Myklebust, linux-fsdevel, linux-kernel

Ncpfs stores a boolean value in ->d_fsdata as well as using d_time.
Introcude ncp_dentry to store both of these and make d_fsdata point to it.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
---
 fs/ncpfs/dir.c           | 21 ++++++++++++++++++---
 fs/ncpfs/ncplib_kernel.h | 16 +++++++++++++---
 2 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 6df2a3827574..ce42dbdde777 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -72,6 +72,8 @@ const struct inode_operations ncp_dir_inode_operations =
 /*
  * Dentry operations routines
  */
+static int ncp_d_init(struct dentry *);
+static void ncp_d_release(struct dentry *);
 static int ncp_lookup_validate(struct dentry *, unsigned int);
 static int ncp_hash_dentry(const struct dentry *, struct qstr *);
 static int ncp_compare_dentry(const struct dentry *,
@@ -81,6 +83,8 @@ static void ncp_d_prune(struct dentry *dentry);
 
 const struct dentry_operations ncp_dentry_operations =
 {
+	.d_init		= ncp_d_init,
+	.d_release	= ncp_d_release,
 	.d_revalidate	= ncp_lookup_validate,
 	.d_hash		= ncp_hash_dentry,
 	.d_compare	= ncp_compare_dentry,
@@ -305,6 +309,17 @@ leave_me:;
 }
 #endif	/* CONFIG_NCPFS_STRONG */
 
+static int ncp_d_init(struct dentry *dentry)
+{
+	dentry->d_fsdata = kzalloc(sizeof(struct ncp_dentry), GFP_KERNEL);
+
+	return dentry->d_fsdata ? 0 : -ENOMEM;
+}
+
+static void ncp_d_release(struct dentry *dentry)
+{
+	kfree(dentry->d_fsdata);
+}
 
 static int
 ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
@@ -408,7 +423,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent)
 
 	spin_lock(&parent->d_lock);
 	list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
-		dentry->d_fsdata = NULL;
+		NCP_DENTRY(dentry)->cached = false;
 		ncp_age_dentry(server, dentry);
 	}
 	spin_unlock(&parent->d_lock);
@@ -568,7 +583,7 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx)
 
 static void ncp_d_prune(struct dentry *dentry)
 {
-	if (!dentry->d_fsdata)	/* not referenced from page cache */
+	if (!NCP_DENTRY(dentry)->cached) /* not referenced from page cache */
 		return;
 	NCP_FINFO(d_inode(dentry->d_parent))->flags &= ~NCPI_DIR_CACHE;
 }
@@ -659,7 +674,7 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx,
 	}
 	if (ctl.cache) {
 		if (d_really_is_positive(newdent)) {
-			newdent->d_fsdata = newdent;
+			NCP_DENTRY(newdent)->cached = true;
 			ctl.cache->dentry[ctl.idx] = newdent;
 			ino = d_inode(newdent)->i_ino;
 			ncp_new_dentry(newdent);
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 17cfb743b5bf..76459e4f6b64 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -168,20 +168,30 @@ static inline int ncp_strnicmp(const struct nls_table *t,
 
 #endif /* CONFIG_NCPFS_NLS */
 
-#define NCP_GET_AGE(dentry)	(jiffies - (dentry)->d_time)
+struct ncp_dentry {
+	unsigned long time;
+	bool cached;
+};
+
+static inline struct ncp_dentry *NCP_DENTRY(struct dentry *dentry)
+{
+	return (struct ncp_dentry *) dentry->d_fsdata;
+}
+
+#define NCP_GET_AGE(dentry)	(jiffies - NCP_DENTRY(dentry)->time)
 #define NCP_MAX_AGE(server)	atomic_read(&(server)->dentry_ttl)
 #define NCP_TEST_AGE(server,dentry)	(NCP_GET_AGE(dentry) < NCP_MAX_AGE(server))
 
 static inline void
 ncp_age_dentry(struct ncp_server* server, struct dentry* dentry)
 {
-	dentry->d_time = jiffies - NCP_MAX_AGE(server);
+	NCP_DENTRY(dentry)->time = jiffies - NCP_MAX_AGE(server);
 }
 
 static inline void
 ncp_new_dentry(struct dentry* dentry)
 {
-	dentry->d_time = jiffies;
+	NCP_DENTRY(dentry)->time = jiffies;
 }
 
 struct ncp_cache_head {
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] vfs: remove ->d_time
  2016-11-07 10:51 [RFC/RFT PATCH 0/3] d_time removal Miklos Szeredi
  2016-11-07 10:51 ` [PATCH 1/3] nfs: don't use ->d_time Miklos Szeredi
  2016-11-07 10:51 ` [PATCH 2/3] ncpfs: " Miklos Szeredi
@ 2016-11-07 10:52 ` Miklos Szeredi
  2016-12-07 19:46 ` [RFC/RFT PATCH 0/3] d_time removal Al Viro
  3 siblings, 0 replies; 5+ messages in thread
From: Miklos Szeredi @ 2016-11-07 10:52 UTC (permalink / raw)
  To: Al Viro; +Cc: Trond Myklebust, linux-fsdevel, linux-kernel

Remove dentry->d_time field, which is now unused.  This makes space for
longer inline names.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
---
 include/linux/dcache.h | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 5beed7b30561..0061089099a8 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -69,12 +69,12 @@ extern struct dentry_stat_t dentry_stat;
  * large memory footprint increase).
  */
 #ifdef CONFIG_64BIT
-# define DNAME_INLINE_LEN 32 /* 192 bytes */
+# define DNAME_INLINE_LEN 40 /* 192 bytes */
 #else
 # ifdef CONFIG_SMP
-#  define DNAME_INLINE_LEN 36 /* 128 bytes */
-# else
 #  define DNAME_INLINE_LEN 40 /* 128 bytes */
+# else
+#  define DNAME_INLINE_LEN 44 /* 128 bytes */
 # endif
 #endif
 
@@ -95,7 +95,6 @@ struct dentry {
 	struct lockref d_lockref;	/* per-dentry lock and refcount */
 	const struct dentry_operations *d_op;
 	struct super_block *d_sb;	/* The root of the dentry tree */
-	unsigned long d_time;		/* used by d_revalidate */
 	void *d_fsdata;			/* fs-specific data */
 
 	union {
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [RFC/RFT PATCH 0/3] d_time removal
  2016-11-07 10:51 [RFC/RFT PATCH 0/3] d_time removal Miklos Szeredi
                   ` (2 preceding siblings ...)
  2016-11-07 10:52 ` [PATCH 3/3] vfs: remove ->d_time Miklos Szeredi
@ 2016-12-07 19:46 ` Al Viro
  3 siblings, 0 replies; 5+ messages in thread
From: Al Viro @ 2016-12-07 19:46 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Trond Myklebust, linux-fsdevel, linux-kernel

On Mon, Nov 07, 2016 at 11:51:57AM +0100, Miklos Szeredi wrote:
> Only two filesystems remaining: nfs and ncpfs.  Both use d_fsdata as well
> as d_time which means we have to allocate a separate structure (RCU freed
> in case of NFS).
> 
> I still haven't tested these; hoping someone will do it for me.

I would suggest profiling the NFS part - you are introducing a separate
allocation for every dentry there, which could get unpleasant for something
like dcache seeding in readdir.  Another interesting part is the extra
cachelines accessed in ->d_revalidate().

In principle, getting rid of ->d_time is nice, but the benefits are not
all that impressive - slightly longer embedded names, but how many files
have names between 32 and 40 characters long?
<checks on a fairly large local box>
33 0.201368%
34 0.183738%
35 0.154355%
36 0.133560%
37 0.117422%
38 0.963897%
39 0.083879%
40 0.156796%

IOW, here it's just a bit under 2% - not a lot.  Getting rid of fs-specific
fields in struct dentry per se...  Fine, but that'd better not come at the
cost of appreciable NFS overhead.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-12-07 19:46 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-07 10:51 [RFC/RFT PATCH 0/3] d_time removal Miklos Szeredi
2016-11-07 10:51 ` [PATCH 1/3] nfs: don't use ->d_time Miklos Szeredi
2016-11-07 10:51 ` [PATCH 2/3] ncpfs: " Miklos Szeredi
2016-11-07 10:52 ` [PATCH 3/3] vfs: remove ->d_time Miklos Szeredi
2016-12-07 19:46 ` [RFC/RFT PATCH 0/3] d_time removal Al Viro

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.