aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-05-14 15:56:24 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-05-14 15:56:24 +0000
commit56bef42828c150ff1817e4ee536a2974ed8222b9 (patch)
treec8efa2ddbd16d22be71eab296fa6b1e13e3af18e
parentb7a02a1c5547b49ef3bc467d335465391d57dab1 (diff)
downloadxen-56bef42828c150ff1817e4ee536a2974ed8222b9.tar.gz
xen-56bef42828c150ff1817e4ee536a2974ed8222b9.tar.bz2
xen-56bef42828c150ff1817e4ee536a2974ed8222b9.zip
bitkeeper revision 1.229 (3ec26728uXDBndxeN2-AxbIwi9afug)
dev.c, vif.h, skbuff.h, dom0_ops.c: Fixed locking in network transmit and receive. Fixed bug I added to DOM0_GETDOMAININFO in previous checkin :-)
-rw-r--r--xen/common/dom0_ops.c16
-rw-r--r--xen/include/xeno/skbuff.h10
-rw-r--r--xen/include/xeno/vif.h3
-rw-r--r--xen/net/dev.c32
4 files changed, 35 insertions, 26 deletions
diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c
index 89872251f7..c62b68b919 100644
--- a/xen/common/dom0_ops.c
+++ b/xen/common/dom0_ops.c
@@ -210,18 +210,20 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
case DOM0_GETDOMAININFO:
{
- struct task_struct *p;
+ struct task_struct *p = &idle0_task;
u_long flags;
- p = idle0_task.next_task;
read_lock_irqsave (&tasklist_lock, flags);
- do {
- if ((!is_idle_task (p)) && (p -> domain >= op.u.getdominfo.domain))
+
+ while ( (p = p->next_task) != &idle0_task )
+ if ( !is_idle_task(p) && (p->domain >= op.u.getdominfo.domain) )
break;
- } while ((p = p -> next_task) != &idle0_task);
- ret = -ESRCH;
- if ( p != &idle0_task )
+ if ( p == &idle0_task )
+ {
+ ret = -ESRCH;
+ }
+ else
{
op.u.getdominfo.domain = p->domain;
strcpy (op.u.getdominfo.name, p->name);
diff --git a/xen/include/xeno/skbuff.h b/xen/include/xeno/skbuff.h
index 367a7c114e..4e0afc0183 100644
--- a/xen/include/xeno/skbuff.h
+++ b/xen/include/xeno/skbuff.h
@@ -156,10 +156,12 @@ struct sk_buff {
unsigned char *end; /* End pointer */
void (*destructor)(struct sk_buff *); /* Destruct function */
- struct pfn_info *pf; /* record of physical pf address for freeing */
- net_vif_t *src_vif; /* vif we came from */
- net_vif_t *dst_vif; /* vif we are bound for */
- struct skb_shared_info shinfo; /* shared info is no longer shared in Xen. */
+
+ unsigned short guest_id; /* guest-OS's id for this packet (tx only!) */
+ struct pfn_info *pf; /* record of physical pf address for freeing */
+ net_vif_t *src_vif; /* vif we came from */
+ net_vif_t *dst_vif; /* vif we are bound for */
+ struct skb_shared_info shinfo; /* shared info not shared in Xen. */
};
extern void __kfree_skb(struct sk_buff *skb);
diff --git a/xen/include/xeno/vif.h b/xen/include/xeno/vif.h
index 6cc339cbd9..8e4fcab444 100644
--- a/xen/include/xeno/vif.h
+++ b/xen/include/xeno/vif.h
@@ -58,8 +58,7 @@ typedef struct net_vif_st {
unsigned int rx_cons; /* Next buffer to fill is here. */
tx_shadow_entry_t tx_shadow_ring[TX_RING_SIZE];
unsigned int tx_prod; /* More packets for sending go here. */
- unsigned int tx_idx; /* Next packet to send is here. */
- unsigned int tx_cons; /* Next packet to create response for is here. */
+ unsigned int tx_cons; /* Next packet to send is here. */
/* Private indexes into shared ring. */
unsigned int rx_req_cons;
diff --git a/xen/net/dev.c b/xen/net/dev.c
index 0f36344e74..ce2795f3a0 100644
--- a/xen/net/dev.c
+++ b/xen/net/dev.c
@@ -504,16 +504,24 @@ void deliver_packet(struct sk_buff *skb, net_vif_t *vif)
if ( ntohs(skb->mac.ethernet->h_proto) == ETH_P_ARP )
memcpy(skb->nh.raw + 18, vif->vmac, ETH_ALEN);
+ /*
+ * Slightly gross: we need the page_lock so that we can do PTE checking.
+ * However, we take it slightly early so that it can protect the update
+ * of rx_cons. This saves us from grabbing two locks.
+ */
+ spin_lock(&vif->domain->page_lock);
+
if ( (i = vif->rx_cons) == vif->rx_prod )
+ {
+ spin_unlock(&vif->domain->page_lock);
return;
-
+ }
rx = vif->rx_shadow_ring + i;
+ vif->rx_cons = RX_RING_INC(i);
size = (unsigned short)skb->len;
offset = (unsigned char)((unsigned long)skb->data & ~PAGE_MASK);
- spin_lock(&vif->domain->page_lock);
-
/* Release the page-table page. */
pte_page = frame_table + (rx->pte_ptr >> PAGE_SHIFT);
put_page_type(pte_page);
@@ -529,6 +537,8 @@ void deliver_packet(struct sk_buff *skb, net_vif_t *vif)
/* Bail out if the PTE has been reused under our feet. */
list_add(&old_page->list, &vif->domain->pg_head);
old_page->flags = vif->domain->domain;
+ unmap_domain_mem(ptep);
+ spin_unlock(&vif->domain->page_lock);
status = RING_STATUS_BAD_PAGE;
goto out;
}
@@ -558,13 +568,11 @@ void deliver_packet(struct sk_buff *skb, net_vif_t *vif)
* NB. The remote flush here should be safe, as we hold no locks. The
* network driver that called us should also have no nasty locks.
*/
- rx = vif->rx_shadow_ring + vif->rx_cons;
if ( rx->flush_count == (unsigned short)
atomic_read(&tlb_flush_count[vif->domain->processor]) )
flush_tlb_cpu(vif->domain->processor);
out:
- vif->rx_cons = RX_RING_INC(vif->rx_cons);
make_rx_response(vif, rx->id, size, status, offset);
}
@@ -682,7 +690,6 @@ static void tx_skb_release(struct sk_buff *skb)
{
int i;
net_vif_t *vif = skb->src_vif;
- tx_shadow_entry_t *tx;
unsigned long flags;
spin_lock_irqsave(&vif->domain->page_lock, flags);
@@ -695,9 +702,7 @@ static void tx_skb_release(struct sk_buff *skb)
skb_shinfo(skb)->nr_frags = 0;
- tx = vif->tx_shadow_ring + vif->tx_cons;
- vif->tx_cons = TX_RING_INC(vif->tx_cons);
- make_tx_response(vif, tx->id, RING_STATUS_OK);
+ make_tx_response(vif, skb->guest_id, RING_STATUS_OK);
put_vif(vif);
}
@@ -720,7 +725,7 @@ static void net_tx_action(unsigned long unused)
vif = list_entry(ent, net_vif_t, list);
get_vif(vif);
remove_from_net_schedule_list(vif);
- if ( vif->tx_idx == vif->tx_prod )
+ if ( vif->tx_cons == vif->tx_prod )
{
put_vif(vif);
continue;
@@ -735,9 +740,9 @@ static void net_tx_action(unsigned long unused)
}
/* Pick an entry from the transmit queue. */
- tx = &vif->tx_shadow_ring[vif->tx_idx];
- vif->tx_idx = TX_RING_INC(vif->tx_idx);
- if ( vif->tx_idx != vif->tx_prod )
+ tx = &vif->tx_shadow_ring[vif->tx_cons];
+ vif->tx_cons = TX_RING_INC(vif->tx_cons);
+ if ( vif->tx_cons != vif->tx_prod )
add_to_net_schedule_list_tail(vif);
skb->destructor = tx_skb_release;
@@ -749,6 +754,7 @@ static void net_tx_action(unsigned long unused)
skb->src_vif = vif;
skb->dst_vif = NULL;
skb->mac.raw = skb->data;
+ skb->guest_id = tx->id;
skb_shinfo(skb)->frags[0].page = frame_table +
(tx->payload >> PAGE_SHIFT);