Skip to content

Commit 1c18edd

Browse files
author
Al Viro
committed
__dentry_kill(): new locking scheme
Currently we enter __dentry_kill() with parent (along with the victim dentry and victim's inode) held locked. Then we mark dentry refcount as dead call ->d_prune() remove dentry from hash remove it from the parent's list of children unlock the parent, don't need it from that point on detach dentry from inode, unlock dentry and drop the inode (via ->d_iput()) call ->d_release() regain the lock on dentry check if it's on a shrink list (in which case freeing its empty husk has to be left to shrink_dentry_list()) or not (in which case we can free it ourselves). In the former case, mark it as an empty husk, so that shrink_dentry_list() would know it can free the sucker. drop the lock on dentry ... and usually the caller proceeds to drop a reference on the parent, possibly retaking the lock on it. That is painful for a bunch of reasons, starting with the need to take locks out of order, but not limited to that - the parent of positive dentry can change if we drop its ->d_lock, so getting these locks has to be done with care. Moreover, as soon as dentry is out of the parent's list of children, shrink_dcache_for_umount() won't see it anymore, making it appear as if the parent is inexplicably busy. We do work around that by having shrink_dentry_list() decrement the parent's refcount first and put it on shrink list to be evicted once we are done with __dentry_kill() of child, but that may in some cases lead to ->d_iput() on child called after the parent got killed. That doesn't happen in cases where in-tree ->d_iput() instances might want to look at the parent, but that's brittle as hell. Solution: do removal from the parent's list of children in the very end of __dentry_kill(). As the result, the callers do not need to lock the parent and by the time we really need the parent locked, dentry is negative and is guaranteed not to be moved around. It does mean that ->d_prune() will be called with parent not locked. It also means that we might see dentries in process of being torn down while going through the parent's list of children; those dentries will be unhashed, negative and with refcount marked dead. In practice, that's enough for in-tree code that looks through the list of children to do the right thing as-is. Out-of-tree code might need to be adjusted. Calling conventions: __dentry_kill(dentry) is called with dentry->d_lock held, along with ->i_lock of its inode (if any). It either returns the parent (locked, with refcount decremented to 0) or NULL (if there'd been no parent or if refcount decrement for parent hadn't reached 0). lock_for_kill() is adjusted for new requirements - it doesn't touch the parent's ->d_lock at all. Callers adjusted. Note that for dput() we don't need to bother with fast_dput() for the parent - we just need to check retain_dentry() for it, since its ->d_lock is still held since the moment when __dentry_kill() had taken it to remove the victim from the list of children. The kludge with early decrement of parent's refcount in shrink_dentry_list() is no longer needed - shrink_dcache_for_umount() sees the half-killed dentries in the list of children for as long as they are pinning the parent. They are easily recognized and accounted for by select_collect(), so we know we are not done yet. As the result, we always have the expected ordering for ->d_iput()/->d_release() vs. __dentry_kill() of the parent, no exceptions. Moreover, the current rules for shrink lists (one must make sure that shrink_dcache_for_umount() won't happen while any dentries from the superblock in question are on any shrink lists) are gone - shrink_dcache_for_umount() will do the right thing in all cases, taking such dentries out. Their empty husks (memory occupied by struct dentry itself + its external name, if any) will remain on the shrink lists, but they are no obstacles to filesystem shutdown. And such husks will get freed as soon as shrink_dentry_list() of the list they are on gets to them. Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent b4cc073 commit 1c18edd

File tree

2 files changed

+65
-81
lines changed

2 files changed

+65
-81
lines changed

Documentation/filesystems/porting.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,3 +1078,20 @@ by compiler.
10781078
->d_delete() instances are now called for dentries with ->d_lock held
10791079
and refcount equal to 0. They are not permitted to drop/regain ->d_lock.
10801080
None of in-tree instances did anything of that sort. Make sure yours do not...
1081+
1082+
--
1083+
1084+
**mandatory**
1085+
1086+
->d_prune() instances are now called without ->d_lock held on the parent.
1087+
->d_lock on dentry itself is still held; if you need per-parent exclusions (none
1088+
of the in-tree instances did), use your own spinlock.
1089+
1090+
->d_iput() and ->d_release() are called with victim dentry still in the
1091+
list of parent's children. It is still unhashed, marked killed, etc., just not
1092+
removed from parent's ->d_children yet.
1093+
1094+
Anyone iterating through the list of children needs to be aware of the
1095+
half-killed dentries that might be seen there; taking ->d_lock on those will
1096+
see them negative, unhashed and with negative refcount, which means that most
1097+
of the in-kernel users would've done the right thing anyway without any adjustment.

fs/dcache.c

Lines changed: 48 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -575,12 +575,10 @@ static inline void dentry_unlist(struct dentry *dentry)
575575
}
576576
}
577577

