[PATCH v2 32/41] CAPI: Rework capiminor RX handler

From: Jan Kiszka
Date: Mon Feb 08 2010 - 15:16:14 EST


Avoid re-queuing skbs unless the error detected in handle_recv_skb is
expected to be recoverable such as lacking memory, a full CAPI queue, a
full TTY input buffer, or a not yet existing TTY.

Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxx>
---
drivers/isdn/capi/capi.c | 60 +++++++++++++++++++++++++++++-----------------
1 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 554fa1b..c5c54fa 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -436,15 +436,13 @@ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)

static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
{
+ unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data);
struct tty_struct *tty;
struct sk_buff *nskb;
- int datalen;
u16 errcode, datahandle;
struct tty_ldisc *ld;
int ret = -1;

- datalen = skb->len - CAPIMSG_LEN(skb->data);
-
tty = tty_port_tty_get(&mp->port);
if (!tty) {
#ifdef _DEBUG_DATAFLOW
@@ -454,50 +452,68 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
}

ld = tty_ldisc_ref(tty);
- if (!ld)
- goto out1;
+ if (!ld) {
+ /* fatal error, do not requeue */
+ ret = 0;
+ kfree_skb(skb);
+ goto deref_tty;
+ }

if (ld->ops->receive_buf == NULL) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
#endif
- goto out2;
+ /* fatal error, do not requeue */
+ goto free_skb;
}
if (mp->ttyinstop) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: recv tty throttled\n");
#endif
- goto out2;
+ goto deref_ldisc;
}
+
if (tty->receive_room < datalen) {
#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
printk(KERN_DEBUG "capi: no room in tty\n");
#endif
- goto out2;
+ goto deref_ldisc;
}
- if ((nskb = gen_data_b3_resp_for(mp, skb)) == NULL) {
+
+ nskb = gen_data_b3_resp_for(mp, skb);
+ if (!nskb) {
printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
- goto out2;
+ goto deref_ldisc;
}
- datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+
+ datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);
+
errcode = capi20_put_message(mp->ap, nskb);
- if (errcode != CAPI_NOERROR) {
+
+ if (errcode == CAPI_NOERROR) {
+ skb_pull(skb, CAPIMSG_LEN(skb->data));
+#ifdef _DEBUG_DATAFLOW
+ printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
+ datahandle, skb->len);
+#endif
+ ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
+ } else {
printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
errcode);
kfree_skb(nskb);
- goto out2;
+
+ if (errcode == CAPI_SENDQUEUEFULL)
+ goto deref_ldisc;
}
- (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
-#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
- datahandle, skb->len);
-#endif
- ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
- kfree_skb(skb);
+
+free_skb:
ret = 0;
-out2:
+ kfree_skb(skb);
+
+deref_ldisc:
tty_ldisc_deref(ld);
-out1:
+
+deref_tty:
tty_kref_put(tty);
return ret;
}
--
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/