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>
This commit is contained in:
parent
b5e4772904
commit
c7b2a99c66
|
@ -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)
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue