aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2008-07-22 15:35:47 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2008-07-25 14:10:32 -0400
commitc0220d686b926a5865a2032c805015758bfdda69 (patch)
tree2b1dd1177e9e24ccea13c517054e78c5abc2eee0
parent95984f62c9b0bf6d89ef4f514b1afe73623481de (diff)
firewire: avoid memleak after phy config transmit failure
Use only statically allocated data for PHY config packet transmission. With the previous incarnation, some data wouldn't be freed if the packet transmit callback was never called. A theoretical drawback now is that, in PCs with more than one card, card A may complete() for a waiter on card B. But this is highly unlikely and its impact not serious. Bus manager B may reset bus B before the PHY config went out, but the next phy config on B should be fine. However, with a timeout of 100ms, this situation is close to impossible. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/fw-transaction.c58
1 files changed, 21 insertions, 37 deletions
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index 861dd60de7d9..e5d1a0b64fcf 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -22,6 +22,7 @@
22#include <linux/kernel.h> 22#include <linux/kernel.h>
23#include <linux/kref.h> 23#include <linux/kref.h>
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/mutex.h>
25#include <linux/init.h> 26#include <linux/init.h>
26#include <linux/interrupt.h> 27#include <linux/interrupt.h>
27#include <linux/pci.h> 28#include <linux/pci.h>
@@ -295,58 +296,41 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
295} 296}
296EXPORT_SYMBOL(fw_send_request); 297EXPORT_SYMBOL(fw_send_request);
297 298
298struct fw_phy_packet { 299static DEFINE_MUTEX(phy_config_mutex);
299 struct fw_packet packet; 300static DECLARE_COMPLETION(phy_config_done);
300 struct completion done;
301 struct kref kref;
302};
303
304static void phy_packet_release(struct kref *kref)
305{
306 struct fw_phy_packet *p =
307 container_of(kref, struct fw_phy_packet, kref);
308 kfree(p);
309}
310 301
311static void transmit_phy_packet_callback(struct fw_packet *packet, 302static void transmit_phy_packet_callback(struct fw_packet *packet,
312 struct fw_card *card, int status) 303 struct fw_card *card, int status)
313{ 304{
314 struct fw_phy_packet *p = 305 complete(&phy_config_done);
315 container_of(packet, struct fw_phy_packet, packet);
316
317 complete(&p->done);
318 kref_put(&p->kref, phy_packet_release);
319} 306}
320 307
308static struct fw_packet phy_config_packet = {
309 .header_length = 8,
310 .payload_length = 0,
311 .speed = SCODE_100,
312 .callback = transmit_phy_packet_callback,
313};
314
321void fw_send_phy_config(struct fw_card *card, 315void fw_send_phy_config(struct fw_card *card,
322 int node_id, int generation, int gap_count) 316 int node_id, int generation, int gap_count)
323{ 317{
324 struct fw_phy_packet *p;
325 long timeout = DIV_ROUND_UP(HZ, 10); 318 long timeout = DIV_ROUND_UP(HZ, 10);
326 u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) | 319 u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
327 PHY_CONFIG_ROOT_ID(node_id) | 320 PHY_CONFIG_ROOT_ID(node_id) |
328 PHY_CONFIG_GAP_COUNT(gap_count); 321 PHY_CONFIG_GAP_COUNT(gap_count);
329 322
330 p = kmalloc(sizeof(*p), GFP_KERNEL); 323 mutex_lock(&phy_config_mutex);
331 if (p == NULL) 324
332 return; 325 phy_config_packet.header[0] = data;
326 phy_config_packet.header[1] = ~data;
327 phy_config_packet.generation = generation;
328 INIT_COMPLETION(phy_config_done);
329
330 card->driver->send_request(card, &phy_config_packet);
331 wait_for_completion_timeout(&phy_config_done, timeout);
333 332
334 p->packet.header[0] = data; 333 mutex_unlock(&phy_config_mutex);
335 p->packet.header[1] = ~data;
336 p->packet.header_length = 8;
337 p->packet.payload_length = 0;
338 p->packet.speed = SCODE_100;
339 p->packet.generation = generation;
340 p->packet.callback = transmit_phy_packet_callback;
341 init_completion(&p->done);
342 kref_set(&p->kref, 2);
343
344 card->driver->send_request(card, &p->packet);
345 timeout = wait_for_completion_timeout(&p->done, timeout);
346 kref_put(&p->kref, phy_packet_release);
347
348 /* will leak p if the callback is never executed */
349 WARN_ON(timeout == 0);
350} 334}
351 335
352void fw_flush_transactions(struct fw_card *card) 336void fw_flush_transactions(struct fw_card *card)