Browse Source

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>
Mike Isely 17 years ago
parent
commit
c4a8828ddb

+ 3 - 4
drivers/media/video/pvrusb2/pvrusb2-context.c

@@ -75,10 +75,9 @@ struct pvr2_context *pvr2_context_create(
 		mp = NULL;
 		mp = NULL;
 		goto done;
 		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:
  done:
 	return mp;
 	return mp;
 }
 }

+ 17 - 14
drivers/media/video/pvrusb2/pvrusb2-hdw.c

@@ -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,
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 				 const struct usb_device_id *devid)
 				 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->ctl_lock_mutex);
 	mutex_init(&hdw->big_lock_mutex);
 	mutex_init(&hdw->big_lock_mutex);
 
 
-	queue_work(hdw->workqueue,&hdw->workinit);
 	return hdw;
 	return hdw;
  fail:
  fail:
 	if (hdw) {
 	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 */
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 {
 {

+ 6 - 5
drivers/media/video/pvrusb2/pvrusb2-hdw.h

@@ -101,14 +101,15 @@ struct pvr2_hdw;
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 				 const struct usb_device_id *devid);
 				 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 */
 /* Destroy hardware interaction structure */
 void pvr2_hdw_destroy(struct pvr2_hdw *);
 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 */
 /* Return true if in the ready (normal) state */
 int pvr2_hdw_dev_ok(struct pvr2_hdw *);
 int pvr2_hdw_dev_ok(struct pvr2_hdw *);