Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6f6111e

Browse files
committed
Merge branch 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs dcache livelock fix from Al Viro: "Fixes for livelocks in shrink_dentry_list() introduced by fixes to shrink list corruption; the root cause was that trylock of parent's ->d_lock could be disrupted by d_walk() happening on other CPUs, resulting in shrink_dentry_list() making no progress *and* the same d_walk() being called again and again for as long as shrink_dentry_list() doesn't get past that mess. The solution is to have shrink_dentry_list() treat that trylock failure not as 'try to do the same thing again', but 'lock them in the right order'" * 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: dentry_kill() doesn't need the second argument now dealing with the rest of shrink_dentry_list() livelock shrink_dentry_list(): take parent's ->d_lock earlier expand dentry_kill(dentry, 0) in shrink_dentry_list() split dentry_kill() lift the "already marked killed" case into shrink_dentry_list()
2 parents fe45736 + 8cbf74d commit 6f6111e

File tree

1 file changed

+107
-46
lines changed

1 file changed

+107
-46
lines changed

fs/dcache.c

Lines changed: 107 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -441,42 +441,12 @@ void d_drop(struct dentry *dentry)
441441
}
442442
EXPORT_SYMBOL(d_drop);
443443

444-
/*
445-
* Finish off a dentry we've decided to kill.
446-
* dentry->d_lock must be held, returns with it unlocked.
447-
* If ref is non-zero, then decrement the refcount too.
448-
* Returns dentry requiring refcount drop, or NULL if we're done.
449-
*/
450-
static struct dentry *
451-
dentry_kill(struct dentry *dentry, int unlock_on_failure)
452-
__releases(dentry->d_lock)
444+
static void __dentry_kill(struct dentry *dentry)
453445
{
454-
struct inode *inode;
455446
struct dentry *parent = NULL;
456447
bool can_free = true;
457-
458-
if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) {
459-
can_free = dentry->d_flags & DCACHE_MAY_FREE;
460-
spin_unlock(&dentry->d_lock);
461-
goto out;
462-
}
463-
464-
inode = dentry->d_inode;
465-
if (inode && !spin_trylock(&inode->i_lock)) {
466-
relock:
467-
if (unlock_on_failure) {
468-
spin_unlock(&dentry->d_lock);
469-
cpu_relax();
470-
}
471-
return dentry; /* try again with same dentry */
472-
}
473448
if (!IS_ROOT(dentry))
474449
parent = dentry->d_parent;
475-
if (parent && !spin_trylock(&parent->d_lock)) {
476-
if (inode)
477-
spin_unlock(&inode->i_lock);
478-
goto relock;
479-
}
480450

481451
/*
482452
* The dentry is now unrecoverably dead to the world.
@@ -520,9 +490,72 @@ dentry_kill(struct dentry *dentry, int unlock_on_failure)
520490
can_free = false;
521491
}
522492
spin_unlock(&dentry->d_lock);
523-
out:
524493
if (likely(can_free))
525494
dentry_free(dentry);
495+
}
496+
497+
/*
498+
* Finish off a dentry we've decided to kill.
499+
* dentry->d_lock must be held, returns with it unlocked.
500+
* If ref is non-zero, then decrement the refcount too.
501+
* Returns dentry requiring refcount drop, or NULL if we're done.
502+
*/
503+
static struct dentry *dentry_kill(struct dentry *dentry)
504+
__releases(dentry->d_lock)
505+
{
506+
struct inode *inode = dentry->d_inode;
507+
struct dentry *parent = NULL;
508+
509+
if (inode && unlikely(!spin_trylock(&inode->i_lock)))
510+
goto failed;
511+
512+
if (!IS_ROOT(dentry)) {
513+
parent = dentry->d_parent;
514+
if (unlikely(!spin_trylock(&parent->d_lock))) {
515+
if (inode)
516+
spin_unlock(&inode->i_lock);
517+
goto failed;
518+
}
519+
}
520+
521+
__dentry_kill(dentry);
522+
return parent;
523+
524+
failed:
525+
spin_unlock(&dentry->d_lock);
526+
cpu_relax();
527+
return dentry; /* try again with same dentry */
528+
}
529+
530+
static inline struct dentry *lock_parent(struct dentry *dentry)
531+
{
532+
struct dentry *parent = dentry->d_parent;
533+
if (IS_ROOT(dentry))
534+
return NULL;
535+
if (likely(spin_trylock(&parent->d_lock)))
536+
return parent;
537+
spin_unlock(&dentry->d_lock);
538+
rcu_read_lock();
539+
again:
540+
parent = ACCESS_ONCE(dentry->d_parent);
541+
spin_lock(&parent->d_lock);
542+
/*
543+
* We can't blindly lock dentry until we are sure
544+
* that we won't violate the locking order.
545+
* Any changes of dentry->d_parent must have
546+
* been done with parent->d_lock held, so
547+
* spin_lock() above is enough of a barrier
548+
* for checking if it's still our child.
549+
*/
550+
if (unlikely(parent != dentry->d_parent)) {
551+
spin_unlock(&parent->d_lock);
552+
goto again;
553+
}
554+
rcu_read_unlock();
555+
if (parent != dentry)
556+
spin_lock(&dentry->d_lock);
557+
else
558+
parent = NULL;
526559
return parent;
527560
}
528561

