]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.9
authorSasha Levin <sashal@kernel.org>
Sun, 15 Aug 2021 12:52:59 +0000 (08:52 -0400)
committerSasha Levin <sashal@kernel.org>
Sun, 15 Aug 2021 12:52:59 +0000 (08:52 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.9/net-bridge-fix-memleak-in-br_add_if.patch [new file with mode: 0644]
queue-4.9/net-fix-memory-leak-in-ieee802154_raw_deliver.patch [new file with mode: 0644]
queue-4.9/ppp-fix-generating-ifname-when-empty-ifla_ifname-is-.patch [new file with mode: 0644]
queue-4.9/series
queue-4.9/tcp_bbr-fix-u32-wrap-bug-in-round-logic-if-bbr_init-.patch [new file with mode: 0644]
queue-4.9/xen-events-fix-race-in-set_evtchn_to_irq.patch [new file with mode: 0644]

diff --git a/queue-4.9/net-bridge-fix-memleak-in-br_add_if.patch b/queue-4.9/net-bridge-fix-memleak-in-br_add_if.patch
new file mode 100644 (file)
index 0000000..4643c43
--- /dev/null
@@ -0,0 +1,75 @@
+From a85607ab1bc6bcd812ef3e29cbeca056014343db Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Aug 2021 21:20:23 +0800
+Subject: net: bridge: fix memleak in br_add_if()
+
+From: Yang Yingliang <yangyingliang@huawei.com>
+
+[ Upstream commit 519133debcc19f5c834e7e28480b60bdc234fe02 ]
+
+I got a memleak report:
+
+BUG: memory leak
+unreferenced object 0x607ee521a658 (size 240):
+comm "syz-executor.0", pid 955, jiffies 4294780569 (age 16.449s)
+hex dump (first 32 bytes, cpu 1):
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+backtrace:
+[<00000000d830ea5a>] br_multicast_add_port+0x1c2/0x300 net/bridge/br_multicast.c:1693
+[<00000000274d9a71>] new_nbp net/bridge/br_if.c:435 [inline]
+[<00000000274d9a71>] br_add_if+0x670/0x1740 net/bridge/br_if.c:611
+[<0000000012ce888e>] do_set_master net/core/rtnetlink.c:2513 [inline]
+[<0000000012ce888e>] do_set_master+0x1aa/0x210 net/core/rtnetlink.c:2487
+[<0000000099d1cafc>] __rtnl_newlink+0x1095/0x13e0 net/core/rtnetlink.c:3457
+[<00000000a01facc0>] rtnl_newlink+0x64/0xa0 net/core/rtnetlink.c:3488
+[<00000000acc9186c>] rtnetlink_rcv_msg+0x369/0xa10 net/core/rtnetlink.c:5550
+[<00000000d4aabb9c>] netlink_rcv_skb+0x134/0x3d0 net/netlink/af_netlink.c:2504
+[<00000000bc2e12a3>] netlink_unicast_kernel net/netlink/af_netlink.c:1314 [inline]
+[<00000000bc2e12a3>] netlink_unicast+0x4a0/0x6a0 net/netlink/af_netlink.c:1340
+[<00000000e4dc2d0e>] netlink_sendmsg+0x789/0xc70 net/netlink/af_netlink.c:1929
+[<000000000d22c8b3>] sock_sendmsg_nosec net/socket.c:654 [inline]
+[<000000000d22c8b3>] sock_sendmsg+0x139/0x170 net/socket.c:674
+[<00000000e281417a>] ____sys_sendmsg+0x658/0x7d0 net/socket.c:2350
+[<00000000237aa2ab>] ___sys_sendmsg+0xf8/0x170 net/socket.c:2404
+[<000000004f2dc381>] __sys_sendmsg+0xd3/0x190 net/socket.c:2433
+[<0000000005feca6c>] do_syscall_64+0x37/0x90 arch/x86/entry/common.c:47
+[<000000007304477d>] entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+On error path of br_add_if(), p->mcast_stats allocated in
+new_nbp() need be freed, or it will be leaked.
+
+Fixes: 1080ab95e3c7 ("net: bridge: add support for IGMP/MLD stats and export them via netlink")
+Reported-by: Hulk Robot <hulkci@huawei.com>
+Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
+Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
+Link: https://lore.kernel.org/r/20210809132023.978546-1-yangyingliang@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bridge/br_if.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
+index 4718c528e100..794fba20afbc 100644
+--- a/net/bridge/br_if.c
++++ b/net/bridge/br_if.c
+@@ -520,6 +520,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
+       err = dev_set_allmulti(dev, 1);
+       if (err) {
++              br_multicast_del_port(p);
+               kfree(p);       /* kobject not yet init'd, manually free */
+               goto err1;
+       }
+@@ -624,6 +625,7 @@ err4:
+ err3:
+       sysfs_remove_link(br->ifobj, p->dev->name);
+ err2:
++      br_multicast_del_port(p);
+       kobject_put(&p->kobj);
+       dev_set_allmulti(dev, -1);
+ err1:
+-- 
+2.30.2
+
diff --git a/queue-4.9/net-fix-memory-leak-in-ieee802154_raw_deliver.patch b/queue-4.9/net-fix-memory-leak-in-ieee802154_raw_deliver.patch
new file mode 100644 (file)
index 0000000..89a501f
--- /dev/null
@@ -0,0 +1,87 @@
+From 866865a996e46ccb04ff698ad1c1ac7ca2ee31e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Aug 2021 16:54:14 +0900
+Subject: net: Fix memory leak in ieee802154_raw_deliver
+
+From: Takeshi Misawa <jeliantsurux@gmail.com>
+
+[ Upstream commit 1090340f7ee53e824fd4eef66a4855d548110c5b ]
+
+If IEEE-802.15.4-RAW is closed before receive skb, skb is leaked.
+Fix this, by freeing sk_receive_queue in sk->sk_destruct().
+
+syzbot report:
+BUG: memory leak
+unreferenced object 0xffff88810f644600 (size 232):
+  comm "softirq", pid 0, jiffies 4294967032 (age 81.270s)
+  hex dump (first 32 bytes):
+    10 7d 4b 12 81 88 ff ff 10 7d 4b 12 81 88 ff ff  .}K......}K.....
+    00 00 00 00 00 00 00 00 40 7c 4b 12 81 88 ff ff  ........@|K.....
+  backtrace:
+    [<ffffffff83651d4a>] skb_clone+0xaa/0x2b0 net/core/skbuff.c:1496
+    [<ffffffff83fe1b80>] ieee802154_raw_deliver net/ieee802154/socket.c:369 [inline]
+    [<ffffffff83fe1b80>] ieee802154_rcv+0x100/0x340 net/ieee802154/socket.c:1070
+    [<ffffffff8367cc7a>] __netif_receive_skb_one_core+0x6a/0xa0 net/core/dev.c:5384
+    [<ffffffff8367cd07>] __netif_receive_skb+0x27/0xa0 net/core/dev.c:5498
+    [<ffffffff8367cdd9>] netif_receive_skb_internal net/core/dev.c:5603 [inline]
+    [<ffffffff8367cdd9>] netif_receive_skb+0x59/0x260 net/core/dev.c:5662
+    [<ffffffff83fe6302>] ieee802154_deliver_skb net/mac802154/rx.c:29 [inline]
+    [<ffffffff83fe6302>] ieee802154_subif_frame net/mac802154/rx.c:102 [inline]
+    [<ffffffff83fe6302>] __ieee802154_rx_handle_packet net/mac802154/rx.c:212 [inline]
+    [<ffffffff83fe6302>] ieee802154_rx+0x612/0x620 net/mac802154/rx.c:284
+    [<ffffffff83fe59a6>] ieee802154_tasklet_handler+0x86/0xa0 net/mac802154/main.c:35
+    [<ffffffff81232aab>] tasklet_action_common.constprop.0+0x5b/0x100 kernel/softirq.c:557
+    [<ffffffff846000bf>] __do_softirq+0xbf/0x2ab kernel/softirq.c:345
+    [<ffffffff81232f4c>] do_softirq kernel/softirq.c:248 [inline]
+    [<ffffffff81232f4c>] do_softirq+0x5c/0x80 kernel/softirq.c:235
+    [<ffffffff81232fc1>] __local_bh_enable_ip+0x51/0x60 kernel/softirq.c:198
+    [<ffffffff8367a9a4>] local_bh_enable include/linux/bottom_half.h:32 [inline]
+    [<ffffffff8367a9a4>] rcu_read_unlock_bh include/linux/rcupdate.h:745 [inline]
+    [<ffffffff8367a9a4>] __dev_queue_xmit+0x7f4/0xf60 net/core/dev.c:4221
+    [<ffffffff83fe2db4>] raw_sendmsg+0x1f4/0x2b0 net/ieee802154/socket.c:295
+    [<ffffffff8363af16>] sock_sendmsg_nosec net/socket.c:654 [inline]
+    [<ffffffff8363af16>] sock_sendmsg+0x56/0x80 net/socket.c:674
+    [<ffffffff8363deec>] __sys_sendto+0x15c/0x200 net/socket.c:1977
+    [<ffffffff8363dfb6>] __do_sys_sendto net/socket.c:1989 [inline]
+    [<ffffffff8363dfb6>] __se_sys_sendto net/socket.c:1985 [inline]
+    [<ffffffff8363dfb6>] __x64_sys_sendto+0x26/0x30 net/socket.c:1985
+
+Fixes: 9ec767160357 ("net: add IEEE 802.15.4 socket family implementation")
+Reported-and-tested-by: syzbot+1f68113fa907bf0695a8@syzkaller.appspotmail.com
+Signed-off-by: Takeshi Misawa <jeliantsurux@gmail.com>
+Acked-by: Alexander Aring <aahringo@redhat.com>
+Link: https://lore.kernel.org/r/20210805075414.GA15796@DESKTOP
+Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ieee802154/socket.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
+index f66e4afb978a..6383627b783e 100644
+--- a/net/ieee802154/socket.c
++++ b/net/ieee802154/socket.c
+@@ -987,6 +987,11 @@ static const struct proto_ops ieee802154_dgram_ops = {
+ #endif
+ };
++static void ieee802154_sock_destruct(struct sock *sk)
++{
++      skb_queue_purge(&sk->sk_receive_queue);
++}
++
+ /* Create a socket. Initialise the socket, blank the addresses
+  * set the state.
+  */
+@@ -1027,7 +1032,7 @@ static int ieee802154_create(struct net *net, struct socket *sock,
+       sock->ops = ops;
+       sock_init_data(sock, sk);
+-      /* FIXME: sk->sk_destruct */
++      sk->sk_destruct = ieee802154_sock_destruct;
+       sk->sk_family = PF_IEEE802154;
+       /* Checksums on by default */
+-- 
+2.30.2
+
diff --git a/queue-4.9/ppp-fix-generating-ifname-when-empty-ifla_ifname-is-.patch b/queue-4.9/ppp-fix-generating-ifname-when-empty-ifla_ifname-is-.patch
new file mode 100644 (file)
index 0000000..f6a9413
--- /dev/null
@@ -0,0 +1,58 @@
+From c81955c82d0c800a16d164c2667479178d851051 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 7 Aug 2021 15:27:03 +0200
+Subject: ppp: Fix generating ifname when empty IFLA_IFNAME is specified
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit 2459dcb96bcba94c08d6861f8a050185ff301672 ]
+
+IFLA_IFNAME is nul-term string which means that IFLA_IFNAME buffer can be
+larger than length of string which contains.
+
+Function __rtnl_newlink() generates new own ifname if either IFLA_IFNAME
+was not specified at all or userspace passed empty nul-term string.
+
+It is expected that if userspace does not specify ifname for new ppp netdev
+then kernel generates one in format "ppp<id>" where id matches to the ppp
+unit id which can be later obtained by PPPIOCGUNIT ioctl.
+
+And it works in this way if IFLA_IFNAME is not specified at all. But it
+does not work when IFLA_IFNAME is specified with empty string.
+
+So fix this logic also for empty IFLA_IFNAME in ppp_nl_newlink() function
+and correctly generates ifname based on ppp unit identifier if userspace
+did not provided preferred ifname.
+
+Without this patch when IFLA_IFNAME was specified with empty string then
+kernel created a new ppp interface in format "ppp<id>" but id did not
+match ppp unit id returned by PPPIOCGUNIT ioctl. In this case id was some
+number generated by __rtnl_newlink() function.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Fixes: bb8082f69138 ("ppp: build ifname using unit identifier for rtnl based devices")
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ppp/ppp_generic.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
+index 5ba472691546..0a29844676f9 100644
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -1136,7 +1136,7 @@ static int ppp_nl_newlink(struct net *src_net, struct net_device *dev,
+        * the PPP unit identifer as suffix (i.e. ppp<unit_id>). This allows
+        * userspace to infer the device name using to the PPPIOCGUNIT ioctl.
+        */
+-      if (!tb[IFLA_IFNAME])
++      if (!tb[IFLA_IFNAME] || !nla_len(tb[IFLA_IFNAME]) || !*(char *)nla_data(tb[IFLA_IFNAME]))
+               conf.ifname_is_set = false;
+       err = ppp_dev_configure(src_net, dev, &conf);
+-- 
+2.30.2
+
index 4caee9ecde03ba59ec29f0b5c86b1330b7185f49..b77d29195174eb809af780fa14b4ab3a1291992a 100644 (file)
@@ -2,3 +2,8 @@ iio-adc-fix-incorrect-exit-of-for-loop.patch
 asoc-intel-atom-fix-reference-to-pcm-buffer-address.patch
 i2c-dev-zero-out-array-used-for-i2c-reads-from-userspace.patch
 acpi-nfit-fix-support-for-virtual-spa-ranges.patch
+ppp-fix-generating-ifname-when-empty-ifla_ifname-is-.patch
+net-fix-memory-leak-in-ieee802154_raw_deliver.patch
+net-bridge-fix-memleak-in-br_add_if.patch
+tcp_bbr-fix-u32-wrap-bug-in-round-logic-if-bbr_init-.patch
+xen-events-fix-race-in-set_evtchn_to_irq.patch
diff --git a/queue-4.9/tcp_bbr-fix-u32-wrap-bug-in-round-logic-if-bbr_init-.patch b/queue-4.9/tcp_bbr-fix-u32-wrap-bug-in-round-logic-if-bbr_init-.patch
new file mode 100644 (file)
index 0000000..cfdf637
--- /dev/null
@@ -0,0 +1,67 @@
+From 48d207a1cbb751921ddb5460b11700b0dff9f782 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Aug 2021 22:40:56 -0400
+Subject: tcp_bbr: fix u32 wrap bug in round logic if bbr_init() called after
+ 2B packets
+
+From: Neal Cardwell <ncardwell@google.com>
+
+[ Upstream commit 6de035fec045f8ae5ee5f3a02373a18b939e91fb ]
+
+Currently if BBR congestion control is initialized after more than 2B
+packets have been delivered, depending on the phase of the
+tp->delivered counter the tracking of BBR round trips can get stuck.
+
+The bug arises because if tp->delivered is between 2^31 and 2^32 at
+the time the BBR congestion control module is initialized, then the
+initialization of bbr->next_rtt_delivered to 0 will cause the logic to
+believe that the end of the round trip is still billions of packets in
+the future. More specifically, the following check will fail
+repeatedly:
+
+  !before(rs->prior_delivered, bbr->next_rtt_delivered)
+
+and thus the connection will take up to 2B packets delivered before
+that check will pass and the connection will set:
+
+  bbr->round_start = 1;
+
+This could cause many mechanisms in BBR to fail to trigger, for
+example bbr_check_full_bw_reached() would likely never exit STARTUP.
+
+This bug is 5 years old and has not been observed, and as a practical
+matter this would likely rarely trigger, since it would require
+transferring at least 2B packets, or likely more than 3 terabytes of
+data, before switching congestion control algorithms to BBR.
+
+This patch is a stable candidate for kernels as far back as v4.9,
+when tcp_bbr.c was added.
+
+Fixes: 0f8782ea1497 ("tcp_bbr: add BBR congestion control")
+Signed-off-by: Neal Cardwell <ncardwell@google.com>
+Reviewed-by: Yuchung Cheng <ycheng@google.com>
+Reviewed-by: Kevin Yang <yyd@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://lore.kernel.org/r/20210811024056.235161-1-ncardwell@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_bbr.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
+index c22da42376fe..47f40e105044 100644
+--- a/net/ipv4/tcp_bbr.c
++++ b/net/ipv4/tcp_bbr.c
+@@ -811,7 +811,7 @@ static void bbr_init(struct sock *sk)
+       bbr->prior_cwnd = 0;
+       bbr->tso_segs_goal = 0;  /* default segs per skb until first ACK */
+       bbr->rtt_cnt = 0;
+-      bbr->next_rtt_delivered = 0;
++      bbr->next_rtt_delivered = tp->delivered;
+       bbr->prev_ca_state = TCP_CA_Open;
+       bbr->packet_conservation = 0;
+-- 
+2.30.2
+
diff --git a/queue-4.9/xen-events-fix-race-in-set_evtchn_to_irq.patch b/queue-4.9/xen-events-fix-race-in-set_evtchn_to_irq.patch
new file mode 100644 (file)
index 0000000..3efbe40
--- /dev/null
@@ -0,0 +1,127 @@
+From 5313cc820744bb8706fd8e5d25f6e11a45e323ee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Aug 2021 13:09:27 +0000
+Subject: xen/events: Fix race in set_evtchn_to_irq
+
+From: Maximilian Heyne <mheyne@amazon.de>
+
+[ Upstream commit 88ca2521bd5b4e8b83743c01a2d4cb09325b51e9 ]
+
+There is a TOCTOU issue in set_evtchn_to_irq. Rows in the evtchn_to_irq
+mapping are lazily allocated in this function. The check whether the row
+is already present and the row initialization is not synchronized. Two
+threads can at the same time allocate a new row for evtchn_to_irq and
+add the irq mapping to the their newly allocated row. One thread will
+overwrite what the other has set for evtchn_to_irq[row] and therefore
+the irq mapping is lost. This will trigger a BUG_ON later in
+bind_evtchn_to_cpu:
+
+  INFO: pci 0000:1a:15.4: [1d0f:8061] type 00 class 0x010802
+  INFO: nvme 0000:1a:12.1: enabling device (0000 -> 0002)
+  INFO: nvme nvme77: 1/0/0 default/read/poll queues
+  CRIT: kernel BUG at drivers/xen/events/events_base.c:427!
+  WARN: invalid opcode: 0000 [#1] SMP NOPTI
+  WARN: Workqueue: nvme-reset-wq nvme_reset_work [nvme]
+  WARN: RIP: e030:bind_evtchn_to_cpu+0xc2/0xd0
+  WARN: Call Trace:
+  WARN:  set_affinity_irq+0x121/0x150
+  WARN:  irq_do_set_affinity+0x37/0xe0
+  WARN:  irq_setup_affinity+0xf6/0x170
+  WARN:  irq_startup+0x64/0xe0
+  WARN:  __setup_irq+0x69e/0x740
+  WARN:  ? request_threaded_irq+0xad/0x160
+  WARN:  request_threaded_irq+0xf5/0x160
+  WARN:  ? nvme_timeout+0x2f0/0x2f0 [nvme]
+  WARN:  pci_request_irq+0xa9/0xf0
+  WARN:  ? pci_alloc_irq_vectors_affinity+0xbb/0x130
+  WARN:  queue_request_irq+0x4c/0x70 [nvme]
+  WARN:  nvme_reset_work+0x82d/0x1550 [nvme]
+  WARN:  ? check_preempt_wakeup+0x14f/0x230
+  WARN:  ? check_preempt_curr+0x29/0x80
+  WARN:  ? nvme_irq_check+0x30/0x30 [nvme]
+  WARN:  process_one_work+0x18e/0x3c0
+  WARN:  worker_thread+0x30/0x3a0
+  WARN:  ? process_one_work+0x3c0/0x3c0
+  WARN:  kthread+0x113/0x130
+  WARN:  ? kthread_park+0x90/0x90
+  WARN:  ret_from_fork+0x3a/0x50
+
+This patch sets evtchn_to_irq rows via a cmpxchg operation so that they
+will be set only once. The row is now cleared before writing it to
+evtchn_to_irq in order to not create a race once the row is visible for
+other threads.
+
+While at it, do not require the page to be zeroed, because it will be
+overwritten with -1's in clear_evtchn_to_irq_row anyway.
+
+Signed-off-by: Maximilian Heyne <mheyne@amazon.de>
+Fixes: d0b075ffeede ("xen/events: Refactor evtchn_to_irq array to be dynamically allocated")
+Link: https://lore.kernel.org/r/20210812130930.127134-1-mheyne@amazon.de
+Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
+Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/xen/events/events_base.c | 20 ++++++++++++++------
+ 1 file changed, 14 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
+index c6e6b7470cbf..fbb6a4701ea3 100644
+--- a/drivers/xen/events/events_base.c
++++ b/drivers/xen/events/events_base.c
+@@ -134,12 +134,12 @@ static void disable_dynirq(struct irq_data *data);
+ static DEFINE_PER_CPU(unsigned int, irq_epoch);
+-static void clear_evtchn_to_irq_row(unsigned row)
++static void clear_evtchn_to_irq_row(int *evtchn_row)
+ {
+       unsigned col;
+       for (col = 0; col < EVTCHN_PER_ROW; col++)
+-              WRITE_ONCE(evtchn_to_irq[row][col], -1);
++              WRITE_ONCE(evtchn_row[col], -1);
+ }
+ static void clear_evtchn_to_irq_all(void)
+@@ -149,7 +149,7 @@ static void clear_evtchn_to_irq_all(void)
+       for (row = 0; row < EVTCHN_ROW(xen_evtchn_max_channels()); row++) {
+               if (evtchn_to_irq[row] == NULL)
+                       continue;
+-              clear_evtchn_to_irq_row(row);
++              clear_evtchn_to_irq_row(evtchn_to_irq[row]);
+       }
+ }
+@@ -157,6 +157,7 @@ static int set_evtchn_to_irq(unsigned evtchn, unsigned irq)
+ {
+       unsigned row;
+       unsigned col;
++      int *evtchn_row;
+       if (evtchn >= xen_evtchn_max_channels())
+               return -EINVAL;
+@@ -169,11 +170,18 @@ static int set_evtchn_to_irq(unsigned evtchn, unsigned irq)
+               if (irq == -1)
+                       return 0;
+-              evtchn_to_irq[row] = (int *)get_zeroed_page(GFP_KERNEL);
+-              if (evtchn_to_irq[row] == NULL)
++              evtchn_row = (int *) __get_free_pages(GFP_KERNEL, 0);
++              if (evtchn_row == NULL)
+                       return -ENOMEM;
+-              clear_evtchn_to_irq_row(row);
++              clear_evtchn_to_irq_row(evtchn_row);
++
++              /*
++               * We've prepared an empty row for the mapping. If a different
++               * thread was faster inserting it, we can drop ours.
++               */
++              if (cmpxchg(&evtchn_to_irq[row], NULL, evtchn_row) != NULL)
++                      free_page((unsigned long) evtchn_row);
+       }
+       WRITE_ONCE(evtchn_to_irq[row][col], irq);
+-- 
+2.30.2
+