Commit e43f3fab authored by Darron Broad's avatar Darron Broad Committed by Mauro Carvalho Chehab

V4L/DVB (9266): videobuf: properly handle attachment failure

This fixes attachment failure where we now unwind
attachment and skip non-attached nodes where
necessary so we can survive a fault situation
correctly.
Signed-off-by: default avatarDarron Broad <darron@kewl.org>
Signed-off-by: default avatarSteven Toth <stoth@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 7bdf84fc
...@@ -145,19 +145,19 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, ...@@ -145,19 +145,19 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
{ {
struct list_head *list, *q; struct list_head *list, *q;
struct videobuf_dvb_frontend *fe; struct videobuf_dvb_frontend *fe;
int res = -EINVAL; int res;
fe = videobuf_dvb_get_frontend(f, 1); fe = videobuf_dvb_get_frontend(f, 1);
if (!fe) { if (!fe) {
printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); printk(KERN_WARNING "Unable to register the adapter which has no frontends\n");
goto err; return -EINVAL;
} }
/* Bring up the adapter */ /* Bring up the adapter */
res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr, mfe_shared); res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr, mfe_shared);
if (res < 0) { if (res < 0) {
printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res);
goto err; return res;
} }
/* Attach all of the frontends to the adapter */ /* Attach all of the frontends to the adapter */
...@@ -168,11 +168,15 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, ...@@ -168,11 +168,15 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f,
if (res < 0) { if (res < 0) {
printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n",
fe->dvb.name, res); fe->dvb.name, res);
goto err;
} }
} }
mutex_unlock(&f->lock); mutex_unlock(&f->lock);
return 0;
err: err:
mutex_unlock(&f->lock);
videobuf_dvb_unregister_bus(f);
return res; return res;
} }
...@@ -264,6 +268,10 @@ int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_ ...@@ -264,6 +268,10 @@ int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_
/* register network adapter */ /* register network adapter */
dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
if (dvb->net.dvbdev == NULL) {
result = -ENOMEM;
goto fail_fe_conn;
}
return 0; return 0;
fail_fe_conn: fail_fe_conn:
...@@ -278,7 +286,7 @@ int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_ ...@@ -278,7 +286,7 @@ int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_
dvb_unregister_frontend(dvb->frontend); dvb_unregister_frontend(dvb->frontend);
fail_frontend: fail_frontend:
dvb_frontend_detach(dvb->frontend); dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(adapter); dvb->frontend = NULL;
return result; return result;
} }
...@@ -291,15 +299,18 @@ void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f) ...@@ -291,15 +299,18 @@ void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f)
mutex_lock(&f->lock); mutex_lock(&f->lock);
list_for_each_safe(list, q, &f->felist) { list_for_each_safe(list, q, &f->felist) {
fe = list_entry(list, struct videobuf_dvb_frontend, felist); fe = list_entry(list, struct videobuf_dvb_frontend, felist);
if(fe->dvb.net.dvbdev) {
dvb_net_release(&fe->dvb.net); dvb_net_release(&fe->dvb.net);
fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem); fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem);
fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw); fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw);
dvb_dmxdev_release(&fe->dvb.dmxdev); dvb_dmxdev_release(&fe->dvb.dmxdev);
dvb_dmx_release(&fe->dvb.demux); dvb_dmx_release(&fe->dvb.demux);
dvb_unregister_frontend(fe->dvb.frontend); dvb_unregister_frontend(fe->dvb.frontend);
}
if(fe->dvb.frontend) { /* always allocated, may have been reset */
dvb_frontend_detach(fe->dvb.frontend); dvb_frontend_detach(fe->dvb.frontend);
fe->dvb.frontend = NULL;
}
list_del(list); list_del(list);
kfree(fe); kfree(fe);
} }
......
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