On Sun, 2011-03-27 at 17:06 +0200, Huber Andreas wrote: > Package: linux-source-2.6.38 > Version: 2.6.38-1 > Severity: important > Tags: upstream > > > [Symptom] > Processes that try to open a cx88-blackbird driven MPEG device will hang up. > > [Cause] > Nestet mutex_locks (which are not allowed) result in a deadlock.
Could you test whether this patch fixes the problem? Instructions for rebuilding the kernel package are at <http://kernel-handbook.alioth.debian.org/ch-common-tasks.html#s-common-official>. Ben. -- Ben Hutchings Once a job is fouled up, anything done to improve it makes it worse.
From 9b33bf237c5b0910efa7a20d3ebc45ba4f5cd2cf Mon Sep 17 00:00:00 2001 From: Ben Hutchings <b...@decadent.org.uk> Date: Tue, 29 Mar 2011 03:25:15 +0100 Subject: [PATCH] cx88: Try to fix locking of sub-driver operations and device lists The BKL conversion of this family of drivers seems to have gone wrong. Opening cx88-blackbird will deadlock. Various other uses of the sub-device and driver lists appear to be subject to race conditions. Add and use a mutex to protect the device list. Note which driver functions require the device core lock, and make the callers (many of which already need it) lock. Compile-tested only. Signed-off-by: Ben Hutchings <b...@decadent.org.uk> --- drivers/media/video/cx88/cx88-blackbird.c | 4 +++- drivers/media/video/cx88/cx88-dvb.c | 2 ++ drivers/media/video/cx88/cx88-mpeg.c | 25 ++++++++++++++++++------- drivers/media/video/cx88/cx88.h | 4 ++++ 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index bca307e..201cdfc 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1120,15 +1120,17 @@ static int mpeg_release(struct file *file) videobuf_mmap_free(&fh->mpegq); mutex_lock(&dev->core->lock); + file->private_data = NULL; kfree(fh); - mutex_unlock(&dev->core->lock); /* Make sure we release the hardware */ drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); if (drv) drv->request_release(drv); + mutex_unlock(&dev->core->lock); + atomic_dec(&dev->core->mpeg_users); return 0; diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 90717ee..5eccd02 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -132,6 +132,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) return -EINVAL; } + mutex_lock(&dev->core->lock); drv = cx8802_get_driver(dev, CX88_MPEG_DVB); if (drv) { if (acquire){ @@ -142,6 +143,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) dev->frontends.active_fe_id = 0; } } + mutex_unlock(&dev->core->lock); return ret; } diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index addf954..57b08c6 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -78,6 +78,7 @@ static void flush_request_modules(struct cx8802_dev *dev) static LIST_HEAD(cx8802_devlist); +static DEFINE_MUTEX(cx8802_mutex); /* ------------------------------------------------------------------ */ static int cx8802_start_dma(struct cx8802_dev *dev, @@ -624,13 +625,11 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) if (drv->advise_acquire) { - mutex_lock(&drv->core->lock); core->active_ref++; if (core->active_type_id == CX88_BOARD_NONE) { core->active_type_id = drv->type_id; drv->advise_acquire(drv); } - mutex_unlock(&drv->core->lock); mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); } @@ -643,14 +642,12 @@ static int cx8802_request_release(struct cx8802_driver *drv) { struct cx88_core *core = drv->core; - mutex_lock(&drv->core->lock); if (drv->advise_release && --core->active_ref == 0) { drv->advise_release(drv); core->active_type_id = CX88_BOARD_NONE; mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); } - mutex_unlock(&drv->core->lock); return 0; } @@ -693,6 +690,8 @@ int cx8802_register_driver(struct cx8802_driver *drv) return err; } + mutex_lock(&cx8802_mutex); + list_for_each_entry(dev, &cx8802_devlist, devlist) { printk(KERN_INFO "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", @@ -702,8 +701,10 @@ int cx8802_register_driver(struct cx8802_driver *drv) /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv),GFP_KERNEL); - if (driver == NULL) - return -ENOMEM; + if (driver == NULL) { + err = -ENOMEM; + goto out; + } /* Snapshot of the driver registration data */ drv->core = dev->core; @@ -727,7 +728,10 @@ int cx8802_register_driver(struct cx8802_driver *drv) } - return i ? 0 : -ENODEV; + err = i ? 0 : -ENODEV; +out: + mutex_unlock(&cx8802_mutex); + return err; } int cx8802_unregister_driver(struct cx8802_driver *drv) @@ -741,6 +745,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + mutex_lock(&cx8802_mutex); + list_for_each_entry(dev, &cx8802_devlist, devlist) { printk(KERN_INFO "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", @@ -748,6 +754,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) dev->pci->subsystem_device, dev->core->board.name, dev->core->boardnr); + mutex_lock(&dev->core->lock); + list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) { /* only unregister the correct driver type */ if (d->type_id != drv->type_id) @@ -764,8 +772,11 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) "failed (%d)\n", dev->core->name, err); } + mutex_unlock(&dev->core->lock); } + mutex_unlock(&cx8802_mutex); + return err; } diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index c9981e7..74a3bad 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -499,6 +499,8 @@ struct cx8802_driver { int (*probe)(struct cx8802_driver *drv); int (*remove)(struct cx8802_driver *drv); + /* Callers to the following functions must hold core->lock */ + /* MPEG 8802 -> mini driver - Access for hardware control */ int (*advise_acquire)(struct cx8802_driver *drv); int (*advise_release)(struct cx8802_driver *drv); @@ -675,6 +677,8 @@ int cx88_audio_thread(void *data); int cx8802_register_driver(struct cx8802_driver *drv); int cx8802_unregister_driver(struct cx8802_driver *drv); + +/* Caller must hold core->lock */ struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); /* ----------------------------------------------------------- */ -- 1.7.4.1
signature.asc
Description: This is a digitally signed message part