Sun Dec 23 12:09:45 2018 UTC ()
Cleanup the TX path:
- split in sub-functions
- ratelimit printf for mbuf allocation failure
- don't loop forever on mbuf allocation failure


(bouyer)
diff -r1.71 -r1.72 src/sys/arch/xen/xen/xennetback_xenbus.c

cvs diff -r1.71 -r1.72 src/sys/arch/xen/xen/xennetback_xenbus.c (expand / switch to unified diff)

--- src/sys/arch/xen/xen/xennetback_xenbus.c 2018/10/26 05:33:21 1.71
+++ src/sys/arch/xen/xen/xennetback_xenbus.c 2018/12/23 12:09:45 1.72
@@ -1,41 +1,41 @@ @@ -1,41 +1,41 @@
1/* $NetBSD: xennetback_xenbus.c,v 1.71 2018/10/26 05:33:21 cherry Exp $ */ 1/* $NetBSD: xennetback_xenbus.c,v 1.72 2018/12/23 12:09:45 bouyer Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006 Manuel Bouyer. 4 * Copyright (c) 2006 Manuel Bouyer.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */ 25 */
26 26
27#include <sys/cdefs.h> 27#include <sys/cdefs.h>
28__KERNEL_RCSID(0, "$NetBSD: xennetback_xenbus.c,v 1.71 2018/10/26 05:33:21 cherry Exp $"); 28__KERNEL_RCSID(0, "$NetBSD: xennetback_xenbus.c,v 1.72 2018/12/23 12:09:45 bouyer Exp $");
29 29
30#include "opt_xen.h" 30#include "opt_xen.h"
31 31
32#include <sys/types.h> 32#include <sys/types.h>
33#include <sys/param.h> 33#include <sys/param.h>
34#include <sys/systm.h> 34#include <sys/systm.h>
35#include <sys/malloc.h> 35#include <sys/malloc.h>
36#include <sys/kmem.h> 36#include <sys/kmem.h>
37#include <sys/queue.h> 37#include <sys/queue.h>
38#include <sys/kernel.h> 38#include <sys/kernel.h>
39#include <sys/mbuf.h> 39#include <sys/mbuf.h>
40#include <sys/protosw.h> 40#include <sys/protosw.h>
41#include <sys/socket.h> 41#include <sys/socket.h>
@@ -1205,135 +1205,156 @@ xennetback_ifsoftstart_transfer(void *ar @@ -1205,135 +1205,156 @@ xennetback_ifsoftstart_transfer(void *ar
1205 * note that we don't use RING_FINAL_CHECK_FOR_REQUESTS() 1205 * note that we don't use RING_FINAL_CHECK_FOR_REQUESTS()
1206 * here, as the frontend doesn't notify when adding 1206 * here, as the frontend doesn't notify when adding
1207 * requests anyway 1207 * requests anyway
1208 */ 1208 */
1209 if (__predict_false( 1209 if (__predict_false(
1210 !RING_HAS_UNCONSUMED_REQUESTS(&xneti->xni_rxring))) { 1210 !RING_HAS_UNCONSUMED_REQUESTS(&xneti->xni_rxring))) {
1211 /* ring full */ 1211 /* ring full */
1212 break; 1212 break;
1213 } 1213 }
1214 } 1214 }
1215 splx(s); 1215 splx(s);
1216} 1216}
1217 1217
 1218/*
 1219 * sighly different from m_dup(); for some reason m_dup() can return
 1220 * a chain where the data area can cross a page boundary.
 1221 * This doesn't happens with the function below.
 1222 */
 1223static struct mbuf *
 1224xennetback_copymbuf(struct mbuf *m)
 1225{
 1226 struct mbuf *new_m;
 1227
 1228 MGETHDR(new_m, M_DONTWAIT, MT_DATA);
 1229 if (__predict_false(new_m == NULL)) {
 1230 return NULL;
 1231 }
 1232 if (m->m_pkthdr.len > MHLEN) {
 1233 MCLGET(new_m, M_DONTWAIT);
 1234 if (__predict_false(
 1235 (new_m->m_flags & M_EXT) == 0)) {
 1236 m_freem(new_m);
 1237 return NULL;
 1238 }
 1239 }
 1240 m_copydata(m, 0, m->m_pkthdr.len,
 1241 mtod(new_m, void *));
 1242 new_m->m_len = new_m->m_pkthdr.len =
 1243 m->m_pkthdr.len;
 1244 return new_m;
 1245}
 1246
 1247/* return physical page address and offset of data area of an mbuf */
 1248static void
 1249xennetback_mbuf_addr(struct mbuf *m, paddr_t *xmit_pa, int *offset)
 1250{
 1251 switch (m->m_flags & (M_EXT|M_EXT_CLUSTER)) {
 1252 case M_EXT|M_EXT_CLUSTER:
 1253 KASSERT(m->m_ext.ext_paddr != M_PADDR_INVALID);
 1254 *xmit_pa = m->m_ext.ext_paddr;
 1255 *offset = m->m_data - m->m_ext.ext_buf;
 1256 break;
 1257 case 0:
 1258 KASSERT(m->m_paddr != M_PADDR_INVALID);
 1259 *xmit_pa = m->m_paddr;
 1260 *offset = M_BUFOFFSET(m) +
 1261 (m->m_data - M_BUFADDR(m));
 1262 break;
 1263 default:
 1264 if (__predict_false(
 1265 !pmap_extract(pmap_kernel(),
 1266 (vaddr_t)m->m_data, xmit_pa))) {
 1267 panic("xennet_start: no pa");
 1268 }
 1269 *offset = 0;
 1270 break;
 1271 }
 1272 *offset += (*xmit_pa & ~PG_FRAME);
 1273 *xmit_pa = (*xmit_pa & PG_FRAME);
 1274}
 1275
