linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] vfs: add d_prune dentry operation
@ 2011-07-08 21:10 Sage Weil
  2011-07-26 23:24 ` Sage Weil
  0 siblings, 1 reply; 15+ messages in thread
From: Sage Weil @ 2011-07-08 21:10 UTC (permalink / raw)
  To: linux-fsdevel, linux-kernel

This adds a d_prune dentry operation that is called by the VFS prior to 
pruning (i.e. unhashing and killing) a hashed dentry from the dcache. This 
allows the file system to maintain visibility into the contents and 
consistency of the dcache:

 - dentry eviction/pruning now calls into the fs
 - any modifications (unlink, rename, create, etc.) are protected by 
   i_mutex and call into the fs

This will be used by Ceph to maintain a flag indicating whether the 
complete contents of a directory are contained in the dcache, allowing it 
to satisfy lookups and readdir with cached results without additional 
server communication.

Signed-off-by: Sage Weil <sage@newdream.net>
---
 Documentation/filesystems/Locking |    1 +
 fs/dcache.c                       |    8 ++++++++
 include/linux/dcache.h            |    3 +++
 3 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 57d827d..b3fa7c8 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -29,6 +29,7 @@ d_hash		no		no		no		maybe
 d_compare:	yes		no		no		maybe
 d_delete:	no		yes		no		no
 d_release:	no		no		yes		no
+d_prune:        no              yes             no              no
 d_iput:		no		no		yes		no
 d_dname:	no		no		no		no
 d_automount:	no		no		yes		no
diff --git a/fs/dcache.c b/fs/dcache.c
index 37f72ee..74d1a30 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -673,6 +673,8 @@ static void try_prune_one_dentry(struct dentry *dentry)
 			spin_unlock(&dentry->d_lock);
 			return;
 		}
+		if (dentry->d_flags & DCACHE_OP_PRUNE)
+			dentry->d_op->d_prune(dentry);
 		dentry = dentry_kill(dentry, 1);
 	}
 }
@@ -879,6 +881,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 
 	/* detach this root from the system */
 	spin_lock(&dentry->d_lock);
+	if (dentry->d_flags & DCACHE_OP_PRUNE)
+		dentry->d_op->d_prune(dentry);
 	dentry_lru_del(dentry);
 	__d_drop(dentry);
 	spin_unlock(&dentry->d_lock);
@@ -895,6 +899,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 					    d_u.d_child) {
 				spin_lock_nested(&loop->d_lock,
 						DENTRY_D_LOCK_NESTED);
+				if (dentry->d_flags & DCACHE_OP_PRUNE)
+					dentry->d_op->d_prune(dentry);
 				dentry_lru_del(loop);
 				__d_drop(loop);
 				spin_unlock(&loop->d_lock);
@@ -1363,6 +1369,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
 		dentry->d_flags |= DCACHE_OP_REVALIDATE;
 	if (op->d_delete)
 		dentry->d_flags |= DCACHE_OP_DELETE;
+	if (op->d_prune)
+		dentry->d_flags |= DCACHE_OP_PRUNE;
 
 }
 EXPORT_SYMBOL(d_set_d_op);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 19d90a5..681f46f 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -165,6 +165,7 @@ struct dentry_operations {
 			unsigned int, const char *, const struct qstr *);
 	int (*d_delete)(const struct dentry *);
 	void (*d_release)(struct dentry *);
+	void (*d_prune)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
 	char *(*d_dname)(struct dentry *, char *, int);
 	struct vfsmount *(*d_automount)(struct path *);
@@ -219,6 +220,8 @@ struct dentry_operations {
 #define DCACHE_MANAGED_DENTRY \
 	(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
 
+#define DCACHE_OP_PRUNE         0x80000
+
 extern seqlock_t rename_lock;
 
 static inline int dname_external(struct dentry *dentry)
-- 
1.7.0


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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-07-08 21:10 Sage Weil
@ 2011-07-26 23:24 ` Sage Weil
  0 siblings, 0 replies; 15+ messages in thread
From: Sage Weil @ 2011-07-26 23:24 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel

Hi Al,

Any chance we can get this in 3.1-rc1?  Not being able to use the dcache 
fully isn't doing good things to our metadata performance.

sage



On Fri, 8 Jul 2011, Sage Weil wrote:

