From: Chris Mason Date: Fri, 3 Feb 2012 16:09:07 +0000 (-0500) Subject: RDS: add debuging code around sock_hold and sock_put. X-Git-Tag: v4.1.12-92~319^2^2~2^2~37 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=7aaa90df89170bc4a64f67953a908016b45e36cc;p=users%2Fjedix%2Flinux-maple.git RDS: add debuging code around sock_hold and sock_put. RDS had a recent series of memory corruptions because of a use-after-free and double-free of rds sockets. This adds some debugging code around sock_put and sock_hold to catch any similar bugs and spit out useful debugging info. This is a temporary commit while customers try out our fix. Signed-off-by: Chris Mason Signed-off-by: Bang Nguyen --- diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index f7620f07fc44..63afc6354bab 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -98,7 +98,19 @@ static int rds_release(struct socket *sock) rds_trans_put(rs->rs_transport); sock->sk = NULL; - sock_put(sk); + if ((atomic_read(&sk->sk_refcnt) == 0)) { + printk(KERN_CRIT "zero refcnt on sock put release\n"); + WARN_ON(1); + } + + if (atomic_dec_and_test(&sk->sk_refcnt)) { + if (rs->poison != 0xABABABAB) { + printk(KERN_CRIT "bad poison on put release %x\n", rs->poison); + WARN_ON(1); + } + rs->poison = 0xDEADBEEF; + sk_free(sk); + } out: return 0; } @@ -430,6 +442,11 @@ static int __rds_create(struct socket *sock, struct sock *sk, int protocol) INIT_LIST_HEAD(&rs->rs_cong_list); spin_lock_init(&rs->rs_rdma_lock); rs->rs_rdma_keys = RB_ROOT; + rs->poison = 0xABABABAB; + + if (rs->rs_bound_addr) { +printk(KERN_CRIT "bound addr %x at create\n", rs->rs_bound_addr); + } spin_lock_irqsave(&rds_sock_lock, flags); list_add_tail(&rs->rs_item, &rds_sock_list); @@ -453,14 +470,47 @@ static int rds_create(struct net *net, struct socket *sock, int protocol) return __rds_create(sock, sk, protocol); } +void debug_sock_hold(struct sock *sk) +{ + struct rds_sock *rs = rds_sk_to_rs(sk); + if ((atomic_read(&sk->sk_refcnt) == 0)) { + printk(KERN_CRIT "zero refcnt on sock hold\n"); + WARN_ON(1); + } + if (rs->poison != 0xABABABAB) { + printk(KERN_CRIT "bad poison on hold %x\n", rs->poison); + WARN_ON(1); + } + sock_hold(sk); +} + + void rds_sock_addref(struct rds_sock *rs) { - sock_hold(rds_rs_to_sk(rs)); + debug_sock_hold(rds_rs_to_sk(rs)); +} + +void debug_sock_put(struct sock *sk) +{ + if ((atomic_read(&sk->sk_refcnt) == 0)) { + printk(KERN_CRIT "zero refcnt on sock put\n"); + WARN_ON(1); + } + if (atomic_dec_and_test(&sk->sk_refcnt)) { + struct rds_sock *rs = rds_sk_to_rs(sk); + if (rs->poison != 0xABABABAB) { + printk(KERN_CRIT "bad poison on put %x\n", rs->poison); + WARN_ON(1); + } + rs->poison = 0xDEADBEEF; + sk_free(sk); + } } + void rds_sock_put(struct rds_sock *rs) { - sock_put(rds_rs_to_sk(rs)); + debug_sock_put(rds_rs_to_sk(rs)); } static struct net_proto_family rds_family_ops = { diff --git a/net/rds/rds.h b/net/rds/rds.h index 5590164fbcea..bdf9a8ed1b2a 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -507,6 +507,7 @@ struct rds_sock { /* Socket options - in case there will be more */ unsigned char rs_recverr, rs_cong_monitor; + int poison; }; static inline struct rds_sock *rds_sk_to_rs(const struct sock *sk) @@ -581,6 +582,8 @@ static inline void __rds_wake_sk_sleep(struct sock *sk) } extern wait_queue_head_t rds_poll_waitq; +void debug_sock_hold(struct sock *sock); +void debug_sock_put(struct sock *sock); /* bind.c */ int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); diff --git a/net/rds/send.c b/net/rds/send.c index 9967e9f5a65a..567f4b292a9c 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -477,7 +477,7 @@ void rds_rdma_send_complete(struct rds_message *rm, int status) && ro->op_active && ro->op_notify && ro->op_notifier) { notifier = ro->op_notifier; rs = rm->m_rs; - sock_hold(rds_rs_to_sk(rs)); + debug_sock_hold(rds_rs_to_sk(rs)); notifier->n_status = status; spin_lock(&rs->rs_lock); @@ -491,7 +491,7 @@ void rds_rdma_send_complete(struct rds_message *rm, int status) if (rs) { rds_wake_sk_sleep(rs); - sock_put(rds_rs_to_sk(rs)); + debug_sock_put(rds_rs_to_sk(rs)); } } EXPORT_SYMBOL_GPL(rds_rdma_send_complete); @@ -513,7 +513,7 @@ void rds_atomic_send_complete(struct rds_message *rm, int status) && ao->op_active && ao->op_notify && ao->op_notifier) { notifier = ao->op_notifier; rs = rm->m_rs; - sock_hold(rds_rs_to_sk(rs)); + debug_sock_hold(rds_rs_to_sk(rs)); notifier->n_status = status; spin_lock(&rs->rs_lock); @@ -527,7 +527,7 @@ void rds_atomic_send_complete(struct rds_message *rm, int status) if (rs) { rds_wake_sk_sleep(rs); - sock_put(rds_rs_to_sk(rs)); + debug_sock_put(rds_rs_to_sk(rs)); } } EXPORT_SYMBOL_GPL(rds_atomic_send_complete); @@ -634,10 +634,10 @@ void rds_send_remove_from_sock(struct list_head *messages, int status) if (rs != rm->m_rs) { if (rs) { rds_wake_sk_sleep(rs); - sock_put(rds_rs_to_sk(rs)); + debug_sock_put(rds_rs_to_sk(rs)); } rs = rm->m_rs; - sock_hold(rds_rs_to_sk(rs)); + debug_sock_hold(rds_rs_to_sk(rs)); } spin_lock(&rs->rs_lock); @@ -671,7 +671,7 @@ unlock_and_drop: if (rs) { rds_wake_sk_sleep(rs); - sock_put(rds_rs_to_sk(rs)); + debug_sock_put(rds_rs_to_sk(rs)); } }