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

rds: Make rds_sock_lock BH rather than IRQ safe.

rds_sock_info() triggers locking warnings because we try to perform a
local_bh_enable() (via sock_i_ino()) while hardware interrupts are
disabled (via taking rds_sock_lock).

There is no reason for rds_sock_lock to be a hardware IRQ disabling
lock, none of these access paths run in hardware interrupt context.

Therefore making it a BH disabling lock is safe and sufficient to
fix this bug.

Reported-by: Kumar Sanghvi <kumaras@chelsio.com>
Reported-by: Josh Boyer <jwboyer@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

+8 -12
+8 -12
net/rds/af_rds.c
··· 68 68 { 69 69 struct sock *sk = sock->sk; 70 70 struct rds_sock *rs; 71 - unsigned long flags; 72 71 73 72 if (!sk) 74 73 goto out; ··· 93 94 rds_rdma_drop_keys(rs); 94 95 rds_notify_queue_get(rs, NULL); 95 96 96 - spin_lock_irqsave(&rds_sock_lock, flags); 97 + spin_lock_bh(&rds_sock_lock); 97 98 list_del_init(&rs->rs_item); 98 99 rds_sock_count--; 99 - spin_unlock_irqrestore(&rds_sock_lock, flags); 100 + spin_unlock_bh(&rds_sock_lock); 100 101 101 102 rds_trans_put(rs->rs_transport); 102 103 ··· 408 409 409 410 static int __rds_create(struct socket *sock, struct sock *sk, int protocol) 410 411 { 411 - unsigned long flags; 412 412 struct rds_sock *rs; 413 413 414 414 sock_init_data(sock, sk); ··· 424 426 spin_lock_init(&rs->rs_rdma_lock); 425 427 rs->rs_rdma_keys = RB_ROOT; 426 428 427 - spin_lock_irqsave(&rds_sock_lock, flags); 429 + spin_lock_bh(&rds_sock_lock); 428 430 list_add_tail(&rs->rs_item, &rds_sock_list); 429 431 rds_sock_count++; 430 - spin_unlock_irqrestore(&rds_sock_lock, flags); 432 + spin_unlock_bh(&rds_sock_lock); 431 433 432 434 return 0; 433 435 } ··· 469 471 { 470 472 struct rds_sock *rs; 471 473 struct rds_incoming *inc; 472 - unsigned long flags; 473 474 unsigned int total = 0; 474 475 475 476 len /= sizeof(struct rds_info_message); 476 477 477 - spin_lock_irqsave(&rds_sock_lock, flags); 478 + spin_lock_bh(&rds_sock_lock); 478 479 479 480 list_for_each_entry(rs, &rds_sock_list, rs_item) { 480 481 read_lock(&rs->rs_recv_lock); ··· 489 492 read_unlock(&rs->rs_recv_lock); 490 493 } 491 494 492 - spin_unlock_irqrestore(&rds_sock_lock, flags); 495 + spin_unlock_bh(&rds_sock_lock); 493 496 494 497 lens->nr = total; 495 498 lens->each = sizeof(struct rds_info_message); ··· 501 504 { 502 505 struct rds_info_socket sinfo; 503 506 struct rds_sock *rs; 504 - unsigned long flags; 505 507 506 508 len /= sizeof(struct rds_info_socket); 507 509 508 - spin_lock_irqsave(&rds_sock_lock, flags); 510 + spin_lock_bh(&rds_sock_lock); 509 511 510 512 if (len < rds_sock_count) 511 513 goto out; ··· 525 529 lens->nr = rds_sock_count; 526 530 lens->each = sizeof(struct rds_info_socket); 527 531 528 - spin_unlock_irqrestore(&rds_sock_lock, flags); 532 + spin_unlock_bh(&rds_sock_lock); 529 533 } 530 534 531 535 static void rds_exit(void)