> This adds a d_prune dentry operation that is called by the VFS prior to 
> pruning (i.e. unhashing and killing) a hashed dentry from the dcache. This 
> allows the file system to maintain visibility into the contents and 
> consistency of the dcache:
> 
>  - dentry eviction/pruning now calls into the fs
>  - any modifications (unlink, rename, create, etc.) are protected by 
>    i_mutex and call into the fs
> 
> This will be used by Ceph to maintain a flag indicating whether the 
> complete contents of a directory are contained in the dcache, allowing it 
> to satisfy lookups and readdir with cached results without additional 
> server communication.
> 
> Signed-off-by: Sage Weil <sage@newdream.net>
> ---
>  Documentation/filesystems/Locking |    1 +
>  fs/dcache.c                       |    8 ++++++++
>  include/linux/dcache.h            |    3 +++
>  3 files changed, 12 insertions(+), 0 deletions(-)
> 
> diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
> index 57d827d..b3fa7c8 100644
> --- a/Documentation/filesystems/Locking
> +++ b/Documentation/filesystems/Locking
> @@ -29,6 +29,7 @@ d_hash		no		no		no		maybe
>  d_compare:	yes		no		no		maybe
>  d_delete:	no		yes		no		no
>  d_release:	no		no		yes		no
> +d_prune:        no              yes             no              no
>  d_iput:		no		no		yes		no
>  d_dname:	no		no		no		no
>  d_automount:	no		no		yes		no
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 37f72ee..74d1a30 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -673,6 +673,8 @@ static void try_prune_one_dentry(struct dentry *dentry)
>  			spin_unlock(&dentry->d_lock);
>  			return;
>  		}
> +		if (dentry->d_flags & DCACHE_OP_PRUNE)
> +			dentry->d_op->d_prune(dentry);
>  		dentry = dentry_kill(dentry, 1);
>  	}
>  }
> @@ -879,6 +881,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
>  
>  	/* detach this root from the system */
>  	spin_lock(&dentry->d_lock);
> +	if (dentry->d_flags & DCACHE_OP_PRUNE)
> +		dentry->d_op->d_prune(dentry);
>  	dentry_lru_del(dentry);
>  	__d_drop(dentry);
>  	spin_unlock(&dentry->d_lock);
> @@ -895,6 +899,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
>  					    d_u.d_child) {
>  				spin_lock_nested(&loop->d_lock,
>  						DENTRY_D_LOCK_NESTED);
> +				if (dentry->d_flags & DCACHE_OP_PRUNE)
> +					dentry->d_op->d_prune(dentry);
>  				dentry_lru_del(loop);
>  				__d_drop(loop);
>  				spin_unlock(&loop->d_lock);
> @@ -1363,6 +1369,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
>  		dentry->d_flags |= DCACHE_OP_REVALIDATE;
>  	if (op->d_delete)
>  		dentry->d_flags |= DCACHE_OP_DELETE;
> +	if (op->d_prune)
> +		dentry->d_flags |= DCACHE_OP_PRUNE;
>  
>  }
>  EXPORT_SYMBOL(d_set_d_op);
> diff --git a/include/linux/dcache.h b/include/linux/dcache.h
> index 19d90a5..681f46f 100644
> --- a/include/linux/dcache.h
> +++ b/include/linux/dcache.h
> @@ -165,6 +165,7 @@ struct dentry_operations {
>  			unsigned int, const char *, const struct qstr *);
>  	int (*d_delete)(const struct dentry *);
>  	void (*d_release)(struct dentry *);
> +	void (*d_prune)(struct dentry *);
>  	void (*d_iput)(struct dentry *, struct inode *);
>  	char *(*d_dname)(struct dentry *, char *, int);
>  	struct vfsmount *(*d_automount)(struct path *);
> @@ -219,6 +220,8 @@ struct dentry_operations {
>  #define DCACHE_MANAGED_DENTRY \
>  	(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
>  
> +#define DCACHE_OP_PRUNE         0x80000
> +
>  extern seqlock_t rename_lock;
>  
>  static inline int dname_external(struct dentry *dentry)
> -- 
> 1.7.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 

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

* [PATCH] d_prune dentry_operation
@ 2011-10-06  4:26 Sage Weil
  2011-10-06  4:26 ` [PATCH] vfs: add d_prune dentry operation Sage Weil
  0 siblings, 1 reply; 15+ messages in thread
From: Sage Weil @ 2011-10-06  4:26 UTC (permalink / raw)
  To: linux-fsdevel, viro; +Cc: hch, ceph-devel, rwheeler, linux-kernel, Sage Weil

Ceph goes to great lengths to keep its client-side cache coherent, 
allowing many operations (lookup, creations, readdir) to be performed 
without any server interaction when the client has the proper leases. 

Sadly, this functionality is all currently disabled because we cannot 
handle races between dcache pruning and any of those activities with the 
current VFS interface.

This patch adds a d_prune hook that allows the filesystem to be informed 
before a dentry is removed from the cache.  Merging this for 3.2-rc1 
will make Ceph users and their metadata-intensive workload very happy.

If anybody has any issues at all with this, please tell me, so I can 
make my case or revise my approach.

Thanks!
sage


Sage Weil (1):
  vfs: add d_prune dentry operation

 Documentation/filesystems/Locking |    1 +
 fs/dcache.c                       |    8 ++++++++
 include/linux/dcache.h            |    3 +++
 3 files changed, 12 insertions(+), 0 deletions(-)

-- 
1.7.2.5


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

* [PATCH] vfs: add d_prune dentry operation
  2011-10-06  4:26 [PATCH] d_prune dentry_operation Sage Weil
@ 2011-10-06  4:26 ` Sage Weil
  2011-10-06 21:21   ` Christoph Hellwig
  0 siblings, 1 reply; 15+ messages in thread
From: Sage Weil @ 2011-10-06  4:26 UTC (permalink / raw)
  To: linux-fsdevel, viro; +Cc: hch, ceph-devel, rwheeler, linux-kernel, Sage Weil

This adds a d_prune dentry operation that is called by the VFS prior to
pruning (i.e. unhashing and killing) a hashed dentry from the dcache.  This
will be used by Ceph to maintain a flag indicating whether the complete
contents of a directory are contained in the dcache, allowing it to satisfy
lookups and readdir without addition server communication.

Signed-off-by: Sage Weil <sage@newdream.net>
---
 Documentation/filesystems/Locking |    1 +
 fs/dcache.c                       |    8 ++++++++
 include/linux/dcache.h            |    3 +++
 3 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 57d827d..b3fa7c8 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -29,6 +29,7 @@ d_hash		no		no		no		maybe
 d_compare:	yes		no		no		maybe
 d_delete:	no		yes		no		no
 d_release:	no		no		yes		no
+d_prune:        no              yes             no              no
 d_iput:		no		no		yes		no
 d_dname:	no		no		no		no
 d_automount:	no		no		yes		no
diff --git a/fs/dcache.c b/fs/dcache.c
index fbdcbca..84e1756 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -673,6 +673,8 @@ static void try_prune_one_dentry(struct dentry *dentry)
 			spin_unlock(&dentry->d_lock);
 			return;
 		}
+		if (dentry->d_flags & DCACHE_OP_PRUNE)
+			dentry->d_op->d_prune(dentry);
 		dentry = dentry_kill(dentry, 1);
 	}
 }
@@ -879,6 +881,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 
 	/* detach this root from the system */
 	spin_lock(&dentry->d_lock);
+	if (dentry->d_flags & DCACHE_OP_PRUNE)
+		dentry->d_op->d_prune(dentry);
 	dentry_lru_del(dentry);
 	__d_drop(dentry);
 	spin_unlock(&dentry->d_lock);
@@ -895,6 +899,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 					    d_u.d_child) {
 				spin_lock_nested(&loop->d_lock,
 						DENTRY_D_LOCK_NESTED);
+				if (dentry->d_flags & DCACHE_OP_PRUNE)
+					dentry->d_op->d_prune(dentry);
 				dentry_lru_del(loop);
 				__d_drop(loop);
 				spin_unlock(&loop->d_lock);
@@ -1363,6 +1369,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
 		dentry->d_flags |= DCACHE_OP_REVALIDATE;
 	if (op->d_delete)
 		dentry->d_flags |= DCACHE_OP_DELETE;
+	if (op->d_prune)
+		dentry->d_flags |= DCACHE_OP_PRUNE;
 
 }
 EXPORT_SYMBOL(d_set_d_op);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 19d90a5..681f46f 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -165,6 +165,7 @@ struct dentry_operations {
 			unsigned int, const char *, const struct qstr *);
 	int (*d_delete)(const struct dentry *);
 	void (*d_release)(struct dentry *);
+	void (*d_prune)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
 	char *(*d_dname)(struct dentry *, char *, int);
 	struct vfsmount *(*d_automount)(struct path *);
@@ -219,6 +220,8 @@ struct dentry_operations {
 #define DCACHE_MANAGED_DENTRY \
 	(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
 
+#define DCACHE_OP_PRUNE         0x80000
+
 extern seqlock_t rename_lock;
 
 static inline int dname_external(struct dentry *dentry)
-- 
1.7.2.5


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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-06  4:26 ` [PATCH] vfs: add d_prune dentry operation Sage Weil
@ 2011-10-06 21:21   ` Christoph Hellwig
  2011-10-06 22:20     ` Sage Weil
  0 siblings, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2011-10-06 21:21 UTC (permalink / raw)
  To: Sage Weil; +Cc: linux-fsdevel, viro, hch, ceph-devel, rwheeler, linux-kernel

On Wed, Oct 05, 2011 at 09:26:10PM -0700, Sage Weil wrote:
> This adds a d_prune dentry operation that is called by the VFS prior to
> pruning (i.e. unhashing and killing) a hashed dentry from the dcache.  This
> will be used by Ceph to maintain a flag indicating whether the complete
> contents of a directory are contained in the dcache, allowing it to satisfy
> lookups and readdir without addition server communication.

What tree is the patch against?  I seems to fail to apply against Linus'
latests.  

It also seem like it basically should not be be opencoded but in a
wrapper around dentry_lru_del for all cases but the lazy removal from
LRU in case that is referenced, with some comments explaining the whole
thing.


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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-06 21:21   ` Christoph Hellwig
@ 2011-10-06 22:20     ` Sage Weil
  2011-10-09 13:21       ` Christoph Hellwig
  2011-10-10  5:11       ` Dave Chinner
  0 siblings, 2 replies; 15+ messages in thread
From: Sage Weil @ 2011-10-06 22:20 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-fsdevel, viro, ceph-devel, rwheeler, linux-kernel

On Thu, 6 Oct 2011, Christoph Hellwig wrote:
> On Wed, Oct 05, 2011 at 09:26:10PM -0700, Sage Weil wrote:
> > This adds a d_prune dentry operation that is called by the VFS prior to
> > pruning (i.e. unhashing and killing) a hashed dentry from the dcache.  This
> > will be used by Ceph to maintain a flag indicating whether the complete
> > contents of a directory are contained in the dcache, allowing it to satisfy
> > lookups and readdir without addition server communication.
> 
> What tree is the patch against?  I seems to fail to apply against Linus'
> latests.  

Whoops, I rebased against v3.0 instead of latest master.

> It also seem like it basically should not be be opencoded but in a
> wrapper around dentry_lru_del for all cases but the lazy removal from
> LRU in case that is referenced, with some comments explaining the whole
> thing.

Yeah, that's a bit better.  There are four dentry_lru_del() callers, two 
where we there is a reference, and two where we want to ->d_prune too.

How does the below look?

Thanks!
sage


>From 182e20331b9b2be15dbecdff7465be26ac00a81c Mon Sep 17 00:00:00 2001
From: Sage Weil <sage@newdream.net>
Date: Thu, 6 Oct 2011 15:18:21 -0700
Subject: [PATCH] vfs: add d_prune dentry operation

This adds a d_prune dentry operation that is called by the VFS prior to
pruning (i.e. unhashing and killing) a hashed dentry from the dcache.
Wrap dentry_lru_del() and use the new _prune() helper in the cases where we
are about to unhash and kill the dentry.

This will be used by Ceph to maintain a flag indicating whether the
complete contents of a directory are contained in the dcache, allowing it
to satisfy lookups and readdir without addition server communication.

Signed-off-by: Sage Weil <sage@newdream.net>
---
 Documentation/filesystems/Locking |    1 +
 fs/dcache.c                       |   33 ++++++++++++++++++++++++++++-----
 include/linux/dcache.h            |    3 +++
 3 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 6533807..d819ba1 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -29,6 +29,7 @@ d_hash		no		no		no		maybe
 d_compare:	yes		no		no		maybe
 d_delete:	no		yes		no		no
 d_release:	no		no		yes		no
+d_prune:        no              yes             no              no
 d_iput:		no		no		yes		no
 d_dname:	no		no		no		no
 d_automount:	no		no		yes		no
diff --git a/fs/dcache.c b/fs/dcache.c
index a88948b..a348f64 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -225,7 +225,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
 }
 
 /*
- * dentry_lru_(add|del|move_tail) must be called with d_lock held.
+ * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held.
  */
 static void dentry_lru_add(struct dentry *dentry)
 {
@@ -254,6 +254,24 @@ static void dentry_lru_del(struct dentry *dentry)
 	}
 }
 
