aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/dcache.c42
-rw-r--r--include/linux/dcache.h4
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 */
328void __d_drop(struct dentry *dentry) 328void __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}
354EXPORT_SYMBOL(__d_drop); 345EXPORT_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
385static inline int d_unhashed(struct dentry *dentry) 385static 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
390static inline int d_unlinked(struct dentry *dentry) 390static inline int d_unlinked(struct dentry *dentry)