mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 16:13:19 +09:00
s390/ism: Fix and simplify add()/remove() callback handling
Previously the clients_lock was protecting the clients array against
concurrent addition/removal of clients but was also accessed from IRQ
context. This meant that it had to be a spinlock and that the add() and
remove() callbacks in which clients need to do allocation and take
mutexes can't be called under the clients_lock. To work around this these
callbacks were moved to workqueues. This not only introduced significant
complexity but is also subtly broken in at least one way.
In ism_dev_init() and ism_dev_exit() clients[i]->tgt_ism is used to
communicate the added/removed ISM device to the work function. While
write access to client[i]->tgt_ism is protected by the clients_lock and
the code waits that there is no pending add/remove work before and after
setting clients[i]->tgt_ism this is not enough. The problem is that the
wait happens based on per ISM device counters. Thus a concurrent
ism_dev_init()/ism_dev_exit() for a different ISM device may overwrite
a clients[i]->tgt_ism between unlocking the clients_lock and the
subsequent wait for the work to finnish.
Thankfully with the clients_lock no longer held in IRQ context it can be
turned into a mutex which can be held during the calls to add()/remove()
completely removing the need for the workqueues and the associated
broken housekeeping including the per ISM device counters and the
clients[i]->tgt_ism.
Fixes: 89e7d2ba61 ("net/ism: Add new API for client registration")
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
6b5c13b591
commit
76631ffa2f
@@ -45,9 +45,6 @@ struct ism_dev {
|
||||
int ieq_idx;
|
||||
|
||||
struct ism_client *subs[MAX_CLIENTS];
|
||||
atomic_t free_clients_cnt;
|
||||
atomic_t add_dev_cnt;
|
||||
wait_queue_head_t waitq;
|
||||
};
|
||||
|
||||
struct ism_event {
|
||||
@@ -69,9 +66,6 @@ struct ism_client {
|
||||
*/
|
||||
void (*handle_irq)(struct ism_dev *dev, unsigned int bit, u16 dmbemask);
|
||||
/* Private area - don't touch! */
|
||||
struct work_struct remove_work;
|
||||
struct work_struct add_work;
|
||||
struct ism_dev *tgt_ism;
|
||||
u8 id;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user