Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vfs: dcache: fix deadlock in tree traversal

IBM reported a deadlock in select_parent(). This was found to be caused
by taking rename_lock when already locked when restarting the tree
traversal.

There are two cases when the traversal needs to be restarted:

1) concurrent d_move(); this can only happen when not already locked,
since taking rename_lock protects against concurrent d_move().

2) racing with final d_put() on child just at the moment of ascending
to parent; rename_lock doesn't protect against this rare race, so it
can happen when already locked.

Because of case 2, we need to be able to handle restarting the traversal
when rename_lock is already held. This patch fixes all three callers of
try_to_ascend().

IBM reported that the deadlock is gone with this patch.

[ I rewrote the patch to be smaller and just do the "goto again" if the
lock was already held, but credit goes to Miklos for the real work.
- Linus ]

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Miklos Szeredi and committed by
Linus Torvalds
8110e16d 6a3e3dbe

+6
+6
fs/dcache.c
··· 1134 1134 return 1; 1135 1135 1136 1136 rename_retry: 1137 + if (locked) 1138 + goto again; 1137 1139 locked = 1; 1138 1140 write_seqlock(&rename_lock); 1139 1141 goto again; ··· 1238 1236 rename_retry: 1239 1237 if (found) 1240 1238 return found; 1239 + if (locked) 1240 + goto again; 1241 1241 locked = 1; 1242 1242 write_seqlock(&rename_lock); 1243 1243 goto again; ··· 3039 3035 return; 3040 3036 3041 3037 rename_retry: 3038 + if (locked) 3039 + goto again; 3042 3040 locked = 1; 3043 3041 write_seqlock(&rename_lock); 3044 3042 goto again;