Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hyperv: Report actual status in receive completion packet

The existing code always reports NVSP_STAT_SUCCESS. This patch adds the
mechanism to report failure when it happens.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Reviewed-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Haiyang Zhang and committed by
David S. Miller
63f6921d 6562640b

+30 -11
+2
drivers/net/hyperv/hyperv_net.h
··· 35 35 /* Represent the xfer page packet which contains 1 or more netvsc packet */ 36 36 struct xferpage_packet { 37 37 struct list_head list_ent; 38 + u32 status; 38 39 39 40 /* # of netvsc packets this xfer packet contains */ 40 41 u32 count; ··· 48 47 struct hv_netvsc_packet { 49 48 /* Bookkeeping stuff */ 50 49 struct list_head list_ent; 50 + u32 status; 51 51 52 52 struct hv_device *device; 53 53 bool is_data_pkt;
+12 -6
drivers/net/hyperv/netvsc.c
··· 558 558 } 559 559 560 560 static void netvsc_send_recv_completion(struct hv_device *device, 561 - u64 transaction_id) 561 + u64 transaction_id, u32 status) 562 562 { 563 563 struct nvsp_message recvcompMessage; 564 564 int retries = 0; ··· 571 571 recvcompMessage.hdr.msg_type = 572 572 NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE; 573 573 574 - /* FIXME: Pass in the status */ 575 - recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = 576 - NVSP_STAT_SUCCESS; 574 + recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = status; 577 575 578 576 retry_send_cmplt: 579 577 /* Send the completion */ ··· 611 613 bool fsend_receive_comp = false; 612 614 unsigned long flags; 613 615 struct net_device *ndev; 616 + u32 status = NVSP_STAT_NONE; 614 617 615 618 /* 616 619 * Even though it seems logical to do a GetOutboundNetDevice() here to ··· 626 627 /* Overloading use of the lock. */ 627 628 spin_lock_irqsave(&net_device->recv_pkt_list_lock, flags); 628 629 630 + if (packet->status != NVSP_STAT_SUCCESS) 631 + packet->xfer_page_pkt->status = NVSP_STAT_FAIL; 632 + 629 633 packet->xfer_page_pkt->count--; 630 634 631 635 /* ··· 638 636 if (packet->xfer_page_pkt->count == 0) { 639 637 fsend_receive_comp = true; 640 638 transaction_id = packet->completion.recv.recv_completion_tid; 639 + status = packet->xfer_page_pkt->status; 641 640 list_add_tail(&packet->xfer_page_pkt->list_ent, 642 641 &net_device->recv_pkt_list); 643 642 ··· 650 647 651 648 /* Send a receive completion for the xfer page packet */ 652 649 if (fsend_receive_comp) 653 - netvsc_send_recv_completion(device, transaction_id); 650 + netvsc_send_recv_completion(device, transaction_id, status); 654 651 655 652 } 656 653 ··· 739 736 flags); 740 737 741 738 netvsc_send_recv_completion(device, 742 - vmxferpage_packet->d.trans_id); 739 + vmxferpage_packet->d.trans_id, 740 + NVSP_STAT_FAIL); 743 741 744 742 return; 745 743 } ··· 748 744 /* Remove the 1st packet to represent the xfer page packet itself */ 749 745 xferpage_packet = (struct xferpage_packet *)listHead.next; 750 746 list_del(&xferpage_packet->list_ent); 747 + xferpage_packet->status = NVSP_STAT_SUCCESS; 751 748 752 749 /* This is how much we can satisfy */ 753 750 xferpage_packet->count = count - 1; ··· 765 760 list_del(&netvsc_packet->list_ent); 766 761 767 762 /* Initialize the netvsc packet */ 763 + netvsc_packet->status = NVSP_STAT_SUCCESS; 768 764 netvsc_packet->xfer_page_pkt = xferpage_packet; 769 765 netvsc_packet->completion.recv.recv_completion = 770 766 netvsc_receive_completion;
+2
drivers/net/hyperv/netvsc_drv.c
··· 265 265 if (!net) { 266 266 netdev_err(net, "got receive callback but net device" 267 267 " not initialized yet\n"); 268 + packet->status = NVSP_STAT_FAIL; 268 269 return 0; 269 270 } 270 271 ··· 273 272 skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen); 274 273 if (unlikely(!skb)) { 275 274 ++net->stats.rx_dropped; 275 + packet->status = NVSP_STAT_FAIL; 276 276 return 0; 277 277 } 278 278
+14 -5
drivers/net/hyperv/rndis_filter.c
··· 411 411 struct rndis_device *rndis_dev; 412 412 struct rndis_message *rndis_msg; 413 413 struct net_device *ndev; 414 + int ret = 0; 414 415 415 - if (!net_dev) 416 - return -EINVAL; 416 + if (!net_dev) { 417 + ret = -EINVAL; 418 + goto exit; 419 + } 417 420 418 421 ndev = net_dev->ndev; 419 422 ··· 424 421 if (!net_dev->extension) { 425 422 netdev_err(ndev, "got rndis message but no rndis device - " 426 423 "dropping this message!\n"); 427 - return -ENODEV; 424 + ret = -ENODEV; 425 + goto exit; 428 426 } 429 427 430 428 rndis_dev = (struct rndis_device *)net_dev->extension; 431 429 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) { 432 430 netdev_err(ndev, "got rndis message but rndis device " 433 431 "uninitialized...dropping this message!\n"); 434 - return -ENODEV; 432 + ret = -ENODEV; 433 + goto exit; 435 434 } 436 435 437 436 rndis_msg = pkt->data; ··· 465 460 break; 466 461 } 467 462 468 - return 0; 463 + exit: 464 + if (ret != 0) 465 + pkt->status = NVSP_STAT_FAIL; 466 + 467 + return ret; 469 468 } 470 469 471 470 static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,