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 |
