diff options
Diffstat (limited to 'drivers/firewire/fw-cdev.c')
-rw-r--r-- | drivers/firewire/fw-cdev.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index 4a541921a14a..c639915fc3cb 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c | |||
@@ -113,6 +113,11 @@ static int fw_device_op_open(struct inode *inode, struct file *file) | |||
113 | if (device == NULL) | 113 | if (device == NULL) |
114 | return -ENODEV; | 114 | return -ENODEV; |
115 | 115 | ||
116 | if (fw_device_is_shutdown(device)) { | ||
117 | fw_device_put(device); | ||
118 | return -ENODEV; | ||
119 | } | ||
120 | |||
116 | client = kzalloc(sizeof(*client), GFP_KERNEL); | 121 | client = kzalloc(sizeof(*client), GFP_KERNEL); |
117 | if (client == NULL) { | 122 | if (client == NULL) { |
118 | fw_device_put(device); | 123 | fw_device_put(device); |
@@ -200,6 +205,7 @@ fw_device_op_read(struct file *file, | |||
200 | return dequeue_event(client, buffer, count); | 205 | return dequeue_event(client, buffer, count); |
201 | } | 206 | } |
202 | 207 | ||
208 | /* caller must hold card->lock so that node pointers can be dereferenced here */ | ||
203 | static void | 209 | static void |
204 | fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, | 210 | fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, |
205 | struct client *client) | 211 | struct client *client) |
@@ -209,7 +215,6 @@ fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, | |||
209 | event->closure = client->bus_reset_closure; | 215 | event->closure = client->bus_reset_closure; |
210 | event->type = FW_CDEV_EVENT_BUS_RESET; | 216 | event->type = FW_CDEV_EVENT_BUS_RESET; |
211 | event->generation = client->device->generation; | 217 | event->generation = client->device->generation; |
212 | smp_rmb(); /* node_id must not be older than generation */ | ||
213 | event->node_id = client->device->node_id; | 218 | event->node_id = client->device->node_id; |
214 | event->local_node_id = card->local_node->node_id; | 219 | event->local_node_id = card->local_node->node_id; |
215 | event->bm_node_id = 0; /* FIXME: We don't track the BM. */ | 220 | event->bm_node_id = 0; /* FIXME: We don't track the BM. */ |
@@ -269,6 +274,7 @@ static int ioctl_get_info(struct client *client, void *buffer) | |||
269 | { | 274 | { |
270 | struct fw_cdev_get_info *get_info = buffer; | 275 | struct fw_cdev_get_info *get_info = buffer; |
271 | struct fw_cdev_event_bus_reset bus_reset; | 276 | struct fw_cdev_event_bus_reset bus_reset; |
277 | struct fw_card *card = client->device->card; | ||
272 | unsigned long ret = 0; | 278 | unsigned long ret = 0; |
273 | 279 | ||
274 | client->version = get_info->version; | 280 | client->version = get_info->version; |
@@ -294,13 +300,17 @@ static int ioctl_get_info(struct client *client, void *buffer) | |||
294 | client->bus_reset_closure = get_info->bus_reset_closure; | 300 | client->bus_reset_closure = get_info->bus_reset_closure; |
295 | if (get_info->bus_reset != 0) { | 301 | if (get_info->bus_reset != 0) { |
296 | void __user *uptr = u64_to_uptr(get_info->bus_reset); | 302 | void __user *uptr = u64_to_uptr(get_info->bus_reset); |
303 | unsigned long flags; | ||
297 | 304 | ||
305 | spin_lock_irqsave(&card->lock, flags); | ||
298 | fill_bus_reset_event(&bus_reset, client); | 306 | fill_bus_reset_event(&bus_reset, client); |
307 | spin_unlock_irqrestore(&card->lock, flags); | ||
308 | |||
299 | if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset))) | 309 | if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset))) |
300 | return -EFAULT; | 310 | return -EFAULT; |
301 | } | 311 | } |
302 | 312 | ||
303 | get_info->card = client->device->card->index; | 313 | get_info->card = card->index; |
304 | 314 | ||
305 | return 0; | 315 | return 0; |
306 | } | 316 | } |
@@ -901,6 +911,9 @@ fw_device_op_ioctl(struct file *file, | |||
901 | { | 911 | { |
902 | struct client *client = file->private_data; | 912 | struct client *client = file->private_data; |
903 | 913 | ||
914 | if (fw_device_is_shutdown(client->device)) | ||
915 | return -ENODEV; | ||
916 | |||
904 | return dispatch_ioctl(client, cmd, (void __user *) arg); | 917 | return dispatch_ioctl(client, cmd, (void __user *) arg); |
905 | } | 918 | } |
906 | 919 | ||
@@ -911,6 +924,9 @@ fw_device_op_compat_ioctl(struct file *file, | |||
911 | { | 924 | { |
912 | struct client *client = file->private_data; | 925 | struct client *client = file->private_data; |
913 | 926 | ||
927 | if (fw_device_is_shutdown(client->device)) | ||
928 | return -ENODEV; | ||
929 | |||
914 | return dispatch_ioctl(client, cmd, compat_ptr(arg)); | 930 | return dispatch_ioctl(client, cmd, compat_ptr(arg)); |
915 | } | 931 | } |
916 | #endif | 932 | #endif |
@@ -922,6 +938,9 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma) | |||
922 | unsigned long size; | 938 | unsigned long size; |
923 | int page_count, retval; | 939 | int page_count, retval; |
924 | 940 | ||
941 | if (fw_device_is_shutdown(client->device)) | ||
942 | return -ENODEV; | ||
943 | |||
925 | /* FIXME: We could support multiple buffers, but we don't. */ | 944 | /* FIXME: We could support multiple buffers, but we don't. */ |
926 | if (client->buffer.pages != NULL) | 945 | if (client->buffer.pages != NULL) |
927 | return -EBUSY; | 946 | return -EBUSY; |