Commit cae1c114 authored by David Vrabel's avatar David Vrabel

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: default avatarDavid Vrabel <david.vrabel@csr.com>
parent b09ac64b
...@@ -59,7 +59,6 @@ static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv) ...@@ -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) ...@@ -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);
} }
...@@ -82,6 +82,23 @@ static void uwb_rsv_dump(struct uwb_rsv *rsv) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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_dev_put(rsv->owner);
uwb_rsv_free(rsv); 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; uwb_rsv_put(rsv);
mutex_lock(&rc->rsvs_mutex);
uwb_rsv_remove(rsv);
mutex_unlock(&rc->rsvs_mutex);
} }
EXPORT_SYMBOL_GPL(uwb_rsv_destroy); EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
...@@ -423,6 +433,7 @@ int uwb_rsv_establish(struct uwb_rsv *rsv) ...@@ -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); ...@@ -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;
......
...@@ -104,6 +104,11 @@ static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -201,6 +201,7 @@ struct uwb_rsv { ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment