bttv: fix mutex use before init
PATCH 1/1 bttv: fix mutex use before init
oops happen in bttv_open while locking uninitialized mutex fh->cap.vb_lock add mutex_init before usage
--- drivers/media/video/bt8xx/bttv-driver.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/media/video/bt8xx/bttv-driver.c +2 -0
@@ -3291,6 +3291,8 @@ static int bttv_open(struct file *file) fh =kmalloc (sizeof (*fh),GFP_KERNEL );if (unlikely (!fh))return -ENOMEM ; + +mutex_init (&fh->cap.vb_lock); file->private_data = fh;/*
Quoted 2 lines · Dave Young
oops happen in
bttv_openwhile locking uninitialized mutexfh->cap.vb_lockaddmutex_initbefore usage
I have seen the same problem twice since I switched of the BKL in 2.6.37-rc2, but only had the time today to search for the cause. (It only happend on two boots out of probably more then 50, so I only investigated after it happened a second time with -rc5)
The cause was making this change to bttv_open() and radio_open() to remove the BKL from them:
+ mutex_lock(&fh->cap.vb_lock);
*fh = btv->init;
+ mutex_unlock(&fh->cap.vb_lock);
This is wrong because of two things:
First: The fh->cap.vb_lock has not been initialised, as you noted.
Second: The middle line will overwrite the mutex!
Just adding mutex_init() will not really help the second problem and seems to be wrong from the point that cap.vb_lock already has a mutex_init() via videobuf_queue_sg_init().
I'm not sure what the correct fix is, but I would rather suggest this:
* change &fh->cap.vb_lock in bttv_open() AND radio_open() to&btv->init.cap.vb_lock
* add a mutex_init(&btv->init.cap.vb_lock) to the setup of init in bttv_probe()
Quoted 23 lines
Signed-off-by Dave Young <[email protected]>Tested-by Chris Clayton <[email protected]>---
drivers/media/video/bt8xx/bttv-driver.c | 2 ++1 file changed, 2 insertions(+)drivers/media/video/bt8xx/bttv-driver.c 2010-12-12 16:31:39.633333338 +0800 renamed from drivers/media/video/bt8xx/bttv-driver.c 2010-11-27 11:21:30.000000000 +0800 +2
-1@@ -3291,6 +3291,8 @@ static int bttv_open(struct file *file) fh = kmalloc(sizeof(*fh), GFP_KERNEL); if (unlikely(!fh)) return -ENOMEM; + + mutex_init(&fh->cap.vb_lock); file->private_data = fh; /* --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/
Quoted 15 lines · Torsten Kaiser
Quoted 2 lines · Dave Young
oops happen in
bttv_openwhile locking uninitialized mutexfh->cap.vb_lockaddmutex_initbefore usageI have seen the same problem twice since I switched of the BKL in 2.6.37-rc2, but only had the time today to search for the cause. (It only happend on two boots out of probably more then 50, so I only investigated after it happened a second time with -rc5)
The cause was making this change to
bttv_open()andradio_open()to remove the BKL from them:(quoted diff) +2
-0+ mutex_lock(&fh->cap.vb_lock); *fh = btv->init; + mutex_unlock(&fh->cap.vb_lock);
Quoted 7 lines
This is wrong because of two things:
First: Thefh->cap.vb_lockhas not been initialised, as you noted.
Second: The middle line will overwrite the mutex!Just adding
mutex_init()will not really help the second problem and seems to be wrong from the point that cap.vb_lock already has amutex_init()viavideobuf_queue_sg_init().
Yes, you are right. I wonder if the above lock code in bttv_open and radio_open can be removed or just use btv->lock.
Quoted 6 lines
I'm not sure what the correct fix is, but I would rather suggest this:
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()
I will test this when the bttv card is available for me tommorrow.
Quoted 24 lines
Quoted 24 lines
Signed-off-by Dave Young <[email protected]>Tested-by Chris Clayton <[email protected]>---
drivers/media/video/bt8xx/bttv-driver.c | 2 ++1 file changed, 2 insertions(+)drivers/media/video/bt8xx/bttv-driver.c 2010-12-12 16:31:39.633333338 +0800 renamed from drivers/media/video/bt8xx/bttv-driver.c 2010-11-27 11:21:30.000000000 +0800 +2
-1@@ -3291,6 +3291,8 @@ static int bttv_open(struct file *file) fh = kmalloc(sizeof(*fh), GFP_KERNEL); if (unlikely(!fh)) return -ENOMEM; + + mutex_init(&fh->cap.vb_lock); file->private_data = fh; /* --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/
Quoted 20 lines · Dave Young
Quoted 19 lines · Torsten Kaiser
Quoted 2 lines · Dave Young
oops happen in
bttv_openwhile locking uninitialized mutexfh->cap.vb_lockaddmutex_initbefore usageI have seen the same problem twice since I switched of the BKL in 2.6.37-rc2, but only had the time today to search for the cause. (It only happend on two boots out of probably more then 50, so I only investigated after it happened a second time with -rc5)
The cause was making this change to
bttv_open()andradio_open()to remove the BKL from them:
+mutex_lock(&fh->cap.vb_lock);
*fh =btv->init;
+mutex_unlock(&fh->cap.vb_lock);This is wrong because of two things:
First: Thefh->cap.vb_lockhas not been initialised, as you noted.
Second: The middle line will overwrite the mutex!
Quoted 5 lines
Quoted 3 lines
Just adding
mutex_init()will not really help the second problem and seems to be wrong from the point that cap.vb_lock already has amutex_init()viavideobuf_queue_sg_init().Yes, you are right. I wonder if the above lock code in
bttv_openandradio_opencan be removed or just usebtv->lock.
In bttv_open there is a comment directly above this lock/unlock sequence that explains why cap.vb_lock was used. As that comment sounded correct, I did not look further into changing it.
Hmmh: I'm not sure, if I understand how this locking should work. It looks like each bttv_open() call will create a bttv_fh structure with its own cap.vb_lock. So if there ever is more then one bttv_fh for one btv, there is nothing that prevents concurrent access to btv->init, because there are two different cap.vb_lock. But if there always is only one bttv_fh, then why allocate it at all and not exclusively use btv->init, as that one will always be there already.
Disclaimer: I only started looking into bttv-driver.c yesterday when I was trying to find out, why I got these OOPSes. I probably missed something there...
Quoted 7 lines
Quoted 5 lines
I'm not sure what the correct fix is, but I would rather suggest this:
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()I will test this when the bttv card is available for me tommorrow.
I do have a bttv card, so if you want me to test something, I could do this.
Although: the current version of the code works for me. Even after the OOPS during bootup, I was later able to watch TV with that card.
Quoted 24 lines
Quoted 23 lines
Quoted 23 lines
Signed-off-by Dave Young <[email protected]>Tested-by Chris Clayton <[email protected]>---
drivers/media/video/bt8xx/bttv-driver.c | 2 ++1 file changed, 2 insertions(+)drivers/media/video/bt8xx/bttv-driver.c 2010-12-12 16:31:39.633333338 +0800 renamed from drivers/media/video/bt8xx/bttv-driver.c 2010-11-27 11:21:30.000000000 +0800 +2
-1@@ -3291,6 +3291,8 @@ static int bttv_open(struct file *file) fh = kmalloc(sizeof(*fh), GFP_KERNEL); if (unlikely(!fh)) return -ENOMEM; + + mutex_init(&fh->cap.vb_lock); file->private_data = fh; /* --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/
Quoted 3 lines · Torsten Kaiser
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()
That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
Quoted 1 line
From
456dc0ce36db523c4c0c8a269f4eec43a72de1dcMon Sep 17 00:00:00 2001
From: Brandon Philips <[email protected]>
Date: Mon, 13 Dec 2010 16:21:55 -0800
Subject: [PATCH] bttv: fix locking for btv->init
Fix locking for the btv->init by using btv->init.cap.vb_lock and in the process fix uninitialized deref introduced in c37db91fd0d.
--- drivers/media/video/bt8xx/bttv-driver.c | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-)
drivers/media/video/bt8xx/bttv-driver.c +13 -11
@@ -2391,16 +2391,11 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, fh->ov.field = win->field; fh->ov.setup_ok =1 ; -/* -* FIXME: btv is protected by btv->lock mutex, while btv->init -* is protected by fh->cap.vb_lock. This seems to open the -* possibility for some race situations. Maybe the better would -* be to unify those locks or to use another way to store the -* init values that will be consumed by videobuf callbacks -*/ +mutex_lock (&btv->init.cap.vb_lock); btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field; +mutex_unlock (&btv->init.cap.vb_lock);/* update overlay if needed */ retval =0 ;
@@ -2620,9 +2615,11 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fh->cap.last =V4L2_FIELD_NONE ; fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; +mutex_lock (&btv->init.cap.vb_lock); btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return 0 ;
@@ -2855,6 +2852,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval =0 ; fh->ovfmt = fmt; +mutex_lock (&btv->init.cap.vb_lock); btv->init.ovfmt = fmt;if (fb->flags &V4L2_FBUF_FLAG_OVERLAY ) { fh->ov.w.left =0 ;
@@ -2876,6 +2874,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval =bttv_switch_overlay (btv, fh, new); } } +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return retval; }
@@ -3141,6 +3140,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) fh->do_crop =1 ;mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock);if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width;
@@ -3158,6 +3158,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return 0 ;
@@ -3302,9 +3303,9 @@ static int bttv_open(struct file *file)* Let's first copy btv->init at fh, holding cap.vb_lock, and then work * with the rest of init, holding btv->lock. */ -mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); +mutex_unlock (&btv->init.cap.vb_lock); fh->type = type; fh->ov.setup_ok =0 ;
@@ -3502,9 +3503,9 @@ static int radio_open(struct file *file)if (unlikely (!fh))return -ENOMEM ; file->private_data = fh; -mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); +mutex_unlock (&btv->init.cap.vb_lock);mutex_lock (&btv->lock);v4l2_prio_open (&btv->prio, &fh->prio);
@@ -4489,6 +4490,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->opt_coring = coring;/* fill struct bttv with some useful defaults */ +mutex_init (&btv->init.cap.vb_lock); btv->init.btv = btv; btv->init.ov.w.width =320 ; btv->init.ov.w.height =240 ;
Signature · 1 line
1.7.3.1
Quoted 10 lines · Brandon Philips
Quoted 3 lines · Torsten Kaiser
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
Quoted 7 lines
From
456dc0ce36db523c4c0c8a269f4eec43a72de1dcMon Sep 17 00:00:00 2001
From: Brandon Philips <[email protected]>
Date: Mon, 13 Dec 2010 16:21:55 -0800
Subject: [PATCH] bttv: fix locking forbtv->initFix locking for the
btv->initby usingbtv->init.cap.vb_lockand in the process fix uninitialized deref introduced inc37db91fd0d.
Tested this patch, seems fine. But there's still possible deadlock, kernel hangs with lockdep warning, I think maybe it is another issue.
Could some v4l2 guys who have deep understand about bttv driver have a look at this issue?
[ 322.172772] bttv: driver version 0.9.18 loaded
[ 322.172781] bttv: using 8 buffers with 2080k (520 pages) each for capture
[ 322.173300] bttv: Bt8xx card found (0).
[ 322.174510] bttv 0000:03:01.0: PCI INT A -> GSI 17 (level, low) -> IRQ 17
[ 322.174560] bttv0: Bt878 (rev 17) at 0000:03:01.0, irq: 17, latency: 64, mmio: 0xd0001000
[ 322.174679] bttv0: detected: Leadtek WinFast TV 2000 [card=34], PCI subsystem ID is 107d:6606
[ 322.174687] bttv0: using: Leadtek WinFast 2000/ WinFast 2000 XP [card=34,autodetected]
[ 322.175062] bttv0: gpio: en=00000000, out=00000000 in=003fbfff [init]
[ 322.178792] bttv0: tuner type=5
[ 322.254454] bttv0: audio absent, no audio device found!
[ 322.289946] tuner 1-0061: chip found @ 0xc2 (bt878 #0 [sw])
[ 322.290944] tuner-simple 1-0061: creating new instance
[ 322.290953] tuner-simple 1-0061: type set to 5 (Philips PAL_BG (FI1216 and compatibles))
[ 322.295830] bttv0: registered device video0
[ 322.300020] bttv0: registered device vbi0
[ 322.303216] bttv0: registered device radio0
[ 322.303636] bttv0: PLL: 28636363 => 35468950 .. ok
[ 322.334635] Registered IR keymap rc-winfast
[ 322.341201] input: bttv IR (card=34) as /devices/pci0000:00/0000:00:1e.0/0000:03:01.0/rc/rc0/input4
[ 322.357025] rc0: bttv IR (card=34) as /devices/pci0000:00/0000:00:1e.0/0000:03:01.0/rc/rc0
[ 382.342433] bttv0: PLL can sleep, using XTAL (28636363).
[ 382.816353] irq event stamp: 1078776
[ 382.816363] hardirqs last enabled at (1078775): [<c105604d>] debug_check_no_locks_freed+0x102/0x113
[ 382.816381]
[ 382.816384] =======================================================
[ 382.816389] [ INFO: possible circular locking dependency detected ]
[ 382.816394] 2.6.37-rc5-00062-g6313e3c-dirty #114
[ 382.816398] -------------------------------------------------------
[ 382.816403] kdetv/2109 is trying to acquire lock:
[ 382.816408] (&mm->mmap_sem){++++++}, at: [<c10b1bf5>] might_fault+0x47/0x81
[ 382.816422]
[ 382.816424] but task is already holding lock:
[ 382.816427] (&q->vb_lock){+.+.+.}, at: [<e00af2be>] videobuf_queue_lock+0x10/0x12 [videobuf_core]
[ 382.816442]
[ 382.816444] which lock already depends on the new lock.
[ 382.816446]
[ 382.816449]
[ 382.816450] the existing dependency chain (in reverse order) is:
[ 382.816455]
[ 382.816456] -> #1 (&q->vb_lock){+.+.+.}:
[ 382.816463] [<c10574dc>] lock_acquire+0xa1/0xc4
[ 382.816472] [<c14ef90d>] __mutex_lock_common+0x35/0x2dc
[ 382.816482] [<c14efc52>] mutex_lock_nested+0x30/0x38
[ 382.816489] [<e00af2be>] videobuf_queue_lock+0x10/0x12 [videobuf_core]
[ 382.816499] [<e00af339>] videobuf_mmap_mapper+0x69/0xc0 [videobuf_core]
[ 382.816509] [<e18aae49>] bttv_mmap+0x66/0x6d [bttv]
[ 382.816522] [<c140009a>] v4l2_mmap+0x5a/0x73
[ 382.816532] [<c10b7f0c>] mmap_region+0x24c/0x400
[ 382.816540] [<c10b82ef>] do_mmap_pgoff+0x22f/0x27f
[ 382.816547] [<c10b841c>] sys_mmap_pgoff+0xdd/0x119
[ 382.816560] [<c14f0d55>] syscall_call+0x7/0xb
[ 382.816569]
[ 382.816571] -> #0 (&mm->mmap_sem){++++++}:
[ 382.816577] [<c105718c>] __lock_acquire+0x9d7/0xc86
[ 382.816585] [<c10574dc>] lock_acquire+0xa1/0xc4
[ 382.816592] [<c10b1c12>] might_fault+0x64/0x81
[ 382.816599] [<c1297552>] copy_to_user+0x2c/0xfe
[ 382.816608] [<e00b0851>] videobuf_read_stream+0x17f/0x24c [videobuf_core]
[ 382.816619] [<e18ab05b>] bttv_read+0xcf/0xe9 [bttv]
[ 382.816633] [<c14002bb>] v4l2_read+0x63/0x7f
[ 382.816640] [<c10ce67e>] vfs_read+0x81/0xdb
[ 382.816649] [<c10ce771>] sys_read+0x3b/0x60
[ 382.816655] [<c14f0d55>] syscall_call+0x7/0xb
[ 382.816663]
[ 382.816665] other info that might help us debug this:
[ 382.816667]
[ 382.816671] 1 lock held by kdetv/2109:
[ 382.816675] #0: (&q->vb_lock){+.+.+.}, at: [<e00af2be>] videobuf_queue_lock+0x10/0x12 [videobuf_core]
[ 382.816688]
[ 382.816690] stack backtrace:
[ 382.816695] Pid: 2109, comm: kdetv Not tainted 2.6.37-rc5-00062-g6313e3c-dirty #114
[ 382.816700] Call Trace:
[ 382.816639] hardirqs last disabled at (1078776): [<c1002ea7>] common_interrupt+0x27/0x34
[ 382.816639] softirqs last enabled at (1078294): [<c1034a8b>] __do_softirq+0x17b/0x183
[ 382.816639] softirqs last disabled at (1078271): [<c1003ffb>] do_softirq+0x67/0xc0
[ 382.816738] [<c14ee80b>] ? printk+0x20/0x24
[ 382.816748] [<c1056480>] print_circular_bug+0x9c/0xa8
[ 382.816758] [<c105718c>] __lock_acquire+0x9d7/0xc86
[ 382.816769] [<c103a908>] ? __mod_timer+0x10c/0x117
[ 382.816779] [<c10574dc>] lock_acquire+0xa1/0xc4
[ 382.816788] [<c10b1bf5>] ? might_fault+0x47/0x81
[ 382.816798] [<c10b1c12>] might_fault+0x64/0x81
[ 382.816807] [<c10b1bf5>] ? might_fault+0x47/0x81
[ 382.816815] [<c1297552>] copy_to_user+0x2c/0xfe
[ 382.816828] [<e00b0851>] videobuf_read_stream+0x17f/0x24c [videobuf_core]
[ 382.816844] [<e18ab05b>] bttv_read+0xcf/0xe9 [bttv]
[ 382.816854] [<c14002bb>] v4l2_read+0x63/0x7f
[ 382.816865] [<c1400258>] ? v4l2_read+0x0/0x7f
[ 382.816874] [<c10ce67e>] vfs_read+0x81/0xdb
[ 382.816883] [<c10ce771>] sys_read+0x3b/0x60
[ 382.816893] [<c14f0d55>] syscall_call+0x7/0xb
[ 382.816902] [<c14f0000>] ? rt_mutex_trylock+0x2a/0x2dQuoted 108 lines
Signed-off-by Brandon Philips <[email protected]>--- drivers/media/video/bt8xx/bttv-driver.c | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-)drivers/media/video/bt8xx/bttv-driver.c +13
-11@@ -2391,16 +2391,11 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, fh->ov.field = win->field; fh->ov.setup_ok =1 ; -/* -* FIXME: btv is protected by btv->lock mutex, while btv->init -* is protected by fh->cap.vb_lock. This seems to open the -* possibility for some race situations. Maybe the better would -* be to unify those locks or to use another way to store the -* init values that will be consumed by videobuf callbacks -*/ +mutex_lock (&btv->init.cap.vb_lock); btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field; +mutex_unlock (&btv->init.cap.vb_lock);/* update overlay if needed */ retval =0 ;@@ -2620,9 +2615,11 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fh->cap.last =V4L2_FIELD_NONE ; fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; +mutex_lock (&btv->init.cap.vb_lock); btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return 0 ;@@ -2855,6 +2852,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval =0 ; fh->ovfmt = fmt; +mutex_lock (&btv->init.cap.vb_lock); btv->init.ovfmt = fmt;if (fb->flags &V4L2_FBUF_FLAG_OVERLAY ) { fh->ov.w.left =0 ;@@ -2876,6 +2874,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval =bttv_switch_overlay (btv, fh, new); } } +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return retval; }@@ -3141,6 +3140,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) fh->do_crop =1 ;mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock);if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width;@@ -3158,6 +3158,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return 0 ;@@ -3302,9 +3303,9 @@ static int bttv_open(struct file *file)* Let's first copy btv->init at fh, holding cap.vb_lock, and then work * with the rest of init, holding btv->lock. */ -mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); +mutex_unlock (&btv->init.cap.vb_lock); fh->type = type; fh->ov.setup_ok =0 ;@@ -3502,9 +3503,9 @@ static int radio_open(struct file *file)if (unlikely (!fh))return -ENOMEM ; file->private_data = fh; -mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); +mutex_unlock (&btv->init.cap.vb_lock);mutex_lock (&btv->lock);v4l2_prio_open (&btv->prio, &fh->prio);@@ -4489,6 +4490,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->opt_coring = coring;/* fill struct bttv with some useful defaults */ +mutex_init (&btv->init.cap.vb_lock); btv->init.btv = btv; btv->init.ov.w.width =320 ; btv->init.ov.w.height =240 ;Signature · 1 line
1.7.3.1
Quoted 9 lines · Brandon Philips
Quoted 3 lines · Torsten Kaiser
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
No. :-)
Without this patch (==vanilla 2.6.37-rc5) I got 2 more OOPSe by restarting hal around 20 times.
After applying this patch, I did not see a single OOPS after 100 restarts. So it looks like the fix is correct.
Using the card also still works, but I think I found out what was causing sporadic shutdown problems with 37-rc kernels: When I try to exit tvtime it gets stuck in an uninterruptible D state and can't be killed. And that seems to mess up the shutdown.
But this happens independent with or without your patch and looks like different problem.
SysRQ+W provided this stack trace, maybe someone seens an obvious bug...:
[ 274.772528] ffff8800dec69680 0000000000000086 ffffffff81089d73 ffff8800729d05a0 [ 274.778599] 0000000000011480 ffff8800df923fd8 0000000000011480 ffff8800df922000 [ 274.778599] ffff8800df923fd8 0000000000011480 ffff8800dec69680 0000000000011480 [ 274.778599] Call Trace: [ 274.778599] [<ffffffff81089d73>] ? free_pcppages_bulk+0x343/0x3b0 [ 274.778599] [<ffffffff8156d0e1>] ? __mutex_lock_slowpath+0xe1/0x160 [ 274.778599] [<ffffffff8156cd8a>] ? mutex_lock+0x1a/0x40 [ 274.778599] [<ffffffff8141ab7f>] ? free_btres_lock.clone.19+0x3f/0x100 [ 274.778599] [<ffffffff8141d311>] ? bttv_release+0x1c1/0x1e0 [ 274.778599] [<ffffffff813fe4ba>] ? v4l2_release+0x4a/0x70 [ 274.778599] [<ffffffff810c5291>] ? fput+0xe1/0x250 [ 274.778599] [<ffffffff810c1d59>] ? filp_close+0x59/0x80 [ 274.778599] [<ffffffff810c1e0b>] ? sys_close+0x8b/0xe0 [ 274.778599] [<ffffffff8100253b>] ? system_call_fastpath+0x16/0x1b
Quoted 116 lines
From
456dc0ce36db523c4c0c8a269f4eec43a72de1dcMon Sep 17 00:00:00 2001
From: Brandon Philips <[email protected]>
Date: Mon, 13 Dec 2010 16:21:55 -0800
Subject: [PATCH] bttv: fix locking forbtv->initFix locking for the
btv->initby usingbtv->init.cap.vb_lockand in the process fix uninitialized deref introduced inc37db91fd0d.Signed-off-by Brandon Philips <[email protected]>---
drivers/media/video/bt8xx/bttv-driver.c | 24 +++++++++++++-----------1 files changed, 13 insertions(+), 11 deletions(-)drivers/media/video/bt8xx/bttv-driver.c +13
-12@@ -2391,16 +2391,11 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, fh->ov.field = win->field; fh->ov.setup_ok = 1; - /* - * FIXME: btv is protected by btv->lock mutex, while btv->init - * is protected by fh->cap.vb_lock. This seems to open the - * possibility for some race situations. Maybe the better would - * be to unify those locks or to use another way to store the - * init values that will be consumed by videobuf callbacks - */ + mutex_lock(&btv->init.cap.vb_lock); btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field; + mutex_unlock(&btv->init.cap.vb_lock); /* update overlay if needed */ retval = 0;@@ -2620,9 +2615,11 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fh->cap.last = V4L2_FIELD_NONE; fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; + mutex_lock(&btv->init.cap.vb_lock); btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; + mutex_unlock(&btv->init.cap.vb_lock); mutex_unlock(&fh->cap.vb_lock); return 0;@@ -2855,6 +2852,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval = 0; fh->ovfmt = fmt; + mutex_lock(&btv->init.cap.vb_lock); btv->init.ovfmt = fmt; if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { fh->ov.w.left = 0;@@ -2876,6 +2874,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval = bttv_switch_overlay(btv, fh, new); } } + mutex_unlock(&btv->init.cap.vb_lock); mutex_unlock(&fh->cap.vb_lock); return retval; }@@ -3141,6 +3140,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) fh->do_crop = 1; mutex_lock(&fh->cap.vb_lock); + mutex_lock(&btv->init.cap.vb_lock); if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width;@@ -3158,6 +3158,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } + mutex_unlock(&btv->init.cap.vb_lock); mutex_unlock(&fh->cap.vb_lock); return 0;@@ -3302,9 +3303,9 @@ static int bttv_open(struct file *file)* Let's first copy btv->init at fh, holding cap.vb_lock, and then work * with the rest of init, holding btv->lock. */ - mutex_lock(&fh->cap.vb_lock); + mutex_lock(&btv->init.cap.vb_lock); *fh = btv->init; - mutex_unlock(&fh->cap.vb_lock); + mutex_unlock(&btv->init.cap.vb_lock); fh->type = type; fh->ov.setup_ok = 0;@@ -3502,9 +3503,9 @@ static int radio_open(struct file *file) if (unlikely(!fh)) return -ENOMEM; file->private_data = fh; - mutex_lock(&fh->cap.vb_lock); + mutex_lock(&btv->init.cap.vb_lock); *fh = btv->init; - mutex_unlock(&fh->cap.vb_lock); + mutex_unlock(&btv->init.cap.vb_lock); mutex_lock(&btv->lock); v4l2_prio_open(&btv->prio, &fh->prio);@@ -4489,6 +4490,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->opt_coring = coring; /* fill struct bttv with some useful defaults */ + mutex_init(&btv->init.cap.vb_lock); btv->init.btv = btv; btv->init.ov.w.width = 320; btv->init.ov.w.height = 240; --1.7.3.1
Quoted 18 lines · Torsten Kaiser
Using the card also still works, but I think I found out what was causing sporadic shutdown problems with 37-rc kernels: When I try to exit tvtime it gets stuck in an uninterruptible D state and can't be killed. And that seems to mess up the shutdown.
But this happens independent with or without your patch and looks like different problem.
SysRQ+W provided this stack trace, maybe someone seens an obvious bug...:
[ 274.772528] ffff8800dec69680 0000000000000086ffffffff81089d73ffff8800729d05a0
[ 274.778599] 0000000000011480ffff8800df923fd80000000000011480ffff8800df922000
[ 274.778599] ffff8800df923fd8 0000000000011480ffff8800dec696800000000000011480
[ 274.778599] Call Trace:
[ 274.778599] [<ffffffff81089d73>] ?free_pcppages_bulk+0x343/0x3b0[ 274.778599] [<ffffffff8156d0e1>] ?__mutex_lock_slowpath+0xe1/0x160
Quoted 8 lines
[ 274.778599] [<ffffffff8156cd8a>] ?
mutex_lock+0x1a/0x40
[ 274.778599] [<ffffffff8141ab7f>] ? free_btres_lock.clone.19+0x3f/0x100 [ 274.778599] [<ffffffff8141d311>] ?bttv_release+0x1c1/0x1e0[ 274.778599] [<ffffffff813fe4ba>] ?v4l2_release+0x4a/0x70[ 274.778599] [<ffffffff810c5291>] ?fput+0xe1/0x250
[ 274.778599] [<ffffffff810c1d59>] ?filp_close+0x59/0x80
[ 274.778599] [<ffffffff810c1e0b>] ?sys_close+0x8b/0xe0
[ 274.778599] [<ffffffff8100253b>] ?system_call_fastpath+0x16/0x1b
Hmm:bttv_release() does mutex_lock(&btv->lock), then calls into free_btres_lock(...) that also first does mutex_lock(&btv->lock);
The calls to lock btv->lock in bttv_release() where added as part of the BKL removal, but I do not understand enough to fix this. Can this be dropped from bttv_release() completely, or would an unlocked version of free_btres_lock() be better?
Torsten
Quoted 9 lines · Torsten Kaiser
Quoted 8 lines · Brandon Philips
Quoted 3 lines · Torsten Kaiser
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Quoted 8 lines
Quoted 1 line
Would you mind testing it?
No. :-)
Without this patch (==vanilla 2.6.37-rc5) I got 2 more OOPSe by restarting hal around 20 times.
After applying this patch, I did not see a single OOPS after 100 restarts. So it looks like the fix is correct.
Dave, Torsten- Great thanks for testing, can I get both you and Dave's Tested-by then?
Mauro- can you please pick up this patch?
Cheers,
Brandon
Quoted 29 lines · Torsten Kaiser
Quoted 18 lines · Torsten Kaiser
Using the card also still works, but I think I found out what was causing sporadic shutdown problems with 37-rc kernels: When I try to exit tvtime it gets stuck in an uninterruptible D state and can't be killed. And that seems to mess up the shutdown.
But this happens independent with or without your patch and looks like different problem.
SysRQ+W provided this stack trace, maybe someone seens an obvious bug...:
[ 274.772528] ffff8800dec69680 0000000000000086ffffffff81089d73ffff8800729d05a0
[ 274.778599] 0000000000011480ffff8800df923fd80000000000011480ffff8800df922000
[ 274.778599] ffff8800df923fd8 0000000000011480ffff8800dec696800000000000011480
[ 274.778599] Call Trace:
[ 274.778599] [<ffffffff81089d73>] ?free_pcppages_bulk+0x343/0x3b0[ 274.778599] [<ffffffff8156d0e1>] ?__mutex_lock_slowpath+0xe1/0x160Quoted 8 lines
[ 274.778599] [<ffffffff8156cd8a>] ?
mutex_lock+0x1a/0x40
[ 274.778599] [<ffffffff8141ab7f>] ? free_btres_lock.clone.19+0x3f/0x100 [ 274.778599] [<ffffffff8141d311>] ?bttv_release+0x1c1/0x1e0[ 274.778599] [<ffffffff813fe4ba>] ?v4l2_release+0x4a/0x70[ 274.778599] [<ffffffff810c5291>] ?fput+0xe1/0x250
[ 274.778599] [<ffffffff810c1d59>] ?filp_close+0x59/0x80
[ 274.778599] [<ffffffff810c1e0b>] ?sys_close+0x8b/0xe0
[ 274.778599] [<ffffffff8100253b>] ?system_call_fastpath+0x16/0x1b
Quoted 4 lines
The calls to lock
btv->lockinbttv_release()where added as part of the BKL removal, but I do not understand enough to fix this. Can this be dropped frombttv_release()completely, or would an unlocked version offree_btres_lock()be better?
I would create an unlocked version of free_btres_lock. Does that fix the issue?
Cheers,
Brandon
Quoted 14 lines · Brandon Philips
Quoted 13 lines · Torsten Kaiser
Quoted 9 lines · Brandon Philips
Quoted 3 lines · Torsten Kaiser
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
No. :-)
Quoted 7 lines
Quoted 4 lines
Without this patch (==vanilla 2.6.37-rc5) I got 2 more OOPSe by restarting hal around 20 times.
After applying this patch, I did not see a single OOPS after 100 restarts. So it looks like the fix is correct.Dave, Torsten- Great thanks for testing, can I get both you and Dave's Tested-by then?
Feel free to add my tested-by line for this, Thanks
Quoted 7 lines
Mauro- can you please pick up this patch?
Cheers,
Brandon
Signature · 2 lines
Regards dave
Torsten Kaiser
Tested-byQuoted 14 lines · Brandon Philips
Quoted 13 lines · Torsten Kaiser
Quoted 9 lines · Brandon Philips
Quoted 3 lines · Torsten Kaiser
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
No. :-)
Quoted 7 lines
Quoted 4 lines
Without this patch (==vanilla 2.6.37-rc5) I got 2 more OOPSe by restarting hal around 20 times.
After applying this patch, I did not see a single OOPS after 100 restarts. So it looks like the fix is correct.Dave, Torsten- Great thanks for testing, can I get both you and Dave's Tested-by then?
Thanks for providing this patch.
Torsten
Chris Clayton
Tested-byQuoted 116 lines · Brandon Philips
Quoted 4 lines · Torsten Kaiser
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
From
456dc0ce36db523c4c0c8a269f4eec43a72de1dcMon Sep 17 00:00:00 2001
From: Brandon Philips <[email protected]>
Date: Mon, 13 Dec 2010 16:21:55 -0800
Subject: [PATCH] bttv: fix locking forbtv->initFix locking for the
btv->initby usingbtv->init.cap.vb_lockand in the process fix uninitialized deref introduced inc37db91fd0d.Signed-off-by Brandon Philips <[email protected]>--- drivers/media/video/bt8xx/bttv-driver.c | 24 +++++++++++++----------- 1 files changed, 13 insertions(+), 11 deletions(-)(quoted diff) +0
-0
b/drivers/media/video/bt8xx/bttv-driver.cindex a529619..e656424 100644drivers/media/video/bt8xx/bttv-driver.c +12
-11@@ -2391,16 +2391,11 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, fh->ov.field = win->field; fh->ov.setup_ok =1 ; -/* -* FIXME: btv is protected by btv->lock mutex, while btv->init -* is protected by fh->cap.vb_lock. This seems to open the -* possibility for some race situations. Maybe the better would -* be to unify those locks or to use another way to store the -* init values that will be consumed by videobuf callbacks -*/ +mutex_lock (&btv->init.cap.vb_lock); btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field; +mutex_unlock (&btv->init.cap.vb_lock);/* update overlay if needed */ retval =0 ;@@ -2620,9 +2615,11 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fh->cap.last = V4L2_FIELD_NONE; fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; +mutex_lock (&btv->init.cap.vb_lock); btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return 0 ;@@ -2855,6 +2852,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval =0 ; fh->ovfmt = fmt; +mutex_lock (&btv->init.cap.vb_lock); btv->init.ovfmt = fmt;if (fb->flags &V4L2_FBUF_FLAG_OVERLAY ) { fh->ov.w.left =0 ;@@ -2876,6 +2874,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval =bttv_switch_overlay (btv, fh, new); } } +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return retval; }@@ -3141,6 +3140,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) fh->do_crop = 1;mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock);if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width;@@ -3158,6 +3158,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } +mutex_unlock (&btv->init.cap.vb_lock);mutex_unlock (&fh->cap.vb_lock);return 0 ;@@ -3302,9 +3303,9 @@ static int bttv_open(struct file *file)* Let's first copy btv->init at fh, holding cap.vb_lock, and then work * with the rest of init, holding btv->lock. */ -mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); +mutex_unlock (&btv->init.cap.vb_lock); fh->type = type; fh->ov.setup_ok =0 ;@@ -3502,9 +3503,9 @@ static int radio_open(struct file *file)if (unlikely (!fh))return -ENOMEM ; file->private_data = fh; -mutex_lock (&fh->cap.vb_lock); +mutex_lock (&btv->init.cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); +mutex_unlock (&btv->init.cap.vb_lock);mutex_lock (&btv->lock);v4l2_prio_open (&btv->prio, &fh->prio);
drivers/media/video/bt8xx/bttv-driver.c static int __devinit bttv_probe(struct pci_dev *dev, · line 4496
Quoted 7 lines
drivers/media/video/bt8xx/bttv-driver.c +1
-0@@ -4489,6 +4490,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->opt_coring = coring;/* fill struct bttv with some useful defaults */ +mutex_init (&btv->init.cap.vb_lock); btv->init.btv = btv; btv->init.ov.w.width =320 ; btv->init.ov.w.height =240 ;
The patch is good here too. Thanks.
Signature · 2 lines
The more I see, the more I know. The more I know, the less I understand. Changing Man - Paul Weller
Em 15-12-2010 16:44, Chris Clayton escreveu:
Quoted 17 lines · Brandon Philips
Quoted 16 lines · Torsten Kaiser
Quoted 4 lines
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
From
456dc0ce36db523c4c0c8a269f4eec43a72de1dcMon Sep 17 00:00:00 2001
From: Brandon Philips <[email protected]>
Date: Mon, 13 Dec 2010 16:21:55 -0800
Subject: [PATCH] bttv: fix locking forbtv->init
Quoted 4 lines
Quoted 4 lines
Fix locking for the
btv->initby usingbtv->init.cap.vb_lockand in the process fix uninitialized deref introduced inc37db91fd0d.Signed-off-by Brandon Philips <[email protected]>
Hi Brandon & all,
While your patch fixes the issue, it has some other troubles, like to the presence of lock code at free_btres_lock(). It is possible to fix, but the better is to just use the core-assisted locking schema. This way, V4L2 core will serialize access to all ioctl's/open/close/mmap/read/poll operations, avoiding to have two processes accessing the hardware at the same time. Also, as there's just one lock, instead of 3, there's no risk of dead locks.
The net result is a cleaner code, with just one lock.
I tested the patch here with an bttv-based STB board (card=3, tuner=6), and it worked fine for me. Could you please test if this fixes the issue?
PS.: The patch is based against the bkl_removal patches, at my linux-next tree:
(I just created the bkl_removal branch, so, it may take some time for you to see at the kernel.org mirrors, but it is basically changeset 673eb9ff. You may also just apply it on the top of the master branch of my linux-next tree).
---
[media] bttv: Fix locking issues due to BKL removal code
The BKL removal patch added a condition where the code would try to use a non-initialized lock. While a patch just addressing the issue is possible, there are some other troubles, like to the presence of lock code at free_btres_lock(), called on some places with the lock already taken. It is possible to fix, but the better is to just use the core-assisted locking schema.
This way, V4L2 core will serialize access to all ioctl's/open/close/mmap/read/poll operations, avoiding to have two processes accessing the hardware at the same time. Also, as there's just one lock, instead of 3, there's no risk of dead locks.
Tested with bttv STB, Gateway P/N 6000699 (card 3, tuner 6).
drivers/media/video/bt8xx/bttv-driver.c +3 -94
@@ -854,7 +854,6 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) xbits |=RESOURCE_VIDEO_READ |RESOURCE_VIDEO_STREAM ;/* is it free? */ -mutex_lock (&btv->lock);if (btv->resources & xbits) {/* no, someone else uses it */ goto fail;
@@ -884,11 +883,9 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)/* it's free, grab it */ fh->resources |= bit; btv->resources |= bit; -mutex_unlock (&btv->lock);return 1 ; fail: -mutex_unlock (&btv->lock);return 0 ; }
@@ -940,7 +937,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)/* trying to free ressources not allocated by us ... */ printk ("bttv: BUG! (btres)\n" ); } -mutex_lock (&btv->lock); fh->resources &= ~bits; btv->resources &= ~bits;
@@ -951,8 +947,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)if (0 == (bits &VBI_RESOURCES ))disclaim_vbi_lines (btv); - -mutex_unlock (&btv->lock); }/* ----------------------------------------------------------------------- */
@@ -1713,28 +1707,20 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,/* Make sure tvnorm and vbi_end remain consistent until we're done. */ -mutex_lock (&btv->lock); norm = btv->tvnorm;/* In this mode capturing always starts at defrect.top (default VDELAY), ignoring cropping parameters. */ if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) { -mutex_unlock (&btv->lock);return -EINVAL ; } -mutex_unlock (&btv->lock); - c.rect = bttv_tvnorms[norm].cropcap.defrect; }else { -mutex_lock (&btv->lock); - norm = btv->tvnorm; c = btv->crop[!!fh->do_crop]; -mutex_unlock (&btv->lock); -if (width < c.min_scaled_width || width > c.max_scaled_width || height < c.min_scaled_height)
@@ -1858,7 +1844,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)unsigned int i;int err; -mutex_lock (&btv->lock); err =v4l2_prio_check (&btv->prio, fh->prio);if (err) goto err;
@@ -1874,7 +1859,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)set_tvnorm (btv, i); err: -mutex_unlock (&btv->lock);return err; }
@@ -1898,7 +1882,6 @@ static int bttv_enum_input(struct file *file, void *priv,struct bttv *btv = fh->btv;int rc =0 ; -mutex_lock (&btv->lock);if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { rc = -EINVAL ; goto err;
@@ -1928,7 +1911,6 @@ static int bttv_enum_input(struct file *file, void *priv, i->std =BTTV_NORMS ; err: -mutex_unlock (&btv->lock);return rc; }
@@ -1938,9 +1920,7 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i)struct bttv_fh *fh = priv;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock); *i = btv->input; -mutex_unlock (&btv->lock);return 0 ; }
@@ -1952,7 +1932,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)int err; -mutex_lock (&btv->lock); err =v4l2_prio_check (&btv->prio, fh->prio);if (unlikely (err)) goto err;
@@ -1965,7 +1944,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)set_input (btv, i, btv->tvnorm); err: -mutex_unlock (&btv->lock);return 0 ; }
@@ -1979,7 +1957,6 @@ static int bttv_s_tuner(struct file *file, void *priv,if (unlikely (0 != t->index))return -EINVAL ; -mutex_lock (&btv->lock);if (unlikely (btv->tuner_type ==TUNER_ABSENT )) { err = -EINVAL ; goto err;
@@ -1995,7 +1972,6 @@ static int bttv_s_tuner(struct file *file, void *priv, btv->audio_mode_gpio (btv, t,1 ); err: -mutex_unlock (&btv->lock);return 0 ; }
@@ -2006,10 +1982,8 @@ static int bttv_g_frequency(struct file *file, void *priv,struct bttv_fh *fh = priv;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock); f->type = btv->radio_user ?V4L2_TUNER_RADIO :V4L2_TUNER_ANALOG_TV ; f->frequency = btv->freq; -mutex_unlock (&btv->lock);return 0 ; }
@@ -2024,7 +1998,6 @@ static int bttv_s_frequency(struct file *file, void *priv,if (unlikely (f->tuner !=0 ))return -EINVAL ; -mutex_lock (&btv->lock); err =v4l2_prio_check (&btv->prio, fh->prio);if (unlikely (err)) goto err;
@@ -2039,7 +2012,6 @@ static int bttv_s_frequency(struct file *file, void *priv,if (btv->has_matchbox && btv->radio_user)tea5757_set_freq (btv, btv->freq); err: -mutex_unlock (&btv->lock);return 0 ; }
@@ -2172,7 +2144,6 @@ limit_scaled_size_lock (struct bttv_fh * fh,/* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. */ -mutex_lock (&btv->lock); b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
@@ -2250,7 +2221,6 @@ limit_scaled_size_lock (struct bttv_fh * fh, rc =0 ;/* success */ fail: -mutex_unlock (&btv->lock);return rc; }
@@ -2282,9 +2252,7 @@ verify_window_lock (struct bttv_fh * fh,if (V4L2_FIELD_ANY == field) {__s32 height2; -mutex_lock (&fh->btv->lock); height2 = fh->btv->crop[!!fh->do_crop].rect.height >>1 ; -mutex_unlock (&fh->btv->lock); field = (win->w.height > height2) ?V4L2_FIELD_INTERLACED :V4L2_FIELD_TOP ;
@@ -2360,7 +2328,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, } } -mutex_lock (&fh->cap.vb_lock);/* clip against screen */ if (NULL != btv->fbuf.base) n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
@@ -2412,7 +2379,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,bttv_overlay_risc (btv, &fh->ov, fh->ovfmt, new); retval =bttv_switch_overlay (btv,fh,new); } -mutex_unlock (&fh->cap.vb_lock);return retval; }
@@ -2526,9 +2492,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,if (V4L2_FIELD_ANY == field) {__s32 height2; -mutex_lock (&btv->lock); height2 = btv->crop[!!fh->do_crop].rect.height >>1 ; -mutex_unlock (&btv->lock); field = (f->fmt.pix.height > height2) ?V4L2_FIELD_INTERLACED :V4L2_FIELD_BOTTOM ;
@@ -2614,7 +2578,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fmt =format_by_fourcc (f->fmt.pix.pixelformat);/* update our state informations */ -mutex_lock (&fh->cap.vb_lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last =V4L2_FIELD_NONE ;
@@ -2623,7 +2586,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; -mutex_unlock (&fh->cap.vb_lock);return 0 ; }
@@ -2649,11 +2611,9 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)unsigned int i;struct bttv_fh *fh = priv; -mutex_lock (&fh->cap.vb_lock); retval =__videobuf_mmap_setup (&fh->cap, gbuffers, gbufsize,V4L2_MEMORY_MMAP );if (retval <0 ) { -mutex_unlock (&fh->cap.vb_lock);return retval; }
@@ -2665,7 +2625,6 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)for (i =0 ; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; -mutex_unlock (&fh->cap.vb_lock); return 0; }#endif
@@ -2775,10 +2734,8 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)int retval =0 ;if (on) { -mutex_lock (&fh->cap.vb_lock);/* verify args */ if (unlikely (!btv->fbuf.base)) { -mutex_unlock (&fh->cap.vb_lock);return -EINVAL ; }if (unlikely (!fh->ov.setup_ok)) {
@@ -2787,13 +2744,11 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) }if (retval)return retval; -mutex_unlock (&fh->cap.vb_lock); }if (!check_alloc_btres_lock (btv, fh,RESOURCE_OVERLAY ))return -EBUSY ; -mutex_lock (&fh->cap.vb_lock);if (on) { fh->ov.tvnorm = btv->tvnorm; new =videobuf_sg_alloc (sizeof (*new));
@@ -2805,7 +2760,6 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)/* switch over */ retval =bttv_switch_overlay (btv, fh, new); -mutex_unlock (&fh->cap.vb_lock);return retval; }
@@ -2844,7 +2798,6 @@ static int bttv_s_fbuf(struct file *file, void *f, }/* ok, accept it */ -mutex_lock (&fh->cap.vb_lock); btv->fbuf.base = fb->base; btv->fbuf.fmt.width = fb->fmt.width; btv->fbuf.fmt.height = fb->fmt.height;
@@ -2876,7 +2829,6 @@ static int bttv_s_fbuf(struct file *file, void *f, retval =bttv_switch_overlay (btv, fh, new); } } -mutex_unlock (&fh->cap.vb_lock);return retval; }
@@ -2955,7 +2907,6 @@ static int bttv_queryctrl(struct file *file, void *priv, c->id >= V4L2_CID_PRIVATE_LASTP1))return -EINVAL ; -mutex_lock (&btv->lock);if (!btv->volume_gpio && (c->id ==V4L2_CID_AUDIO_VOLUME )) *c = no_ctl;else {
@@ -2963,7 +2914,6 @@ static int bttv_queryctrl(struct file *file, void *priv, *c = (NULL != ctrl) ? *ctrl : no_ctl; } -mutex_unlock (&btv->lock);return 0 ; }
@@ -2974,10 +2924,8 @@ static int bttv_g_parm(struct file *file, void *f,struct bttv_fh *fh = f;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock);v4l2_video_std_frame_period (bttv_tvnorms[btv->tvnorm].v4l2_id, &parm->parm.capture.timeperframe); -mutex_unlock (&btv->lock);return 0 ; }
@@ -2993,7 +2941,6 @@ static int bttv_g_tuner(struct file *file, void *priv,if (0 != t->index)return -EINVAL ; -mutex_lock (&btv->lock); t->rxsubchans =V4L2_TUNER_SUB_MONO ;bttv_call_all (btv, tuner, g_tuner, t);strcpy (t->name,"Television" );
@@ -3005,7 +2952,6 @@ static int bttv_g_tuner(struct file *file, void *priv,if (btv->audio_mode_gpio) btv->audio_mode_gpio (btv, t,0 ); -mutex_unlock (&btv->lock);return 0 ; }
@@ -3014,9 +2960,7 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)struct bttv_fh *fh = f;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock); *p =v4l2_prio_max (&btv->prio); -mutex_unlock (&btv->lock);return 0 ; }
@@ -3028,9 +2972,7 @@ static int bttv_s_priority(struct file *file, void *f,struct bttv *btv = fh->btv;int rc; -mutex_lock (&btv->lock); rc =v4l2_prio_change (&btv->prio, &fh->prio, prio); -mutex_unlock (&btv->lock);return rc; }
@@ -3045,9 +2987,7 @@ static int bttv_cropcap(struct file *file, void *priv, cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) return -EINVAL; -mutex_lock (&btv->lock); *cap = bttv_tvnorms[btv->tvnorm].cropcap; -mutex_unlock (&btv->lock);return 0 ; }
@@ -3065,9 +3005,7 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)inconsistent with fh->width or fh->height and apps do not expect a change here. */ -mutex_lock (&btv->lock); crop->c = btv->crop[!!fh->do_crop].rect; -mutex_unlock (&btv->lock);return 0 ; }
@@ -3091,17 +3029,14 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)/* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. Note read() may change vbi_end in check_alloc_btres_lock(). */ -mutex_lock (&btv->lock); retval =v4l2_prio_check (&btv->prio, fh->prio);if (0 != retval) { -mutex_unlock (&btv->lock);return retval; } retval = -EBUSY ;if (locked_btres (fh->btv,VIDEO_RESOURCES )) { -mutex_unlock (&btv->lock);return retval; }
@@ -3113,7 +3048,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) b_top =max (b->top, btv->vbi_end);if (b_top +32 >= b_bottom) { -mutex_unlock (&btv->lock);return retval; }
@@ -3136,12 +3070,8 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->crop[1 ] = c; -mutex_unlock (&btv->lock); - fh->do_crop =1 ; -mutex_lock (&fh->cap.vb_lock); -if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width; btv->init.width = c.min_scaled_width;
@@ -3158,8 +3088,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } -mutex_unlock (&fh->cap.vb_lock); -return 0 ; }
@@ -3227,7 +3155,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)return videobuf_poll_stream (file, &fh->vbi, wait); } -mutex_lock (&fh->cap.vb_lock);if (check_btres (fh,RESOURCE_VIDEO_STREAM )) {/* streaming capture */ if (list_empty (&fh->cap.stream))
@@ -3262,7 +3189,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)else rc =0 ; err: -mutex_unlock (&fh->cap.vb_lock);return rc; }
@@ -3302,14 +3228,11 @@ static int bttv_open(struct file *file)* Let's first copy btv->init at fh, holding cap.vb_lock, and then work * with the rest of init, holding btv->lock. */ -mutex_lock (&fh->cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); fh->type = type; fh->ov.setup_ok =0 ; -mutex_lock (&btv->lock);v4l2_prio_open (&btv->prio, &fh->prio); videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
@@ -3317,13 +3240,13 @@ static int bttv_open(struct file *file)V4L2_BUF_TYPE_VIDEO_CAPTURE ,V4L2_FIELD_INTERLACED ,sizeof (struct bttv_buffer ), - fh, NULL); + fh, &btv->lock);videobuf_queue_sg_init (&fh->vbi, &bttv_vbi_qops, &btv->c.pci->dev, &btv->s_lock,V4L2_BUF_TYPE_VBI_CAPTURE ,V4L2_FIELD_SEQ_TB ,sizeof (struct bttv_buffer ), - fh,NULL ); + fh, &btv->lock);set_tvnorm (btv,btv->tvnorm);set_input (btv, btv->input, btv->tvnorm);
@@ -3346,7 +3269,6 @@ static int bttv_open(struct file *file)bttv_vbi_fmt_reset (&fh->vbi_fmt, btv->tvnorm);bttv_field_count (btv); -mutex_unlock (&btv->lock);return 0 ; }
@@ -3355,7 +3277,6 @@ static int bttv_release(struct file *file)struct bttv_fh *fh = file->private_data;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock);/* turn off overlay */ if (check_btres (fh,RESOURCE_OVERLAY ))bttv_switch_overlay (btv,fh,NULL );
@@ -3385,10 +3306,8 @@ static int bttv_release(struct file *file)* videobuf uses cap.vb_lock - we should avoid holding btv->lock, * otherwise we may have dead lock conditions */ -mutex_unlock (&btv->lock);videobuf_mmap_free (&fh->cap);videobuf_mmap_free (&fh->vbi); -mutex_lock (&btv->lock);v4l2_prio_close (&btv->prio, fh->prio); file->private_data =NULL ;kfree (fh);
@@ -3398,7 +3317,6 @@ static int bttv_release(struct file *file)if (!btv->users)audio_mute (btv,1 ); -mutex_unlock (&btv->lock);return 0 ; }
@@ -3502,11 +3420,8 @@ static int radio_open(struct file *file)if (unlikely (!fh))return -ENOMEM ; file->private_data = fh; -mutex_lock (&fh->cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); -mutex_lock (&btv->lock);v4l2_prio_open (&btv->prio, &fh->prio); btv->radio_user++;
@@ -3514,7 +3429,6 @@ static int radio_open(struct file *file)bttv_call_all (btv, tuner, s_radio);audio_input (btv,TVAUDIO_INPUT_RADIO ); -mutex_unlock (&btv->lock);return 0 ; }
@@ -3524,7 +3438,6 @@ static int radio_release(struct file *file)struct bttv *btv = fh->btv;struct rds_command cmd; -mutex_lock (&btv->lock);v4l2_prio_close (&btv->prio, fh->prio); file->private_data =NULL ;kfree (fh);
@@ -3532,7 +3445,6 @@ static int radio_release(struct file *file) btv->radio_user--;bttv_call_all (btv, core, ioctl,RDS_CMD_CLOSE , &cmd); -mutex_unlock (&btv->lock);return 0 ; }
@@ -3561,7 +3473,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)return -EINVAL ;if (0 != t->index)return -EINVAL ; -mutex_lock (&btv->lock);strcpy (t->name,"Radio" ); t->type =V4L2_TUNER_RADIO ;
@@ -3570,8 +3481,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)if (btv->audio_mode_gpio) btv->audio_mode_gpio (btv, t,0 ); -mutex_unlock (&btv->lock); -return 0 ; }
@@ -3692,7 +3601,7 @@ static const struct v4l2_file_operations radio_fops = .open = radio_open, .read = radio_read, .release = radio_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = radio_poll, };
Chris Clayton
Tested-byQuoted 657 lines · Mauro Carvalho Chehab
Em 15-12-2010 16:44, Chris Clayton escreveu:
Quoted 17 lines · Brandon Philips
Quoted 16 lines · Torsten Kaiser
Quoted 4 lines
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock
* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
From
456dc0ce36db523c4c0c8a269f4eec43a72de1dcMon Sep 17 00:00:00 2001
From: Brandon Philips <[email protected]>
Date: Mon, 13 Dec 2010 16:21:55 -0800
Subject: [PATCH] bttv: fix locking forbtv->initQuoted 4 lines
Quoted 4 lines
Fix locking for the
btv->initby usingbtv->init.cap.vb_lockand in the process fix uninitialized deref introduced inc37db91fd0d.Signed-off-by Brandon Philips <[email protected]>Hi Brandon & all,
While your patch fixes the issue, it has some other troubles, like to the presence of lock code at
free_btres_lock(). It is possible to fix, but the better is to just use the core-assisted locking schema. This way, V4L2 core will serialize access to all ioctl's/open/close/mmap/read/poll operations, avoiding to have two processes accessing the hardware at the same time. Also, as there's just one lock, instead of 3, there's no risk of dead locks.The net result is a cleaner code, with just one lock.
I tested the patch here with an bttv-based STB board (card=3, tuner=6), and it worked fine for me. Could you please test if this fixes the issue?
PS.: The patch is based against the
bkl_removalpatches, at my linux-next tree:http://git.kernel.org/?p=linux/kernel/git/mchehab/linux-next.git;a=commit;h
=673eb9ff33e26ee6f4278cdab06749aef1bbef5b(I just created the
bkl_removalbranch, so, it may take some time for you to see at the kernel.org mirrors, but it is basically changeset673eb9ff. You may also just apply it on the top of the master branch of my linux-next tree).---
[media] bttv: Fix locking issues due to BKL removal code
The BKL removal patch added a condition where the code would try to use a non-initialized lock. While a patch just addressing the issue is possible, there are some other troubles, like to the presence of lock code at
free_btres_lock(), called on some places with the lock already taken. It is possible to fix, but the better is to just use the core-assisted locking schema.This way, V4L2 core will serialize access to all ioctl's/open/close/mmap/read/poll operations, avoiding to have two processes accessing the hardware at the same time. Also, as there's just one lock, instead of 3, there's no risk of dead locks.
Tested with bttv STB, Gateway P/N 6000699 (card 3, tuner 6).
Signed-off-by Mauro Carvalho Chehab <[email protected]>(quoted diff) +0
-0
b/drivers/media/video/bt8xx/bttv-driver.cindex a529619..25e1ca0 100644drivers/media/video/bt8xx/bttv-driver.c +0
-1@@ -854,7 +854,6 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;/* is it free? */ -mutex_lock (&btv->lock);if (btv->resources & xbits) {/* no, someone else uses it */ goto fail;@@ -884,11 +883,9 @@ int check_alloc_btres_lock(struct bttv *btv, struct
bttv_fh*fh, int bit) /* it's free, grab it */drivers/media/video/bt8xx/bttv-driver.c +0
-5fh->resources |= bit; btv->resources |= bit; -mutex_unlock (&btv->lock);return 1 ; fail: -mutex_unlock (&btv->lock);return 0 ; }@@ -940,7 +937,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) /* trying to free ressources not allocated by us ... */printk ("bttv: BUG! (btres)\n" ); } -mutex_lock (&btv->lock); fh->resources &= ~bits; btv->resources &= ~bits;@@ -951,8 +947,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)if (0 == (bits &VBI_RESOURCES ))disclaim_vbi_lines (btv); - -mutex_unlock (&btv->lock); }/* -----------------------------------------------------------------------
*/ @@ -1713,28 +1707,20 @@ static int bttv_prepare_buffer(structvideobuf_queue*q,struct bttv *btv,drivers/media/video/bt8xx/bttv-driver.c +0
-15/* Make sure tvnorm and vbi_end remain consistent until we're done. */ -mutex_lock (&btv->lock); norm = btv->tvnorm;/* In this mode capturing always starts at defrect.top (default VDELAY), ignoring cropping parameters. */ if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) { -mutex_unlock (&btv->lock);return -EINVAL ; } -mutex_unlock (&btv->lock); - c.rect = bttv_tvnorms[norm].cropcap.defrect; }else { -mutex_lock (&btv->lock); - norm = btv->tvnorm; c = btv->crop[!!fh->do_crop]; -mutex_unlock (&btv->lock); -if (width < c.min_scaled_width || width > c.max_scaled_width || height < c.min_scaled_height)@@ -1858,7 +1844,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) unsigned int i;int err; -mutex_lock (&btv->lock); err =v4l2_prio_check (&btv->prio, fh->prio);if (err) goto err;@@ -1874,7 +1859,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) set_tvnorm(btv, i); err: -mutex_unlock (&btv->lock);return err; }@@ -1898,7 +1882,6 @@ static int bttv_enum_input(struct file *file, void *priv, struct bttv *btv = fh->btv;int rc =0 ; -mutex_lock (&btv->lock);if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { rc = -EINVAL ; goto err;@@ -1928,7 +1911,6 @@ static int bttv_enum_input(struct file *file, void *priv, i->std =BTTV_NORMS ; err: -mutex_unlock (&btv->lock);return rc; }@@ -1938,9 +1920,7 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i) struct bttv_fh *fh = priv;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock); *i = btv->input; -mutex_unlock (&btv->lock);return 0 ; }@@ -1952,7 +1932,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)int err; -mutex_lock (&btv->lock); err =v4l2_prio_check (&btv->prio, fh->prio);if (unlikely (err))drivers/media/video/bt8xx/bttv-driver.c +0
-11goto err;@@ -1965,7 +1944,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) set_input(btv, i, btv->tvnorm); err: -mutex_unlock (&btv->lock);return 0 ; }@@ -1979,7 +1957,6 @@ static int bttv_s_tuner(struct file *file, void *priv, if (unlikely(0 != t->index)) return -EINVAL; -mutex_lock (&btv->lock);if (unlikely (btv->tuner_type ==TUNER_ABSENT )) { err = -EINVAL ; goto err;@@ -1995,7 +1972,6 @@ static int bttv_s_tuner(struct file *file, void *priv, btv->audio_mode_gpio (btv, t,1 ); err: -mutex_unlock (&btv->lock);return 0 ; }@@ -2006,10 +1982,8 @@ static int bttv_g_frequency(struct file *file, void *priv, struct bttv_fh *fh = priv;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock); f->type = btv->radio_user ?V4L2_TUNER_RADIO :V4L2_TUNER_ANALOG_TV ; f->frequency = btv->freq; -mutex_unlock (&btv->lock);return 0 ; }@@ -2024,7 +1998,6 @@ static int bttv_s_frequency(struct file *file, void *priv, if (unlikely(f->tuner != 0)) return -EINVAL; -mutex_lock (&btv->lock); err =v4l2_prio_check (&btv->prio, fh->prio);if (unlikely (err)) goto err;@@ -2039,7 +2012,6 @@ static int bttv_s_frequency(struct file *file, void *priv, if (btv->has_matchbox && btv->radio_user)tea5757_set_freq (btv, btv->freq); err: -mutex_unlock (&btv->lock);return 0 ; }@@ -2172,7 +2144,6 @@ limit_scaled_size_lock (struct bttv_fh * fh,/* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. */ -mutex_lock (&btv->lock); b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;@@ -2250,7 +2221,6 @@ limit_scaled_size_lock (struct bttv_fh * fh, rc =0 ;/* success */ fail: -mutex_unlock (&btv->lock);return rc; }@@ -2282,9 +2252,7 @@ verify_window_lock (struct bttv_fh * fh, if (V4L2_FIELD_ANY == field) {__s32 height2; -mutex_lock (&fh->btv->lock); height2 = fh->btv->crop[!!fh->do_crop].rect.height >>1 ; -mutex_unlock (&fh->btv->lock); field = (win->w.height > height2) ? V4L2_FIELD_INTERLACEDdrivers/media/video/bt8xx/bttv-driver.c +0
-4: V4L2_FIELD_TOP;@@ -2360,7 +2328,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, } } -mutex_lock (&fh->cap.vb_lock);/* clip against screen */ if (NULL != btv->fbuf.base) n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,@@ -2412,7 +2379,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval =bttv_switch_overlay (btv,fh,new); } -mutex_unlock (&fh->cap.vb_lock);return retval; }@@ -2526,9 +2492,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, if (V4L2_FIELD_ANY == field) {__s32 height2; -mutex_lock (&btv->lock); height2 = btv->crop[!!fh->do_crop].rect.height >>1 ; -mutex_unlock (&btv->lock); field = (f->fmt.pix.height > height2) ? V4L2_FIELD_INTERLACEDdrivers/media/video/bt8xx/bttv-driver.c +0
-14: V4L2_FIELD_BOTTOM;@@ -2614,7 +2578,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fmt =format_by_fourcc (f->fmt.pix.pixelformat);/* update our state informations */ -mutex_lock (&fh->cap.vb_lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last =V4L2_FIELD_NONE ;@@ -2623,7 +2586,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; -mutex_unlock (&fh->cap.vb_lock);return 0 ; }@@ -2649,11 +2611,9 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) unsigned int i;struct bttv_fh *fh = priv; -mutex_lock (&fh->cap.vb_lock); retval =__videobuf_mmap_setup (&fh->cap, gbuffers, gbufsize,V4L2_MEMORY_MMAP );if (retval <0 ) { -mutex_unlock (&fh->cap.vb_lock);return retval; }@@ -2665,7 +2625,6 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; -mutex_unlock (&fh->cap.vb_lock); return 0; }#endif @@ -2775,10 +2734,8 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) int retval = 0;if (on) { -mutex_lock (&fh->cap.vb_lock);/* verify args */ if (unlikely (!btv->fbuf.base)) { -mutex_unlock (&fh->cap.vb_lock);return -EINVAL ; }if (unlikely (!fh->ov.setup_ok)) {@@ -2787,13 +2744,11 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) }if (retval)return retval; -mutex_unlock (&fh->cap.vb_lock); }if (!check_alloc_btres_lock (btv, fh,RESOURCE_OVERLAY ))return -EBUSY ; -mutex_lock (&fh->cap.vb_lock);if (on) { fh->ov.tvnorm = btv->tvnorm; new =videobuf_sg_alloc (sizeof (*new));@@ -2805,7 +2760,6 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)/* switch over */ retval =bttv_switch_overlay (btv, fh, new); -mutex_unlock (&fh->cap.vb_lock);return retval; }@@ -2844,7 +2798,6 @@ static int bttv_s_fbuf(struct file *file, void *f, }/* ok, accept it */ -mutex_lock (&fh->cap.vb_lock); btv->fbuf.base = fb->base; btv->fbuf.fmt.width = fb->fmt.width; btv->fbuf.fmt.height = fb->fmt.height;@@ -2876,7 +2829,6 @@ static int bttv_s_fbuf(struct file *file, void *f, retval =bttv_switch_overlay (btv, fh, new); } } -mutex_unlock (&fh->cap.vb_lock);return retval; }@@ -2955,7 +2907,6 @@ static int bttv_queryctrl(struct file *file, void *priv, c->id >= V4L2_CID_PRIVATE_LASTP1))return -EINVAL ; -mutex_lock (&btv->lock);if (!btv->volume_gpio && (c->id ==V4L2_CID_AUDIO_VOLUME )) *c = no_ctl;else {@@ -2963,7 +2914,6 @@ static int bttv_queryctrl(struct file *file, void *priv, *c = (NULL != ctrl) ? *ctrl : no_ctl; } -mutex_unlock (&btv->lock);return 0 ;}
drivers/media/video/bt8xx/bttv-driver.c +0
-10@@ -2974,10 +2924,8 @@ static int bttv_g_parm(struct file *file, void *f,struct bttv_fh *fh = f;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock);v4l2_video_std_frame_period (bttv_tvnorms[btv->tvnorm].v4l2_id, &parm->parm.capture.timeperframe); -mutex_unlock (&btv->lock);return 0 ; }@@ -2993,7 +2941,6 @@ static int bttv_g_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; -mutex_lock (&btv->lock); t->rxsubchans =V4L2_TUNER_SUB_MONO ;bttv_call_all (btv, tuner, g_tuner, t);strcpy (t->name,"Television" );@@ -3005,7 +2952,6 @@ static int bttv_g_tuner(struct file *file, void *priv, if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 0); -mutex_unlock (&btv->lock);return 0 ; }@@ -3014,9 +2960,7 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) struct bttv_fh *fh = f;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock); *p =v4l2_prio_max (&btv->prio); -mutex_unlock (&btv->lock);return 0 ; }@@ -3028,9 +2972,7 @@ static int bttv_s_priority(struct file *file, void *f, struct bttv *btv = fh->btv;int rc; -mutex_lock (&btv->lock); rc =v4l2_prio_change (&btv->prio, &fh->prio, prio); -mutex_unlock (&btv->lock);return rc; }@@ -3045,9 +2987,7 @@ static int bttv_cropcap(struct file *file, void *priv, cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)return -EINVAL ; -mutex_lock (&btv->lock); *cap = bttv_tvnorms[btv->tvnorm].cropcap; -mutex_unlock (&btv->lock);return 0 ; }@@ -3065,9 +3005,7 @@ static int bttv_g_crop(struct file *file, void *f,struct
v4l2_crop*crop) inconsistent withfh->widthorfh->heightand appsdrivers/media/video/bt8xx/bttv-driver.c +0
-2do not expect a change here. */ -mutex_lock (&btv->lock); crop->c = btv->crop[!!fh->do_crop].rect; -mutex_unlock (&btv->lock);return 0 ; }@@ -3091,17 +3029,14 @@ static int bttv_s_crop(struct file *file, void *f,struct
v4l2_crop*crop) /* Make sure tvnorm,vbi_endand the current croppingdrivers/media/video/bt8xx/bttv-driver.c +0
-8parameters remain consistent until we're done. Note read() may change vbi_end in check_alloc_btres_lock(). */ -mutex_lock (&btv->lock); retval =v4l2_prio_check (&btv->prio, fh->prio);if (0 != retval) { -mutex_unlock (&btv->lock);return retval; } retval = -EBUSY ;if (locked_btres (fh->btv,VIDEO_RESOURCES )) { -mutex_unlock (&btv->lock);return retval; }@@ -3113,7 +3048,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) b_top =max (b->top, btv->vbi_end);if (b_top +32 >= b_bottom) { -mutex_unlock (&btv->lock);return retval; }@@ -3136,12 +3070,8 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->crop[1] = c; -mutex_unlock (&btv->lock); - fh->do_crop =1 ; -mutex_lock (&fh->cap.vb_lock); -if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width;drivers/media/video/bt8xx/bttv-driver.c +0
-3btv->init.width = c.min_scaled_width;@@ -3158,8 +3088,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } -mutex_unlock (&fh->cap.vb_lock); -return 0 ; }@@ -3227,7 +3155,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) return videobuf_poll_stream(file, &fh->vbi, wait); } -mutex_lock (&fh->cap.vb_lock);if (check_btres (fh,RESOURCE_VIDEO_STREAM )) {/* streaming capture */ if (list_empty (&fh->cap.stream))@@ -3262,7 +3189,6 @@ static unsigned int bttv_poll(struct file *file,
poll_table*wait) elsedrivers/media/video/bt8xx/bttv-driver.c +2
-20rc =0 ; err: -mutex_unlock (&fh->cap.vb_lock);return rc; }@@ -3302,14 +3228,11 @@ static int bttv_open(struct file *file)* Let's first copy btv->init at fh, holding cap.vb_lock, and then work * with the rest of init, holding btv->lock. */ -mutex_lock (&fh->cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); fh->type = type; fh->ov.setup_ok =0 ; -mutex_lock (&btv->lock);v4l2_prio_open (&btv->prio, &fh->prio); videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,@@ -3317,13 +3240,13 @@ static int bttv_open(struct file *file)V4L2_BUF_TYPE_VIDEO_CAPTURE ,V4L2_FIELD_INTERLACED ,sizeof (struct bttv_buffer ), - fh, NULL); + fh, &btv->lock);videobuf_queue_sg_init (&fh->vbi, &bttv_vbi_qops, &btv->c.pci->dev, &btv->s_lock,V4L2_BUF_TYPE_VBI_CAPTURE ,V4L2_FIELD_SEQ_TB ,sizeof (struct bttv_buffer ), - fh,NULL ); + fh, &btv->lock);set_tvnorm (btv,btv->tvnorm);set_input (btv, btv->input, btv->tvnorm);@@ -3346,7 +3269,6 @@ static int bttv_open(struct file *file)bttv_vbi_fmt_reset (&fh->vbi_fmt, btv->tvnorm);bttv_field_count (btv); -mutex_unlock (&btv->lock);return 0 ; }@@ -3355,7 +3277,6 @@ static int bttv_release(struct file *file)struct bttv_fh *fh = file->private_data;struct bttv *btv = fh->btv; -mutex_lock (&btv->lock);/* turn off overlay */ if (check_btres (fh,RESOURCE_OVERLAY ))bttv_switch_overlay (btv,fh,NULL );@@ -3385,10 +3306,8 @@ static int bttv_release(struct file *file)* videobuf uses cap.vb_lock - we should avoid holding btv->lock, * otherwise we may have dead lock conditions */ -mutex_unlock (&btv->lock);videobuf_mmap_free (&fh->cap);videobuf_mmap_free (&fh->vbi); -mutex_lock (&btv->lock);v4l2_prio_close (&btv->prio, fh->prio); file->private_data =NULL ;kfree (fh);@@ -3398,7 +3317,6 @@ static int bttv_release(struct file *file)if (!btv->users)audio_mute (btv,1 ); -mutex_unlock (&btv->lock);return 0 ; }@@ -3502,11 +3420,8 @@ static int radio_open(struct file *file)if (unlikely (!fh))return -ENOMEM ; file->private_data = fh; -mutex_lock (&fh->cap.vb_lock); *fh = btv->init; -mutex_unlock (&fh->cap.vb_lock); -mutex_lock (&btv->lock);v4l2_prio_open (&btv->prio, &fh->prio); btv->radio_user++;@@ -3514,7 +3429,6 @@ static int radio_open(struct file *file)bttv_call_all (btv, tuner, s_radio);audio_input (btv,TVAUDIO_INPUT_RADIO ); -mutex_unlock (&btv->lock);return 0 ; }@@ -3524,7 +3438,6 @@ static int radio_release(struct file *file)struct bttv *btv = fh->btv;struct rds_command cmd; -mutex_lock (&btv->lock);v4l2_prio_close (&btv->prio, fh->prio); file->private_data =NULL ;kfree (fh);@@ -3532,7 +3445,6 @@ static int radio_release(struct file *file) btv->radio_user--;bttv_call_all (btv, core, ioctl,RDS_CMD_CLOSE , &cmd); -mutex_unlock (&btv->lock);return 0 ; }@@ -3561,7 +3473,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return -EINVAL;if (0 != t->index)return -EINVAL ; -mutex_lock (&btv->lock);strcpy (t->name,"Radio" ); t->type =V4L2_TUNER_RADIO ;@@ -3570,8 +3481,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) if (btv->audio_mode_gpio) btv->audio_mode_gpio (btv, t,0 ); -mutex_unlock (&btv->lock); -return 0 ; }
drivers/media/video/bt8xx/bttv-driver.c static const struct v4l2_file_operations radio_fops = · line 3606
Quoted 7 lines
drivers/media/video/bt8xx/bttv-driver.c +1
-1@@ -3692,7 +3601,7 @@ static const struct v4l2_file_operations radio_fops = .open = radio_open, .read = radio_read, .release = radio_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = radio_poll, };
This patch also prevents the oops and the Pinnacle PCTV Pro card TV is fine. Thanks Mauro.
Signature · 2 lines
The more I see, the more I know. The more I know, the less I understand. Changing Man - Paul Weller
Quoted 11 lines · Mauro Carvalho Chehab
While your patch fixes the issue, it has some other troubles, like to the presence of lock code at
free_btres_lock(). It is possible to fix, but the better is to just use the core-assisted locking schema. This way, V4L2 core will serialize access to all ioctl's/open/close/mmap/read/poll operations, avoiding to have two processes accessing the hardware at the same time. Also, as there's just one lock, instead of 3, there's no risk of dead locks.The net result is a cleaner code, with just one lock.
I tested the patch here with an bttv-based STB board (card=3, tuner=6), and it worked fine for me. Could you please test if this fixes the issue?
I tested your patch against 2.6.37-rc6 and it fixed both problems I was seeing. Restarting hald 100 times did not oops and tvtime now again quits cleanly.
So as it "WorksForMe", you can add my Tested-By, if you want.
Thanks,
Torsten
Quoted 610 lines
PS.: The patch is based against the
bkl_removalpatches, at my linux-next tree:(I just created the
bkl_removalbranch, so, it may take some time for you to see at the kernel.org mirrors, but it is basically changeset673eb9ff. You may also just apply it on the top of the master branch of my linux-next tree).---
[media] bttv: Fix locking issues due to BKL removal code
The BKL removal patch added a condition where the code would try to use a non-initialized lock. While a patch just addressing the issue is possible, there are some other troubles, like to the presence of lock code at
free_btres_lock(), called on some places with the lock already taken. It is possible to fix, but the better is to just use the core-assisted locking schema.This way, V4L2 core will serialize access to all ioctl's/open/close/mmap/read/poll operations, avoiding to have two processes accessing the hardware at the same time. Also, as there's just one lock, instead of 3, there's no risk of dead locks.
Tested with bttv STB, Gateway P/N 6000699 (card 3, tuner 6).
Signed-off-by Mauro Carvalho Chehab <[email protected]>drivers/media/video/bt8xx/bttv-driver.c +0
-2@@ -854,7 +854,6 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM; /* is it free? */ - mutex_lock(&btv->lock); if (btv->resources & xbits) { /* no, someone else uses it */ goto fail;@@ -884,11 +883,9 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) /* it's free, grab it */ fh->resources |= bit; btv->resources |= bit; - mutex_unlock(&btv->lock); return 1;fail:
-mutex_unlock(&btv->lock);
return 0;
}drivers/media/video/bt8xx/bttv-driver.c +0
-3@@ -940,7 +937,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) /* trying to free ressources not allocated by us ... */ printk("bttv: BUG! (btres)\n"); } - mutex_lock(&btv->lock); fh->resources &= ~bits; btv->resources &= ~bits;@@ -951,8 +947,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) if (0 == (bits & VBI_RESOURCES)) disclaim_vbi_lines(btv); - - mutex_unlock(&btv->lock); } /* ----------------------------------------------------------------------- */@@ -1713,28 +1707,20 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, /* Make sure tvnorm and vbi_end remain consistentuntil we're done. */
-mutex_lock(&btv->lock);norm =
btv->tvnorm;/* In this mode capturing always starts at defrect.top (default VDELAY), ignoring cropping parameters. */ if (
btv->vbi_end> bttv_tvnorms[norm].cropcap.defrect.top) {
-mutex_unlock(&btv->lock);
return-EINVAL;
}-
mutex_unlock(&btv->lock);
-
c.rect = bttv_tvnorms[norm].cropcap.defrect; } else {
-mutex_lock(&btv->lock);
-
norm =btv->tvnorm;
c = btv->crop[!!fh->do_crop];-
mutex_unlock(&btv->lock);
-
if (width < c.min_scaled_width ||
width > c.max_scaled_width ||
height < c.min_scaled_height)drivers/media/video/bt8xx/bttv-driver.c +0
-1@@ -1858,7 +1844,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) unsigned int i; int err; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (err) goto err;@@ -1874,7 +1859,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) set_tvnorm(btv, i);err:
-mutex_unlock(&btv->lock);return err;
}drivers/media/video/bt8xx/bttv-driver.c +0
-1@@ -1898,7 +1882,6 @@ static int bttv_enum_input(struct file *file, void *priv, struct bttv *btv = fh->btv; int rc = 0; - mutex_lock(&btv->lock); if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { rc = -EINVAL; goto err;@@ -1928,7 +1911,6 @@ static int bttv_enum_input(struct file *file, void *priv, i->std = BTTV_NORMS;err:
-mutex_unlock(&btv->lock);return rc;
}drivers/media/video/bt8xx/bttv-driver.c +0
-3@@ -1938,9 +1920,7 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i) struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); *i = btv->input; - mutex_unlock(&btv->lock); return 0; }@@ -1952,7 +1932,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) int err; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (unlikely(err)) goto err;@@ -1965,7 +1944,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) set_input(btv, i, btv->tvnorm);err:
-mutex_unlock(&btv->lock);
return 0;
}drivers/media/video/bt8xx/bttv-driver.c +0
-1@@ -1979,7 +1957,6 @@ static int bttv_s_tuner(struct file *file, void *priv, if (unlikely(0 != t->index)) return -EINVAL; - mutex_lock(&btv->lock); if (unlikely(btv->tuner_type == TUNER_ABSENT)) { err = -EINVAL; goto err;@@ -1995,7 +1972,6 @@ static int bttv_s_tuner(struct file *file, void *priv, btv->audio_mode_gpio(btv, t, 1);err:
-mutex_unlock(&btv->lock);return 0;
}drivers/media/video/bt8xx/bttv-driver.c +0
-3@@ -2006,10 +1982,8 @@ static int bttv_g_frequency(struct file *file, void *priv, struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = btv->freq; - mutex_unlock(&btv->lock); return 0; }@@ -2024,7 +1998,6 @@ static int bttv_s_frequency(struct file *file, void *priv, if (unlikely(f->tuner != 0)) return -EINVAL; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (unlikely(err)) goto err;@@ -2039,7 +2012,6 @@ static int bttv_s_frequency(struct file *file, void *priv, if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv, btv->freq);err:
-mutex_unlock(&btv->lock);return 0;
}drivers/media/video/bt8xx/bttv-driver.c +0
-0@@ -2172,7 +2144,6 @@ limit_scaled_size_lock (struct bttv_fh * fh, /* Make sure tvnorm, vbi_end and the current cropping parametersremain consistent until we're done. */
-mutex_lock(&btv->lock);b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
drivers/media/video/bt8xx/bttv-driver.c +0
-0@@ -2250,7 +2221,6 @@ limit_scaled_size_lock (struct bttv_fh * fh,rc = 0; /* success */
fail:
-mutex_unlock(&btv->lock);return rc;
}drivers/media/video/bt8xx/bttv-driver.c +0
-2@@ -2282,9 +2252,7 @@ verify_window_lock (struct bttv_fh * fh, if (V4L2_FIELD_ANY == field) { __s32 height2; - mutex_lock(&fh->btv->lock); height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1; - mutex_unlock(&fh->btv->lock); field = (win->w.height > height2)?
V4L2_FIELD_INTERLACED
:V4L2_FIELD_TOP;drivers/media/video/bt8xx/bttv-driver.c +0
-4@@ -2360,7 +2328,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, } } - mutex_lock(&fh->cap.vb_lock); /* clip against screen */ if (NULL != btv->fbuf.base) n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,@@ -2412,7 +2379,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); } - mutex_unlock(&fh->cap.vb_lock); return retval; }@@ -2526,9 +2492,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, if (V4L2_FIELD_ANY == field) { __s32 height2; - mutex_lock(&btv->lock); height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - mutex_unlock(&btv->lock); field = (f->fmt.pix.height > height2)?
V4L2_FIELD_INTERLACED
:V4L2_FIELD_BOTTOM;drivers/media/video/bt8xx/bttv-driver.c +0
-24@@ -2614,7 +2578,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); /* update our state informations */ - mutex_lock(&fh->cap.vb_lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last = V4L2_FIELD_NONE;@@ -2623,7 +2586,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; - mutex_unlock(&fh->cap.vb_lock); return 0; }@@ -2649,11 +2611,9 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) unsigned int i; struct bttv_fh *fh = priv; - mutex_lock(&fh->cap.vb_lock); retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, V4L2_MEMORY_MMAP); if (retval < 0) { - mutex_unlock(&fh->cap.vb_lock); return retval; }@@ -2665,7 +2625,6 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; - mutex_unlock(&fh->cap.vb_lock); return 0; } #endif@@ -2775,10 +2734,8 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) int retval = 0; if (on) { - mutex_lock(&fh->cap.vb_lock); /* verify args */ if (unlikely(!btv->fbuf.base)) { - mutex_unlock(&fh->cap.vb_lock); return -EINVAL; } if (unlikely(!fh->ov.setup_ok)) {@@ -2787,13 +2744,11 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) } if (retval) return retval; - mutex_unlock(&fh->cap.vb_lock); } if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY)) return -EBUSY; - mutex_lock(&fh->cap.vb_lock); if (on) { fh->ov.tvnorm = btv->tvnorm; new = videobuf_sg_alloc(sizeof(*new));@@ -2805,7 +2760,6 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) /* switch over */ retval = bttv_switch_overlay(btv, fh, new); - mutex_unlock(&fh->cap.vb_lock); return retval; }@@ -2844,7 +2798,6 @@ static int bttv_s_fbuf(struct file *file, void *f, } /* ok, accept it */ - mutex_lock(&fh->cap.vb_lock); btv->fbuf.base = fb->base; btv->fbuf.fmt.width = fb->fmt.width; btv->fbuf.fmt.height = fb->fmt.height;@@ -2876,7 +2829,6 @@ static int bttv_s_fbuf(struct file *file, void *f, retval = bttv_switch_overlay(btv, fh, new); } } - mutex_unlock(&fh->cap.vb_lock); return retval; }@@ -2955,7 +2907,6 @@ static int bttv_queryctrl(struct file *file, void *priv, c->id >= V4L2_CID_PRIVATE_LASTP1)) return -EINVAL; - mutex_lock(&btv->lock); if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) *c = no_ctl; else {@@ -2963,7 +2914,6 @@ static int bttv_queryctrl(struct file *file, void *priv, *c = (NULL != ctrl) ? *ctrl : no_ctl; } - mutex_unlock(&btv->lock); return 0; }@@ -2974,10 +2924,8 @@ static int bttv_g_parm(struct file *file, void *f, struct bttv_fh *fh = f; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id, &parm->parm.capture.timeperframe); - mutex_unlock(&btv->lock); return 0; }@@ -2993,7 +2941,6 @@ static int bttv_g_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - mutex_lock(&btv->lock); t->rxsubchans = V4L2_TUNER_SUB_MONO; bttv_call_all(btv, tuner, g_tuner, t); strcpy(t->name, "Television");@@ -3005,7 +2952,6 @@ static int bttv_g_tuner(struct file *file, void *priv, if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 0); - mutex_unlock(&btv->lock); return 0; }@@ -3014,9 +2960,7 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) struct bttv_fh *fh = f; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); *p = v4l2_prio_max(&btv->prio); - mutex_unlock(&btv->lock); return 0; }@@ -3028,9 +2972,7 @@ static int bttv_s_priority(struct file *file, void *f, struct bttv *btv = fh->btv; int rc; - mutex_lock(&btv->lock); rc = v4l2_prio_change(&btv->prio, &fh->prio, prio); - mutex_unlock(&btv->lock); return rc; }@@ -3045,9 +2987,7 @@ static int bttv_cropcap(struct file *file, void *priv, cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) return -EINVAL; - mutex_lock(&btv->lock); *cap = bttv_tvnorms[btv->tvnorm].cropcap; - mutex_unlock(&btv->lock); return 0; }@@ -3065,9 +3005,7 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)inconsistent with
fh->widthorfh->heightand apps do not expect a change here. */-
mutex_lock(&btv->lock);
crop->c = btv->crop[!!fh->do_crop].rect;
-mutex_unlock(&btv->lock);return 0;
}drivers/media/video/bt8xx/bttv-driver.c +0
-0@@ -3091,17 +3029,14 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) /* Make sure tvnorm, vbi_end and the current croppingparameters remain consistent until we're done. Note
read()may changevbi_endincheck_alloc_btres_lock(). */
-mutex_lock(&btv->lock);
retval =v4l2_prio_check(&btv->prio, fh->prio); if (0 != retval) {
-mutex_unlock(&btv->lock);
return retval;
}retval =
-EBUSY;if (
locked_btres(fh->btv, VIDEO_RESOURCES)) {
-mutex_unlock(&btv->lock); return retval;
}drivers/media/video/bt8xx/bttv-driver.c +0
-8@@ -3113,7 +3048,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) b_top = max(b->top, btv->vbi_end); if (b_top + 32 >= b_bottom) { - mutex_unlock(&btv->lock); return retval; }@@ -3136,12 +3070,8 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->crop[1] = c; - mutex_unlock(&btv->lock); - fh->do_crop = 1; - mutex_lock(&fh->cap.vb_lock); - if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width; btv->init.width = c.min_scaled_width;@@ -3158,8 +3088,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } - mutex_unlock(&fh->cap.vb_lock); - return 0; }@@ -3227,7 +3155,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) return videobuf_poll_stream(file, &fh->vbi, wait); } - mutex_lock(&fh->cap.vb_lock); if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { /* streaming capture */ if (list_empty(&fh->cap.stream))@@ -3262,7 +3189,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)else
rc = 0;
err:
-mutex_unlock(&fh->cap.vb_lock);
return rc;
}drivers/media/video/bt8xx/bttv-driver.c +3
-20@@ -3302,14 +3228,11 @@ static int bttv_open(struct file *file)* Let's first copy btv->init at fh, holding cap.vb_lock, and then work * with the rest of init, holding btv->lock. */ - mutex_lock(&fh->cap.vb_lock); *fh = btv->init; - mutex_unlock(&fh->cap.vb_lock); fh->type = type; fh->ov.setup_ok = 0; - mutex_lock(&btv->lock); v4l2_prio_open(&btv->prio, &fh->prio); videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,@@ -3317,13 +3240,13 @@ static int bttv_open(struct file *file) V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct bttv_buffer), - fh, NULL); + fh, &btv->lock); videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops, &btv->c.pci->dev, &btv->s_lock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, sizeof(struct bttv_buffer), - fh, NULL); + fh, &btv->lock); set_tvnorm(btv,btv->tvnorm); set_input(btv, btv->input, btv->tvnorm);@@ -3346,7 +3269,6 @@ static int bttv_open(struct file *file) bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); bttv_field_count(btv); - mutex_unlock(&btv->lock); return 0; }@@ -3355,7 +3277,6 @@ static int bttv_release(struct file *file) struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); /* turn off overlay */ if (check_btres(fh, RESOURCE_OVERLAY)) bttv_switch_overlay(btv,fh,NULL);@@ -3385,10 +3306,8 @@ static int bttv_release(struct file *file)* videobuf uses cap.vb_lock - we should avoid holding btv->lock, * otherwise we may have dead lock conditions */ - mutex_unlock(&btv->lock); videobuf_mmap_free(&fh->cap); videobuf_mmap_free(&fh->vbi); - mutex_lock(&btv->lock); v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; kfree(fh);@@ -3398,7 +3317,6 @@ static int bttv_release(struct file *file) if (!btv->users) audio_mute(btv, 1); - mutex_unlock(&btv->lock); return 0; }@@ -3502,11 +3420,8 @@ static int radio_open(struct file *file) if (unlikely(!fh)) return -ENOMEM; file->private_data = fh; - mutex_lock(&fh->cap.vb_lock); *fh = btv->init; - mutex_unlock(&fh->cap.vb_lock); - mutex_lock(&btv->lock); v4l2_prio_open(&btv->prio, &fh->prio); btv->radio_user++;@@ -3514,7 +3429,6 @@ static int radio_open(struct file *file) bttv_call_all(btv, tuner, s_radio); audio_input(btv,TVAUDIO_INPUT_RADIO); - mutex_unlock(&btv->lock); return 0; }@@ -3524,7 +3438,6 @@ static int radio_release(struct file *file) struct bttv *btv = fh->btv; struct rds_command cmd; - mutex_lock(&btv->lock); v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; kfree(fh);@@ -3532,7 +3445,6 @@ static int radio_release(struct file *file) btv->radio_user--; bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd); - mutex_unlock(&btv->lock); return 0; }@@ -3561,7 +3473,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return -EINVAL; if (0 != t->index) return -EINVAL; - mutex_lock(&btv->lock); strcpy(t->name, "Radio"); t->type = V4L2_TUNER_RADIO;@@ -3570,8 +3481,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 0); - mutex_unlock(&btv->lock); - return 0; }@@ -3692,7 +3601,7 @@ static const struct v4l2_file_operations radio_fops = .open = radio_open, .read = radio_read, .release = radio_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = radio_poll, };
Quoted 23 lines · Mauro Carvalho Chehab
Em 15-12-2010 16:44, Chris Clayton escreveu:
Quoted 17 lines · Brandon Philips
Quoted 16 lines · Torsten Kaiser
Quoted 3 lines
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
From
456dc0ce36db523c4c0c8a269f4eec43a72de1dcMon Sep 17 00:00:00 2001 From: Brandon Philips <[email protected]> Date: Mon, 13 Dec 2010 16:21:55 -0800 Subject: [PATCH] bttv: fix locking forbtv->initQuoted 4 lines
Quoted 4 lines
Fix locking for the
btv->initby usingbtv->init.cap.vb_lockand in the process fix uninitialized deref introduced inc37db91fd0d.Signed-off-by Brandon Philips <[email protected]>
Quoted 7 lines
While your patch fixes the issue, it has some other troubles, like to the presence of lock code at
free_btres_lock(). It is possible to fix, but the better is to just use the core-assisted locking schema. This way, V4L2 core will serialize access to all ioctl's/open/close/mmap/read/poll operations, avoiding to have two processes accessing the hardware at the same time. Also, as there's just one lock, instead of 3, there's no risk of dead locks.
Thanks, but, why wasn't this done instead of c37db91f?
Will this make it in before 2.6.37 is released? Otherwise 2.6.37 will need to be fixed in -stable immediatly after release.
Quoted 1 line
The net result is a cleaner code, with just one lock.
Could you take this patch to remove all of the comments about locking order with btv->lock since it doesn't seem to matter any longer.
Cheers,
Brandon
P.S. Your mail client creates really long lines- somewhere around 90 characters. Could you fix that?
Quoted 1 line
From
7643db7bf5e9e557a27e3783786a1abecbdf82a7Mon Sep 17 00:00:00 2001
From: Brandon Philips <[email protected]>
Date: Fri, 17 Dec 2010 07:58:22 -0800
Subject: [PATCH] bttv: remove unneeded locking comments
After Mauro's "bttv: Fix locking issues due to BKL removal code" there are a number of comments that are no longer needed about lock ordering. Remove them.
--- drivers/media/video/bt8xx/bttv-driver.c | 20 -------------------- 1 files changed, 0 insertions(+), 20 deletions(-)
drivers/media/video/bt8xx/bttv-driver.c +0 -20
@@ -2358,13 +2358,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, fh->ov.field = win->field; fh->ov.setup_ok =1 ; -/* -* FIXME: btv is protected by btv->lock mutex, while btv->init -* is protected by fh->cap.vb_lock. This seems to open the -* possibility for some race situations. Maybe the better would -* be to unify those locks or to use another way to store the -* init values that will be consumed by videobuf callbacks -*/ btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field;
@@ -3219,15 +3212,6 @@ static int bttv_open(struct file *file)return -ENOMEM ; file->private_data = fh; -/* -* btv is protected by btv->lock mutex, while btv->init and other -* streaming vars are protected by fh->cap.vb_lock. We need to take -* care of both locks to avoid troubles. However, vb_lock is used also -* inside videobuf, without calling buf->lock. So, it is a very bad -* idea to hold both locks at the same time. -* Let's first copy btv->init at fh, holding cap.vb_lock, and then work -* with the rest of init, holding btv->lock. -*/ *fh = btv->init; fh->type = type;
@@ -3302,10 +3286,6 @@ static int bttv_release(struct file *file)/* free stuff */ -/* -* videobuf uses cap.vb_lock - we should avoid holding btv->lock, -* otherwise we may have dead lock conditions -*/ videobuf_mmap_free (&fh->cap);videobuf_mmap_free (&fh->vbi);v4l2_prio_close (&btv->prio, fh->prio);
Signature · 1 line
1.7.3.1
Em 17-12-2010 14:07, Brandon Philips escreveu:
Quoted 32 lines · Mauro Carvalho Chehab
Quoted 23 lines
Em 15-12-2010 16:44, Chris Clayton escreveu:
Quoted 17 lines · Brandon Philips
Quoted 16 lines · Torsten Kaiser
Quoted 3 lines
* change
&fh->cap.vb_lockinbttv_open()ANDradio_open()to&btv->init.cap.vb_lock* add amutex_init(&btv->init.cap.vb_lock)to the setup of init inbttv_probe()That seems like a reasonable suggestion. An openSUSE user submitted this bug to our tracker too. Here is the patch I am having him test.
Would you mind testing it?
From
456dc0ce36db523c4c0c8a269f4eec43a72de1dcMon Sep 17 00:00:00 2001 From: Brandon Philips <[email protected]> Date: Mon, 13 Dec 2010 16:21:55 -0800 Subject: [PATCH] bttv: fix locking forbtv->initQuoted 4 lines
Quoted 4 lines
Fix locking for the
btv->initby usingbtv->init.cap.vb_lockand in the process fix uninitialized deref introduced inc37db91fd0d.Signed-off-by Brandon Philips <[email protected]>Quoted 7 lines
While your patch fixes the issue, it has some other troubles, like to the presence of lock code at
free_btres_lock(). It is possible to fix, but the better is to just use the core-assisted locking schema. This way, V4L2 core will serialize access to all ioctl's/open/close/mmap/read/poll operations, avoiding to have two processes accessing the hardware at the same time. Also, as there's just one lock, instead of 3, there's no risk of dead locks.
Quoted 1 line
Thanks, but, why wasn't this done instead of
c37db91f?
Because c37db91f were a first attempt. I was expecting that it would be enough, but, after some discussions at the ML, it seemed to be better to use a different approach. As you probably noticed, the locking schema at bttv driver were very complex, and it were likely to ask for problems. The new schema is simpler. The principle is to serialize the access to the hardware or to the hardware-mirrored data. It does that by serializing the access to all file operations for a given bttv device.
While this is a little overkill (as there are a very few set of operations that won't require locking, like retrieving some static read-only data), there's no performance impact at the critical path, as such ioctl's typically happen only during hardware discovery phase at the userspace apps.
Quoted 3 lines
Will this make it in before 2.6.37 is released? Otherwise 2.6.37 will need to be fixed in -stable immediatly after release.
I'll intend to add it today for -next, and send upstream by Sunday, hopefully in time for .37.
Quoted 5 lines
Quoted 2 lines
The net result is a cleaner code, with just one lock.
Could you take this patch to remove all of the comments about locking order with
btv->locksince it doesn't seem to matter any longer.
Yes, sure. Thanks for the patch.
Quoted 67 lines
Cheers,
Brandon
P.S. Your mail client creates really long lines- somewhere around 90 characters. Could you fix that?From
7643db7bf5e9e557a27e3783786a1abecbdf82a7Mon Sep 17 00:00:00 2001
From: Brandon Philips <[email protected]>
Date: Fri, 17 Dec 2010 07:58:22 -0800
Subject: [PATCH] bttv: remove unneeded locking commentsAfter Mauro's "bttv: Fix locking issues due to BKL removal code" there are a number of comments that are no longer needed about lock ordering. Remove them.
Signed-off-by Brandon Philips <[email protected]>--- drivers/media/video/bt8xx/bttv-driver.c | 20 -------------------- 1 files changed, 0 insertions(+), 20 deletions(-)drivers/media/video/bt8xx/bttv-driver.c +0
-20@@ -2358,13 +2358,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, fh->ov.field = win->field; fh->ov.setup_ok =1 ; -/* -* FIXME: btv is protected by btv->lock mutex, while btv->init -* is protected by fh->cap.vb_lock. This seems to open the -* possibility for some race situations. Maybe the better would -* be to unify those locks or to use another way to store the -* init values that will be consumed by videobuf callbacks -*/ btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field;@@ -3219,15 +3212,6 @@ static int bttv_open(struct file *file)return -ENOMEM ; file->private_data = fh; -/* -* btv is protected by btv->lock mutex, while btv->init and other -* streaming vars are protected by fh->cap.vb_lock. We need to take -* care of both locks to avoid troubles. However, vb_lock is used also -* inside videobuf, without calling buf->lock. So, it is a very bad -* idea to hold both locks at the same time. -* Let's first copy btv->init at fh, holding cap.vb_lock, and then work -* with the rest of init, holding btv->lock. -*/ *fh = btv->init; fh->type = type;@@ -3302,10 +3286,6 @@ static int bttv_release(struct file *file)/* free stuff */ -/* -* videobuf uses cap.vb_lock - we should avoid holding btv->lock, -* otherwise we may have dead lock conditions -*/ videobuf_mmap_free (&fh->cap);videobuf_mmap_free (&fh->vbi);v4l2_prio_close (&btv->prio, fh->prio);