aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/Locking1
-rw-r--r--fs/dcache.c40
-rw-r--r--include/linux/dcache.h8
3 files changed, 41 insertions, 8 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 653380793a6c..d819ba16a0c7 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -29,6 +29,7 @@ d_hash no no no maybe
29d_compare: yes no no maybe 29d_compare: yes no no maybe
30d_delete: no yes no no 30d_delete: no yes no no
31d_release: no no yes no 31d_release: no no yes no
32d_prune: no yes no no
32d_iput: no no yes no 33d_iput: no no yes no
33d_dname: no no no no 34d_dname: no no no no
34d_automount: no no yes no 35d_automount: no no yes no
diff --git a/fs/dcache.c b/fs/dcache.c
index a88948b8bd17..274f13e2f094 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -225,7 +225,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
225} 225}
226 226
227/* 227/*
228 * dentry_lru_(add|del|move_tail) must be called with d_lock held. 228 * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held.
229 */ 229 */
230static void dentry_lru_add(struct dentry *dentry) 230static void dentry_lru_add(struct dentry *dentry)
231{ 231{
@@ -245,6 +245,9 @@ static void __dentry_lru_del(struct dentry *dentry)
245 dentry_stat.nr_unused--; 245 dentry_stat.nr_unused--;
246} 246}
247 247
248/*
249 * Remove a dentry with references from the LRU.
250 */
248static void dentry_lru_del(struct dentry *dentry) 251static void dentry_lru_del(struct dentry *dentry)
249{ 252{
250 if (!list_empty(&dentry->d_lru)) { 253 if (!list_empty(&dentry->d_lru)) {
@@ -254,6 +257,23 @@ static void dentry_lru_del(struct dentry *dentry)
254 } 257 }
255} 258}
256 259
260/*
261 * Remove a dentry that is unreferenced and about to be pruned
262 * (unhashed and destroyed) from the LRU, and inform the file system.
263 * This wrapper should be called _prior_ to unhashing a victim dentry.
264 */
265static void dentry_lru_prune(struct dentry *dentry)
266{
267 if (!list_empty(&dentry->d_lru)) {
268 if (dentry->d_flags & DCACHE_OP_PRUNE)
269 dentry->d_op->d_prune(dentry);
270
271 spin_lock(&dcache_lru_lock);
272 __dentry_lru_del(dentry);
273 spin_unlock(&dcache_lru_lock);
274 }
275}
276
257static void dentry_lru_move_tail(struct dentry *dentry) 277static void dentry_lru_move_tail(struct dentry *dentry)
258{ 278{
259 spin_lock(&dcache_lru_lock); 279 spin_lock(&dcache_lru_lock);
@@ -403,8 +423,12 @@ relock:
403 423
404 if (ref) 424 if (ref)
405 dentry->d_count--; 425 dentry->d_count--;
406 /* if dentry was on the d_lru list delete it from there */ 426 /*
407 dentry_lru_del(dentry); 427 * if dentry was on the d_lru list delete it from there.
428 * inform the fs via d_prune that this dentry is about to be
429 * unhashed and destroyed.
430 */
431 dentry_lru_prune(dentry);
408 /* if it was on the hash then remove it */ 432 /* if it was on the hash then remove it */
409 __d_drop(dentry); 433 __d_drop(dentry);
410 return d_kill(dentry, parent); 434 return d_kill(dentry, parent);
@@ -854,8 +878,12 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
854 do { 878 do {
855 struct inode *inode; 879 struct inode *inode;
856 880
857 /* detach from the system */ 881 /*
858 dentry_lru_del(dentry); 882 * remove the dentry from the lru, and inform
883 * the fs that this dentry is about to be
884 * unhashed and destroyed.
885 */
886 dentry_lru_prune(dentry);
859 __d_shrink(dentry); 887 __d_shrink(dentry);
860 888
861 if (dentry->d_count != 0) { 889 if (dentry->d_count != 0) {
@@ -1283,6 +1311,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
1283 dentry->d_flags |= DCACHE_OP_REVALIDATE; 1311 dentry->d_flags |= DCACHE_OP_REVALIDATE;
1284 if (op->d_delete) 1312 if (op->d_delete)
1285 dentry->d_flags |= DCACHE_OP_DELETE; 1313 dentry->d_flags |= DCACHE_OP_DELETE;
1314 if (op->d_prune)
1315 dentry->d_flags |= DCACHE_OP_PRUNE;
1286 1316
1287} 1317}
1288EXPORT_SYMBOL(d_set_d_op); 1318EXPORT_SYMBOL(d_set_d_op);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 62157c03caf7..4df926199369 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -165,6 +165,7 @@ struct dentry_operations {
165 unsigned int, const char *, const struct qstr *); 165 unsigned int, const char *, const struct qstr *);
166 int (*d_delete)(const struct dentry *); 166 int (*d_delete)(const struct dentry *);
167 void (*d_release)(struct dentry *); 167 void (*d_release)(struct dentry *);
168 void (*d_prune)(struct dentry *);
168 void (*d_iput)(struct dentry *, struct inode *); 169 void (*d_iput)(struct dentry *, struct inode *);
169 char *(*d_dname)(struct dentry *, char *, int); 170 char *(*d_dname)(struct dentry *, char *, int);
170 struct vfsmount *(*d_automount)(struct path *); 171 struct vfsmount *(*d_automount)(struct path *);
@@ -184,8 +185,9 @@ struct dentry_operations {
184#define DCACHE_OP_COMPARE 0x0002 185#define DCACHE_OP_COMPARE 0x0002
185#define DCACHE_OP_REVALIDATE 0x0004 186#define DCACHE_OP_REVALIDATE 0x0004
186#define DCACHE_OP_DELETE 0x0008 187#define DCACHE_OP_DELETE 0x0008
188#define DCACHE_OP_PRUNE 0x0010
187 189
188#define DCACHE_DISCONNECTED 0x0010 190#define DCACHE_DISCONNECTED 0x0020
189 /* This dentry is possibly not currently connected to the dcache tree, in 191 /* This dentry is possibly not currently connected to the dcache tree, in
190 * which case its parent will either be itself, or will have this flag as 192 * which case its parent will either be itself, or will have this flag as
191 * well. nfsd will not use a dentry with this bit set, but will first 193 * well. nfsd will not use a dentry with this bit set, but will first
@@ -196,8 +198,8 @@ struct dentry_operations {
196 * dentry into place and return that dentry rather than the passed one, 198 * dentry into place and return that dentry rather than the passed one,
197 * typically using d_splice_alias. */ 199 * typically using d_splice_alias. */
198 200
199#define DCACHE_REFERENCED 0x0020 /* Recently used, don't discard. */ 201#define DCACHE_REFERENCED 0x0040 /* Recently used, don't discard. */
200#define DCACHE_RCUACCESS 0x0040 /* Entry has ever been RCU-visible */ 202#define DCACHE_RCUACCESS 0x0080 /* Entry has ever been RCU-visible */
201 203
202#define DCACHE_CANT_MOUNT 0x0100 204#define DCACHE_CANT_MOUNT 0x0100
203#define DCACHE_GENOCIDE 0x0200 205#define DCACHE_GENOCIDE 0x0200