aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/nosy.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-22 05:56:38 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-27 05:04:10 -0400
commitc7b2a99c66e7b40d8843a70f2981e375eeedf062 (patch)
tree56039d14506b685e009f0b501264cba08d3e5484 /drivers/firewire/nosy.c
parentb5e47729043c9224b21ab3dc7c63e8a38dbb4923 (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.c29
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
109struct client { 109struct 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
354static int 354static long
355nosy_ioctl(struct inode *inode, struct file *file, 355nosy_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
388static const struct file_operations nosy_ops = { 393static 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;