@@ -579,7 +612,7 @@ void dput(struct dentry *dentry)
579612
return;
580613

581614
kill_it:
582-
dentry = dentry_kill(dentry, 1);
615+
dentry = dentry_kill(dentry);
583616
if (dentry)
584617
goto repeat;
585618
}
@@ -797,8 +830,11 @@ static void shrink_dentry_list(struct list_head *list)
797830
struct dentry *dentry, *parent;
798831

799832
while (!list_empty(list)) {
833+
struct inode *inode;
800834
dentry = list_entry(list->prev, struct dentry, d_lru);
801835
spin_lock(&dentry->d_lock);
836+
parent = lock_parent(dentry);
837+
802838
/*
803839
* The dispose list is isolated and dentries are not accounted
804840
* to the LRU here, so we can simply remove it from the list
@@ -812,35 +848,60 @@ static void shrink_dentry_list(struct list_head *list)
812848
*/
813849
if ((int)dentry->d_lockref.count > 0) {
814850
spin_unlock(&dentry->d_lock);
851+
if (parent)
852+
spin_unlock(&parent->d_lock);
815853
continue;
816854
}
817855

818-
parent = dentry_kill(dentry, 0);
819-
/*
820-
* If dentry_kill returns NULL, we have nothing more to do.
821-
*/
822-
if (!parent)
856+
857+
if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) {
858+
bool can_free = dentry->d_flags & DCACHE_MAY_FREE;
859+
spin_unlock(&dentry->d_lock);
860+
if (parent)
861+
spin_unlock(&parent->d_lock);
862+
if (can_free)
863+
dentry_free(dentry);
823864
continue;
865+
}
824866

825-
if (unlikely(parent == dentry)) {
826-
/*
827-
* trylocks have failed and d_lock has been held the
828-
* whole time, so it could not have been added to any
829-
* other lists. Just add it back to the shrink list.
830-
*/
867+
inode = dentry->d_inode;
868+
if (inode && unlikely(!spin_trylock(&inode->i_lock))) {
831869
d_shrink_add(dentry, list);
832870
spin_unlock(&dentry->d_lock);
871+
if (parent)
872+
spin_unlock(&parent->d_lock);
833873
continue;
834874
}
875+
876+
__dentry_kill(dentry);
877+
835878
/*
836879
* We need to prune ancestors too. This is necessary to prevent
837880
* quadratic behavior of shrink_dcache_parent(), but is also
838881
* expected to be beneficial in reducing dentry cache
839882
* fragmentation.
840883
*/
841884
dentry = parent;
842-
while (dentry && !lockref_put_or_lock(&dentry->d_lockref))
843-
dentry = dentry_kill(dentry, 1);
885+
while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) {
886+
parent = lock_parent(dentry);
887+
if (dentry->d_lockref.count != 1) {
888+
dentry->d_lockref.count--;
889+
spin_unlock(&dentry->d_lock);
890+
if (parent)
891+
spin_unlock(&parent->d_lock);
892+
break;
893+
}
894+
inode = dentry->d_inode; /* can't be NULL */
895+
if (unlikely(!spin_trylock(&inode->i_lock))) {
896+
spin_unlock(&dentry->d_lock);
897+
if (parent)
898+
spin_unlock(&parent->d_lock);
899+
cpu_relax();
900+
continue;
901+
}
902+
__dentry_kill(dentry);
903+
dentry = parent;
904+
}
844905
}
845906
}
846907

0 commit comments

Comments
 (0)