diff options
-rw-r--r-- | fs/dcache.c | 42 | ||||
-rw-r--r-- | include/linux/dcache.h | 4 |
2 files changed, 18 insertions, 28 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 7108c15685dd..d600a0af3b2e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -164,8 +164,8 @@ static void d_free(struct dentry *dentry) | |||
164 | if (dentry->d_op && dentry->d_op->d_release) | 164 | if (dentry->d_op && dentry->d_op->d_release) |
165 | dentry->d_op->d_release(dentry); | 165 | dentry->d_op->d_release(dentry); |
166 | 166 | ||
167 | /* if dentry was never inserted into hash, immediate free is OK */ | 167 | /* if dentry was never visible to RCU, immediate free is OK */ |
168 | if (hlist_bl_unhashed(&dentry->d_hash)) | 168 | if (!(dentry->d_flags & DCACHE_RCUACCESS)) |
169 | __d_free(&dentry->d_u.d_rcu); | 169 | __d_free(&dentry->d_u.d_rcu); |
170 | else | 170 | else |
171 | call_rcu(&dentry->d_u.d_rcu, __d_free); | 171 | call_rcu(&dentry->d_u.d_rcu, __d_free); |
@@ -327,28 +327,19 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) | |||
327 | */ | 327 | */ |
328 | void __d_drop(struct dentry *dentry) | 328 | void __d_drop(struct dentry *dentry) |
329 | { | 329 | { |
330 | if (!(dentry->d_flags & DCACHE_UNHASHED)) { | 330 | if (!d_unhashed(dentry)) { |
331 | struct hlist_bl_head *b; | 331 | struct hlist_bl_head *b; |
332 | if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) { | 332 | if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) |
333 | b = &dentry->d_sb->s_anon; | 333 | b = &dentry->d_sb->s_anon; |
334 | spin_lock_bucket(b); | 334 | else |
335 | dentry->d_flags |= DCACHE_UNHASHED; | ||
336 | hlist_bl_del_init(&dentry->d_hash); | ||
337 | spin_unlock_bucket(b); | ||
338 | } else { | ||
339 | struct hlist_bl_head *b; | ||
340 | b = d_hash(dentry->d_parent, dentry->d_name.hash); | 335 | b = d_hash(dentry->d_parent, dentry->d_name.hash); |
341 | spin_lock_bucket(b); | 336 | |
342 | /* | 337 | spin_lock_bucket(b); |
343 | * We may not actually need to put DCACHE_UNHASHED | 338 | __hlist_bl_del(&dentry->d_hash); |
344 | * manipulations under the hash lock, but follow | 339 | dentry->d_hash.pprev = NULL; |
345 | * the principle of least surprise. | 340 | spin_unlock_bucket(b); |
346 | */ | 341 | |
347 | dentry->d_flags |= DCACHE_UNHASHED; | 342 | dentry_rcuwalk_barrier(dentry); |
348 | hlist_bl_del_rcu(&dentry->d_hash); | ||
349 | spin_unlock_bucket(b); | ||
350 | dentry_rcuwalk_barrier(dentry); | ||
351 | } | ||
352 | } | 343 | } |
353 | } | 344 | } |
354 | EXPORT_SYMBOL(__d_drop); | 345 | EXPORT_SYMBOL(__d_drop); |
@@ -1301,7 +1292,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
1301 | dname[name->len] = 0; | 1292 | dname[name->len] = 0; |
1302 | 1293 | ||
1303 | dentry->d_count = 1; | 1294 | dentry->d_count = 1; |
1304 | dentry->d_flags = DCACHE_UNHASHED; | 1295 | dentry->d_flags = 0; |
1305 | spin_lock_init(&dentry->d_lock); | 1296 | spin_lock_init(&dentry->d_lock); |
1306 | seqcount_init(&dentry->d_seq); | 1297 | seqcount_init(&dentry->d_seq); |
1307 | dentry->d_inode = NULL; | 1298 | dentry->d_inode = NULL; |
@@ -1603,10 +1594,9 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1603 | tmp->d_inode = inode; | 1594 | tmp->d_inode = inode; |
1604 | tmp->d_flags |= DCACHE_DISCONNECTED; | 1595 | tmp->d_flags |= DCACHE_DISCONNECTED; |
1605 | list_add(&tmp->d_alias, &inode->i_dentry); | 1596 | list_add(&tmp->d_alias, &inode->i_dentry); |
1606 | bit_spin_lock(0, (unsigned long *)&tmp->d_sb->s_anon.first); | 1597 | spin_lock_bucket(&tmp->d_sb->s_anon); |
1607 | tmp->d_flags &= ~DCACHE_UNHASHED; | ||
1608 | hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); | 1598 | hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); |
1609 | __bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first); | 1599 | spin_unlock_bucket(&tmp->d_sb->s_anon); |
1610 | spin_unlock(&tmp->d_lock); | 1600 | spin_unlock(&tmp->d_lock); |
1611 | spin_unlock(&inode->i_lock); | 1601 | spin_unlock(&inode->i_lock); |
1612 | security_d_instantiate(tmp, inode); | 1602 | security_d_instantiate(tmp, inode); |
@@ -2087,7 +2077,7 @@ static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b) | |||
2087 | { | 2077 | { |
2088 | BUG_ON(!d_unhashed(entry)); | 2078 | BUG_ON(!d_unhashed(entry)); |
2089 | spin_lock_bucket(b); | 2079 | spin_lock_bucket(b); |
2090 | entry->d_flags &= ~DCACHE_UNHASHED; | 2080 | entry->d_flags |= DCACHE_RCUACCESS; |
2091 | hlist_bl_add_head_rcu(&entry->d_hash, b); | 2081 | hlist_bl_add_head_rcu(&entry->d_hash, b); |
2092 | spin_unlock_bucket(b); | 2082 | spin_unlock_bucket(b); |
2093 | } | 2083 | } |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index f2afed4fa945..19d90a55541d 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -197,7 +197,7 @@ struct dentry_operations { | |||
197 | * typically using d_splice_alias. */ | 197 | * typically using d_splice_alias. */ |
198 | 198 | ||
199 | #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ | 199 | #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ |
200 | #define DCACHE_UNHASHED 0x0010 | 200 | #define DCACHE_RCUACCESS 0x0010 /* Entry has ever been RCU-visible */ |
201 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 | 201 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 |
202 | /* Parent inode is watched by inotify */ | 202 | /* Parent inode is watched by inotify */ |
203 | 203 | ||
@@ -384,7 +384,7 @@ extern struct dentry *dget_parent(struct dentry *dentry); | |||
384 | 384 | ||
385 | static inline int d_unhashed(struct dentry *dentry) | 385 | static inline int d_unhashed(struct dentry *dentry) |
386 | { | 386 | { |
387 | return (dentry->d_flags & DCACHE_UNHASHED); | 387 | return hlist_bl_unhashed(&dentry->d_hash); |
388 | } | 388 | } |
389 | 389 | ||
390 | static inline int d_unlinked(struct dentry *dentry) | 390 | static inline int d_unlinked(struct dentry *dentry) |