dvb-core: Fix several locking related problems.
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/1 dvb-core: Fix several locking related problems.
Fix several instances of dvb-core functions using mutex_lock_interruptible and returning -ERESTARTSYS where the calling function will either never retry or never check the return value.
These cause a race condition with dvb_dmxdev_filter_free and dvb_dvr_release, both of which are filesystem release functions whose return value is ignored and will never be retried. When this happens it becomes impossible to open dvr0 again (-EBUSY) since it has not been released properly.
---
Quoted 3 lines · Andreas Oberritter
please send an updated patch together with
Signed-off-by line to Mauro <[email protected]> and ask him to apply it for inclusion into the -mm tree for further testing.
Unless there are other -mm trees I've not heard about, presumably I should just do this myself. Doesn't linux-dvb have it's own development tree this would get better tested in?
The dvb_dvr_release change has been working for me for 6 months and the dvb_dmxdev_filter_free (dvb_dmxdev_filter_free) change looks equivalent. See http://www.linuxtv.org/pipermail/linux-dvb/2007-February/016120.html for an example of the bug before and after fixing.
All the other changes run ok for me but should have lockdep enabled when testing (if there's a possible deadlock somewhere, using _interruptible will hide it).
drivers/media/dvb/dvb-core/dmxdev.c | 12 +++--------- drivers/media/dvb/dvb-core/dvb_demux.c | 21 +++++++-------------- drivers/media/dvb/dvb-core/dvbdev.c | 9 +++------ 3 files changed, 13 insertions(+), 29 deletions(-)
drivers/media/dvb/dvb-core/dmxdev.c +0 -0
@@ -180,8 +180,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv;
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&dmxdev->mutex);
if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
dmxdev->demux->disconnect_frontend(dmxdev->demux);@@ -673,13 +672,8 @@ static int dvb_demux_open(struct inode *inode, struct file *file) static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter)
{
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
-
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- mutex_unlock(&dmxdev->mutex);
- return -ERESTARTSYS;
- }
+ mutex_lock(&dmxdev->mutex);
+ mutex_lock(&dmxdevfilter->mutex);
dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter);
drivers/media/dvb/dvb-core/dvb_demux.c +0 -0
@@ -673,8 +673,7 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
struct dvb_demux *demux = feed->demux; int ret;
- if (mutex_lock_interruptible(&demux->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&demux->mutex);
if (feed->state < DMX_STATE_GO) {
mutex_unlock(&demux->mutex);
@@ -748,8 +747,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
struct dvb_demux *demux = (struct dvb_demux *)dmx;
struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;- if (mutex_lock_interruptible(&demux->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&demux->mutex);
if (feed->state == DMX_STATE_FREE) {
mutex_unlock(&demux->mutex);
@@ -916,8 +914,7 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
int ret;- if (mutex_lock_interruptible(&dvbdmx->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&dvbdmx->mutex);
if (!dvbdmx->stop_feed) {
mutex_unlock(&dvbdmx->mutex);
@@ -942,8 +939,7 @@ static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;- if (mutex_lock_interruptible(&dvbdmx->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&dvbdmx->mutex);
if (dvbdmxfilter->feed != dvbdmxfeed) {
mutex_unlock(&dvbdmx->mutex);
@@ -1016,8 +1012,7 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;- if (mutex_lock_interruptible(&dvbdmx->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&dvbdmx->mutex);
if (dvbdmxfeed->state == DMX_STATE_FREE) {
mutex_unlock(&dvbdmx->mutex);
@@ -1126,8 +1121,7 @@ static int dvbdmx_connect_frontend(struct dmx_demux *demux,
if (demux->frontend)
return -EINVAL;- if (mutex_lock_interruptible(&dvbdemux->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&dvbdemux->mutex);
demux->frontend = frontend;
mutex_unlock(&dvbdemux->mutex);
@@ -1138,8 +1132,7 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
{
struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;- if (mutex_lock_interruptible(&dvbdemux->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&dvbdemux->mutex);
demux->frontend = NULL; mutex_unlock(&dvbdemux->mutex);
drivers/media/dvb/dvb-core/dvbdev.c +0 -0
@@ -203,8 +203,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
int id;
- if (mutex_lock_interruptible(&dvbdev_register_lock))
- return -ERESTARTSYS;
+ mutex_lock(&dvbdev_register_lock);
if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
@@ -294,8 +293,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
{
int num;- if (mutex_lock_interruptible(&dvbdev_register_lock))
- return -ERESTARTSYS;
+ mutex_lock(&dvbdev_register_lock);
if ((num = dvbdev_get_free_adapter_num ()) < 0) {
mutex_unlock(&dvbdev_register_lock);@@ -323,8 +321,7 @@ EXPORT_SYMBOL(dvb_register_adapter);
int dvb_unregister_adapter(struct dvb_adapter *adap) {
- if (mutex_lock_interruptible(&dvbdev_register_lock))
- return -ERESTARTSYS;
+ mutex_lock(&dvbdev_register_lock); list_del (&adap->list_head); mutex_unlock(&dvbdev_register_lock); return 0;
Signature · 4 lines
1.5.0.1 -- Simon Arlott
Quoted 11 lines · Simon Arlott
Fix several instances of dvb-core functions using
mutex_lock_interruptibleand returning-ERESTARTSYSwhere the calling function will either never retry or never check the return value.These cause a race condition with
dvb_dmxdev_filter_freeanddvb_dvr_release, both of which are filesystem release functions whose return value is ignored and will never be retried. When this happens it becomes impossible to open dvr0 again (-EBUSY) since it has not been released properly.Signed-off-by Simon Arlott <[email protected]>
I can't test this but to me it looks good. Mauro, could you please pick it up and keep it in the linuxtv.org repository for a while for testing?
Thanks,
Johannes
Quoted 186 lines
---
Quoted 3 lines · Andreas Oberritter
please send an updated patch together with
Signed-off-by line to Mauro <[email protected]> and ask him to apply it for inclusion into the -mm tree for further testing.Unless there are other -mm trees I've not heard about, presumably I should just do this myself. Doesn't linux-dvb have it's own development tree this would get better tested in?
The
dvb_dvr_releasechange has been working for me for 6 months and thedvb_dmxdev_filter_free(dvb_dmxdev_filter_free) change looks equivalent. See http://www.linuxtv.org/pipermail/linux-dvb/2007-February/016120.html
for an example of the bug before and after fixing.All the other changes run ok for me but should have lockdep enabled when testing (if there's a possible deadlock somewhere, using
_interruptiblewill hide it).drivers/media/dvb/dvb-core/dmxdev.c | 12 +++--------- drivers/media/dvb/dvb-core/dvb_demux.c | 21 +++++++-------------- drivers/media/dvb/dvb-core/dvbdev.c | 9 +++------ 3 files changed, 13 insertions(+), 29 deletions(-)drivers/media/dvb/dvb-core/dmxdev.c +1
-2@@ -180,8 +180,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)struct dvb_device *dvbdev = file->private_data;struct dmxdev *dmxdev = dvbdev->priv; -if (mutex_lock_interruptible (&dmxdev->mutex)) -return -ERESTARTSYS ; +mutex_lock (&dmxdev->mutex);if ((file->f_flags &O_ACCMODE ) ==O_WRONLY ) {dmxdev->demux->disconnect_frontend(dmxdev->demux);drivers/media/dvb/dvb-core/dmxdev.c +2
-7@@ -673,13 +672,8 @@ static int dvb_demux_open(struct inode *inode, struct file *file)static int dvb_dmxdev_filter_free (struct dmxdev *dmxdev,struct dmxdev_filter *dmxdevfilter) { -if (mutex_lock_interruptible (&dmxdev->mutex)) -return -ERESTARTSYS ; - -if (mutex_lock_interruptible (&dmxdevfilter->mutex)) { -mutex_unlock (&dmxdev->mutex); -return -ERESTARTSYS ; - } +mutex_lock (&dmxdev->mutex); +mutex_lock (&dmxdevfilter->mutex);dvb_dmxdev_filter_stop (dmxdevfilter);dvb_dmxdev_filter_reset(dmxdevfilter);drivers/media/dvb/dvb-core/dvb_demux.c +1
-2@@ -673,8 +673,7 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)struct dvb_demux *demux = feed->demux;int ret; -if (mutex_lock_interruptible (&demux->mutex)) -return -ERESTARTSYS ; +mutex_lock (&demux->mutex);if (feed->state <DMX_STATE_GO ) {mutex_unlock(&demux->mutex);drivers/media/dvb/dvb-core/dvb_demux.c +2
-4@@ -748,8 +747,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,struct dvb_demux *demux = (struct dvb_demux *)dmx;struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; -if (mutex_lock_interruptible (&demux->mutex)) -return -ERESTARTSYS ; +mutex_lock (&demux->mutex);if (feed->state ==DMX_STATE_FREE ) {mutex_unlock (&demux->mutex);@@ -916,8 +914,7 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)struct dvb_demux *dvbdmx = dvbdmxfeed->demux;int ret; -if (mutex_lock_interruptible (&dvbdmx->mutex)) -return -ERESTARTSYS ; +mutex_lock (&dvbdmx->mutex);if (!dvbdmx->stop_feed) {mutex_unlock(&dvbdmx->mutex);drivers/media/dvb/dvb-core/dvb_demux.c +1
-2@@ -942,8 +939,7 @@ static int dmx_section_feed_release_filter(structdmx_section_feed *feed, struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;struct dvb_demux *dvbdmx = dvbdmxfeed->demux; -if (mutex_lock_interruptible (&dvbdmx->mutex)) -return -ERESTARTSYS ; +mutex_lock (&dvbdmx->mutex);if (dvbdmxfilter->feed != dvbdmxfeed) {mutex_unlock(&dvbdmx->mutex);drivers/media/dvb/dvb-core/dvb_demux.c +1
-2@@ -1016,8 +1012,7 @@ static int dvbdmx_release_section_feed(structdmx_demux *demux, struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; -if (mutex_lock_interruptible (&dvbdmx->mutex)) -return -ERESTARTSYS ; +mutex_lock (&dvbdmx->mutex);if (dvbdmxfeed->state ==DMX_STATE_FREE ) {mutex_unlock(&dvbdmx->mutex);drivers/media/dvb/dvb-core/dvb_demux.c +1
-2@@ -1126,8 +1121,7 @@ static int dvbdmx_connect_frontend(struct dmx_demux *demux, if (demux->frontend) return -EINVAL; -if (mutex_lock_interruptible (&dvbdemux->mutex)) -return -ERESTARTSYS ; +mutex_lock (&dvbdemux->mutex); demux->frontend = frontend;mutex_unlock(&dvbdemux->mutex);drivers/media/dvb/dvb-core/dvb_demux.c +1
-2@@ -1138,8 +1132,7 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) {struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; -if (mutex_lock_interruptible (&dvbdemux->mutex)) -return -ERESTARTSYS ; +mutex_lock (&dvbdemux->mutex); demux->frontend =NULL ;mutex_unlock(&dvbdemux->mutex);drivers/media/dvb/dvb-core/dvbdev.c +1
-2@@ -203,8 +203,7 @@ int dvb_register_device(struct dvb_adapter *adap,struct dvb_device **pdvbdev, int id; -if (mutex_lock_interruptible (&dvbdev_register_lock)) -return -ERESTARTSYS ; +mutex_lock (&dvbdev_register_lock);if ((id =dvbdev_get_free_id (adap, type)) <0 ){mutex_unlock(&dvbdev_register_lock);drivers/media/dvb/dvb-core/dvbdev.c +0
-0@@ -294,8 +293,7 @@ int dvb_register_adapter(struct dvb_adapter *adap,const char *name, struct modu
{ int num;drivers/media/dvb/dvb-core/dvbdev.c +1
-2-if (mutex_lock_interruptible (&dvbdev_register_lock)) -return -ERESTARTSYS ; +mutex_lock (&dvbdev_register_lock);if ((num = dvbdev_get_free_adapter_num ()) < 0) { mutex_unlock(&dvbdev_register_lock);drivers/media/dvb/dvb-core/dvbdev.c +1
-2@@ -323,8 +321,7 @@ EXPORT_SYMBOL(dvb_register_adapter);int dvb_unregister_adapter (struct dvb_adapter *adap) { -if (mutex_lock_interruptible (&dvbdev_register_lock)) -return -ERESTARTSYS ; +mutex_lock (&dvbdev_register_lock);list_del (&adap->list_head);mutex_unlock (&dvbdev_register_lock);return 0 ;Signature · 9 lines
1.5.0.1 -- Simon Arlott - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Em Sáb, 2007-03-10 às 02:49 +0100, Johannes Stezenbach escreveu:
Quoted 11 lines · Simon Arlott
Quoted 10 lines
Fix several instances of dvb-core functions using
mutex_lock_interruptibleand returning-ERESTARTSYSwhere the calling function will either never retry or never check the return value.These cause a race condition with
dvb_dmxdev_filter_freeanddvb_dvr_release, both of which are filesystem release functions whose return value is ignored and will never be retried. When this happens it becomes impossible to open dvr0 again (-EBUSY) since it has not been released properly.
Quoted 7 lines
Quoted 1 line
Signed-off-by Simon Arlott <[email protected]>I can't test this but to me it looks good. Mauro, could you please pick it up and keep it in the linuxtv.org repository for a while for testing?
Done.
Thanks, Johannes.
Signature · 2 lines
Cheers, Mauro