From: Eldad Zinger Date: Wed, 6 Oct 2010 07:47:27 +0000 (+0200) Subject: sdp: refcnt debug tool X-Git-Tag: v4.1.12-92~264^2~5^2~95 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=49083c60b39e98f38d2138eadcff0cb266e0a88c;p=users%2Fjedix%2Flinux-maple.git sdp: refcnt debug tool Signed-off-by: Eldad Zinger --- diff --git a/drivers/infiniband/ulp/sdp/sdp.h b/drivers/infiniband/ulp/sdp/sdp.h index 99848cf5ea1d4..9cfc09cb07694 100644 --- a/drivers/infiniband/ulp/sdp/sdp.h +++ b/drivers/infiniband/ulp/sdp/sdp.h @@ -60,6 +60,10 @@ #define SDP_OP_RDMA 0x200000000LL #define SDP_OP_NOP 0x100000000LL +#ifdef SDP_SOCK_HISTORY +#define SDP_SOCK_HISTORY_LEN 128 +#endif + /* how long (in jiffies) to block sender till tx completion*/ #define SDP_BZCOPY_POLL_TIMEOUT (HZ / 10) @@ -107,10 +111,13 @@ struct sdp_skb_cb { } while (0) #define sdp_common_release(sk) do { \ - sdp_dbg(sk, "%s:%d - sock_put(" SOCK_REF_ALIVE \ + sdp_dbg(sk, "%s:%d - sock_put(SOCK_REF_ALIVE" \ ") - refcount = %d from withing sk_common_release\n",\ __func__, __LINE__, atomic_read(&(sk)->sk_refcnt));\ percpu_counter_inc((sk)->sk_prot->orphan_count);\ + sdp_add_to_history(sk, "sdp_common_release"); \ + _sdp_add_to_history(sk, "SOCK_REF_ALIVE", __func__, __LINE__, \ + 2, SOCK_REF_ALIVE); \ sk_common_release(sk); \ } while (0) @@ -333,6 +340,26 @@ struct sdp_moderation { int moder_time; }; +#ifdef SDP_SOCK_HISTORY +enum sdp_ref_type { + NOT_REF, + HOLD_REF, + PUT_REF, + __PUT_REF, + BOTH_REF +}; + +struct sdp_sock_hist { + char *str; + char *func; + int line; + int pid; + u8 cnt; + u8 ref_type; /* enum sdp_ref_type */ + u8 ref_enum; /* enum sdp_ref */ +}; +#endif /* SDP_SOCK_HISTORY */ + struct sdp_sock { /* sk has to be the first member of inet_sock */ struct inet_sock isk; @@ -344,6 +371,12 @@ struct sdp_sock { struct sdp_device *sdp_dev; int cpu; +#ifdef SDP_SOCK_HISTORY + struct sdp_sock_hist hst[SDP_SOCK_HISTORY_LEN]; + unsigned hst_idx; /* next free slot */ + spinlock_t hst_lock; +#endif /* SDP_SOCK_HISTORY */ + int qp_active; spinlock_t tx_sa_lock; struct tx_srcavail_state *tx_sa; @@ -457,6 +490,139 @@ static inline struct sdp_sock *sdp_sk(const struct sock *sk) return (struct sdp_sock *)sk; } +#ifdef SDP_SOCK_HISTORY +static inline char *reftype2str(int reftype) +{ +#define ENUM2STR(e) [e] = #e + static char *enum2str[] = { + ENUM2STR(NOT_REF), + ENUM2STR(HOLD_REF), + ENUM2STR(PUT_REF), + ENUM2STR(__PUT_REF), + ENUM2STR(BOTH_REF) + }; + + if (reftype < 0 || reftype >= ARRAY_SIZE(enum2str)) { + printk(KERN_WARNING "reftype %d is illegal\n", reftype); + return NULL; + } + + return enum2str[reftype]; +} + +static inline void sdp_print_history(struct sock *sk) +{ + struct sdp_sock *ssk = sdp_sk(sk); + unsigned i; + unsigned long flags; + + spin_lock_irqsave(&ssk->hst_lock, flags); + + sdp_warn(sk, "############## %p %s %u/%lu ##############\n", + sk, sdp_state_str(sk->sk_state), + ssk->hst_idx, ARRAY_SIZE(ssk->hst)); + + for (i = 0; i < ssk->hst_idx; ++i) { + struct sdp_sock_hist *hst = &ssk->hst[i]; + char *ref_str = reftype2str(hst->ref_type); + + if (hst->ref_type == NOT_REF) + ref_str = ""; + + if (hst->cnt != 1) { + sdp_warn(sk, "[%s:%d pid: %d] %s %s : %d\n", + hst->func, hst->line, hst->pid, + ref_str, hst->str, hst->cnt); + } else { + sdp_warn(sk, "[%s:%d pid: %d] %s %s\n", + hst->func, hst->line, hst->pid, + ref_str, hst->str); + } + } + + spin_unlock_irqrestore(&ssk->hst_lock, flags); +} + +static inline void _sdp_add_to_history(struct sock *sk, const char *str, + const char *func, int line, int ref_type, int ref_enum) +{ + struct sdp_sock *ssk = sdp_sk(sk); + unsigned i; + unsigned long flags; + struct sdp_sock_hist *hst; + + spin_lock_irqsave(&ssk->hst_lock, flags); + + i = ssk->hst_idx; + + if (i >= ARRAY_SIZE(ssk->hst)) { + //sdp_warn(sk, "overflow, drop: %s\n", s); + ++ssk->hst_idx; + goto out; + } + + if (ssk->hst[i].str) + sdp_warn(sk, "overwriting %s\n", ssk->hst[i].str); + + switch (ref_type) { + case NOT_REF: + case HOLD_REF: +simple_add: + hst = &ssk->hst[i]; + hst->str = (char *)str; + hst->func = (char *)func; + hst->line = line; + hst->ref_type = ref_type; + hst->ref_enum = ref_enum; + hst->cnt = 1; + hst->pid = current->pid; + ++ssk->hst_idx; + break; + case PUT_REF: + case __PUT_REF: + /* Try to shrink history by attaching HOLD+PUT + * together */ + hst = i > 0 ? &ssk->hst[i - 1] : NULL; + if (hst && hst->ref_type == HOLD_REF && + hst->ref_enum == ref_enum) { + hst->ref_type = BOTH_REF; + hst->func = (char *)func; + hst->line = line; + hst->pid = current->pid; + + /* try to shrink some more - by summing up */ + --i; + hst = i > 0 ? &ssk->hst[i - 1] : NULL; + if (hst && hst->ref_type == BOTH_REF && + hst->ref_enum == ref_enum) { + ++hst->cnt; + hst->func = (char *)func; + hst->line = line; + hst->pid = current->pid; + ssk->hst[i].str = NULL; + + --ssk->hst_idx; + } + } else + goto simple_add; + break; + default: + sdp_warn(sk, "error\n"); + } +out: + spin_unlock_irqrestore(&ssk->hst_lock, flags); +} + +#define sdp_add_to_history(sk, str) \ + _sdp_add_to_history(sk, str, __func__, __LINE__, 0, 0) +#else +static inline void _sdp_add_to_history(struct sock *sk, const char *str, + const char *func, int line, int ref_type, int ref_enum) +{ +} +#define sdp_add_to_history(sk, str) +#endif /* SDP_SOCK_HISTORY */ + static inline int _sdp_exch_state(const char *func, int line, struct sock *sk, int from_states, int state) { @@ -481,6 +647,8 @@ static inline int _sdp_exch_state(const char *func, int line, struct sock *sk, spin_unlock_irqrestore(&sdp_sk(sk)->lock, flags); + sdp_add_to_history(sk, sdp_state_str(state)); + return old; } #define sdp_exch_state(sk, from_states, state) \ diff --git a/drivers/infiniband/ulp/sdp/sdp_cma.c b/drivers/infiniband/ulp/sdp/sdp_cma.c index 564cb78e4d70d..78fafa267919d 100644 --- a/drivers/infiniband/ulp/sdp/sdp_cma.c +++ b/drivers/infiniband/ulp/sdp/sdp_cma.c @@ -328,6 +328,8 @@ int sdp_cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) -EINVAL : 0; } + sdp_add_to_history(sk, rdma_cm_event_str(event->event)); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); sdp_dbg(sk, "event: %s\n", rdma_cm_event_str(event->event)); if (!sdp_sk(sk)->id) { diff --git a/drivers/infiniband/ulp/sdp/sdp_dbg.h b/drivers/infiniband/ulp/sdp/sdp_dbg.h index f9a8a637e2611..61cb1a35c1607 100644 --- a/drivers/infiniband/ulp/sdp/sdp_dbg.h +++ b/drivers/infiniband/ulp/sdp/sdp_dbg.h @@ -3,6 +3,10 @@ #define SDPSTATS_ON +#ifdef CONFIG_INFINIBAND_SDP_DEBUG +#define SDP_SOCK_HISTORY +#endif + #ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA #define SDP_PROFILING #endif @@ -99,6 +103,7 @@ extern int sdp_debug_level; if (!atomic_read(&(sk)->sk_refcnt)) {\ sdp_warn(sk, "%s:%d - %s (%s) ref = 0.\n", \ __func__, __LINE__, #sock_op, msg); \ + sdp_print_history(sk); \ SDP_WARN_ON(1); \ } else { \ sdp_dbg(sk, "%s:%d - %s (%s) ref = %d.\n", __func__, __LINE__, \ @@ -132,19 +137,44 @@ extern int sdp_data_debug_level; #define SDP_DUMP_PACKET(sk, str, skb, h) #endif -#define SOCK_REF_RESET "RESET" -#define SOCK_REF_ALIVE "ALIVE" /* sock_alloc -> destruct_sock */ -#define SOCK_REF_CLONE "CLONE" -#define SOCK_REF_CMA "CMA" /* sdp_cma_handler() is expected to be invoked */ -#define SOCK_REF_SEQ "SEQ" /* during proc read */ -#define SOCK_REF_DREQ_TO "DREQ_TO" /* dreq timeout is pending */ -#define SOCK_REF_ZCOPY "ZCOPY" /* zcopy send in process */ -#define SOCK_REF_RDMA_RD "RDMA_RD" /* RDMA read in process */ -#define SOCK_REF_KEEPALIVE "KEEPALIVE" /* socket is held by sk_reset_timer */ - -#define sock_hold(sk, msg) sock_ref(sk, msg, sock_hold) -#define sock_put(sk, msg) sock_ref(sk, msg, sock_put) -#define __sock_put(sk, msg) sock_ref(sk, msg, __sock_put) +enum sdp_ref { + SOCK_REF_RESET, + SOCK_REF_ALIVE, /* sock_alloc -> destruct_sock */ + SOCK_REF_CLONE, + SOCK_REF_CMA, /* sdp_cma_handler is expected to be invoked */ + SOCK_REF_SEQ, /* during proc read */ + SOCK_REF_DREQ_TO, /* dreq timeout is pending */ + SOCK_REF_ZCOPY, /* zcopy send in process */ + SOCK_REF_RDMA_RD, /* RDMA read in process */ + SOCK_REF_KEEPALIVE /* socket is held by sk_reset_timer */ +}; + +#ifdef SDP_SOCK_HISTORY +#define sock_hold(sk, msg) \ + do { \ + _sdp_add_to_history(sk, #msg, __func__, __LINE__, \ + HOLD_REF, msg); \ + sock_ref(sk, #msg, sock_hold); \ + } while (0) + +#define sock_put(sk, msg) \ + do { \ + _sdp_add_to_history(sk, #msg, __func__, __LINE__, \ + PUT_REF, msg); \ + sock_ref(sk, #msg, sock_put); \ + } while (0) + +#define __sock_put(sk, msg) \ + do { \ + _sdp_add_to_history(sk, #msg, __func__, __LINE__, \ + __PUT_REF, msg); \ + sock_ref(sk, #msg, __sock_put); \ + } while (0) +#else +#define sock_hold(sk, msg) sock_ref(sk, #msg, sock_hold) +#define sock_put(sk, msg) sock_ref(sk, #msg, sock_put) +#define __sock_put(sk, msg) sock_ref(sk, #msg, __sock_put) +#endif /* SDP_SOCK_HISTORY */ #define ENUM2STR(e) [e] = #e diff --git a/drivers/infiniband/ulp/sdp/sdp_main.c b/drivers/infiniband/ulp/sdp/sdp_main.c index 2a2afea1e5548..3b7c249194d08 100644 --- a/drivers/infiniband/ulp/sdp/sdp_main.c +++ b/drivers/infiniband/ulp/sdp/sdp_main.c @@ -155,6 +155,7 @@ static int sdp_get_port(struct sock *sk, unsigned short snum) .sin_addr.s_addr = inet_sk(sk)->rcv_saddr, }; + sdp_add_to_history(sk, __func__); sdp_dbg(sk, "%s: %u.%u.%u.%u:%hu\n", __func__, NIPQUAD(addr.sin_addr.s_addr), ntohs(addr.sin_port)); @@ -187,6 +188,7 @@ static void sdp_destroy_qp(struct sdp_sock *ssk) sdp_dbg(&ssk->isk.sk, "destroying qp\n"); sdp_prf(&ssk->isk.sk, NULL, "destroying qp"); + sdp_add_to_history(&ssk->isk.sk, __func__); ssk->qp_active = 0; if (ssk->qp) { @@ -532,6 +534,7 @@ static void sdp_destruct(struct sock *sk) return; } + sdp_add_to_history(sk, __func__); percpu_counter_dec(sk->sk_prot->orphan_count); ssk->destructed_already = 1; @@ -654,6 +657,7 @@ static void sdp_close(struct sock *sk, long timeout) struct sk_buff *skb; int data_was_unread = 0; + sdp_add_to_history(sk, __func__); lock_sock(sk); sdp_dbg(sk, "%s\n", __func__); @@ -754,6 +758,7 @@ static int sdp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) }; int rc; + sdp_add_to_history(sk, __func__); ssk->cpu = smp_processor_id(); release_sock(sk); flush_workqueue(sdp_wq); @@ -889,6 +894,7 @@ static struct sock *sdp_accept(struct sock *sk, int flags, int *err) struct sock *newsk; int error; + sdp_add_to_history(sk, __func__); sdp_dbg(sk, "%s state %d expected %d *err %d\n", __func__, sk->sk_state, TCP_LISTEN, *err); @@ -949,6 +955,7 @@ static int sdp_ioctl(struct sock *sk, int cmd, unsigned long arg) struct sdp_sock *ssk = sdp_sk(sk); int answ; + sdp_add_to_history(sk, __func__); sdp_dbg(sk, "%s\n", __func__); switch (cmd) { @@ -1142,6 +1149,12 @@ int sdp_init_sock(struct sock *sk) ssk->zcopy_thresh = -1; /* use global sdp_zcopy_thresh */ ssk->last_bind_err = 0; +#ifdef SDP_SOCK_HISTORY + memset(ssk->hst, 0, sizeof ssk->hst); + ssk->hst_idx = 0; + spin_lock_init(&ssk->hst_lock); +#endif + return 0; } @@ -1149,6 +1162,7 @@ static void sdp_shutdown(struct sock *sk, int how) { struct sdp_sock *ssk = sdp_sk(sk); + sdp_add_to_history(sk, __func__); sdp_dbg(sk, "%s\n", __func__); if (!(how & SEND_SHUTDOWN)) return; @@ -1197,6 +1211,7 @@ static int sdp_setsockopt(struct sock *sk, int level, int optname, int val; int err = 0; + sdp_add_to_history(sk, __func__); sdp_dbg(sk, "%s\n", __func__); if (optlen < sizeof(int)) return -EINVAL; @@ -1305,6 +1320,7 @@ static int sdp_getsockopt(struct sock *sk, int level, int optname, struct sdp_sock *ssk = sdp_sk(sk); int val, len; + sdp_add_to_history(sk, __func__); sdp_dbg(sk, "%s\n", __func__); if (level != SOL_TCP) @@ -2531,6 +2547,7 @@ static int sdp_listen(struct sock *sk, int backlog) int rc; sdp_dbg(sk, "%s\n", __func__); + sdp_add_to_history(sk, __func__); if (!ssk->id) { rc = sdp_get_port(sk, 0); @@ -2747,6 +2764,7 @@ static int sdp_create_socket(struct net *net, struct socket *sock, int protocol) return -ENOMEM; } + sdp_add_to_history(sk, __func__); sk->sk_destruct = sdp_destruct; sock->ops = &sdp_proto_ops; sock->state = SS_UNCONNECTED; @@ -2823,6 +2841,7 @@ do_next: if (ssk->ib_device == device && !ssk->id_destroyed_already) { spin_unlock_irq(&sock_list_lock); sk = &ssk->isk.sk; + sdp_add_to_history(sk, __func__); lock_sock(sk); /* ssk->id must be lock-protected, * to enable mutex with sdp_close() */