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>
This commit is contained in:
parent
b09ac64b7b
commit
cae1c11414
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue