diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2018-02-23 21:25:42 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2018-03-29 15:07:44 -0400 |
commit | f657a666fd1b1b9fe59963943c74c245ae66f4cc (patch) | |
tree | cf01b5b08611520699f8425b24029f7076a6357a /fs/dcache.c | |
parent | 62d9956cefe6ecc4b43a7fae37af78ba7adaceaa (diff) |
get rid of trylock loop around dentry_kill()
In case when trylock in there fails, deal with it directly in
dentry_kill(). Note that in cases when we drop and retake
->d_lock, we need to recheck whether to retain the dentry.
Another thing is that dropping/retaking ->d_lock might have
ended up with negative dentry turning into positive; that,
of course, can happen only once...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index f5609902c6dd..f2d945688025 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -651,23 +651,43 @@ static struct dentry *dentry_kill(struct dentry *dentry) | |||
651 | struct dentry *parent = NULL; | 651 | struct dentry *parent = NULL; |
652 | 652 | ||
653 | if (inode && unlikely(!spin_trylock(&inode->i_lock))) | 653 | if (inode && unlikely(!spin_trylock(&inode->i_lock))) |
654 | goto failed; | 654 | goto slow_positive; |
655 | 655 | ||
656 | if (!IS_ROOT(dentry)) { | 656 | if (!IS_ROOT(dentry)) { |
657 | parent = dentry->d_parent; | 657 | parent = dentry->d_parent; |
658 | if (unlikely(!spin_trylock(&parent->d_lock))) { | 658 | if (unlikely(!spin_trylock(&parent->d_lock))) { |
659 | if (inode) | 659 | parent = __lock_parent(dentry); |
660 | spin_unlock(&inode->i_lock); | 660 | if (likely(inode || !dentry->d_inode)) |
661 | goto failed; | 661 | goto got_locks; |
662 | /* negative that became positive */ | ||
663 | if (parent) | ||
664 | spin_unlock(&parent->d_lock); | ||
665 | inode = dentry->d_inode; | ||
666 | goto slow_positive; | ||
662 | } | 667 | } |
663 | } | 668 | } |
664 | |||
665 | __dentry_kill(dentry); | 669 | __dentry_kill(dentry); |
666 | return parent; | 670 | return parent; |
667 | 671 | ||
668 | failed: | 672 | slow_positive: |
673 | spin_unlock(&dentry->d_lock); | ||
674 | spin_lock(&inode->i_lock); | ||
675 | spin_lock(&dentry->d_lock); | ||
676 | parent = lock_parent(dentry); | ||
677 | got_locks: | ||
678 | if (unlikely(dentry->d_lockref.count != 1)) { | ||
679 | dentry->d_lockref.count--; | ||
680 | } else if (likely(!retain_dentry(dentry))) { | ||
681 | __dentry_kill(dentry); | ||
682 | return parent; | ||
683 | } | ||
684 | /* we are keeping it, after all */ | ||
685 | if (inode) | ||
686 | spin_unlock(&inode->i_lock); | ||
687 | if (parent) | ||
688 | spin_unlock(&parent->d_lock); | ||
669 | spin_unlock(&dentry->d_lock); | 689 | spin_unlock(&dentry->d_lock); |
670 | return dentry; /* try again with same dentry */ | 690 | return NULL; |
671 | } | 691 | } |
672 | 692 | ||
673 | /* | 693 | /* |