Commit dfd3ad98 authored by Russell King's avatar Russell King

[PCMCIA] Prevent class_device related oops.

Although no such oops has been reported, removing a socket driver
while a file under /sysfs/class/pcmcia_socket/pcmcia_socket* is
held open by user space could potentially cause an oops.

Plug this by preventing pcmcia_unregister_socket from returning
until all references by sysfs to the pcmcia socket have been dropped.
parent 8ae9c851
...@@ -387,6 +387,12 @@ static void pcmcia_remove_socket(struct class_device *class_dev) ...@@ -387,6 +387,12 @@ static void pcmcia_remove_socket(struct class_device *class_dev)
socket->ss_entry = NULL; socket->ss_entry = NULL;
} }
static void pcmcia_release_socket(struct class_device *class_dev)
{
struct pcmcia_socket *socket = class_get_devdata(class_dev);
complete(&socket->socket_released);
}
/** /**
* pcmcia_register_socket - add a new pcmcia socket device * pcmcia_register_socket - add a new pcmcia socket device
...@@ -450,6 +456,8 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) ...@@ -450,6 +456,8 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ss_entry); DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ss_entry);
init_completion(&socket->socket_released);
/* remove from the device core */ /* remove from the device core */
class_device_unregister(&socket->dev); class_device_unregister(&socket->dev);
...@@ -457,6 +465,9 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) ...@@ -457,6 +465,9 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
down_write(&pcmcia_socket_list_rwsem); down_write(&pcmcia_socket_list_rwsem);
list_del(&socket->socket_list); list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem); up_write(&pcmcia_socket_list_rwsem);
/* wait for sysfs to drop all references */
wait_for_completion(&socket->socket_released);
} /* pcmcia_unregister_socket */ } /* pcmcia_unregister_socket */
EXPORT_SYMBOL(pcmcia_unregister_socket); EXPORT_SYMBOL(pcmcia_unregister_socket);
...@@ -2496,6 +2507,7 @@ EXPORT_SYMBOL(MTDHelperEntry); ...@@ -2496,6 +2507,7 @@ EXPORT_SYMBOL(MTDHelperEntry);
struct class pcmcia_socket_class = { struct class pcmcia_socket_class = {
.name = "pcmcia_socket", .name = "pcmcia_socket",
.release = pcmcia_release_socket,
}; };
EXPORT_SYMBOL(pcmcia_socket_class); EXPORT_SYMBOL(pcmcia_socket_class);
......
...@@ -193,6 +193,7 @@ struct pcmcia_socket { ...@@ -193,6 +193,7 @@ struct pcmcia_socket {
char *fake_cis; char *fake_cis;
struct list_head socket_list; struct list_head socket_list;
struct completion socket_released;
/* deprecated */ /* deprecated */
unsigned int sock; /* socket number */ unsigned int sock; /* socket number */
......
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