Skip to content

Commit 44d1987

Browse files
Hakon-Buggevijay-suman
authored andcommitted
net/rds: Fix call to sleeping function in a non-sleeping context
Commit 4d19ae2 ("net/rds: Implement ARP flushing correctly") uses read_lock() to protect traversal of the netdev list. This lock disables preemption, and we hit: kernel: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:755 kernel: in_atomic(): 1, irqs_disabled(): 0, pid: 6, name: kworker/u176:0 kernel: INFO: lockdep is turned off. kernel: CPU: 62 PID: 6 Comm: kworker/u176:0 Tainted: G W OE 4.14.35-1836.el7uek.x86_64.debug #2 kernel: Hardware name: Oracle Corporation ORACLE SERVER X6-2/ASM,MOTHERBOARD,1U, BIOS 38080000 05/08/2017 kernel: Workqueue: rdma_cm cma_work_handler [rdma_cm] kernel: Call Trace: kernel: dump_stack+0x81/0xb6 kernel: ___might_sleep+0x239/0x25a kernel: __might_sleep+0x4a/0x78 kernel: __mutex_lock+0x58/0xad7 kernel: ? get_page_from_freelist+0x3a7/0xca6 kernel: ? rtnl_lock+0x17/0x19 kernel: ? get_page_from_freelist+0x3a7/0xca6 kernel: ? security_capable+0x4e/0x66 kernel: mutex_lock_nested+0x1b/0x1d kernel: rtnl_lock+0x17/0x19 kernel: arp_ioctl+0xca/0x33d kernel: inet_ioctl+0x2e/0x76 kernel: __flush_arp_entry+0x3d/0xa0 [rds_rdma] kernel: rds_ib_flush_arp_entry+0x1df/0x280 [rds_rdma] kernel: rds_rdma_cm_event_handler_cmn+0x255/0x770 [rds_rdma] kernel: rds_rdma_cm_event_handler+0x10/0x20 [rds_rdma] kernel: cma_work_handler+0x69/0x90 [rdma_cm] kernel: process_one_work+0x228/0x6d9 kernel: ? process_one_work+0x186/0x6d9 kernel: worker_thread+0x4d/0x3d6 kernel: kthread+0x113/0x146 kernel: ? process_one_work+0x6e0/0x6d9 kernel: ? kthread_bind+0x20/0x15 kernel: ret_from_fork+0x3a/0x45 Fixing it by copying the netdev names whilst iterating and call __flush_arp_entry() afterwards. Also, since we are at it, changing the locking to rcu_read_lock() and using the corresponding rcu list traversal. Orabug: 28642686 Fixes: 4d19ae2 ("net/rds: Implement ARP flushing correctly") Signed-off-by: Håkon Bugge <[email protected]> Suggested-by: Alan Maguire <[email protected]> Reviewed-by: Ka-cheong Poon <[email protected]> Orabug: 33590097 UEK6 => UEK7 (cherry picked from commit 68be6b7) cherry-pick-repo=UEK/production/linux-uek.git Signed-off-by: Gerd Rausch <[email protected]> Reviewed-by: William Kucharski <[email protected]> Orabug: 33590087 UEK7 => LUCI (cherry picked from commit 25a76d0) cherry-pick-repo=UEK/production/linux-uek.git Signed-off-by: Gerd Rausch <[email protected]> Reviewed-by: William Kucharski <[email protected]>
1 parent 78beb25 commit 44d1987

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

net/rds/ib.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ static void __flush_arp_entry(struct arpreq *r, char name[IFNAMSIZ])
825825

826826
r->arp_flags = ATF_PERM;
827827
((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr = htonl(0);
828-
strcpy(r->arp_dev, name);
828+
strncpy(r->arp_dev, name, IFNAMSIZ);
829829
ret = inet_ioctl(rds_ib_inet_socket, SIOCDARP, (unsigned long)r);
830830
if ((ret == -ENOENT) || (ret == -ENXIO)) {
831831
r->arp_flags |= ATF_PUBL;
@@ -863,13 +863,40 @@ static void __flush_eth_arp_entry(struct arpreq *r)
863863

864864
static void __flush_ib_arp_entry(struct arpreq *r)
865865
{
866+
const int nmbr_dev_per_realloc = 10;
866867
struct net_device *ndev;
868+
char *dev_array = NULL;
869+
int dev_found = 0;
870+
int dev_left = 0;
871+
char *ret;
872+
int i;
873+
874+
rcu_read_lock();
875+
for_each_netdev_rcu(&init_net, ndev) {
876+
if (ndev->type != ARPHRD_INFINIBAND)
877+
continue;
878+
879+
if (!dev_left) {
880+
ret = krealloc(dev_array,
881+
(dev_found + nmbr_dev_per_realloc) * IFNAMSIZ,
882+
GFP_ATOMIC);
883+
if (!ret) {
884+
pr_err("krealloc failed");
885+
break;
886+
}
887+
dev_array = ret;
888+
dev_left = nmbr_dev_per_realloc;
889+
}
890+
strncpy(dev_array + dev_found * IFNAMSIZ, ndev->name, IFNAMSIZ);
891+
++dev_found;
892+
--dev_left;
893+
}
894+
rcu_read_unlock();
895+
896+
for (i = 0; i < dev_found; ++i)
897+
__flush_arp_entry(r, dev_array + i * IFNAMSIZ);
867898

868-
read_lock(&dev_base_lock);
869-
for_each_netdev(&init_net, ndev)
870-
if (ndev->type == ARPHRD_INFINIBAND)
871-
__flush_arp_entry(r, ndev->name);
872-
read_unlock(&dev_base_lock);
899+
kfree(dev_array);
873900
}
874901

875902
void rds_ib_flush_arp_entry(struct in6_addr *prot_addr)

0 commit comments

Comments
 (0)