+static void dentry_lru_prune(struct dentry *dentry)
+{
+	if (!list_empty(&dentry->d_lru)) {
+		/*
+		 * Notify the fs this dentry is about to be pruned
+		 * before removing from the LRU.  This should happen
+		 * before we unhash it (if it was hashed to begin
+		 * with).
+		 */
+		if (dentry->d_flags & DCACHE_OP_PRUNE)
+			dentry->d_op->d_prune(dentry);
+
+		spin_lock(&dcache_lru_lock);
+		__dentry_lru_del(dentry);
+		spin_unlock(&dcache_lru_lock);
+	}
+}
+
 static void dentry_lru_move_tail(struct dentry *dentry)
 {
 	spin_lock(&dcache_lru_lock);
@@ -403,8 +421,11 @@ relock:
 
 	if (ref)
 		dentry->d_count--;
-	/* if dentry was on the d_lru list delete it from there */
-	dentry_lru_del(dentry);
+	/*
+	 * if dentry was on the d_lru list delete it from there and
+	 * inform the fs via d_prune.
+	 */
+	dentry_lru_prune(dentry);
 	/* if it was on the hash then remove it */
 	__d_drop(dentry);
 	return d_kill(dentry, parent);
@@ -854,8 +875,8 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 		do {
 			struct inode *inode;
 
-			/* detach from the system */
-			dentry_lru_del(dentry);
+			/* detach from the system, inform the fs via d_prune */
+			dentry_lru_prune(dentry);
 			__d_shrink(dentry);
 
 			if (dentry->d_count != 0) {
@@ -1283,6 +1304,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
 		dentry->d_flags |= DCACHE_OP_REVALIDATE;
 	if (op->d_delete)
 		dentry->d_flags |= DCACHE_OP_DELETE;
+	if (op->d_prune)
+		dentry->d_flags |= DCACHE_OP_PRUNE;
 
 }
 EXPORT_SYMBOL(d_set_d_op);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 62157c0..69ee43a 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -165,6 +165,7 @@ struct dentry_operations {
 			unsigned int, const char *, const struct qstr *);
 	int (*d_delete)(const struct dentry *);
 	void (*d_release)(struct dentry *);
+	void (*d_prune)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
 	char *(*d_dname)(struct dentry *, char *, int);
 	struct vfsmount *(*d_automount)(struct path *);
@@ -216,6 +217,8 @@ struct dentry_operations {
 #define DCACHE_MANAGED_DENTRY \
 	(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
 
+#define DCACHE_OP_PRUNE         0x80000
+
 extern seqlock_t rename_lock;
 
 static inline int dname_external(struct dentry *dentry)
-- 
1.7.0


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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-06 22:20     ` Sage Weil
@ 2011-10-09 13:21       ` Christoph Hellwig
  2011-10-10  5:11       ` Dave Chinner
  1 sibling, 0 replies; 15+ messages in thread
From: Christoph Hellwig @ 2011-10-09 13:21 UTC (permalink / raw)
  To: Sage Weil
  Cc: Christoph Hellwig, linux-fsdevel, viro, ceph-devel, rwheeler,
	linux-kernel, Dave Chinner

On Thu, Oct 06, 2011 at 03:20:37PM -0700, Sage Weil wrote:
> > It also seem like it basically should not be be opencoded but in a
> > wrapper around dentry_lru_del for all cases but the lazy removal from
> > LRU in case that is referenced, with some comments explaining the whole
> > thing.
> 
> Yeah, that's a bit better.  There are four dentry_lru_del() callers, two 
> where we there is a reference, and two where we want to ->d_prune too.
> 
> How does the below look?

This looks much better.

It will clash a bit with Dave's dcache series that were part of his
shrinker/lru series, which I really hope he is going to resumit for
3.2 (at least the dcache cleanup parts).

Al, any progress on getting the current VFS queue up somewhere for
review?

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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-06 22:20     ` Sage Weil
  2011-10-09 13:21       ` Christoph Hellwig
@ 2011-10-10  5:11       ` Dave Chinner
  2011-10-10 11:23         ` Christoph Hellwig
  2011-10-10 16:19         ` Sage Weil
  1 sibling, 2 replies; 15+ messages in thread
From: Dave Chinner @ 2011-10-10  5:11 UTC (permalink / raw)
  To: Sage Weil
  Cc: Christoph Hellwig, linux-fsdevel, viro, ceph-devel, rwheeler,
	linux-kernel

On Thu, Oct 06, 2011 at 03:20:37PM -0700, Sage Weil wrote:
> On Thu, 6 Oct 2011, Christoph Hellwig wrote:
> > On Wed, Oct 05, 2011 at 09:26:10PM -0700, Sage Weil wrote:
> > > This adds a d_prune dentry operation that is called by the VFS prior to
> > > pruning (i.e. unhashing and killing) a hashed dentry from the dcache.  This
> > > will be used by Ceph to maintain a flag indicating whether the complete
> > > contents of a directory are contained in the dcache, allowing it to satisfy
> > > lookups and readdir without addition server communication.
> > 
> > What tree is the patch against?  I seems to fail to apply against Linus'
> > latests.  
> 
> Whoops, I rebased against v3.0 instead of latest master.
> 
> > It also seem like it basically should not be be opencoded but in a
> > wrapper around dentry_lru_del for all cases but the lazy removal from
> > LRU in case that is referenced, with some comments explaining the whole
> > thing.
> 
> Yeah, that's a bit better.  There are four dentry_lru_del() callers, two 
> where we there is a reference, and two where we want to ->d_prune too.

The code in the patch doesn't explain to me why you'd need to call
dentry_lru_prune() rather than dentry_lru_del()? It's something to
do with the difference between active and inactive LRU removal, but
I can't really tell. My patchset removes the LRU abuse from
select_parent, so I'm kind of wondering what the correct thing is to
do there. 

Hence, can you add a bit of documentation to those functions
explaining why and when you should use one or the other?  i.e
document the situations where the FS needs to be notified of
pruning, rather than leaving anyone who is reading the code
guessing.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-10  5:11       ` Dave Chinner
@ 2011-10-10 11:23         ` Christoph Hellwig
  2011-10-10 16:19         ` Sage Weil
  1 sibling, 0 replies; 15+ messages in thread
From: Christoph Hellwig @ 2011-10-10 11:23 UTC (permalink / raw)
  To: Dave Chinner
  Cc: Sage Weil, Christoph Hellwig, linux-fsdevel, viro, ceph-devel,
	rwheeler, linux-kernel

On Mon, Oct 10, 2011 at 04:11:41PM +1100, Dave Chinner wrote:
> The code in the patch doesn't explain to me why you'd need to call
> dentry_lru_prune() rather than dentry_lru_del()? It's something to
> do with the difference between active and inactive LRU removal, but

Whenever we actually remove a object it needs to be removed, if it
only gets deleted from the LRU because it now has a reference and
doesn't belong onto the LRU it doesn't.

But yes, this really should be documented better in the code.

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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-10  5:11       ` Dave Chinner
  2011-10-10 11:23         ` Christoph Hellwig
@ 2011-10-10 16:19         ` Sage Weil
  2011-10-10 16:21           ` Christoph Hellwig
  2011-10-28 12:16           ` Christoph Hellwig
  1 sibling, 2 replies; 15+ messages in thread
From: Sage Weil @ 2011-10-10 16:19 UTC (permalink / raw)
  To: Dave Chinner
  Cc: Christoph Hellwig, linux-fsdevel, viro, ceph-devel, rwheeler,
	linux-kernel

On Mon, 10 Oct 2011, Dave Chinner wrote:
> On Thu, Oct 06, 2011 at 03:20:37PM -0700, Sage Weil wrote:
> > On Thu, 6 Oct 2011, Christoph Hellwig wrote:
> > > On Wed, Oct 05, 2011 at 09:26:10PM -0700, Sage Weil wrote:
> > > > This adds a d_prune dentry operation that is called by the VFS prior to
> > > > pruning (i.e. unhashing and killing) a hashed dentry from the dcache.  This
> > > > will be used by Ceph to maintain a flag indicating whether the complete
> > > > contents of a directory are contained in the dcache, allowing it to satisfy
> > > > lookups and readdir without addition server communication.
> > > 
> > > What tree is the patch against?  I seems to fail to apply against Linus'
> > > latests.  
> > 
> > Whoops, I rebased against v3.0 instead of latest master.
> > 
> > > It also seem like it basically should not be be opencoded but in a
> > > wrapper around dentry_lru_del for all cases but the lazy removal from
> > > LRU in case that is referenced, with some comments explaining the whole
> > > thing.
> > 
> > Yeah, that's a bit better.  There are four dentry_lru_del() callers, two 
> > where we there is a reference, and two where we want to ->d_prune too.
> 
> The code in the patch doesn't explain to me why you'd need to call
> dentry_lru_prune() rather than dentry_lru_del()? It's something to
> do with the difference between active and inactive LRU removal, but
> I can't really tell. My patchset removes the LRU abuse from
> select_parent, so I'm kind of wondering what the correct thing is to
> do there. 
> 
> Hence, can you add a bit of documentation to those functions
> explaining why and when you should use one or the other?  i.e
> document the situations where the FS needs to be notified of
> pruning, rather than leaving anyone who is reading the code
> guessing.

Let me know if the below is clearer.  The requirement is that ->d_prune be 
called prior to unhashing (and then destroying) a victim dentry.  I'm a 
little worried about mixing that in with the lru helpers because it is 
only indirectly related to whether the dentry is on the LRU, and that may 
confuse people.  A cleaned up opencoded patch is here:

	https://github.com/NewDreamNetwork/ceph-client/commit/784a6aa6dc7baf2069c40988d79130dba17c7068

and the updated dentry_lru_prune() wrapper version is below.

Thanks-
sage



>From 619707e0b6fca69f165d1d4f048ab8211531d559 Mon Sep 17 00:00:00 2001
From: Sage Weil <sage@newdream.net>
Date: Mon, 10 Oct 2011 09:18:16 -0700
Subject: [PATCH] vfs: add d_prune dentry operation

This adds a d_prune dentry operation that is called by the VFS prior to
pruning (i.e. unhashing and killing) a hashed dentry from the dcache.
Wrap dentry_lru_del() and use the new _prune() helper in the cases where we
are about to unhash and kill the dentry.

This will be used by Ceph to maintain a flag indicating whether the
complete contents of a directory are contained in the dcache, allowing it
to satisfy lookups and readdir without addition server communication.

Signed-off-by: Sage Weil <sage@newdream.net>
---
 Documentation/filesystems/Locking |    1 +
 fs/dcache.c                       |   40 ++++++++++++++++++++++++++++++++----
 include/linux/dcache.h            |    3 ++
 3 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 6533807..d819ba1 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -29,6 +29,7 @@ d_hash		no		no		no		maybe
 d_compare:	yes		no		no		maybe
 d_delete:	no		yes		no		no
 d_release:	no		no		yes		no
+d_prune:        no              yes             no              no
 d_iput:		no		no		yes		no
 d_dname:	no		no		no		no
 d_automount:	no		no		yes		no
diff --git a/fs/dcache.c b/fs/dcache.c
index a88948b..274f13e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -225,7 +225,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
 }
 
 /*
- * dentry_lru_(add|del|move_tail) must be called with d_lock held.
+ * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held.
  */
 static void dentry_lru_add(struct dentry *dentry)
 {
@@ -245,6 +245,9 @@ static void __dentry_lru_del(struct dentry *dentry)
 	dentry_stat.nr_unused--;
 }
 
+/*
+ * Remove a dentry with references from the LRU.
+ */
 static void dentry_lru_del(struct dentry *dentry)
 {
 	if (!list_empty(&dentry->d_lru)) {
@@ -254,6 +257,23 @@ static void dentry_lru_del(struct dentry *dentry)
 	}
 }
 
+/*
+ * Remove a dentry that is unreferenced and about to be pruned
+ * (unhashed and destroyed) from the LRU, and inform the file system.
+ * This wrapper should be called _prior_ to unhashing a victim dentry.
+ */
+static void dentry_lru_prune(struct dentry *dentry)
+{
+	if (!list_empty(&dentry->d_lru)) {
+		if (dentry->d_flags & DCACHE_OP_PRUNE)
+			dentry->d_op->d_prune(dentry);
+
+		spin_lock(&dcache_lru_lock);
+		__dentry_lru_del(dentry);
+		spin_unlock(&dcache_lru_lock);
+	}
+}
+
 static void dentry_lru_move_tail(struct dentry *dentry)
 {
 	spin_lock(&dcache_lru_lock);
@@ -403,8 +423,12 @@ relock:
 
 	if (ref)
 		dentry->d_count--;
-	/* if dentry was on the d_lru list delete it from there */
-	dentry_lru_del(dentry);
+	/*
+	 * if dentry was on the d_lru list delete it from there.
+	 * inform the fs via d_prune that this dentry is about to be
+	 * unhashed and destroyed.
+	 */
+	dentry_lru_prune(dentry);
 	/* if it was on the hash then remove it */
 	__d_drop(dentry);
 	return d_kill(dentry, parent);
@@ -854,8 +878,12 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 		do {
 			struct inode *inode;
 
-			/* detach from the system */
-			dentry_lru_del(dentry);
+			/*
+			 * remove the dentry from the lru, and inform
+			 * the fs that this dentry is about to be
+			 * unhashed and destroyed.
+			 */
+			dentry_lru_prune(dentry);
 			__d_shrink(dentry);
 
 			if (dentry->d_count != 0) {
@@ -1283,6 +1311,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
 		dentry->d_flags |= DCACHE_OP_REVALIDATE;
 	if (op->d_delete)
 		dentry->d_flags |= DCACHE_OP_DELETE;
+	if (op->d_prune)
+		dentry->d_flags |= DCACHE_OP_PRUNE;
 
 }
 EXPORT_SYMBOL(d_set_d_op);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 62157c0..69ee43a 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -165,6 +165,7 @@ struct dentry_operations {
 			unsigned int, const char *, const struct qstr *);
 	int (*d_delete)(const struct dentry *);
 	void (*d_release)(struct dentry *);
+	void (*d_prune)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
 	char *(*d_dname)(struct dentry *, char *, int);
 	struct vfsmount *(*d_automount)(struct path *);
@@ -216,6 +217,8 @@ struct dentry_operations {
 #define DCACHE_MANAGED_DENTRY \
 	(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
 
+#define DCACHE_OP_PRUNE         0x80000
+
 extern seqlock_t rename_lock;
 
 static inline int dname_external(struct dentry *dentry)
-- 
1.7.0


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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-10 16:19         ` Sage Weil
@ 2011-10-10 16:21           ` Christoph Hellwig
  2011-10-11 15:39             ` Sage Weil
  2011-10-28 12:16           ` Christoph Hellwig
  1 sibling, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2011-10-10 16:21 UTC (permalink / raw)
  To: Sage Weil
  Cc: Dave Chinner, Christoph Hellwig, linux-fsdevel, viro, ceph-devel,
	rwheeler, linux-kernel

On Mon, Oct 10, 2011 at 09:19:43AM -0700, Sage Weil wrote:
> Let me know if the below is clearer.  The requirement is that ->d_prune be 
> called prior to unhashing (and then destroying) a victim dentry.  I'm a 
> little worried about mixing that in with the lru helpers because it is 
> only indirectly related to whether the dentry is on the LRU, and that may 
> confuse people.  A cleaned up opencoded patch is here:
> 
> 	https://github.com/NewDreamNetwork/ceph-client/commit/784a6aa6dc7baf2069c40988d79130dba17c7068
> 
> and the updated dentry_lru_prune() wrapper version is below.

Long term what I really want is a helper for doing more of the real
removal in single place.  This is one step towards it, and the series
from Dave is another.


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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-10 16:21           ` Christoph Hellwig
@ 2011-10-11 15:39             ` Sage Weil
  2011-10-11 21:56               ` Dave Chinner
  0 siblings, 1 reply; 15+ messages in thread
From: Sage Weil @ 2011-10-11 15:39 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Dave Chinner, linux-fsdevel, viro, ceph-devel, rwheeler,
	linux-kernel

On Mon, 10 Oct 2011, Christoph Hellwig wrote:
> On Mon, Oct 10, 2011 at 09:19:43AM -0700, Sage Weil wrote:
> > Let me know if the below is clearer.  The requirement is that ->d_prune be 
> > called prior to unhashing (and then destroying) a victim dentry.  I'm a 
> > little worried about mixing that in with the lru helpers because it is 
> > only indirectly related to whether the dentry is on the LRU, and that may 
> > confuse people.  A cleaned up opencoded patch is here:
> > 
> > 	https://github.com/NewDreamNetwork/ceph-client/commit/784a6aa6dc7baf2069c40988d79130dba17c7068
> > 
> > and the updated dentry_lru_prune() wrapper version is below.
> 
> Long term what I really want is a helper for doing more of the real
> removal in single place.  This is one step towards it, and the series
> from Dave is another.

Ah, makes sense.

Dave, is the revised patch more clear?  

sage


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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-11 15:39             ` Sage Weil
@ 2011-10-11 21:56               ` Dave Chinner
  0 siblings, 0 replies; 15+ messages in thread
From: Dave Chinner @ 2011-10-11 21:56 UTC (permalink / raw)
  To: Sage Weil
  Cc: Christoph Hellwig, linux-fsdevel, viro, ceph-devel, rwheeler,
	linux-kernel

On Tue, Oct 11, 2011 at 08:39:24AM -0700, Sage Weil wrote:
> On Mon, 10 Oct 2011, Christoph Hellwig wrote:
> > On Mon, Oct 10, 2011 at 09:19:43AM -0700, Sage Weil wrote:
> > > Let me know if the below is clearer.  The requirement is that ->d_prune be 
> > > called prior to unhashing (and then destroying) a victim dentry.  I'm a 
> > > little worried about mixing that in with the lru helpers because it is 
> > > only indirectly related to whether the dentry is on the LRU, and that may 
> > > confuse people.  A cleaned up opencoded patch is here:
> > > 
> > > 	https://github.com/NewDreamNetwork/ceph-client/commit/784a6aa6dc7baf2069c40988d79130dba17c7068
> > > 
> > > and the updated dentry_lru_prune() wrapper version is below.
> > 
> > Long term what I really want is a helper for doing more of the real
> > removal in single place.  This is one step towards it, and the series
> > from Dave is another.
> 
> Ah, makes sense.
> 
> Dave, is the revised patch more clear?  

Yeah, I kind of understand what it is doing now, and the comments
will remind me when I start digging in this code again. Thanks.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-10 16:19         ` Sage Weil
  2011-10-10 16:21           ` Christoph Hellwig
@ 2011-10-28 12:16           ` Christoph Hellwig
  2011-10-28 17:02             ` Sage Weil
  1 sibling, 1 reply; 15+ messages in thread
From: Christoph Hellwig @ 2011-10-28 12:16 UTC (permalink / raw)
  To: Sage Weil
  Cc: Dave Chinner, Christoph Hellwig, linux-fsdevel, viro, ceph-devel,
	rwheeler, linux-kernel

This variant seems to crash btrfs in xfstests 010:

010 0s ... 0s
[ 8093.504387] BUG: unable to handle kernel NULL pointer dereference at (null)
[ 8093.505618] IP: [<          (null)>]           (null)
[ 8093.505930] PGD 196f5067 PUD 5507d067 PMD 0 
[ 8093.505930] Oops: 0010 [#1] SMP 
[ 8093.505930] CPU 0 
[ 8093.505930] Modules linked in:
[ 8093.505930] 
[ 8093.505930] Pid: 26328, comm: umount Not tainted 3.1.0+ #90 Bochs Bochs
[ 8093.505930] RIP: 0010:[<0000000000000000>]  [<          (null)>] (null)
[ 8093.505930] RSP: 0018:ffff880009f63dc0  EFLAGS: 00010206
[ 8093.505930] RAX: ffffffff81ae7780 RBX: ffff88002b93a840 RCX: 000000010023ad06
[ 8093.505930] RDX: ffff88002b93a8e0 RSI: ffffffff8114fef0 RDI: ffff88002b93a840
[ 8093.505930] RBP: ffff880009f63dd8 R08: 0000000000000000 R09: 002dffe1ea51a56d
[ 8093.505930] R10: ffff880058c7f680 R11: 0000000000000004 R12: ffff88002b93a8c0
[ 8093.505930] R13: 0000000000000000 R14: ffff88005a56d0c0 R15: ffff88001a896000
[ 8093.505930] FS:  0000000000000000(0000) GS:ffff88005d800000(0063) knlGS:00000000f75c6700
[ 8093.505930] CS:  0010 DS: 002b ES: 002b CR0: 0000000080050033
[ 8093.505930] CR2: 0000000000000000 CR3: 0000000041ddc000 CR4: 00000000000006f0
[ 8093.505930] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 8093.505930] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 8093.505930] Process umount (pid: 26328, threadinfo ffff880009f62000, task ffff88003abd6500)
[ 8093.505930] Stack:
[ 8093.505930]  ffffffff8114efb7 ffff88002b93a840 ffff88005a3c4500 ffff880009f63e08
[ 8093.505930]  ffffffff811516ea ffff880009f63f08 0000000000000000 ffff88001a896000
[ 8093.505930]  ffffffff81ae40c0 ffff880009f63e28 ffffffff8115192e ffff880009f63e38
[ 8093.505930] Call Trace:
[ 8093.505930]  [<ffffffff8114efb7>] ? dentry_lru_prune+0x87/0x90
[ 8093.505930]  [<ffffffff811516ea>] shrink_dcache_for_umount_subtree+0x7a/0x1e0
[ 8093.505930]  [<ffffffff8115192e>] shrink_dcache_for_umount+0x2e/0x60
[ 8093.505930]  [<ffffffff8113d977>] generic_shutdown_super+0x27/0xd0
[ 8093.505930]  [<ffffffff8113dab1>] kill_anon_super+0x11/0x20
[ 8093.505930]  [<ffffffff8113de25>] deactivate_locked_super+0x45/0x70
[ 8093.505930]  [<ffffffff8113e7e9>] deactivate_super+0x49/0x70
[ 8093.505930]  [<ffffffff81157f7b>] mntput_no_expire+0xab/0xf0
[ 8093.505930]  [<ffffffff81158c1a>] sys_umount+0x6a/0x360
[ 8093.505930]  [<ffffffff81158f1b>] sys_oldumount+0xb/0x10
[ 8093.505930]  [<ffffffff819e2f05>] sysenter_dispatch+0x7/0x2b
[ 8093.505930] Code:  Bad RIP value.
[ 8093.505930] RIP  [<          (null)>]           (null)

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

* Re: [PATCH] vfs: add d_prune dentry operation
  2011-10-28 12:16           ` Christoph Hellwig
@ 2011-10-28 17:02             ` Sage Weil
  0 siblings, 0 replies; 15+ messages in thread
From: Sage Weil @ 2011-10-28 17:02 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Dave Chinner, linux-fsdevel, viro, ceph-devel, rwheeler,
	linux-kernel

On Fri, 28 Oct 2011, Christoph Hellwig wrote:
> This variant seems to crash btrfs in xfstests 010:

This got rebased enough times that DCACHE_OP_PRUNE collided with 
DCACHE_NEEDS_LOOKUP.  The version below fixes that, and also renumbers a 
few of those constants to group it with the other DCACHE_OP_* guys.  I 
assume it's okay to switch those up?

sage


>From 2c39148ba12ce13442d66319f9d1ba91ce62974d Mon Sep 17 00:00:00 2001
From: Sage Weil <sage@newdream.net>
Date: Fri, 28 Oct 2011 09:55:21 -0700
Subject: [PATCH] vfs: add d_prune dentry operation

This adds a d_prune dentry operation that is called by the VFS prior to
pruning (i.e. unhashing and killing) a hashed dentry from the dcache.
Wrap dentry_lru_del() and use the new _prune() helper in the cases where we
are about to unhash and kill the dentry.

This will be used by Ceph to maintain a flag indicating whether the
complete contents of a directory are contained in the dcache, allowing it
to satisfy lookups and readdir without addition server communication.

Renumber a few DCACHE_* #defines to group DCACHE_OP_PRUNE with the other
DCACHE_OP_ bits.

Signed-off-by: Sage Weil <sage@newdream.net>
---

v4: fixed DCACHE_OP_PRUNE collision with DCACHE_NEEDS_LOOKUP.
v3: better comments for dentry_lru_{del,prune}
v2: move prune call into dentry_lru_prune() wrapper

 Documentation/filesystems/Locking |    1 +
 fs/dcache.c                       |   40 ++++++++++++++++++++++++++++++++----
 include/linux/dcache.h            |    8 ++++--
 3 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 6533807..d819ba1 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -29,6 +29,7 @@ d_hash		no		no		no		maybe
 d_compare:	yes		no		no		maybe
 d_delete:	no		yes		no		no
 d_release:	no		no		yes		no
+d_prune:        no              yes             no              no
 d_iput:		no		no		yes		no
 d_dname:	no		no		no		no
 d_automount:	no		no		yes		no
diff --git a/fs/dcache.c b/fs/dcache.c
index a88948b..274f13e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -225,7 +225,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
 }
 
 /*
- * dentry_lru_(add|del|move_tail) must be called with d_lock held.
+ * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held.
  */
 static void dentry_lru_add(struct dentry *dentry)
 {
@@ -245,6 +245,9 @@ static void __dentry_lru_del(struct dentry *dentry)
 	dentry_stat.nr_unused--;
 }
 
+/*
+ * Remove a dentry with references from the LRU.
+ */
 static void dentry_lru_del(struct dentry *dentry)
 {
 	if (!list_empty(&dentry->d_lru)) {
@@ -254,6 +257,23 @@ static void dentry_lru_del(struct dentry *dentry)
 	}
 }
 
+/*
+ * Remove a dentry that is unreferenced and about to be pruned
+ * (unhashed and destroyed) from the LRU, and inform the file system.
+ * This wrapper should be called _prior_ to unhashing a victim dentry.
+ */
+static void dentry_lru_prune(struct dentry *dentry)
+{
+	if (!list_empty(&dentry->d_lru)) {
+		if (dentry->d_flags & DCACHE_OP_PRUNE)
+			dentry->d_op->d_prune(dentry);
+
+		spin_lock(&dcache_lru_lock);
+		__dentry_lru_del(dentry);
+		spin_unlock(&dcache_lru_lock);
+	}
+}
+
 static void dentry_lru_move_tail(struct dentry *dentry)
 {
 	spin_lock(&dcache_lru_lock);
@@ -403,8 +423,12 @@ relock:
 
 	if (ref)
 		dentry->d_count--;
-	/* if dentry was on the d_lru list delete it from there */
-	dentry_lru_del(dentry);
+	/*
+	 * if dentry was on the d_lru list delete it from there.
+	 * inform the fs via d_prune that this dentry is about to be
+	 * unhashed and destroyed.
+	 */
+	dentry_lru_prune(dentry);
 	/* if it was on the hash then remove it */
 	__d_drop(dentry);
 	return d_kill(dentry, parent);
@@ -854,8 +878,12 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
 		do {
 			struct inode *inode;
 
-			/* detach from the system */
-			dentry_lru_del(dentry);
+			/*
+			 * remove the dentry from the lru, and inform
+			 * the fs that this dentry is about to be
+			 * unhashed and destroyed.
+			 */
+			dentry_lru_prune(dentry);
 			__d_shrink(dentry);
 
 			if (dentry->d_count != 0) {
@@ -1283,6 +1311,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
 		dentry->d_flags |= DCACHE_OP_REVALIDATE;
 	if (op->d_delete)
 		dentry->d_flags |= DCACHE_OP_DELETE;
+	if (op->d_prune)
+		dentry->d_flags |= DCACHE_OP_PRUNE;
 
 }
 EXPORT_SYMBOL(d_set_d_op);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 62157c0..4df9261 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -165,6 +165,7 @@ struct dentry_operations {
 			unsigned int, const char *, const struct qstr *);
 	int (*d_delete)(const struct dentry *);
 	void (*d_release)(struct dentry *);
+	void (*d_prune)(struct dentry *);
 	void (*d_iput)(struct dentry *, struct inode *);
 	char *(*d_dname)(struct dentry *, char *, int);
 	struct vfsmount *(*d_automount)(struct path *);
@@ -184,8 +185,9 @@ struct dentry_operations {
 #define DCACHE_OP_COMPARE	0x0002
 #define DCACHE_OP_REVALIDATE	0x0004
 #define DCACHE_OP_DELETE	0x0008
+#define DCACHE_OP_PRUNE         0x0010
 
-#define	DCACHE_DISCONNECTED	0x0010
+#define	DCACHE_DISCONNECTED	0x0020
      /* This dentry is possibly not currently connected to the dcache tree, in
       * which case its parent will either be itself, or will have this flag as
       * well.  nfsd will not use a dentry with this bit set, but will first
@@ -196,8 +198,8 @@ struct dentry_operations {
       * dentry into place and return that dentry rather than the passed one,
       * typically using d_splice_alias. */
 
-#define DCACHE_REFERENCED	0x0020  /* Recently used, don't discard. */
-#define DCACHE_RCUACCESS	0x0040	/* Entry has ever been RCU-visible */
+#define DCACHE_REFERENCED	0x0040  /* Recently used, don't discard. */
+#define DCACHE_RCUACCESS	0x0080	/* Entry has ever been RCU-visible */
 
 #define DCACHE_CANT_MOUNT	0x0100
 #define DCACHE_GENOCIDE		0x0200
-- 
1.7.0


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

end of thread, other threads:[~2011-10-28 17:02 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-06  4:26 [PATCH] d_prune dentry_operation Sage Weil
2011-10-06  4:26 ` [PATCH] vfs: add d_prune dentry operation Sage Weil
2011-10-06 21:21   ` Christoph Hellwig
2011-10-06 22:20     ` Sage Weil
2011-10-09 13:21       ` Christoph Hellwig
2011-10-10  5:11       ` Dave Chinner
2011-10-10 11:23         ` Christoph Hellwig
2011-10-10 16:19         ` Sage Weil
2011-10-10 16:21           ` Christoph Hellwig
2011-10-11 15:39             ` Sage Weil
2011-10-11 21:56               ` Dave Chinner
2011-10-28 12:16           ` Christoph Hellwig
2011-10-28 17:02             ` Sage Weil
  -- strict thread matches above, loose matches on Subject: below --
2011-07-08 21:10 Sage Weil
2011-07-26 23:24 ` Sage Weil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).