mirror of https://gitee.com/openkylin/linux.git
V4L/DVB (7319): pvrusb2: Close potential race condition during initialization
There is a callback that is issued to into pvr2_context from pvr2_hdw after initialization is done. There was a probability that this callback could get missed. Fixed. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
ee9ca4b24f
commit
c4a8828ddb
|
@ -75,10 +75,9 @@ struct pvr2_context *pvr2_context_create(
|
|||
mp = NULL;
|
||||
goto done;
|
||||
}
|
||||
pvr2_hdw_set_state_callback(mp->hdw,
|
||||
(void (*)(void *))pvr2_context_state_check,
|
||||
mp);
|
||||
pvr2_context_state_check(mp);
|
||||
pvr2_hdw_initialize(mp->hdw,
|
||||
(void (*)(void *))pvr2_context_state_check,
|
||||
mp);
|
||||
done:
|
||||
return mp;
|
||||
}
|
||||
|
|
|
@ -1813,8 +1813,23 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
|
|||
}
|
||||
|
||||
|
||||
/* Create and return a structure for interacting with the underlying
|
||||
hardware */
|
||||
/* Perform second stage initialization. Set callback pointer first so that
|
||||
we can avoid a possible initialization race (if the kernel thread runs
|
||||
before the callback has been set). */
|
||||
void pvr2_hdw_initialize(struct pvr2_hdw *hdw,
|
||||
void (*callback_func)(void *),
|
||||
void *callback_data)
|
||||
{
|
||||
LOCK_TAKE(hdw->big_lock); do {
|
||||
hdw->state_data = callback_data;
|
||||
hdw->state_func = callback_func;
|
||||
} while (0); LOCK_GIVE(hdw->big_lock);
|
||||
queue_work(hdw->workqueue,&hdw->workinit);
|
||||
}
|
||||
|
||||
|
||||
/* Create, set up, and return a structure for interacting with the
|
||||
underlying hardware. */
|
||||
struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
|
||||
const struct usb_device_id *devid)
|
||||
{
|
||||
|
@ -2039,7 +2054,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
|
|||
mutex_init(&hdw->ctl_lock_mutex);
|
||||
mutex_init(&hdw->big_lock_mutex);
|
||||
|
||||
queue_work(hdw->workqueue,&hdw->workinit);
|
||||
return hdw;
|
||||
fail:
|
||||
if (hdw) {
|
||||
|
@ -2521,17 +2535,6 @@ static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
|
|||
}
|
||||
|
||||
|
||||
void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
|
||||
void (*callback_func)(void *),
|
||||
void *callback_data)
|
||||
{
|
||||
LOCK_TAKE(hdw->big_lock); do {
|
||||
hdw->state_data = callback_data;
|
||||
hdw->state_func = callback_func;
|
||||
} while (0); LOCK_GIVE(hdw->big_lock);
|
||||
}
|
||||
|
||||
|
||||
/* Return name for this driver instance */
|
||||
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
|
||||
{
|
||||
|
|
|
@ -101,14 +101,15 @@ struct pvr2_hdw;
|
|||
struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
|
||||
const struct usb_device_id *devid);
|
||||
|
||||
/* Perform second stage initialization, passing in a notification callback
|
||||
for when the master state changes. */
|
||||
void pvr2_hdw_initialize(struct pvr2_hdw *,
|
||||
void (*callback_func)(void *),
|
||||
void *callback_data);
|
||||
|
||||
/* Destroy hardware interaction structure */
|
||||
void pvr2_hdw_destroy(struct pvr2_hdw *);
|
||||
|
||||
/* Register a function to be called whenever the master state changes. */
|
||||
void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
|
||||
void (*callback_func)(void *),
|
||||
void *callback_data);
|
||||
|
||||
/* Return true if in the ready (normal) state */
|
||||
int pvr2_hdw_dev_ok(struct pvr2_hdw *);
|
||||
|
||||
|
|
Loading…
Reference in New Issue