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 | |
| 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>
| -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; |
