[svn-commits] sruffell: linux/trunk r6222 - /linux/trunk/drivers/dahdi/wctc4xxp/base.c
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Mon Mar 23 18:48:47 CDT 2009
Author: sruffell
Date: Mon Mar 23 18:48:43 2009
New Revision: 6222
URL: http://svn.digium.com/svn-view/dahdi?view=rev&rev=6222
Log:
Set TX_COMPLETE atomically with changes to the waiting_for_response_list.
This change is to catch a condition where it is possible, for whatever reason,
for a response to come in before the request is marked tx complete.
If this happened, it was possible to leak the response packet and double complete
the command.
Modified:
linux/trunk/drivers/dahdi/wctc4xxp/base.c
Modified: linux/trunk/drivers/dahdi/wctc4xxp/base.c
URL: http://svn.digium.com/svn-view/dahdi/linux/trunk/drivers/dahdi/wctc4xxp/base.c?view=diff&rev=6222&r1=6221&r2=6222
==============================================================================
--- linux/trunk/drivers/dahdi/wctc4xxp/base.c (original)
+++ linux/trunk/drivers/dahdi/wctc4xxp/base.c Mon Mar 23 18:48:43 2009
@@ -212,6 +212,7 @@
void *data;
/* The number of bytes available in data. */
int data_len;
+ spinlock_t lock;
};
static inline void *hdr_from_cmd(struct tcb *cmd)
@@ -235,6 +236,7 @@
cmd->flags = cmd_flags;
cmd->data = &cmd->cmd[0];
cmd->data_len = SFRAME_SIZE;
+ spin_lock_init(&cmd->lock);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
@@ -910,7 +912,6 @@
--dr->count;
WARN_ON(!c);
c->data_len = (d->des0 >> 16) & BUFFER1_SIZE_MASK;
- c->flags |= TX_COMPLETE;
} else {
c = NULL;
}
@@ -2024,6 +2025,7 @@
const struct csm_encaps_hdr *rxhdr;
struct tcb *pos;
struct tcb *temp;
+ unsigned long flags;
rxhdr = cmd->data;
spin_lock_bh(&wc->cmd_list_lock);
@@ -2032,11 +2034,14 @@
listhdr = pos->data;
if ((listhdr->function == rxhdr->function) &&
(listhdr->channel == rxhdr->channel)) {
+ spin_lock_irqsave(&pos->lock, flags);
list_del_init(&pos->node);
pos->flags &= ~(__WAIT_FOR_RESPONSE);
pos->response = cmd;
- WARN_ON(!(pos->flags & TX_COMPLETE));
- complete(&pos->complete);
+ if (pos->flags & TX_COMPLETE) {
+ complete(&pos->complete);
+ }
+ spin_unlock_irqrestore(&pos->lock, flags);
break;
}
}
@@ -2234,18 +2239,25 @@
static inline void service_tx_ring(struct wcdte *wc)
{
struct tcb *cmd;
+ unsigned long flags;
while ((cmd = wctc4xxp_retrieve(wc->txd))) {
+ spin_lock_irqsave(&cmd->lock, flags);
+ cmd->flags |= TX_COMPLETE;
if (!(cmd->flags & (__WAIT_FOR_ACK | __WAIT_FOR_RESPONSE))) {
/* If we're not waiting for an ACK or Response from
* the DTE, this message should not be sitting on any
* lists. */
WARN_ON(!list_empty(&cmd->node));
if (DO_NOT_AUTO_FREE & cmd->flags) {
+ spin_unlock_irqrestore(&cmd->lock, flags);
WARN_ON(!(cmd->flags & TX_COMPLETE));
complete(&cmd->complete);
} else {
+ spin_unlock_irqrestore(&cmd->lock, flags);
free_cmd(cmd);
}
+ } else {
+ spin_unlock_irqrestore(&cmd->lock, flags);
}
/* We've freed up a spot in the hardware ring buffer. If
* another packet is queued up, let's submit it to the
More information about the svn-commits
mailing list