diff options
-rw-r--r-- | Documentation/filesystems/Locking | 1 | ||||
-rw-r--r-- | fs/dcache.c | 40 | ||||
-rw-r--r-- | include/linux/dcache.h | 8 |
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 | |||
29 | d_compare: yes no no maybe | 29 | d_compare: yes no no maybe |
30 | d_delete: no yes no no | 30 | d_delete: no yes no no |
31 | d_release: no no yes no | 31 | d_release: no no yes no |
32 | d_prune: no yes no no | ||
32 | d_iput: no no yes no | 33 | d_iput: no no yes no |
33 | d_dname: no no no no | 34 | d_dname: no no no no |
34 | d_automount: no no yes no | 35 | d_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 | */ |
230 | static void dentry_lru_add(struct dentry *dentry) | 230 | static 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 | */ | ||
248 | static void dentry_lru_del(struct dentry *dentry) | 251 | static 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 | */ | ||
265 | static 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 | |||
257 | static void dentry_lru_move_tail(struct dentry *dentry) | 277 | static 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 | } |
1288 | EXPORT_SYMBOL(d_set_d_op); | 1318 | EXPORT_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 |