Commit c4a8828d authored by Mike Isely's avatar Mike Isely Committed by Mauro Carvalho Chehab
Browse files

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: default avatarMike Isely <isely@pobox.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent ee9ca4b2
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -75,10 +75,9 @@ struct pvr2_context *pvr2_context_create(
		mp = NULL;
		goto done;
	}
	pvr2_hdw_set_state_callback(mp->hdw,
	pvr2_hdw_initialize(mp->hdw,
			    (void (*)(void *))pvr2_context_state_check,
			    mp);
	pvr2_context_state_check(mp);
 done:
	return mp;
}
+17 −14
Original line number Diff line number Diff line
@@ -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)
{
+6 −5
Original line number Diff line number Diff line
@@ -101,14 +101,15 @@ struct pvr2_hdw;
struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
				 const struct usb_device_id *devid);

/* 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 *,
/* 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 *);

/* Return true if in the ready (normal) state */
int pvr2_hdw_dev_ok(struct pvr2_hdw *);