summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2008-10-27 18:22:46 +0300
committerDavid Vrabel <david.vrabel@csr.com>2008-10-28 15:07:23 +0300
commitcae1c11414912bf77a62aebd65ced321f0b9da51 (patch)
tree1f83b9b82aec7f86740f8b1f7f5e8be1c6cf3196
parentb09ac64b7b2d93efab3998033588f5cb0e470ccf (diff)
downloadlinux-cae1c11414912bf77a62aebd65ced321f0b9da51.tar.xz
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>
-rw-r--r--drivers/usb/wusbcore/reservation.c7
-rw-r--r--drivers/uwb/rsv.c48
-rw-r--r--drivers/uwb/uwb-debug.c13
-rw-r--r--include/linux/uwb.h1
4 files changed, 46 insertions, 23 deletions
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c
index fc63e77ded2d..7b6525dac2f1 100644
--- a/drivers/usb/wusbcore/reservation.c
+++ b/drivers/usb/wusbcore/reservation.c
@@ -59,7 +59,6 @@ static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)
case UWB_RSV_STATE_NONE:
dev_dbg(dev, "removed reservation\n");
wusbhc_bwa_set(wusbhc, 0, NULL);
- wusbhc->rsv = NULL;
break;
default:
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
*/
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);
}
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
index e4facae46e0d..bcc41a4a6606 100644
--- a/drivers/uwb/rsv.c
+++ b/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));
}
+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.
*
@@ -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->pal_node);
+ kref_init(&rsv->kref);
init_timer(&rsv->timer);
rsv->timer.function = uwb_rsv_timer;
rsv->timer.data = (unsigned long)rsv;
@@ -334,14 +352,6 @@ static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
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
* @rc: the radio controller
@@ -375,23 +385,23 @@ void uwb_rsv_remove(struct uwb_rsv *rsv)
if (rsv->state != UWB_RSV_STATE_NONE)
uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
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
* @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)
{
- 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);
@@ -423,6 +433,7 @@ int uwb_rsv_establish(struct uwb_rsv *rsv)
goto out;
}
+ uwb_rsv_get(rsv);
list_add_tail(&rsv->rc_node, &rc->reservations);
rsv->owner = &rc->uwb_dev;
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
* 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)
{
+ uwb_rsv_get(rsv);
+
rsv->callback = cb;
rsv->pal_priv = pal_priv;
rsv->state = UWB_RSV_STATE_T_ACCEPTED;
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
index 6d232c35d07d..6db641e45313 100644
--- a/drivers/uwb/uwb-debug.c
+++ b/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",
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,
@@ -153,11 +158,11 @@ static int cmd_rsv_terminate(struct uwb_rc *rc,
found = rsv;
break;
}
+ i++;
}
if (!found)
return -EINVAL;
- list_del(&found->pal_node);
uwb_rsv_terminate(found);
return 0;
@@ -287,8 +292,10 @@ static void uwb_dbg_new_rsv(struct uwb_rsv *rsv)
{
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);
+ }
}
/**
@@ -336,7 +343,7 @@ void uwb_dbg_del_rc(struct uwb_rc *rc)
return;
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);
diff --git a/include/linux/uwb.h b/include/linux/uwb.h
index f9ccbd9a2ced..010ee708304d 100644
--- a/include/linux/uwb.h
+++ b/include/linux/uwb.h
@@ -201,6 +201,7 @@ struct uwb_rsv {
struct uwb_rc *rc;
struct list_head rc_node;
struct list_head pal_node;
+ struct kref kref;
struct uwb_dev *owner;
struct uwb_rsv_target target;