]> git.baikalelectronics.ru Git - kernel.git/commit
target: Fix race between multiple invocations of target_qf_do_work()
authorRoland Dreier <roland@purestorage.com>
Sun, 28 Aug 2011 04:33:16 +0000 (21:33 -0700)
committerNicholas A. Bellinger <nab@linux-iscsi.org>
Fri, 16 Sep 2011 09:29:20 +0000 (09:29 +0000)
commit2d327f9122822f9b67378932f9a3daa172a4961e
tree121757157452bf6e546c53c0efd2a3d463f4aa2e
parentc0ae2db6db6ab38b7ddf58284da3fb70864b252e
target: Fix race between multiple invocations of target_qf_do_work()

When work is scheduled with schedule_work(), the work can end up
running on multiple CPUs at the same time -- this happens if
the work is already running on one CPU and schedule_work() is called
on another CPU.  This leads to list corruption with target_qf_do_work(),
which is roughly doing:

spin_lock(...);
list_for_each_entry_safe(...) {
list_del(...);
spin_unlock(...);

// do stuff

spin_lock(...);
}

With multiple CPUs running this code, one CPU can end up deleting the
list entry that the other CPU is about to work on.

Fix this by splicing the list entries onto a local list and then
operating on that in the work function.  This way, each invocation of
target_qf_do_work() operates on its own local list and so multiple
invocations don't corrupt each other's list.  This also avoids dropping
and reacquiring the lock for each list entry.

Signed-off-by: Roland Dreier <roland@purestorage.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/target/target_core_transport.c