Commit c7b2a99c authored by Stefan Richter's avatar Stefan Richter

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: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent b5e47729
...@@ -108,7 +108,7 @@ struct pcilynx { ...@@ -108,7 +108,7 @@ struct pcilynx {
struct client { struct client {
struct pcilynx *lynx; struct pcilynx *lynx;
unsigned long tcode_mask; u32 tcode_mask;
struct packet_buffer buffer; struct packet_buffer buffer;
struct list_head link; struct list_head link;
}; };
...@@ -351,17 +351,20 @@ nosy_read(struct file *file, char *buffer, size_t count, loff_t *offset) ...@@ -351,17 +351,20 @@ nosy_read(struct file *file, char *buffer, size_t count, loff_t *offset)
return packet_buffer_get(&client->buffer, buffer, count); return packet_buffer_get(&client->buffer, buffer, count);
} }
static int static long
nosy_ioctl(struct inode *inode, struct file *file, nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
unsigned int cmd, unsigned long arg)
{ {
struct client *client = file->private_data; struct client *client = file->private_data;
spinlock_t *client_list_lock = &client->lynx->client_list_lock;
struct nosy_stats stats; struct nosy_stats stats;
switch (cmd) { switch (cmd) {
case NOSY_IOC_GET_STATS: case NOSY_IOC_GET_STATS:
spin_lock_irq(client_list_lock);
stats.total_packet_count = client->buffer.total_packet_count; stats.total_packet_count = client->buffer.total_packet_count;
stats.lost_packet_count = client->buffer.lost_packet_count; stats.lost_packet_count = client->buffer.lost_packet_count;
spin_unlock_irq(client_list_lock);
if (copy_to_user((void *) arg, &stats, sizeof stats)) if (copy_to_user((void *) arg, &stats, sizeof stats))
return -EFAULT; return -EFAULT;
else else
...@@ -376,7 +379,9 @@ nosy_ioctl(struct inode *inode, struct file *file, ...@@ -376,7 +379,9 @@ nosy_ioctl(struct inode *inode, struct file *file,
return 0; return 0;
case NOSY_IOC_FILTER: case NOSY_IOC_FILTER:
spin_lock_irq(client_list_lock);
client->tcode_mask = arg; client->tcode_mask = arg;
spin_unlock_irq(client_list_lock);
return 0; return 0;
default: default:
...@@ -386,12 +391,12 @@ nosy_ioctl(struct inode *inode, struct file *file, ...@@ -386,12 +391,12 @@ nosy_ioctl(struct inode *inode, struct file *file,
} }
static const struct file_operations nosy_ops = { static const struct file_operations nosy_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = nosy_read, .read = nosy_read,
.ioctl = nosy_ioctl, .unlocked_ioctl = nosy_ioctl,
.poll = nosy_poll, .poll = nosy_poll,
.open = nosy_open, .open = nosy_open,
.release = nosy_release, .release = nosy_release,
}; };
#define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */
...@@ -409,7 +414,7 @@ packet_handler(struct pcilynx *lynx) ...@@ -409,7 +414,7 @@ packet_handler(struct pcilynx *lynx)
{ {
unsigned long flags; unsigned long flags;
struct client *client; struct client *client;
unsigned long tcode_mask; u32 tcode_mask;
size_t length; size_t length;
struct link_packet *packet; struct link_packet *packet;
struct timeval tv; struct timeval tv;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment