diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-07-22 05:56:38 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-07-27 05:04:10 -0400 |
commit | c7b2a99c66e7b40d8843a70f2981e375eeedf062 (patch) | |
tree | 56039d14506b685e009f0b501264cba08d3e5484 /drivers/firewire/nosy.c | |
parent | b5e47729043c9224b21ab3dc7c63e8a38dbb4923 (diff) |
firewire: nosy: convert to unlocked ioctl
The required serialization of NOSY_IOC_START and NOSY_IOC_STOP is
already provided by the client_list_lock.
NOSY_IOC_FILTER does not really require serialization since accesses
to tcode_mask are atomic on any sane CPU architecture. Nevertheless,
make it explicit that we want this to be atomic by means of
client_list_lock (which also surrounds the other tcode_mask access in
the IRQ handler). While we are at it, change the type of tcode_mask to
u32 for consistency with the user API.
NOSY_IOC_GET_STATS does not require serialization against itself. But
there is a bug here regarding concurrent updates of the two counters
by the IRQ handler. Fix it by taking the client_list_lock in this ioctl
too.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/nosy.c')
-rw-r--r-- | drivers/firewire/nosy.c | 29 |
1 files changed, 17 insertions, 12 deletions
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index ea392d0985a5..6470514190d5 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c | |||
@@ -108,7 +108,7 @@ struct pcilynx { | |||
108 | 108 | ||
109 | struct client { | 109 | struct client { |
110 | struct pcilynx *lynx; | 110 | struct pcilynx *lynx; |
111 | unsigned long tcode_mask; | 111 | u32 tcode_mask; |
112 | struct packet_buffer buffer; | 112 | struct packet_buffer buffer; |
113 | struct list_head link; | 113 | struct list_head link; |
114 | }; | 114 | }; |
@@ -351,17 +351,20 @@ nosy_read(struct file *file, char *buffer, size_t count, loff_t *offset) | |||
351 | return packet_buffer_get(&client->buffer, buffer, count); | 351 | return packet_buffer_get(&client->buffer, buffer, count); |
352 | } | 352 | } |
353 | 353 | ||
354 | static int | 354 | static long |
355 | nosy_ioctl(struct inode *inode, struct file *file, | 355 | nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
356 | unsigned int cmd, unsigned long arg) | ||
357 | { | 356 | { |
358 | struct client *client = file->private_data; | 357 | struct client *client = file->private_data; |
358 | spinlock_t *client_list_lock = &client->lynx->client_list_lock; | ||
359 | struct nosy_stats stats; | 359 | struct nosy_stats stats; |
360 | 360 | ||
361 | switch (cmd) { | 361 | switch (cmd) { |
362 | case NOSY_IOC_GET_STATS: | 362 | case NOSY_IOC_GET_STATS: |
363 | spin_lock_irq(client_list_lock); | ||
363 | stats.total_packet_count = client->buffer.total_packet_count; | 364 | stats.total_packet_count = client->buffer.total_packet_count; |
364 | stats.lost_packet_count = client->buffer.lost_packet_count; | 365 | stats.lost_packet_count = client->buffer.lost_packet_count; |
366 | spin_unlock_irq(client_list_lock); | ||
367 | |||
365 | if (copy_to_user((void *) arg, &stats, sizeof stats)) | 368 | if (copy_to_user((void *) arg, &stats, sizeof stats)) |
366 | return -EFAULT; | 369 | return -EFAULT; |
367 | else | 370 | else |
@@ -376,7 +379,9 @@ nosy_ioctl(struct inode *inode, struct file *file, | |||
376 | return 0; | 379 | return 0; |
377 | 380 | ||
378 | case NOSY_IOC_FILTER: | 381 | case NOSY_IOC_FILTER: |
382 | spin_lock_irq(client_list_lock); | ||
379 | client->tcode_mask = arg; | 383 | client->tcode_mask = arg; |
384 | spin_unlock_irq(client_list_lock); | ||
380 | return 0; | 385 | return 0; |
381 | 386 | ||
382 | default: | 387 | default: |
@@ -386,12 +391,12 @@ nosy_ioctl(struct inode *inode, struct file *file, | |||
386 | } | 391 | } |
387 | 392 | ||
388 | static const struct file_operations nosy_ops = { | 393 | static const struct file_operations nosy_ops = { |
389 | .owner = THIS_MODULE, | 394 | .owner = THIS_MODULE, |
390 | .read = nosy_read, | 395 | .read = nosy_read, |
391 | .ioctl = nosy_ioctl, | 396 | .unlocked_ioctl = nosy_ioctl, |
392 | .poll = nosy_poll, | 397 | .poll = nosy_poll, |
393 | .open = nosy_open, | 398 | .open = nosy_open, |
394 | .release = nosy_release, | 399 | .release = nosy_release, |
395 | }; | 400 | }; |
396 | 401 | ||
397 | #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ | 402 | #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ |
@@ -409,7 +414,7 @@ packet_handler(struct pcilynx *lynx) | |||
409 | { | 414 | { |
410 | unsigned long flags; | 415 | unsigned long flags; |
411 | struct client *client; | 416 | struct client *client; |
412 | unsigned long tcode_mask; | 417 | u32 tcode_mask; |
413 | size_t length; | 418 | size_t length; |
414 | struct link_packet *packet; | 419 | struct link_packet *packet; |
415 | struct timeval tv; | 420 | struct timeval tv; |