1218static void 1276static void
1219xennetback_ifsoftstart_copy(void *arg) 1277xennetback_ifsoftstart_copy(void *arg)
1220{ 1278{
1221 struct xnetback_instance *xneti = arg; 1279 struct xnetback_instance *xneti = arg;
1222 struct ifnet *ifp = &xneti->xni_if; 1280 struct ifnet *ifp = &xneti->xni_if;
1223 struct mbuf *m, *new_m; 1281 struct mbuf *m, *new_m;
1224 paddr_t xmit_pa; 1282 paddr_t xmit_pa;
1225 paddr_t xmit_ma; 1283 paddr_t xmit_ma;
1226 int i, j; 1284 int i, j;
1227 netif_rx_response_t *rxresp; 1285 netif_rx_response_t *rxresp;
1228 netif_rx_request_t rxreq; 1286 netif_rx_request_t rxreq;
1229 RING_IDX req_prod, resp_prod; 1287 RING_IDX req_prod, resp_prod;
1230 int do_event = 0; 1288 int do_event = 0;
1231 gnttab_copy_t *gop; 1289 gnttab_copy_t *gop;
1232 int id, offset; 1290 int id, offset;
 1291 bool abort;
1233 1292
1234 XENPRINTF(("xennetback_ifsoftstart_copy ")); 1293 XENPRINTF(("xennetback_ifsoftstart_copy "));
1235 int s = splnet(); 1294 int s = splnet();
1236 if (__predict_false( 1295 if (__predict_false(
1237 (ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)) { 1296 (ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)) {
1238 splx(s); 1297 splx(s);
1239 return; 1298 return;
1240 } 1299 }
1241 1300
1242 while (!IFQ_IS_EMPTY(&ifp->if_snd)) { 1301 while (!IFQ_IS_EMPTY(&ifp->if_snd)) {
1243 XENPRINTF(("pkt\n")); 1302 XENPRINTF(("pkt\n"));
1244 req_prod = xneti->xni_rxring.sring->req_prod; 1303 req_prod = xneti->xni_rxring.sring->req_prod;
1245 resp_prod = xneti->xni_rxring.rsp_prod_pvt; 1304 resp_prod = xneti->xni_rxring.rsp_prod_pvt;
1246 xen_rmb(); 1305 xen_rmb();
1247 1306
1248 gop = xstart_gop_copy; 1307 gop = xstart_gop_copy;
 1308 abort = false;
1249 for (i = 0; !IFQ_IS_EMPTY(&ifp->if_snd);) { 1309 for (i = 0; !IFQ_IS_EMPTY(&ifp->if_snd);) {
1250 XENPRINTF(("have a packet\n")); 1310 XENPRINTF(("have a packet\n"));
1251 IFQ_POLL(&ifp->if_snd, m); 1311 IFQ_POLL(&ifp->if_snd, m);
1252 if (__predict_false(m == NULL)) 1312 if (__predict_false(m == NULL))
1253 panic("xennetback_ifstart: IFQ_POLL"); 1313 panic("xennetback_ifstart: IFQ_POLL");
1254 if (__predict_false( 1314 if (__predict_false(
1255 req_prod == xneti->xni_rxring.req_cons || 1315 req_prod == xneti->xni_rxring.req_cons ||
1256 xneti->xni_rxring.req_cons - resp_prod == 1316 xneti->xni_rxring.req_cons - resp_prod ==
1257 NET_RX_RING_SIZE)) { 1317 NET_RX_RING_SIZE)) {
1258 /* out of ring space */ 1318 /* out of ring space */
1259 XENPRINTF(("xennetback_ifstart: ring full " 1319 XENPRINTF(("xennetback_ifstart: ring full "
1260 "req_prod 0x%x req_cons 0x%x resp_prod " 1320 "req_prod 0x%x req_cons 0x%x resp_prod "
1261 "0x%x\n", 1321 "0x%x\n",
1262 req_prod, xneti->xni_rxring.req_cons, 1322 req_prod, xneti->xni_rxring.req_cons,
1263 resp_prod)); 1323 resp_prod));
1264 ifp->if_timer = 1; 1324 abort = true;
1265 break; 1325 break;
1266 } 1326 }
1267 if (__predict_false(i == NB_XMIT_PAGES_BATCH)) 1327 if (__predict_false(i == NB_XMIT_PAGES_BATCH))
1268 break; /* we filled the array */ 1328 break; /* we filled the array */
1269 switch (m->m_flags & (M_EXT|M_EXT_CLUSTER)) { 1329
1270 case M_EXT|M_EXT_CLUSTER: 1330 xennetback_mbuf_addr(m, &xmit_pa, &offset);
1271 KASSERT(m->m_ext.ext_paddr != M_PADDR_INVALID); 
1272 xmit_pa = m->m_ext.ext_paddr; 
1273 offset = m->m_data - m->m_ext.ext_buf; 
1274 break; 
1275 case 0: 
1276 KASSERT(m->m_paddr != M_PADDR_INVALID); 
1277 xmit_pa = m->m_paddr; 
1278 offset = M_BUFOFFSET(m) + 
1279 (m->m_data - M_BUFADDR(m)); 
1280 break; 
1281 default: 
1282 if (__predict_false( 
1283 !pmap_extract(pmap_kernel(), 
1284 (vaddr_t)m->m_data, &xmit_pa))) { 
1285 panic("xennet_start: no pa"); 
1286 } 
1287 offset = 0; 
1288 break; 
1289 } 
1290 offset += (xmit_pa & ~PG_FRAME); 
1291 xmit_pa = (xmit_pa & PG_FRAME); 
1292 if (m->m_pkthdr.len != m->m_len || 1331 if (m->m_pkthdr.len != m->m_len ||
1293 (offset + m->m_pkthdr.len) > PAGE_SIZE) { 1332 (offset + m->m_pkthdr.len) > PAGE_SIZE) {
1294 MGETHDR(new_m, M_DONTWAIT, MT_DATA); 1333 new_m = xennetback_copymbuf(m);
1295 if (__predict_false(new_m == NULL)) { 1334 if (__predict_false(new_m == NULL)) {
1296 printf("%s: cannot allocate new mbuf\n", 1335 static struct timeval lasttime;
1297 ifp->if_xname); 1336 if (ratecheck(&lasttime, &xni_pool_errintvl))
 1337 printf("%s: cannot allocate new mbuf\n",
 1338 ifp->if_xname);
 1339 abort = 1;
1298 break; 1340 break;
1299 } 
1300 if (m->m_pkthdr.len > MHLEN) { 
1301 MCLGET(new_m, M_DONTWAIT); 
1302 if (__predict_false( 
1303 (new_m->m_flags & M_EXT) == 0)) { 
1304 XENPRINTF(( 
1305 "%s: no mbuf cluster\n", 
1306 ifp->if_xname)); 
1307 m_freem(new_m); 
1308 break; 
1309 } 
1310 xmit_pa = new_m->m_ext.ext_paddr; 
1311 offset = new_m->m_data - 
1312 new_m->m_ext.ext_buf; 
1313 } else { 1341 } else {
1314 xmit_pa = new_m->m_paddr; 1342 IFQ_DEQUEUE(&ifp->if_snd, m);
1315 offset = M_BUFOFFSET(new_m) + 1343 m_freem(m);
1316 (new_m->m_data - M_BUFADDR(new_m)); 1344 m = new_m;
 1345 xennetback_mbuf_addr(m,
 1346 &xmit_pa, &offset);
1317 } 1347 }
1318 offset += (xmit_pa & ~PG_FRAME); 
1319 xmit_pa = (xmit_pa & PG_FRAME); 
1320 m_copydata(m, 0, m->m_pkthdr.len, 
1321 mtod(new_m, void *)); 
1322 new_m->m_len = new_m->m_pkthdr.len = 
1323 m->m_pkthdr.len; 
1324 IFQ_DEQUEUE(&ifp->if_snd, m); 
1325 m_freem(m); 
1326 m = new_m; 
1327 } else { 1348 } else {
1328 IFQ_DEQUEUE(&ifp->if_snd, m); 1349 IFQ_DEQUEUE(&ifp->if_snd, m);
1329 } 1350 }
1330 1351
1331 KASSERT(xmit_pa != POOL_PADDR_INVALID); 1352 KASSERT(xmit_pa != POOL_PADDR_INVALID);
1332 KASSERT((offset + m->m_pkthdr.len) <= PAGE_SIZE); 1353 KASSERT((offset + m->m_pkthdr.len) <= PAGE_SIZE);
1333 xmit_ma = xpmap_ptom(xmit_pa); 1354 xmit_ma = xpmap_ptom(xmit_pa);
1334 /* start filling ring */ 1355 /* start filling ring */
1335 gop->flags = GNTCOPY_dest_gref; 1356 gop->flags = GNTCOPY_dest_gref;
1336 gop->source.offset = offset; 1357 gop->source.offset = offset;
1337 gop->source.domid = DOMID_SELF; 1358 gop->source.domid = DOMID_SELF;
1338 gop->source.u.gmfn = xmit_ma >> PAGE_SHIFT; 1359 gop->source.u.gmfn = xmit_ma >> PAGE_SHIFT;
1339 1360
@@ -1411,29 +1432,30 @@ xennetback_ifsoftstart_copy(void *arg) @@ -1411,29 +1432,30 @@ xennetback_ifsoftstart_copy(void *arg)
1411 /* send event */ 1432 /* send event */
1412 if (do_event) { 1433 if (do_event) {
1413 xen_rmb(); 1434 xen_rmb();
1414 XENPRINTF(("%s receive event\n", 1435 XENPRINTF(("%s receive event\n",
1415 xneti->xni_if.if_xname)); 1436 xneti->xni_if.if_xname));
1416 hypervisor_notify_via_evtchn(xneti->xni_evtchn); 1437 hypervisor_notify_via_evtchn(xneti->xni_evtchn);
1417 do_event = 0; 1438 do_event = 0;
1418 } 1439 }
1419 /* 1440 /*
1420 * note that we don't use RING_FINAL_CHECK_FOR_REQUESTS() 1441 * note that we don't use RING_FINAL_CHECK_FOR_REQUESTS()
1421 * here, as the frontend doesn't notify when adding 1442 * here, as the frontend doesn't notify when adding
1422 * requests anyway 1443 * requests anyway
1423 */ 1444 */
1424 if (__predict_false( 1445 if (__predict_false(abort ||
1425 !RING_HAS_UNCONSUMED_REQUESTS(&xneti->xni_rxring))) { 1446 !RING_HAS_UNCONSUMED_REQUESTS(&xneti->xni_rxring))) {
1426 /* ring full */ 1447 /* ring full */
 1448 ifp->if_timer = 1;
1427 break; 1449 break;
1428 } 1450 }
1429 } 1451 }
1430 splx(s); 1452 splx(s);
1431} 1453}
1432 1454
1433static void 1455static void
1434xennetback_ifwatchdog(struct ifnet * ifp) 1456xennetback_ifwatchdog(struct ifnet * ifp)
1435{ 1457{
1436 /* 1458 /*
1437 * We can get to the following condition: transmit stalls because the 1459 * We can get to the following condition: transmit stalls because the
1438 * ring is full when the ifq is full too. 1460 * ring is full when the ifq is full too.
1439 * 1461 *