Files
kernel-tenderloin-3.0/include/linux
Miklos Szeredi 8039a47e67 fix shrink_dcache_parent() livelock
commit eaf5f9073533cde21c7121c136f1c3f072d9cf59 upstream.

Two (or more) concurrent calls of shrink_dcache_parent() on the same dentry may
cause shrink_dcache_parent() to loop forever.

Here's what appears to happen:

1 - CPU0: select_parent(P) finds C and puts it on dispose list, returns 1

2 - CPU1: select_parent(P) locks P->d_lock

3 - CPU0: shrink_dentry_list() locks C->d_lock
   dentry_kill(C) tries to lock P->d_lock but fails, unlocks C->d_lock

4 - CPU1: select_parent(P) locks C->d_lock,
         moves C from dispose list being processed on CPU0 to the new
dispose list, returns 1

5 - CPU0: shrink_dentry_list() finds dispose list empty, returns

6 - Goto 2 with CPU0 and CPU1 switched

Basically select_parent() steals the dentry from shrink_dentry_list() and thinks
it found a new one, causing shrink_dentry_list() to think it's making progress
and loop over and over.

One way to trigger this is to make udev calls stat() on the sysfs file while it
is going away.

Having a file in /lib/udev/rules.d/ with only this one rule seems to the trick:

ATTR{vendor}=="0x8086", ATTR{device}=="0x10ca", ENV{PCI_SLOT_NAME}="%k", ENV{MATCHADDR}="$attr{address}", RUN+="/bin/true"

Then execute the following loop:

while true; do
        echo -bond0 > /sys/class/net/bonding_masters
        echo +bond0 > /sys/class/net/bonding_masters
        echo -bond1 > /sys/class/net/bonding_masters
        echo +bond1 > /sys/class/net/bonding_masters
done

One fix would be to check all callers and prevent concurrent calls to
shrink_dcache_parent().  But I think a better solution is to stop the
stealing behavior.

This patch adds a new dentry flag that is set when the dentry is added to the
dispose list.  The flag is cleared in dentry_lru_del() in case the dentry gets a
new reference just before being pruned.

If the dentry has this flag, select_parent() will skip it and let
shrink_dentry_list() retry pruning it.  With select_parent() skipping those
dentries there will not be the appearance of progress (new dentries found) when
there is none, hence shrink_dcache_parent() will not loop forever.

Set the flag is also set in prune_dcache_sb() for consistency as suggested by
Linus.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2012-01-25 17:24:51 -08:00
..
2011-05-04 14:08:36 -07:00
2011-06-01 11:36:49 +01:00
2012-01-12 11:35:33 -08:00
2011-05-28 17:41:46 +02:00
2011-05-26 17:12:34 -07:00
2011-05-26 17:12:34 -07:00
2011-05-19 15:59:38 -07:00
2012-01-25 17:24:51 -08:00
2011-06-27 16:06:19 -07:00
2011-05-23 10:47:06 -05:00
2011-05-29 13:03:09 +01:00
2011-05-24 10:21:29 +02:00
2011-05-24 10:21:29 +02:00
2011-06-09 15:05:48 -07:00
2011-06-27 16:06:19 -07:00
2011-05-26 12:03:50 -07:00
2011-05-25 20:43:32 +02:00
2011-05-08 16:41:45 -07:00
2011-05-26 17:12:37 -07:00
2011-05-22 08:47:53 -04:00
2011-05-19 20:50:53 -04:00
2011-05-24 14:33:35 +02:00
2011-04-25 18:14:10 -07:00
2011-11-11 09:36:29 -08:00
2011-11-11 09:36:48 -08:00
2011-05-19 16:55:27 +09:30
2011-05-20 11:46:11 -07:00
2011-05-26 17:12:34 -07:00
2011-04-20 17:01:19 +10:00
2012-01-25 17:24:38 -08:00
2011-05-26 17:12:37 -07:00
2011-05-24 12:10:51 +02:00
2011-05-13 16:31:00 -07:00
2011-05-05 23:16:59 -07:00
2011-05-25 08:39:19 -07:00
2011-10-03 11:40:08 -07:00
2011-10-16 14:14:51 -07:00
2011-12-09 08:52:39 -08:00
2011-05-05 11:10:14 -07:00
2011-06-27 18:00:12 -07:00
2011-06-15 20:03:59 -07:00
2011-10-03 11:39:49 -07:00
2011-11-11 09:35:12 -08:00
2011-06-07 09:05:42 -07:00
2012-01-12 11:35:25 -08:00
2011-05-30 11:14:16 +09:30