Olaf Hering 74794c
From: Haiyang Zhang <haiyangz@microsoft.com>
Olaf Hering 74794c
Date: Thu, 6 Feb 2020 14:01:05 -0800
Olaf Hering 74794c
Patch-mainline: v5.6-rc1
Olaf Hering 74794c
Subject: hv_netvsc: Fix XDP refcnt for synthetic and VF NICs
Olaf Hering 74794c
Git-commit: 184367dce4f744bde54377203305ccc8889aa79f
Olaf Hering 74794c
References: bsc#1177819, bsc#1177820
Olaf Hering 74794c
MIME-Version: 1.0
Olaf Hering 74794c
Content-Type: text/plain; charset=UTF-8
Olaf Hering 74794c
Content-Transfer-Encoding: 8bit
Olaf Hering 74794c
Olaf Hering 74794c
The caller of XDP_SETUP_PROG has already incremented refcnt in
Olaf Hering 74794c
__bpf_prog_get(), so drivers should only increment refcnt by
Olaf Hering 74794c
num_queues - 1.
Olaf Hering 74794c
Olaf Hering 74794c
To fix the issue, update netvsc_xdp_set() to add the correct number
Olaf Hering 74794c
to refcnt.
Olaf Hering 74794c
Olaf Hering 74794c
Hold a refcnt in netvsc_xdp_set()’s other caller, netvsc_attach().
Olaf Hering 74794c
Olaf Hering 74794c
And, do the same in netvsc_vf_setxdp(). Otherwise, every time when VF is
Olaf Hering 74794c
removed and added from the host side, the refcnt will be decreased by one,
Olaf Hering 74794c
which may cause page fault when unloading xdp program.
Olaf Hering 74794c
Olaf Hering 74794c
Fixes: 351e1581395f ("hv_netvsc: Add XDP support")
Olaf Hering 74794c
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Olaf Hering 74794c
Signed-off-by: David S. Miller <davem@davemloft.net>
Olaf Hering 74794c
Acked-by: Olaf Hering <ohering@suse.de>
Olaf Hering 74794c
---
Olaf Hering 74794c
 drivers/net/hyperv/netvsc_bpf.c | 13 +++++++++++--
Olaf Hering 74794c
 drivers/net/hyperv/netvsc_drv.c |  5 ++++-
Olaf Hering 74794c
 2 files changed, 15 insertions(+), 3 deletions(-)
Olaf Hering 74794c
Olaf Hering 74794c
diff --git a/drivers/net/hyperv/netvsc_bpf.c b/drivers/net/hyperv/netvsc_bpf.c
Olaf Hering 74794c
--- a/drivers/net/hyperv/netvsc_bpf.c
Olaf Hering 74794c
+++ b/drivers/net/hyperv/netvsc_bpf.c
Olaf Hering 74794c
@@ -120,7 +120,7 @@ int netvsc_xdp_set(struct net_device *dev, struct bpf_prog *prog,
Olaf Hering 74794c
 	}
Olaf Hering 74794c
 
Olaf Hering 74794c
 	if (prog)
Olaf Hering 74794c
-		bpf_prog_add(prog, nvdev->num_chn);
Olaf Hering 74794c
+		bpf_prog_add(prog, nvdev->num_chn - 1);
Olaf Hering 74794c
 
Olaf Hering 74794c
 	for (i = 0; i < nvdev->num_chn; i++)
Olaf Hering 74794c
 		rcu_assign_pointer(nvdev->chan_table[i].bpf_prog, prog);
Olaf Hering 74794c
@@ -136,6 +136,7 @@ int netvsc_vf_setxdp(struct net_device *vf_netdev, struct bpf_prog *prog)
Olaf Hering 74794c
 {
Olaf Hering 74794c
 	struct netdev_bpf xdp;
Olaf Hering 74794c
 	bpf_op_t ndo_bpf;
Olaf Hering 74794c
+	int ret;
Olaf Hering 74794c
 
Olaf Hering 74794c
 	ASSERT_RTNL();
Olaf Hering 74794c
 
Olaf Hering 74794c
@@ -148,10 +149,18 @@ int netvsc_vf_setxdp(struct net_device *vf_netdev, struct bpf_prog *prog)
Olaf Hering 74794c
 
Olaf Hering 74794c
 	memset(&xdp, 0, sizeof(xdp));
Olaf Hering 74794c
 
Olaf Hering 74794c
+	if (prog)
Olaf Hering 74794c
+		bpf_prog_inc(prog);
Olaf Hering 74794c
+
Olaf Hering 74794c
 	xdp.command = XDP_SETUP_PROG;
Olaf Hering 74794c
 	xdp.prog = prog;
Olaf Hering 74794c
 
Olaf Hering 74794c
-	return ndo_bpf(vf_netdev, &xdp;;
Olaf Hering 74794c
+	ret = ndo_bpf(vf_netdev, &xdp;;
Olaf Hering 74794c
+
Olaf Hering 74794c
+	if (ret && prog)
Olaf Hering 74794c
+		bpf_prog_put(prog);
Olaf Hering 74794c
+
Olaf Hering 74794c
+	return ret;
Olaf Hering 74794c
 }
Olaf Hering 74794c
 
Olaf Hering 74794c
 static u32 netvsc_xdp_query(struct netvsc_device *nvdev)
Olaf Hering 74794c
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
Olaf Hering 74794c
--- a/drivers/net/hyperv/netvsc_drv.c
Olaf Hering 74794c
+++ b/drivers/net/hyperv/netvsc_drv.c
Olaf Hering 74794c
@@ -1059,9 +1059,12 @@ static int netvsc_attach(struct net_device *ndev,
Olaf Hering 74794c
 
Olaf Hering 74794c
 	prog = dev_info->bprog;
Olaf Hering 74794c
 	if (prog) {
Olaf Hering 74794c
+		bpf_prog_inc(prog);
Olaf Hering 74794c
 		ret = netvsc_xdp_set(ndev, prog, NULL, nvdev);
Olaf Hering 74794c
-		if (ret)
Olaf Hering 74794c
+		if (ret) {
Olaf Hering 74794c
+			bpf_prog_put(prog);
Olaf Hering 74794c
 			goto err1;
Olaf Hering 74794c
+		}
Olaf Hering 74794c
 	}
Olaf Hering 74794c
 
Olaf Hering 74794c
 	/* In any case device is now ready */