From 62f1ff1e18b911651502364dda66f8ca8497b71b Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 28 Oct 2011 10:02:42 -0700 Subject: [PATCH] --- yaml --- r: 273199 b: refs/heads/master c: f0023bc617ba600956b9226f1806033d7486c8ba h: refs/heads/master i: 273197: 71edb7166ca77963fb63a665c6b4943f643326ab 273195: c1d719456d10670e062ed70766be84b71ae81ede 273191: 1faedc6387d9a5ddef532f4c60cb0ab60a761f01 273183: c86ba5b9ced959ae0e9aba278d9e6ac73ed85ff0 v: v3 --- [refs] | 2 +- trunk/Documentation/filesystems/Locking | 1 + trunk/fs/dcache.c | 40 +++++++++++++++++++++---- trunk/include/linux/dcache.h | 8 +++-- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/[refs] b/[refs] index 1b1e0ccdc4bf..39350e4e07ad 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: a78ef704a8dd430225955f0709b22d4a6ba21deb +refs/heads/master: f0023bc617ba600956b9226f1806033d7486c8ba diff --git a/trunk/Documentation/filesystems/Locking b/trunk/Documentation/filesystems/Locking index 653380793a6c..d819ba16a0c7 100644 --- a/trunk/Documentation/filesystems/Locking +++ b/trunk/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/trunk/fs/dcache.c b/trunk/fs/dcache.c index a88948b8bd17..274f13e2f094 100644 --- a/trunk/fs/dcache.c +++ b/trunk/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 @@ static inline struct dentry *dentry_kill(struct dentry *dentry, int ref) 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/trunk/include/linux/dcache.h b/trunk/include/linux/dcache.h index 62157c03caf7..4df926199369 100644 --- a/trunk/include/linux/dcache.h +++ b/trunk/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