usb: avoid pagefault during session destruction
due to pointer to object allocated in context of the session object. Fixes #2565
This commit is contained in:
parent
03ae78173b
commit
c1493b2ed2
|
@ -114,7 +114,7 @@ struct Device : List<Device>::Element
|
||||||
* Handle packet stream request, this way the entrypoint always returns to it's
|
* Handle packet stream request, this way the entrypoint always returns to it's
|
||||||
* server loop
|
* server loop
|
||||||
*/
|
*/
|
||||||
class Usb::Worker
|
class Usb::Worker : public Genode::Weak_object<Usb::Worker>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -205,10 +205,27 @@ class Usb::Worker
|
||||||
*/
|
*/
|
||||||
struct Complete_data
|
struct Complete_data
|
||||||
{
|
{
|
||||||
Worker *worker;
|
Weak_ptr<Worker> worker;
|
||||||
Packet_descriptor packet;
|
Packet_descriptor packet;
|
||||||
|
|
||||||
|
Complete_data(Weak_ptr<Worker> &w, Packet_descriptor &p)
|
||||||
|
: worker(w), packet(p) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Complete_data * alloc_complete_data(Packet_descriptor &p)
|
||||||
|
{
|
||||||
|
void * data = kmalloc(sizeof(Complete_data), GFP_KERNEL);
|
||||||
|
construct_at<Complete_data>(data, this->weak_ptr(), p);
|
||||||
|
return reinterpret_cast<Complete_data *>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_complete_data(Complete_data *data)
|
||||||
|
{
|
||||||
|
data->packet.~Packet_descriptor();
|
||||||
|
data->worker.~Weak_ptr<Worker>();
|
||||||
|
kfree (data);
|
||||||
|
}
|
||||||
|
|
||||||
void _async_finish(Packet_descriptor &p, urb *urb, bool read)
|
void _async_finish(Packet_descriptor &p, urb *urb, bool read)
|
||||||
{
|
{
|
||||||
if (urb->status == 0) {
|
if (urb->status == 0) {
|
||||||
|
@ -231,9 +248,15 @@ class Usb::Worker
|
||||||
{
|
{
|
||||||
Complete_data *data = (Complete_data *)urb->context;
|
Complete_data *data = (Complete_data *)urb->context;
|
||||||
|
|
||||||
data->worker->_async_finish(data->packet, urb,
|
{
|
||||||
!!(data->packet.transfer.ep & USB_DIR_IN));
|
Locked_ptr<Worker> worker(data->worker);
|
||||||
kfree (data);
|
|
||||||
|
if (worker.valid())
|
||||||
|
worker->_async_finish(data->packet, urb,
|
||||||
|
!!(data->packet.transfer.ep & USB_DIR_IN));
|
||||||
|
}
|
||||||
|
|
||||||
|
free_complete_data(data);
|
||||||
dma_free(urb->transfer_buffer);
|
dma_free(urb->transfer_buffer);
|
||||||
usb_free_urb(urb);
|
usb_free_urb(urb);
|
||||||
}
|
}
|
||||||
|
@ -261,9 +284,7 @@ class Usb::Worker
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Complete_data *data = (Complete_data *)kmalloc(sizeof(Complete_data), GFP_KERNEL);
|
Complete_data *data = alloc_complete_data(p);
|
||||||
data->packet = p;
|
|
||||||
data->worker = this;
|
|
||||||
|
|
||||||
usb_fill_bulk_urb(bulk_urb, _device->udev, pipe, buf, p.size(),
|
usb_fill_bulk_urb(bulk_urb, _device->udev, pipe, buf, p.size(),
|
||||||
_async_complete, data);
|
_async_complete, data);
|
||||||
|
@ -272,7 +293,8 @@ class Usb::Worker
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
error("Failed to submit URB, error: ", ret);
|
error("Failed to submit URB, error: ", ret);
|
||||||
p.error = Usb::Packet_descriptor::SUBMIT_ERROR;
|
p.error = Usb::Packet_descriptor::SUBMIT_ERROR;
|
||||||
kfree(data);
|
|
||||||
|
free_complete_data(data);
|
||||||
usb_free_urb(bulk_urb);
|
usb_free_urb(bulk_urb);
|
||||||
dma_free(buf);
|
dma_free(buf);
|
||||||
return false;
|
return false;
|
||||||
|
@ -304,9 +326,7 @@ class Usb::Worker
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Complete_data *data = (Complete_data *)kmalloc(sizeof(Complete_data), GFP_KERNEL);
|
Complete_data *data = alloc_complete_data(p);
|
||||||
data->packet = p;
|
|
||||||
data->worker = this;
|
|
||||||
|
|
||||||
int polling_interval;
|
int polling_interval;
|
||||||
|
|
||||||
|
@ -326,7 +346,8 @@ class Usb::Worker
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
error("Failed to submit URB, error: ", ret);
|
error("Failed to submit URB, error: ", ret);
|
||||||
p.error = Usb::Packet_descriptor::SUBMIT_ERROR;
|
p.error = Usb::Packet_descriptor::SUBMIT_ERROR;
|
||||||
kfree(data);
|
|
||||||
|
free_complete_data(data);
|
||||||
usb_free_urb(irq_urb);
|
usb_free_urb(irq_urb);
|
||||||
dma_free(buf);
|
dma_free(buf);
|
||||||
return false;
|
return false;
|
||||||
|
@ -485,6 +506,11 @@ class Usb::Worker
|
||||||
: _sink(sink)
|
: _sink(sink)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
~Worker()
|
||||||
|
{
|
||||||
|
Weak_object<Worker>::lock_for_destruction();
|
||||||
|
}
|
||||||
|
|
||||||
void start()
|
void start()
|
||||||
{
|
{
|
||||||
if (!_task) {
|
if (!_task) {
|
||||||
|
|
|
@ -45,7 +45,9 @@ set config {
|
||||||
</parent-provides>
|
</parent-provides>
|
||||||
<default-route>
|
<default-route>
|
||||||
<any-service> <parent/> <any-child/> </any-service>
|
<any-service> <parent/> <any-child/> </any-service>
|
||||||
</default-route>}
|
</default-route>
|
||||||
|
|
||||||
|
<default caps="100"/>}
|
||||||
|
|
||||||
append_platform_drv_config
|
append_platform_drv_config
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ struct Usb::Block_driver : Usb::Completion,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p.succeded) {
|
if (!p.succeded) {
|
||||||
Genode::error("init complete error: packet not succeded");
|
Genode::error("init complete error: packet not succeeded");
|
||||||
iface.release(p);
|
iface.release(p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -720,6 +720,12 @@ struct Usb::Block_driver : Usb::Completion,
|
||||||
/* USB device gets initialized by handle_state_change() */
|
/* USB device gets initialized by handle_state_change() */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~Block_driver()
|
||||||
|
{
|
||||||
|
Interface &iface = device.interface(active_interface);
|
||||||
|
iface.release();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send CBW
|
* Send CBW
|
||||||
*/
|
*/
|
||||||
|
@ -812,9 +818,13 @@ struct Usb::Main
|
||||||
driver = new (&alloc) Usb::Block_driver(env, alloc, sigh);
|
driver = new (&alloc) Usb::Block_driver(env, alloc, sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block::Driver *create() { return driver; }
|
Block::Driver *create() override { return driver; }
|
||||||
|
|
||||||
void destroy(Block::Driver *driver) { }
|
void destroy(Block::Driver *driver) override
|
||||||
|
{
|
||||||
|
Genode::destroy(alloc, driver);
|
||||||
|
driver = nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory factory { env, heap, announce_dispatcher };
|
Factory factory { env, heap, announce_dispatcher };
|
||||||
|
|
Loading…
Reference in New Issue