From: Alexey Klimov <klimov.linux@gmail.com>
To: David Ellingsworth <david@identd.dyndns.org>
Cc: video4linux-list@redhat.com, Mauro Carvalho Chehab <mchehab@redhat.com>
Subject: Re: [PATCH 1/1] radio-mr800: fix unplug
Date: Thu, 27 Nov 2008 15:00:10 +0300 [thread overview]
Message-ID: <1227787210.11477.7.camel@tux.localhost> (raw)
In-Reply-To: <30353c3d0811240635t3649fa2bk5f5982c4d3d6e87c@mail.gmail.com>
Hello, David
On Mon, 2008-11-24 at 09:35 -0500, David Ellingsworth wrote:
> On Sat, Nov 22, 2008 at 10:19 PM, Alexey Klimov <klimov.linux@gmail.com> wrote:
> > Hello, David
> >
> > On Thu, 2008-11-20 at 10:53 -0500, David Ellingsworth wrote:
> >> NACK
> >
> >> video_unregister_device should _always_ be called once the device is
> >> disconnect, no matter how many handles are still open.
> >>
> >> > - radio->videodev = NULL;
> >> > - if (radio->users) {
> >> > - kfree(radio->buffer);
> >> > - kfree(radio);
> >> > - } else {
> >> > - radio->removed = 1;
> >> > - }
> >> > + kfree(radio->buffer);
> >> > + kfree(radio);
> >>
> >> You should not be freeing memory here. The video_device release
> >> callback should be used for this purpose. It is called once all open
> >> file handles are closed and after video_unregister_device has been
> >> called.
> >
> > Well, things what you said make me feel ill at ease (feel
> > uncomfortable). Looks like 3 usb radio drivers don't implement right
> > disconnect and video release functions ?
> > Generaly, i took order of release/kfree-functions from dsbr100 and
> > si470x.
>
> Yes, this is probably true. Not many drivers handled this properly
> since the video_device release callback used to occur immediately
> after calling video_unregister_device while the structure was
> potentially still being used. Some drivers implemented a kref object
> to work around this deficiency, others used a user count. Now that the
> v4l2-core correctly calls this release after video_unregister_device
> has been called and all open handles have been close, no work-arounds
> are needed by v4l2 sub-drivers.
>
> The suggested method to simply set the video_device release callback
> to video_device_release was from the beginning flawed. The only
> instance where it was actually safe to do so was in the vivi driver
> since there was no way to abruptly remove the device while it was
> still being used. All usb and pci devices can be removed at will and
> have to properly handle that case. Sadly most do not. In my opinion,
> the video_device_alloc and video_device_release functions should be
> removed entirely, they only add unnecessary complexity to a v4l2
> sub-driver.
>
> Before the v4l2-core was fixed, if a driver set the release callback
> to video_device_release and _always_ called video_unregister_device in
> it's disconnect callback then the video_device struct used by the
> driver would be immediately freed. Once the video_device struct had
> been freed, any call to video_get_drvdata would fail and crash the
> driver. Sub-drivers could then do one of two things to avoid this
> crash, 1. not call video_unregister_device upon disconnect, or 2. set
> the release callback to a null function. The problem with the first
> method is that by not calling video_unregister_device the driver had
> to ensure the device was present during the fops open callback, aka
> handling a call to open after disconnect. The problem with the second
> method is that the sub-driver had to implement it's own reference
> count to determine when it was safe to free it's structure. Both
> methods had their own challenges and neither was something that most
> drivers got right.
>
> >
> >> Again, video_unregister_device should always be called from the usb
> >> disconnect callback.
> >>
> >> > kfree(radio->buffer);
> >> > kfree(radio);
> >>
> >> Again, memory should not be freed here. It should be freed by the
> >> video_device release callback for reasons stated above.
> >
> > Ok. I were in deep quest of finding video_device release callback. I had
> > release function only in file_operations, but it wasn't right function.
> > Then i found video_device_release in video_device
> > amradio_videodev_template.
> > Looks like disconnect function called before video_device_release in all
> > cases. And i need to call kfree(radio) after disconnect but before probe
> > function(if device pluged in again).
> >
> > Do this general examples below look right ?
>
> Yes, this looks correct.
>
> >
> > static struct video_device amradio_videodev_template = {
> > .name = "AverMedia MR 800 USB FM Radio",
> > .fops = &usb_amradio_fops,
> > .ioctl_ops = &usb_amradio_ioctl_ops,
> > .release = video_device_release_am,
> > };
> >
> > I need my own release function, right ? To free radio structure.
>
> Correct. You'll need your own function.
>
> >
> > void video_device_release_am(struct video_device *videodev)
> > {
> > struct amradio_device *radio = video_get_drvdata(videodev);
> > printk("we are in video_device_release\n");
> > video_device_release(videodev);
> > kfree(radio->buffer);
> > kfree(radio);
> > }
> > May be something like "container_of" to get *radio from *videodev ? Or it's okay ?
>
> Since the video_device struct is not embedded within the
> amradio_device structure you can't use container_of to get a pointer
> to the amradio_device structure. What you have here is correct. If you
> choose to do so, I advocate embedding the video_device struct into the
> amradio struct since it simplifies memory allocation. You would then
> be able to use container_of in many places to go from the video_device
> struct to the amradio_device struct.
>
> >
> > static void usb_amradio_disconnect(struct usb_interface *intf)
> > {
> > struct amradio_device *radio = usb_get_intfdata(intf);
> >
> > printk("disconnect called\n");
> > // mutex_lock(&radio->disconnect_lock);
> > radio->removed = 1;
> >
> > usb_set_intfdata(intf, NULL);
> > video_unregister_device(radio->videodev);
> >
> > // mutex_unlock(&radio->disconnect_lock);
> > }
> >
> >> I suspect you'll find little need for this mutex once you have
> >> properly implemented the video_device release callback. You may
> >> however still need the removed flag as some usb calls obviously can't
> >> be made once the device has been removed. For reference, please review
> >> the stk-webcam driver as it implements this properly
>
> If you have a general mutex, which you should, for locking access to
> the amradio_device struct it should probably be used here while
> setting the removed member to 1. Admittedly, stk-webcam currently
> lacks the required mutex. The state change in it's disconnect callback
> is not safe and should be protected by a general mutex, as should
> operations in it's open, release, and read functions. I merely haven't
> had the time to submit a patch to correct it.
Do this patch looks correct ? (it is fix for current hg-tree)
I'm still confused about part of probe-function where
video_register_device failed and we should free memory. Will disconnect
function be called if probe-function failed ?
It's in the end of this patch. David, if you have some free time - can
you you review it ?
diff -r 602d3ac1f476 linux/drivers/media/radio/radio-mr800.c
--- a/linux/drivers/media/radio/radio-mr800.c Thu Nov 20 19:47:37 2008 -0200
+++ b/linux/drivers/media/radio/radio-mr800.c Wed Nov 26 17:29:54 2008 +0300
@@ -142,7 +142,6 @@
unsigned char *buffer;
struct mutex lock; /* buffer locking */
- struct mutex disconnect_lock;
int curfreq;
int stereo;
int users;
@@ -305,16 +304,12 @@
{
struct amradio_device *radio = usb_get_intfdata(intf);
- mutex_lock(&radio->disconnect_lock);
+ mutex_lock(&radio->lock);
radio->removed = 1;
+ mutex_unlock(&radio->lock);
+
usb_set_intfdata(intf, NULL);
-
- if (radio->users == 0) {
- video_unregister_device(radio->videodev);
- kfree(radio->buffer);
- kfree(radio);
- }
- mutex_unlock(&radio->disconnect_lock);
+ video_unregister_device(radio->videodev);
}
/* vidioc_querycap - query device capabilities */
@@ -532,7 +527,7 @@
return 0;
}
-/*close device - free driver structures */
+/*close device */
static int usb_amradio_close(struct inode *inode, struct file *file)
{
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
@@ -541,21 +536,15 @@
if (!radio)
return -ENODEV;
- mutex_lock(&radio->disconnect_lock);
radio->users = 0;
- if (radio->removed) {
- video_unregister_device(radio->videodev);
- kfree(radio->buffer);
- kfree(radio);
- } else {
+ if (!radio->removed) {
retval = amradio_stop(radio);
if (retval < 0)
amradio_dev_warn(&radio->videodev->dev,
"amradio_stop failed\n");
}
- mutex_unlock(&radio->disconnect_lock);
return 0;
}
@@ -612,12 +601,30 @@
.vidioc_s_input = vidioc_s_input,
};
+static void usb_amradio_device_release(struct video_device *videodev)
+{
+ struct amradio_device *radio = video_get_drvdata(videodev);
+
+ mutex_lock(&radio->lock);
+
+ /* we call v4l to free radio->videodev */
+ video_device_release(videodev);
+
+ /* free rest memory */
+ kfree(radio->buffer);
+ kfree(radio);
+
+ mutex_unlock(&radio->lock);
+}
+
+
+
/* V4L2 interface */
static struct video_device amradio_videodev_template = {
.name = "AverMedia MR 800 USB FM Radio",
.fops = &usb_amradio_fops,
.ioctl_ops = &usb_amradio_ioctl_ops,
- .release = video_device_release,
+ .release = usb_amradio_device_release,
};
/* check if the device is present and register with v4l and
@@ -655,15 +662,12 @@
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = 95.16 * FREQ_MUL;
- mutex_init(&radio->disconnect_lock);
mutex_init(&radio->lock);
video_set_drvdata(radio->videodev, radio);
if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
dev_warn(&intf->dev, "could not register video device\n");
- video_device_release(radio->videodev);
- kfree(radio->buffer);
- kfree(radio);
+ video_unregister_device(radio->videodev);
return -EIO;
}
--
Best regards, Klimov Alexey
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
next prev parent reply other threads:[~2008-11-27 12:10 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-11-19 0:36 [PATCH 1/1] radio-mr800: fix unplug Alexey Klimov
2008-11-20 15:53 ` David Ellingsworth
2008-11-23 3:19 ` Alexey Klimov
2008-11-24 14:35 ` David Ellingsworth
2008-11-27 12:00 ` Alexey Klimov [this message]
2008-11-30 5:19 ` David Ellingsworth
2008-12-06 0:04 ` Alexey Klimov
2008-12-06 10:05 ` Mauro Carvalho Chehab
2008-12-09 1:35 ` [please review patch] dsbr100: fix unplug oops Alexey Klimov
2008-12-09 14:02 ` David Ellingsworth
2008-12-09 20:55 ` [PATCH] " Alexey Klimov
2008-12-12 3:05 ` Douglas Schilling Landgraf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1227787210.11477.7.camel@tux.localhost \
--to=klimov.linux@gmail.com \
--cc=david@identd.dyndns.org \
--cc=mchehab@redhat.com \
--cc=video4linux-list@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox