Browse Source

uwb: reference count reservations

Reference counting the struct uwb_rsv's is safer and easier to get right than
the transferring ownership of the structures from the PAL to reservation
manager.

This fixes an oops in the debug PAL after a reservation timed out.

Signed-off-by: David Vrabel <david.vrabel@csr.com>
David Vrabel 16 years ago
parent
commit
cae1c11414
4 changed files with 46 additions and 23 deletions
  1. 3 4
      drivers/usb/wusbcore/reservation.c
  2. 32 16
      drivers/uwb/rsv.c
  3. 10 3
      drivers/uwb/uwb-debug.c
  4. 1 0
      include/linux/uwb.h

+ 3 - 4
drivers/usb/wusbcore/reservation.c

@@ -59,7 +59,6 @@ static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)
 	case UWB_RSV_STATE_NONE:
 	case UWB_RSV_STATE_NONE:
 		dev_dbg(dev, "removed reservation\n");
 		dev_dbg(dev, "removed reservation\n");
 		wusbhc_bwa_set(wusbhc, 0, NULL);
 		wusbhc_bwa_set(wusbhc, 0, NULL);
-		wusbhc->rsv = NULL;
 		break;
 		break;
 	default:
 	default:
 		dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state);
 		dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state);
@@ -105,11 +104,11 @@ int wusbhc_rsv_establish(struct wusbhc *wusbhc)
 
 
 
 
 /**
 /**
- * wusbhc_rsv_terminate - terminate any cluster reservation
+ * wusbhc_rsv_terminate - terminate the cluster reservation
  * @wusbhc: the WUSB host whose reservation is to be terminated
  * @wusbhc: the WUSB host whose reservation is to be terminated
  */
  */
 void wusbhc_rsv_terminate(struct wusbhc *wusbhc)
 void wusbhc_rsv_terminate(struct wusbhc *wusbhc)
 {
 {
-	if (wusbhc->rsv)
-		uwb_rsv_terminate(wusbhc->rsv);
+	uwb_rsv_terminate(wusbhc->rsv);
+	uwb_rsv_destroy(wusbhc->rsv);
 }
 }

+ 32 - 16
drivers/uwb/rsv.c

@@ -82,6 +82,23 @@ static void uwb_rsv_dump(struct uwb_rsv *rsv)
 	dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state));
 	dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state));
 }
 }
 
 
+static void uwb_rsv_release(struct kref *kref)
+{
+	struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref);
+
+	kfree(rsv);
+}
+
+static void uwb_rsv_get(struct uwb_rsv *rsv)
+{
+	kref_get(&rsv->kref);
+}
+
+static void uwb_rsv_put(struct uwb_rsv *rsv)
+{
+	kref_put(&rsv->kref, uwb_rsv_release);
+}
+
 /*
 /*
  * Get a free stream index for a reservation.
  * Get a free stream index for a reservation.
  *
  *
@@ -325,6 +342,7 @@ static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
 
 
 	INIT_LIST_HEAD(&rsv->rc_node);
 	INIT_LIST_HEAD(&rsv->rc_node);
 	INIT_LIST_HEAD(&rsv->pal_node);
 	INIT_LIST_HEAD(&rsv->pal_node);
+	kref_init(&rsv->kref);
 	init_timer(&rsv->timer);
 	init_timer(&rsv->timer);
 	rsv->timer.function = uwb_rsv_timer;
 	rsv->timer.function = uwb_rsv_timer;
 	rsv->timer.data     = (unsigned long)rsv;
 	rsv->timer.data     = (unsigned long)rsv;
@@ -334,14 +352,6 @@ static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
 	return rsv;
 	return rsv;
 }
 }
 
 
-static void uwb_rsv_free(struct uwb_rsv *rsv)
-{
-	uwb_dev_put(rsv->owner);
-	if (rsv->target.type == UWB_RSV_TARGET_DEV)
-		uwb_dev_put(rsv->target.dev);
-	kfree(rsv);
-}
-
 /**
 /**
  * uwb_rsv_create - allocate and initialize a UWB reservation structure
  * uwb_rsv_create - allocate and initialize a UWB reservation structure
  * @rc: the radio controller
  * @rc: the radio controller
@@ -375,23 +385,23 @@ void uwb_rsv_remove(struct uwb_rsv *rsv)
 	if (rsv->state != UWB_RSV_STATE_NONE)
 	if (rsv->state != UWB_RSV_STATE_NONE)
 		uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
 		uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
 	del_timer_sync(&rsv->timer);
 	del_timer_sync(&rsv->timer);
-	list_del(&rsv->rc_node);
-	uwb_rsv_free(rsv);
+	uwb_dev_put(rsv->owner);
+	if (rsv->target.type == UWB_RSV_TARGET_DEV)
+		uwb_dev_put(rsv->target.dev);
+
+	list_del_init(&rsv->rc_node);
+	uwb_rsv_put(rsv);
 }
 }
 
 
 /**
 /**
  * uwb_rsv_destroy - free a UWB reservation structure
  * uwb_rsv_destroy - free a UWB reservation structure
  * @rsv: the reservation to free
  * @rsv: the reservation to free
  *
  *
- * The reservation will be terminated if it is pending or established.
+ * The reservation must already be terminated.
  */
  */
 void uwb_rsv_destroy(struct uwb_rsv *rsv)
 void uwb_rsv_destroy(struct uwb_rsv *rsv)
 {
 {
-	struct uwb_rc *rc = rsv->rc;
-
-	mutex_lock(&rc->rsvs_mutex);
-	uwb_rsv_remove(rsv);
-	mutex_unlock(&rc->rsvs_mutex);
+	uwb_rsv_put(rsv);
 }
 }
 EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
 EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
 
 
