Skip to content

Commit f4d87ad

Browse files
committed
Merge branch 'hv_netvsc-minor-changes'
Stephen Hemminger says: ==================== hv_netvsc: minor changes This includes minor cleanup of code in send and receive path and also a new statistic to check for allocation failures. This also eliminates some of the extra RCU when not needed. There is a theoritical bug where buffered data could be blocked for longer than necessary if the ring buffer got full. This has not been seen in the wild, found by inspection. The reference count between net device and internal RNDIS is not needed. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 824c2d6 + cfd8afd commit f4d87ad

File tree

4 files changed

+47
-68
lines changed

4 files changed

+47
-68
lines changed

drivers/net/hyperv/hyperv_net.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,15 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
194194
const struct netvsc_device_info *info);
195195
int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx);
196196
void netvsc_device_remove(struct hv_device *device);
197-
int netvsc_send(struct net_device_context *ndc,
197+
int netvsc_send(struct net_device *net,
198198
struct hv_netvsc_packet *packet,
199199
struct rndis_message *rndis_msg,
200200
struct hv_page_buffer *page_buffer,
201201
struct sk_buff *skb);
202-
void netvsc_linkstatus_callback(struct hv_device *device_obj,
202+
void netvsc_linkstatus_callback(struct net_device *net,
203203
struct rndis_message *resp);
204204
int netvsc_recv_callback(struct net_device *net,
205+
struct netvsc_device *nvdev,
205206
struct vmbus_channel *channel,
206207
void *data, u32 len,
207208
const struct ndis_tcp_ip_checksum_info *csum_info,
@@ -222,7 +223,6 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev,
222223
const u8 *key);
223224
int rndis_filter_receive(struct net_device *ndev,
224225
struct netvsc_device *net_dev,
225-
struct hv_device *dev,
226226
struct vmbus_channel *channel,
227227
void *data, u32 buflen);
228228

@@ -705,6 +705,7 @@ struct netvsc_ethtool_stats {
705705
unsigned long tx_busy;
706706
unsigned long tx_send_full;
707707
unsigned long rx_comp_busy;
708+
unsigned long rx_no_memory;
708709
unsigned long stop_queue;
709710
unsigned long wake_queue;
710711
};
@@ -822,8 +823,6 @@ struct netvsc_device {
822823
u32 max_pkt; /* max number of pkt in one send, e.g. 8 */
823824
u32 pkt_align; /* alignment bytes, e.g. 8 */
824825

825-
atomic_t open_cnt;
826-
827826
struct netvsc_channel chan_table[VRSS_CHANNEL_MAX];
828827

829828
struct rcu_head rcu;

drivers/net/hyperv/netvsc.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ static struct netvsc_device *alloc_net_device(void)
7373

7474
init_waitqueue_head(&net_device->wait_drain);
7575
net_device->destroy = false;
76-
atomic_set(&net_device->open_cnt, 0);
76+
7777
net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
7878
net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
7979

@@ -701,27 +701,26 @@ static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
701701
return NETVSC_INVALID_INDEX;
702702
}
703703

704-
static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
705-
unsigned int section_index,
706-
u32 pend_size,
707-
struct hv_netvsc_packet *packet,
708-
struct rndis_message *rndis_msg,
709-
struct hv_page_buffer *pb,
710-
struct sk_buff *skb)
704+
static void netvsc_copy_to_send_buf(struct netvsc_device *net_device,
705+
unsigned int section_index,
706+
u32 pend_size,
707+
struct hv_netvsc_packet *packet,
708+
struct rndis_message *rndis_msg,
709+
struct hv_page_buffer *pb,
710+
bool xmit_more)
711711
{
712712
char *start = net_device->send_buf;
713713
char *dest = start + (section_index * net_device->send_section_size)
714714
+ pend_size;
715715
int i;
716-
u32 msg_size = 0;
717716
u32 padding = 0;
718717
u32 page_count = packet->cp_partial ? packet->rmsg_pgcnt :
719718
packet->page_buf_cnt;
720719
u32 remain;
721720

722721
/* Add padding */
723722
remain = packet->total_data_buflen & (net_device->pkt_align - 1);
724-
if (skb->xmit_more && remain && !packet->cp_partial) {
723+
if (xmit_more && remain) {
725724
padding = net_device->pkt_align - remain;
726725
rndis_msg->msg_len += padding;
727726
packet->total_data_buflen += padding;
@@ -733,16 +732,11 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
733732
u32 len = pb[i].len;
734733

735734
memcpy(dest, (src + offset), len);
736-
msg_size += len;
737735
dest += len;
738736
}
739737

740-
if (padding) {
738+
if (padding)
741739
memset(dest, 0, padding);
742-
msg_size += padding;
743-
}
744-
745-
return msg_size;
746740
}
747741

748742
static inline int netvsc_send_pkt(
@@ -835,12 +829,13 @@ static inline void move_pkt_msd(struct hv_netvsc_packet **msd_send,
835829
}
836830

837831
/* RCU already held by caller */
838-
int netvsc_send(struct net_device_context *ndev_ctx,
832+
int netvsc_send(struct net_device *ndev,
839833
struct hv_netvsc_packet *packet,
840834
struct rndis_message *rndis_msg,
841835
struct hv_page_buffer *pb,
842836
struct sk_buff *skb)
843837
{
838+
struct net_device_context *ndev_ctx = netdev_priv(ndev);
844839
struct netvsc_device *net_device
845840
= rcu_dereference_bh(ndev_ctx->nvdev);
846841
struct hv_device *device = ndev_ctx->device_ctx;
@@ -851,7 +846,7 @@ int netvsc_send(struct net_device_context *ndev_ctx,
851846
struct multi_send_data *msdp;
852847
struct hv_netvsc_packet *msd_send = NULL, *cur_send = NULL;
853848
struct sk_buff *msd_skb = NULL;
854-
bool try_batch;
849+
bool try_batch, xmit_more;
855850

856851
/* If device is rescinded, return error and packet will get dropped. */
857852
if (unlikely(!net_device || net_device->destroy))
@@ -902,10 +897,17 @@ int netvsc_send(struct net_device_context *ndev_ctx,
902897
}
903898
}
904899

900+
/* Keep aggregating only if stack says more data is coming
901+
* and not doing mixed modes send and not flow blocked
902+
*/
903+
xmit_more = skb->xmit_more &&
904+
!packet->cp_partial &&
905+
!netif_xmit_stopped(netdev_get_tx_queue(ndev, packet->q_idx));
906+
905907
if (section_index != NETVSC_INVALID_INDEX) {
906908
netvsc_copy_to_send_buf(net_device,
907909
section_index, msd_len,
908-
packet, rndis_msg, pb, skb);
910+
packet, rndis_msg, pb, xmit_more);
909911

910912
packet->send_buf_index = section_index;
911913

@@ -925,7 +927,7 @@ int netvsc_send(struct net_device_context *ndev_ctx,
925927
if (msdp->skb)
926928
dev_consume_skb_any(msdp->skb);
927929

928-
if (skb->xmit_more && !packet->cp_partial) {
930+
if (xmit_more) {
929931
msdp->skb = skb;
930932
msdp->pkt = packet;
931933
msdp->count++;
@@ -1088,7 +1090,7 @@ static int netvsc_receive(struct net_device *ndev,
10881090
u32 buflen = vmxferpage_packet->ranges[i].byte_count;
10891091

10901092
/* Pass it to the upper layer */
1091-
status = rndis_filter_receive(ndev, net_device, device,
1093+
status = rndis_filter_receive(ndev, net_device,
10921094
channel, data, buflen);
10931095
}
10941096

drivers/net/hyperv/netvsc_drv.c

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
626626
/* timestamp packet in software */
627627
skb_tx_timestamp(skb);
628628

629-
ret = netvsc_send(net_device_ctx, packet, rndis_msg, pb, skb);
629+
ret = netvsc_send(net, packet, rndis_msg, pb, skb);
630630
if (likely(ret == 0))
631631
return NETDEV_TX_OK;
632632

@@ -652,22 +652,14 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
652652
/*
653653
* netvsc_linkstatus_callback - Link up/down notification
654654
*/
655-
void netvsc_linkstatus_callback(struct hv_device *device_obj,
655+
void netvsc_linkstatus_callback(struct net_device *net,
656656
struct rndis_message *resp)
657657
{
658658
struct rndis_indicate_status *indicate = &resp->msg.indicate_status;
659-
struct net_device *net;
660-
struct net_device_context *ndev_ctx;
659+
struct net_device_context *ndev_ctx = netdev_priv(net);
661660
struct netvsc_reconfig *event;
662661
unsigned long flags;
663662

664-
net = hv_get_drvdata(device_obj);
665-
666-
if (!net)
667-
return;
668-
669-
ndev_ctx = netdev_priv(net);
670-
671663
/* Update the physical link speed when changing to another vSwitch */
672664
if (indicate->status == RNDIS_STATUS_LINK_SPEED_CHANGE) {
673665
u32 speed;
@@ -747,34 +739,26 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net,
747739
* "wire" on the specified device.
748740
*/
749741
int netvsc_recv_callback(struct net_device *net,
742+
struct netvsc_device *net_device,
750743
struct vmbus_channel *channel,
751744
void *data, u32 len,
752745
const struct ndis_tcp_ip_checksum_info *csum_info,
753746
const struct ndis_pkt_8021q_info *vlan)
754747
{
755748
struct net_device_context *net_device_ctx = netdev_priv(net);
756-
struct netvsc_device *net_device;
757749
u16 q_idx = channel->offermsg.offer.sub_channel_index;
758-
struct netvsc_channel *nvchan;
750+
struct netvsc_channel *nvchan = &net_device->chan_table[q_idx];
759751
struct sk_buff *skb;
760752
struct netvsc_stats *rx_stats;
761753

762754
if (net->reg_state != NETREG_REGISTERED)
763755
return NVSP_STAT_FAIL;
764756

765-
rcu_read_lock();
766-
net_device = rcu_dereference(net_device_ctx->nvdev);
767-
if (unlikely(!net_device))
768-
goto drop;
769-
770-
nvchan = &net_device->chan_table[q_idx];
771-
772757
/* Allocate a skb - TODO direct I/O to pages? */
773758
skb = netvsc_alloc_recv_skb(net, &nvchan->napi,
774759
csum_info, vlan, data, len);
775760
if (unlikely(!skb)) {
776-
drop:
777-
++net->stats.rx_dropped;
761+
++net_device_ctx->eth_stats.rx_no_memory;
778762
rcu_read_unlock();
779763
return NVSP_STAT_FAIL;
780764
}
@@ -798,8 +782,6 @@ int netvsc_recv_callback(struct net_device *net,
798782
u64_stats_update_end(&rx_stats->syncp);
799783

800784
napi_gro_receive(&nvchan->napi, skb);
801-
rcu_read_unlock();
802-
803785
return 0;
804786
}
805787

@@ -1125,12 +1107,13 @@ static const struct {
11251107
u16 offset;
11261108
} netvsc_stats[] = {
11271109
{ "tx_scattered", offsetof(struct netvsc_ethtool_stats, tx_scattered) },
1128-
{ "tx_no_memory", offsetof(struct netvsc_ethtool_stats, tx_no_memory) },
1110+
{ "tx_no_memory", offsetof(struct netvsc_ethtool_stats, tx_no_memory) },
11291111
{ "tx_no_space", offsetof(struct netvsc_ethtool_stats, tx_no_space) },
11301112
{ "tx_too_big", offsetof(struct netvsc_ethtool_stats, tx_too_big) },
11311113
{ "tx_busy", offsetof(struct netvsc_ethtool_stats, tx_busy) },
11321114
{ "tx_send_full", offsetof(struct netvsc_ethtool_stats, tx_send_full) },
11331115
{ "rx_comp_busy", offsetof(struct netvsc_ethtool_stats, rx_comp_busy) },
1116+
{ "rx_no_memory", offsetof(struct netvsc_ethtool_stats, rx_no_memory) },
11341117
{ "stop_queue", offsetof(struct netvsc_ethtool_stats, stop_queue) },
11351118
{ "wake_queue", offsetof(struct netvsc_ethtool_stats, wake_queue) },
11361119
}, vf_stats[] = {

drivers/net/hyperv/rndis_filter.c

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,9 @@ static void put_rndis_request(struct rndis_device *dev,
134134
kfree(req);
135135
}
136136

137-
static void dump_rndis_message(struct hv_device *hv_dev,
137+
static void dump_rndis_message(struct net_device *netdev,
138138
const struct rndis_message *rndis_msg)
139139
{
140-
struct net_device *netdev = hv_get_drvdata(hv_dev);
141-
142140
switch (rndis_msg->ndis_msg_type) {
143141
case RNDIS_MSG_PACKET:
144142
netdev_dbg(netdev, "RNDIS_MSG_PACKET (len %u, "
@@ -217,7 +215,6 @@ static int rndis_filter_send_request(struct rndis_device *dev,
217215
struct hv_netvsc_packet *packet;
218216
struct hv_page_buffer page_buf[2];
219217
struct hv_page_buffer *pb = page_buf;
220-
struct net_device_context *net_device_ctx = netdev_priv(dev->ndev);
221218
int ret;
222219

223220
/* Setup the packet to send it */
@@ -245,7 +242,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
245242
}
246243

247244
rcu_read_lock_bh();
248-
ret = netvsc_send(net_device_ctx, packet, NULL, pb, NULL);
245+
ret = netvsc_send(dev->ndev, packet, NULL, pb, NULL);
249246
rcu_read_unlock_bh();
250247

251248
return ret;
@@ -354,6 +351,7 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
354351
}
355352

356353
static int rndis_filter_receive_data(struct net_device *ndev,
354+
struct netvsc_device *nvdev,
357355
struct rndis_device *dev,
358356
struct rndis_message *msg,
359357
struct vmbus_channel *channel,
@@ -390,14 +388,14 @@ static int rndis_filter_receive_data(struct net_device *ndev,
390388
*/
391389
data = (void *)((unsigned long)data + data_offset);
392390
csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
393-
return netvsc_recv_callback(ndev, channel,
391+
392+
return netvsc_recv_callback(ndev, nvdev, channel,
394393
data, rndis_pkt->data_len,
395394
csum_info, vlan);
396395
}
397396

398397
int rndis_filter_receive(struct net_device *ndev,
399398
struct netvsc_device *net_dev,
400-
struct hv_device *dev,
401399
struct vmbus_channel *channel,
402400
void *data, u32 buflen)
403401
{
@@ -419,11 +417,12 @@ int rndis_filter_receive(struct net_device *ndev,
419417
}
420418

421419
if (netif_msg_rx_status(net_device_ctx))
422-
dump_rndis_message(dev, rndis_msg);
420+
dump_rndis_message(ndev, rndis_msg);
423421

424422
switch (rndis_msg->ndis_msg_type) {
425423
case RNDIS_MSG_PACKET:
426-
return rndis_filter_receive_data(ndev, rndis_dev, rndis_msg,
424+
return rndis_filter_receive_data(ndev, net_dev,
425+
rndis_dev, rndis_msg,
427426
channel, data, buflen);
428427
case RNDIS_MSG_INIT_C:
429428
case RNDIS_MSG_QUERY_C:
@@ -434,7 +433,7 @@ int rndis_filter_receive(struct net_device *ndev,
434433

435434
case RNDIS_MSG_INDICATE:
436435
/* notification msgs */
437-
netvsc_linkstatus_callback(dev, rndis_msg);
436+
netvsc_linkstatus_callback(ndev, rndis_msg);
438437
break;
439438
default:
440439
netdev_err(ndev,
@@ -1362,9 +1361,6 @@ int rndis_filter_open(struct netvsc_device *nvdev)
13621361
if (!nvdev)
13631362
return -EINVAL;
13641363

1365-
if (atomic_inc_return(&nvdev->open_cnt) != 1)
1366-
return 0;
1367-
13681364
return rndis_filter_open_device(nvdev->extension);
13691365
}
13701366

@@ -1373,13 +1369,12 @@ int rndis_filter_close(struct netvsc_device *nvdev)
13731369
if (!nvdev)
13741370
return -EINVAL;
13751371

1376-
if (atomic_dec_return(&nvdev->open_cnt) != 0)
1377-
return 0;
1378-
13791372
return rndis_filter_close_device(nvdev->extension);
13801373
}
13811374

13821375
bool rndis_filter_opened(const struct netvsc_device *nvdev)
13831376
{
1384-
return atomic_read(&nvdev->open_cnt) > 0;
1377+
const struct rndis_device *dev = nvdev->extension;
1378+
1379+
return dev->state == RNDIS_DEV_DATAINITIALIZED;
13851380
}

0 commit comments

Comments
 (0)