Commit 88c896ef authored by Jan Kiszka's avatar Jan Kiszka Committed by David S. Miller

CAPI: Rework application locking

Drop the application rw-lock in favour of RCU. This synchronizes
capi20_release against capi_ctr_handle_message which may dereference an
application from (soft-)IRQ context. Any other access to the application
list is now protected by the capi_controller_lock as well. This also
allows to safely inspect applications for /proc dumping by holding
capi_controller_lock.

At this chance, drop some useless release_in_progress checks where we
obtained the application pointer from the list (which becomes NULL on
release_in_progress).
Signed-off-by: default avatarJan Kiszka <jan.kiszka@web.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0ca3a017
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/b1lli.h> #include <linux/b1lli.h>
#endif #endif
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/rcupdate.h>
static int showcapimsgs = 0; static int showcapimsgs = 0;
...@@ -64,8 +65,6 @@ DEFINE_MUTEX(capi_drivers_lock); ...@@ -64,8 +65,6 @@ DEFINE_MUTEX(capi_drivers_lock);
struct capi_ctr *capi_controller[CAPI_MAXCONTR]; struct capi_ctr *capi_controller[CAPI_MAXCONTR];
DEFINE_MUTEX(capi_controller_lock); DEFINE_MUTEX(capi_controller_lock);
static DEFINE_RWLOCK(application_lock);
struct capi20_appl *capi_applications[CAPI_MAXAPPL]; struct capi20_appl *capi_applications[CAPI_MAXAPPL];
static int ncontrollers; static int ncontrollers;
...@@ -103,7 +102,7 @@ static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid) ...@@ -103,7 +102,7 @@ static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
if (applid - 1 >= CAPI_MAXAPPL) if (applid - 1 >= CAPI_MAXAPPL)
return NULL; return NULL;
return capi_applications[applid - 1]; return rcu_dereference(capi_applications[applid - 1]);
} }
/* -------- util functions ------------------------------------ */ /* -------- util functions ------------------------------------ */
...@@ -186,7 +185,7 @@ static void notify_up(u32 contr) ...@@ -186,7 +185,7 @@ static void notify_up(u32 contr)
for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
ap = get_capi_appl_by_nr(applid); ap = get_capi_appl_by_nr(applid);
if (!ap || ap->release_in_progress) if (!ap)
continue; continue;
register_appl(ctr, applid, &ap->rparam); register_appl(ctr, applid, &ap->rparam);
} }
...@@ -216,7 +215,7 @@ static void ctr_down(struct capi_ctr *ctr, int new_state) ...@@ -216,7 +215,7 @@ static void ctr_down(struct capi_ctr *ctr, int new_state)
for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
ap = get_capi_appl_by_nr(applid); ap = get_capi_appl_by_nr(applid);
if (ap && !ap->release_in_progress) if (ap)
capi_ctr_put(ctr); capi_ctr_put(ctr);
} }
...@@ -336,7 +335,6 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, ...@@ -336,7 +335,6 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
struct capi20_appl *ap; struct capi20_appl *ap;
int showctl = 0; int showctl = 0;
u8 cmd, subcmd; u8 cmd, subcmd;
unsigned long flags;
_cdebbuf *cdb; _cdebbuf *cdb;
if (ctr->state != CAPI_CTR_RUNNING) { if (ctr->state != CAPI_CTR_RUNNING) {
...@@ -384,10 +382,10 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, ...@@ -384,10 +382,10 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
} }
read_lock_irqsave(&application_lock, flags); rcu_read_lock();
ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
if ((!ap) || (ap->release_in_progress)) { if (!ap) {
read_unlock_irqrestore(&application_lock, flags); rcu_read_unlock();
cdb = capi_message2str(skb->data); cdb = capi_message2str(skb->data);
if (cdb) { if (cdb) {
printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n", printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n",
...@@ -401,7 +399,7 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, ...@@ -401,7 +399,7 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,
} }
skb_queue_tail(&ap->recv_queue, skb); skb_queue_tail(&ap->recv_queue, skb);
schedule_work(&ap->recv_work); schedule_work(&ap->recv_work);
read_unlock_irqrestore(&application_lock, flags); rcu_read_unlock();
return; return;
...@@ -656,40 +654,35 @@ u16 capi20_register(struct capi20_appl *ap) ...@@ -656,40 +654,35 @@ u16 capi20_register(struct capi20_appl *ap)
{ {
int i; int i;
u16 applid; u16 applid;
unsigned long flags;
DBG(""); DBG("");
if (ap->rparam.datablklen < 128) if (ap->rparam.datablklen < 128)
return CAPI_LOGBLKSIZETOSMALL; return CAPI_LOGBLKSIZETOSMALL;
write_lock_irqsave(&application_lock, flags); ap->nrecvctlpkt = 0;
ap->nrecvdatapkt = 0;
ap->nsentctlpkt = 0;
ap->nsentdatapkt = 0;
mutex_init(&ap->recv_mtx);
skb_queue_head_init(&ap->recv_queue);
INIT_WORK(&ap->recv_work, recv_handler);
ap->release_in_progress = 0;
mutex_lock(&capi_controller_lock);
for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
if (capi_applications[applid - 1] == NULL) if (capi_applications[applid - 1] == NULL)
break; break;
} }
if (applid > CAPI_MAXAPPL) { if (applid > CAPI_MAXAPPL) {
write_unlock_irqrestore(&application_lock, flags); mutex_unlock(&capi_controller_lock);
return CAPI_TOOMANYAPPLS; return CAPI_TOOMANYAPPLS;
} }
ap->applid = applid; ap->applid = applid;
capi_applications[applid - 1] = ap; capi_applications[applid - 1] = ap;
ap->nrecvctlpkt = 0;
ap->nrecvdatapkt = 0;
ap->nsentctlpkt = 0;
ap->nsentdatapkt = 0;
mutex_init(&ap->recv_mtx);
skb_queue_head_init(&ap->recv_queue);
INIT_WORK(&ap->recv_work, recv_handler);
ap->release_in_progress = 0;
write_unlock_irqrestore(&application_lock, flags);
mutex_lock(&capi_controller_lock);
for (i = 0; i < CAPI_MAXCONTR; i++) { for (i = 0; i < CAPI_MAXCONTR; i++) {
if (!capi_controller[i] || if (!capi_controller[i] ||
capi_controller[i]->state != CAPI_CTR_RUNNING) capi_controller[i]->state != CAPI_CTR_RUNNING)
...@@ -721,16 +714,15 @@ EXPORT_SYMBOL(capi20_register); ...@@ -721,16 +714,15 @@ EXPORT_SYMBOL(capi20_register);
u16 capi20_release(struct capi20_appl *ap) u16 capi20_release(struct capi20_appl *ap)
{ {
int i; int i;
unsigned long flags;
DBG("applid %#x", ap->applid); DBG("applid %#x", ap->applid);
write_lock_irqsave(&application_lock, flags); mutex_lock(&capi_controller_lock);
ap->release_in_progress = 1; ap->release_in_progress = 1;
capi_applications[ap->applid - 1] = NULL; capi_applications[ap->applid - 1] = NULL;
write_unlock_irqrestore(&application_lock, flags);
mutex_lock(&capi_controller_lock); synchronize_rcu();
for (i = 0; i < CAPI_MAXCONTR; i++) { for (i = 0; i < CAPI_MAXCONTR; i++) {
if (!capi_controller[i] || if (!capi_controller[i] ||
......
...@@ -139,9 +139,11 @@ static const struct file_operations proc_contrstats_ops = { ...@@ -139,9 +139,11 @@ static const struct file_operations proc_contrstats_ops = {
// applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt // applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
static void * static void *applications_start(struct seq_file *seq, loff_t *pos)
applications_start(struct seq_file *seq, loff_t *pos) __acquires(capi_controller_lock)
{ {
mutex_lock(&capi_controller_lock);
if (*pos < CAPI_MAXAPPL) if (*pos < CAPI_MAXAPPL)
return &capi_applications[*pos]; return &capi_applications[*pos];
...@@ -158,9 +160,10 @@ applications_next(struct seq_file *seq, void *v, loff_t *pos) ...@@ -158,9 +160,10 @@ applications_next(struct seq_file *seq, void *v, loff_t *pos)
return NULL; return NULL;
} }
static void static void applications_stop(struct seq_file *seq, void *v)
applications_stop(struct seq_file *seq, void *v) __releases(capi_controller_lock)
{ {
mutex_unlock(&capi_controller_lock);
} }
static int static int
......
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