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