578-
static void __dentry_kill(struct dentry *dentry)
578+
static struct dentry *__dentry_kill(struct dentry *dentry)
579579
{
580580
struct dentry *parent = NULL;
581581
bool can_free = true;
582-
if (!IS_ROOT(dentry))
583-
parent = dentry->d_parent;
584582

585583
/*
586584
* The dentry is now unrecoverably dead to the world.
@@ -600,9 +598,6 @@ static void __dentry_kill(struct dentry *dentry)
600598
}
601599
/* if it was on the hash then remove it */
602600
__d_drop(dentry);
603-
dentry_unlist(dentry);
604-
if (parent)
605-
spin_unlock(&parent->d_lock);
606601
if (dentry->d_inode)
607602
dentry_unlink_inode(dentry);
608603
else
@@ -611,39 +606,25 @@ static void __dentry_kill(struct dentry *dentry)
611606
if (dentry->d_op && dentry->d_op->d_release)
612607
dentry->d_op->d_release(dentry);
613608

614-
spin_lock(&dentry->d_lock);
609+
cond_resched();
610+
/* now that it's negative, ->d_parent is stable */
611+
if (!IS_ROOT(dentry)) {
612+
parent = dentry->d_parent;
613+
spin_lock(&parent->d_lock);
614+
}
615+
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
616+
dentry_unlist(dentry);
615617
if (dentry->d_flags & DCACHE_SHRINK_LIST) {
616618
dentry->d_flags |= DCACHE_MAY_FREE;
617619
can_free = false;
618620
}
619621
spin_unlock(&dentry->d_lock);
620622
if (likely(can_free))
621623
dentry_free(dentry);
622-
cond_resched();
623-
}
624-
625-
static struct dentry *__lock_parent(struct dentry *dentry)
626-
{
627-
struct dentry *parent;
628-
again:
629-
parent = READ_ONCE(dentry->d_parent);
630-
spin_lock(&parent->d_lock);
631-
/*
632-
* We can't blindly lock dentry until we are sure
633-
* that we won't violate the locking order.
634-
* Any changes of dentry->d_parent must have
635-
* been done with parent->d_lock held, so
636-
* spin_lock() above is enough of a barrier
637-
* for checking if it's still our child.
638-
*/
639-
if (unlikely(parent != dentry->d_parent)) {
624+
if (parent && --parent->d_lockref.count) {
640625
spin_unlock(&parent->d_lock);
641-
goto again;
626+
return NULL;
642627
}
643-
if (parent != dentry)
644-
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
645-
else
646-
parent = NULL;
647628
return parent;
648629
}
649630

@@ -655,48 +636,32 @@ static struct dentry *__lock_parent(struct dentry *dentry)
655636
* d_delete(), etc.
656637
*
657638
* Return false if dentry is busy. Otherwise, return true and have
658-
* that dentry's inode and parent both locked.
639+
* that dentry's inode locked.
659640
*/
660641

661642
static bool lock_for_kill(struct dentry *dentry)
662643
{
663644
struct inode *inode = dentry->d_inode;
664-
struct dentry *parent = dentry->d_parent;
665645

666646
if (unlikely(dentry->d_lockref.count))
667647
return false;
668648

669-
if (inode && unlikely(!spin_trylock(&inode->i_lock)))
670-
goto slow;
671-
if (dentry == parent)
672-
return true;
673-
if (likely(spin_trylock(&parent->d_lock)))
649+
if (!inode || likely(spin_trylock(&inode->i_lock)))
674650
return true;
675651

676-
if (inode)
677-
spin_unlock(&inode->i_lock);
678-
slow:
679-
spin_unlock(&dentry->d_lock);
680-
681-
for (;;) {
682-
if (inode)
683-
spin_lock(&inode->i_lock);
684-
parent = __lock_parent(dentry);
652+
do {
653+
spin_unlock(&dentry->d_lock);
654+
spin_lock(&inode->i_lock);
655+
spin_lock(&dentry->d_lock);
685656
if (likely(inode == dentry->d_inode))
686657
break;
687-
if (inode)
688-
spin_unlock(&inode->i_lock);
658+
spin_unlock(&inode->i_lock);
689659
inode = dentry->d_inode;
690-
spin_unlock(&dentry->d_lock);
691-
if (parent)
692-
spin_unlock(&parent->d_lock);
693-
}
660+
} while (inode);
694661
if (likely(!dentry->d_lockref.count))
695662
return true;
696663
if (inode)
697664
spin_unlock(&inode->i_lock);
698-
if (parent)
699-
spin_unlock(&parent->d_lock);
700665
return false;
701666
}
702667

@@ -869,29 +834,27 @@ static inline bool fast_dput(struct dentry *dentry)
869834
*/
870835
void dput(struct dentry *dentry)
871836
{
872-
while (dentry) {
873-
might_sleep();
874-
875-
rcu_read_lock();
876-
if (likely(fast_dput(dentry))) {
877-
rcu_read_unlock();
837+
if (!dentry)
838+
return;
839+
might_sleep();
840+
rcu_read_lock();
841+
if (likely(fast_dput(dentry))) {
842+
rcu_read_unlock();
843+
return;
844+
}
845+
while (lock_for_kill(dentry)) {
846+
rcu_read_unlock();
847+
dentry = __dentry_kill(dentry);
848+
if (!dentry)
878849
return;
879-
}
880-
881-
/* Slow case: now with the dentry lock held */
882-
if (likely(lock_for_kill(dentry))) {
883-
struct dentry *parent = dentry->d_parent;
884-
rcu_read_unlock();
885-
__dentry_kill(dentry);
886-
if (dentry == parent)
887-
return;
888-
dentry = parent;
889-
} else {
890-
rcu_read_unlock();
850+
if (retain_dentry(dentry)) {
891851
spin_unlock(&dentry->d_lock);
892852
return;
893853
}
854+
rcu_read_lock();
894855
}
856+
rcu_read_unlock();
857+
spin_unlock(&dentry->d_lock);
895858
}
896859
EXPORT_SYMBOL(dput);
897860

@@ -1091,12 +1054,16 @@ void d_prune_aliases(struct inode *inode)
10911054
}
10921055
EXPORT_SYMBOL(d_prune_aliases);
10931056

1094-
static inline void shrink_kill(struct dentry *victim, struct list_head *list)
1057+
static inline void shrink_kill(struct dentry *victim)
10951058
{
1096-
struct dentry *parent = victim->d_parent;
1097-
if (parent != victim && !--parent->d_lockref.count)
1098-
to_shrink_list(parent, list);
1099-
__dentry_kill(victim);
1059+
do {
1060+
rcu_read_unlock();
1061+
victim = __dentry_kill(victim);
1062+
rcu_read_lock();
1063+
} while (victim && lock_for_kill(victim));
1064+
rcu_read_unlock();
1065+
if (victim)
1066+
spin_unlock(&victim->d_lock);
11001067
}
11011068

11021069
void shrink_dentry_list(struct list_head *list)
@@ -1117,9 +1084,8 @@ void shrink_dentry_list(struct list_head *list)
11171084
dentry_free(dentry);
11181085
continue;
11191086
}
1120-
rcu_read_unlock();
11211087
d_shrink_del(dentry);
1122-
shrink_kill(dentry, list);
1088+
shrink_kill(dentry);
11231089
}
11241090
}
11251091

@@ -1478,6 +1444,8 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
14781444
} else if (!dentry->d_lockref.count) {
14791445
to_shrink_list(dentry, &data->dispose);
14801446
data->found++;
1447+
} else if (dentry->d_lockref.count < 0) {
1448+
data->found++;
14811449
}
14821450
/*
14831451
* We can return to the caller if we have found some (this
@@ -1547,8 +1515,7 @@ void shrink_dcache_parent(struct dentry *parent)
15471515
spin_unlock(&data.victim->d_lock);
15481516
rcu_read_unlock();
15491517
} else {
1550-
rcu_read_unlock();
1551-
shrink_kill(data.victim, &data.dispose);
1518+
shrink_kill(data.victim);
15521519
}
15531520
}
15541521
if (!list_empty(&data.dispose))

0 commit comments

Comments
 (0)