xpp: stability -- better xbus shut down

* Maintain a "shutting_down" flag per-xbus
* Use it to prevent xbus dereferencing (via xbus_get()/xbus_put())
  during an xbus shutdown.
* Also, remove xbus from global array earlier.

Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
This commit is contained in:
Oron Peled
2014-05-12 10:51:59 -04:00
committed by Tzafrir Cohen
parent db07e1b74d
commit 9a00fc6321

View File

@@ -80,8 +80,14 @@ static struct proc_dir_entry *proc_xbuses;
static struct xbus_desc {
xbus_t *xbus;
int shutting_down;
} xbuses_array[MAX_BUSES];
static int xbus_is_shutting_down(int num)
{
return xbuses_array[num].shutting_down;
}
static xbus_t *xbus_byhwid(const char *hwid)
{
int i;
@@ -149,6 +155,8 @@ static void init_xbus(uint num, xbus_t *xbus)
BUG_ON(num >= ARRAY_SIZE(xbuses_array));
desc = &xbuses_array[num];
desc->xbus = xbus;
if (xbus)
desc->shutting_down = 0;
}
xbus_t *xbus_num(uint num)
@@ -188,9 +196,12 @@ static void finalize_xbuses_array(void)
static void xbus_destroy(struct kref *kref)
{
xbus_t *xbus;
int num;
xbus = kref_to_xbus(kref);
XBUS_NOTICE(xbus, "%s\n", __func__);
num = xbus->num;
xbuses_array[num].shutting_down = 1;
xbus_sysfs_remove(xbus);
}
@@ -199,6 +210,11 @@ xbus_t *get_xbus(const char *msg, uint num)
unsigned long flags;
xbus_t *xbus;
if (xbus_is_shutting_down(num)) {
DBG(DEVICES, "%s(%s): XBUS-%d: shutting down\n", __func__,
msg, num);
return NULL;
}
spin_lock_irqsave(&xbuses_lock, flags);
xbus = xbus_num(num);
if (xbus != NULL) {
@@ -212,6 +228,13 @@ xbus_t *get_xbus(const char *msg, uint num)
void put_xbus(const char *msg, xbus_t *xbus)
{
if (xbus_is_shutting_down(xbus->num)) {
if (!refcount_xbus(xbus)) {
DBG(DEVICES, "%s(%s): XBUS-%d: shutting down\n",
__func__, msg, xbus->num);
return;
}
}
XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n", msg,
refcount_xbus(xbus));
kref_put(&xbus->kref, xbus_destroy);
@@ -561,6 +584,14 @@ static void receive_tasklet_func(unsigned long data)
void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe)
{
BUG_ON(!xbus);
if (xbus_is_shutting_down(xbus->num)) {
static int rate_limit;
if ((rate_limit++ % 1000) == 0)
XBUS_NOTICE(xbus, "%s: during shutdown (%d)\n",
__func__, rate_limit);
return;
}
if (rx_tasklet) {
xframe_enqueue_recv(xbus, xframe);
} else {
@@ -1483,6 +1514,7 @@ void xbus_free(xbus_t *xbus)
num = xbus->num;
BUG_ON(!xbuses_array[num].xbus);
BUG_ON(xbus != xbuses_array[num].xbus);
init_xbus(num, NULL);
spin_unlock_irqrestore(&xbuses_lock, flags);
#ifdef CONFIG_PROC_FS
if (xbus->proc_xbus_dir) {
@@ -1509,7 +1541,6 @@ void xbus_free(xbus_t *xbus)
#endif
spin_lock_irqsave(&xbuses_lock, flags);
XBUS_DBG(DEVICES, xbus, "Going to free...\n");
init_xbus(num, NULL);
spin_unlock_irqrestore(&xbuses_lock, flags);
KZFREE(xbus);
}