@@ -423,6 +433,7 @@ int uwb_rsv_establish(struct uwb_rsv *rsv)
 		goto out;
 		goto out;
 	}
 	}
 
 
+	uwb_rsv_get(rsv);
 	list_add_tail(&rsv->rc_node, &rc->reservations);
 	list_add_tail(&rsv->rc_node, &rc->reservations);
 	rsv->owner = &rc->uwb_dev;
 	rsv->owner = &rc->uwb_dev;
 	uwb_dev_get(rsv->owner);
 	uwb_dev_get(rsv->owner);
@@ -478,9 +489,14 @@ EXPORT_SYMBOL_GPL(uwb_rsv_terminate);
  *
  *
  * Reservation requests from peers are denied unless a PAL accepts it
  * Reservation requests from peers are denied unless a PAL accepts it
  * by calling this function.
  * by calling this function.
+ *
+ * The PAL call uwb_rsv_destroy() for all accepted reservations before
+ * calling uwb_pal_unregister().
  */
  */
 void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv)
 void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv)
 {
 {
+	uwb_rsv_get(rsv);
+
 	rsv->callback = cb;
 	rsv->callback = cb;
 	rsv->pal_priv = pal_priv;
 	rsv->pal_priv = pal_priv;
 	rsv->state    = UWB_RSV_STATE_T_ACCEPTED;
 	rsv->state    = UWB_RSV_STATE_T_ACCEPTED;

+ 10 - 3
drivers/uwb/uwb-debug.c

@@ -104,6 +104,11 @@ static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
 
 
 	dev_dbg(dev, "debug: rsv %s -> %s: %s\n",
 	dev_dbg(dev, "debug: rsv %s -> %s: %s\n",
 		owner, target, uwb_rsv_state_str(rsv->state));
 		owner, target, uwb_rsv_state_str(rsv->state));
+
+	if (rsv->state == UWB_RSV_STATE_NONE) {
+		list_del(&rsv->pal_node);
+		uwb_rsv_destroy(rsv);
+	}
 }
 }
 
 
 static int cmd_rsv_establish(struct uwb_rc *rc,
 static int cmd_rsv_establish(struct uwb_rc *rc,
@@ -153,11 +158,11 @@ static int cmd_rsv_terminate(struct uwb_rc *rc,
 			found = rsv;
 			found = rsv;
 			break;
 			break;
 		}
 		}
+		i++;
 	}
 	}
 	if (!found)
 	if (!found)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	list_del(&found->pal_node);
 	uwb_rsv_terminate(found);
 	uwb_rsv_terminate(found);
 
 
 	return 0;
 	return 0;
@@ -287,8 +292,10 @@ static void uwb_dbg_new_rsv(struct uwb_rsv *rsv)
 {
 {
 	struct uwb_rc *rc = rsv->rc;
 	struct uwb_rc *rc = rsv->rc;
 
 
-	if (rc->dbg->accept)
+	if (rc->dbg->accept) {
+		list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
 		uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, NULL);
 		uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, NULL);
+	}
 }
 }
 
 
 /**
 /**
@@ -336,7 +343,7 @@ void uwb_dbg_del_rc(struct uwb_rc *rc)
 		return;
 		return;
 
 
 	list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
 	list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
-		uwb_rsv_destroy(rsv);
+		uwb_rsv_terminate(rsv);
 	}
 	}
 
 
 	uwb_pal_unregister(rc, &rc->dbg->pal);
 	uwb_pal_unregister(rc, &rc->dbg->pal);

+ 1 - 0
include/linux/uwb.h

@@ -201,6 +201,7 @@ struct uwb_rsv {
 	struct uwb_rc *rc;
 	struct uwb_rc *rc;
 	struct list_head rc_node;
 	struct list_head rc_node;
 	struct list_head pal_node;
 	struct list_head pal_node;
+	struct kref kref;
 
 
 	struct uwb_dev *owner;
 	struct uwb_dev *owner;
 	struct uwb_rsv_target target;
 	struct uwb_rsv_target target;