diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-05-29 20:13:30 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-05-29 20:28:22 -0400 |
commit | 550dce01dd606c88a837138aa448ccd367fb0cbb (patch) | |
tree | e6cc564fc18e012ed2bdd76ee5e5d0785c310c50 | |
parent | ea7d4c046ba6e2c6135c98721f4f09efd1adaabc (diff) |
unify dentry_iput() and dentry_unlink_inode()
There is a lot of duplication between dentry_unlink_inode() and dentry_iput().
The only real difference is that dentry_unlink_inode() bumps ->d_seq and
dentry_iput() doesn't. The argument of the latter is known to have been
unhashed, so anybody who might've found it in RCU lookup would already be
doomed to a ->d_seq mismatch. And we want to avoid pointless smp_rmb() there.
This patch makes dentry_unlink_inode() bump ->d_seq only for hashed dentries.
It's safe (d_delete() calls that sucker only if we are holding the only
reference to dentry, so rehash is not going to happen) and it allows
to use dentry_unlink_inode() in __dentry_kill() and get rid of dentry_iput().
The interesting question here is profiling; it *is* a hot path, and extra
conditional jumps in there might or might not be painful.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/dcache.c | 45 |
1 files changed, 10 insertions, 35 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index f9c63c108881..fe7cde2f2fe5 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -335,44 +335,21 @@ static inline void dentry_rcuwalk_invalidate(struct dentry *dentry) | |||
335 | 335 | ||
336 | /* | 336 | /* |
337 | * Release the dentry's inode, using the filesystem | 337 | * Release the dentry's inode, using the filesystem |
338 | * d_iput() operation if defined. Dentry has no refcount | 338 | * d_iput() operation if defined. |
339 | * and is unhashed. | ||
340 | */ | ||
341 | static void dentry_iput(struct dentry * dentry) | ||
342 | __releases(dentry->d_lock) | ||
343 | __releases(dentry->d_inode->i_lock) | ||
344 | { | ||
345 | struct inode *inode = dentry->d_inode; | ||
346 | if (inode) { | ||
347 | __d_clear_type_and_inode(dentry); | ||
348 | hlist_del_init(&dentry->d_u.d_alias); | ||
349 | spin_unlock(&dentry->d_lock); | ||
350 | spin_unlock(&inode->i_lock); | ||
351 | if (!inode->i_nlink) | ||
352 | fsnotify_inoderemove(inode); | ||
353 | if (dentry->d_op && dentry->d_op->d_iput) | ||
354 | dentry->d_op->d_iput(dentry, inode); | ||
355 | else | ||
356 | iput(inode); | ||
357 | } else { | ||
358 | spin_unlock(&dentry->d_lock); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * Release the dentry's inode, using the filesystem | ||
364 | * d_iput() operation if defined. dentry remains in-use. | ||
365 | */ | 339 | */ |
366 | static void dentry_unlink_inode(struct dentry * dentry) | 340 | static void dentry_unlink_inode(struct dentry * dentry) |
367 | __releases(dentry->d_lock) | 341 | __releases(dentry->d_lock) |
368 | __releases(dentry->d_inode->i_lock) | 342 | __releases(dentry->d_inode->i_lock) |
369 | { | 343 | { |
370 | struct inode *inode = dentry->d_inode; | 344 | struct inode *inode = dentry->d_inode; |
345 | bool hashed = !d_unhashed(dentry); | ||
371 | 346 | ||
372 | raw_write_seqcount_begin(&dentry->d_seq); | 347 | if (hashed) |
348 | raw_write_seqcount_begin(&dentry->d_seq); | ||
373 | __d_clear_type_and_inode(dentry); | 349 | __d_clear_type_and_inode(dentry); |
374 | hlist_del_init(&dentry->d_u.d_alias); | 350 | hlist_del_init(&dentry->d_u.d_alias); |
375 | raw_write_seqcount_end(&dentry->d_seq); | 351 | if (hashed) |
352 | raw_write_seqcount_end(&dentry->d_seq); | ||
376 | spin_unlock(&dentry->d_lock); | 353 | spin_unlock(&dentry->d_lock); |
377 | spin_unlock(&inode->i_lock); | 354 | spin_unlock(&inode->i_lock); |
378 | if (!inode->i_nlink) | 355 | if (!inode->i_nlink) |
@@ -540,12 +517,10 @@ static void __dentry_kill(struct dentry *dentry) | |||
540 | dentry->d_flags |= DCACHE_DENTRY_KILLED; | 517 | dentry->d_flags |= DCACHE_DENTRY_KILLED; |
541 | if (parent) | 518 | if (parent) |
542 | spin_unlock(&parent->d_lock); | 519 | spin_unlock(&parent->d_lock); |
543 | dentry_iput(dentry); | 520 | if (dentry->d_inode) |
544 | /* | 521 | dentry_unlink_inode(dentry); |
545 | * dentry_iput drops the locks, at which point nobody (except | 522 | else |
546 | * transient RCU lookups) can reach this dentry. | 523 | spin_unlock(&dentry->d_lock); |
547 | */ | ||
548 | BUG_ON(dentry->d_lockref.count > 0); | ||
549 | this_cpu_dec(nr_dentry); | 524 | this_cpu_dec(nr_dentry); |
550 | if (dentry->d_op && dentry->d_op->d_release) | 525 | if (dentry->d_op && dentry->d_op->d_release) |
551 | dentry->d_op->d_release(dentry); | 526 | dentry->d_op->d_release(dentry); |