Skip to content

Commit

Permalink
firewire: core: fix sleep in atomic context due to driver core change
Browse files Browse the repository at this point in the history
Due to commit 2831fe6, "driver core:
create a private portion of struct device", device_initialize() can no
longer be called from atomic contexts.

We now defer it until after config ROM probing.  This requires changes
to the bus manager code because this may use a device before it was
probed.

Reported-by: Jay Fenlason <fenlason@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
  • Loading branch information
Stefan Richter committed Jan 9, 2009
1 parent 73d5931 commit 6230582
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 16 deletions.
13 changes: 7 additions & 6 deletions drivers/firewire/fw-card.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ fw_card_bm_work(struct work_struct *work)
unsigned long flags;
int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
bool do_reset = false;
bool root_device_is_running;
bool root_device_is_cmc;
__be32 lock_data[2];

spin_lock_irqsave(&card->lock, flags);
Expand All @@ -224,8 +226,9 @@ fw_card_bm_work(struct work_struct *work)

generation = card->generation;
root_device = root_node->data;
if (root_device)
fw_device_get(root_device);
root_device_is_running = root_device &&
atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
root_device_is_cmc = root_device && root_device->cmc;
root_id = root_node->node_id;
grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));

Expand Down Expand Up @@ -308,14 +311,14 @@ fw_card_bm_work(struct work_struct *work)
* config rom. In either case, pick another root.
*/
new_root_id = local_node->node_id;
} else if (atomic_read(&root_device->state) != FW_DEVICE_RUNNING) {
} else if (!root_device_is_running) {
/*
* If we haven't probed this device yet, bail out now
* and let's try again once that's done.
*/
spin_unlock_irqrestore(&card->lock, flags);
goto out;
} else if (root_device->cmc) {
} else if (root_device_is_cmc) {
/*
* FIXME: I suppose we should set the cmstr bit in the
* STATE_CLEAR register of this node, as described in
Expand Down Expand Up @@ -362,8 +365,6 @@ fw_card_bm_work(struct work_struct *work)
fw_core_initiate_bus_reset(card, 1);
}
out:
if (root_device)
fw_device_put(root_device);
fw_node_put(root_node);
fw_node_put(local_node);
out_put_card:
Expand Down
23 changes: 13 additions & 10 deletions drivers/firewire/fw-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ static void fw_device_release(struct device *dev)

/*
* Take the card lock so we don't set this to NULL while a
* FW_NODE_UPDATED callback is being handled.
* FW_NODE_UPDATED callback is being handled or while the
* bus manager work looks at this node.
*/
spin_lock_irqsave(&card->lock, flags);
device->node->data = NULL;
Expand Down Expand Up @@ -695,12 +696,13 @@ static void fw_device_init(struct work_struct *work)
return;
}

err = -ENOMEM;
device_initialize(&device->device);

fw_device_get(device);
down_write(&fw_device_rwsem);
if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
err = idr_get_new(&fw_device_idr, device, &minor);
err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
idr_get_new(&fw_device_idr, device, &minor) :
-ENOMEM;
up_write(&fw_device_rwsem);

if (err < 0)
Expand Down Expand Up @@ -911,13 +913,14 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)

/*
* Do minimal intialization of the device here, the
* rest will happen in fw_device_init(). We need the
* card and node so we can read the config rom and we
* need to do device_initialize() now so
* device_for_each_child() in FW_NODE_UPDATED is
* doesn't freak out.
* rest will happen in fw_device_init().
*
* Attention: A lot of things, even fw_device_get(),
* cannot be done before fw_device_init() finished!
* You can basically just check device->state and
* schedule work until then, but only while holding
* card->lock.
*/
device_initialize(&device->device);
atomic_set(&device->state, FW_DEVICE_INITIALIZING);
device->card = fw_card_get(card);
device->node = fw_node_get(node);
Expand Down

0 comments on commit 6230582

Please sign in to comment.