Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cae1c114 authored by David Vrabel's avatar David Vrabel
Browse files

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
Loading
Loading
Loading
Loading
+3 −4
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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_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)
		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
Original line number Original line Diff line number Diff line
@@ -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,9 +292,11 @@ 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);
	}
	}
}


/**
/**
 * uwb_dbg_add_rc - add a debug interface for a radio controller
 * uwb_dbg_add_rc - add a debug interface for a radio controller
@@ -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
Original line number Original line Diff line number Diff line
@@ -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;