From owner-svn-src-all@freebsd.org Wed Mar 29 02:21:07 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 033C4D22908; Wed, 29 Mar 2017 02:21:07 +0000 (UTC) (envelope-from np@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C61E865081; Wed, 29 Mar 2017 02:21:06 +0000 (UTC) (envelope-from np@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v2T2L544013733; Wed, 29 Mar 2017 02:21:05 GMT (envelope-from np@FreeBSD.org) Received: (from np@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v2T2L5an013730; Wed, 29 Mar 2017 02:21:05 GMT (envelope-from np@FreeBSD.org) Message-Id: <201703290221.v2T2L5an013730@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: np set sender to np@FreeBSD.org using -f From: Navdeep Parhar Date: Wed, 29 Mar 2017 02:21:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r316123 - in stable/10/sys/dev/cxgbe: . iw_cxgbe X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 29 Mar 2017 02:21:07 -0000 Author: np Date: Wed Mar 29 02:21:05 2017 New Revision: 316123 URL: https://svnweb.freebsd.org/changeset/base/316123 Log: MFC r315201, r315920, r315921, r315922, r316008, and r316062. r315201: cxgbe(4): Fix an always-true assertion (reported by PVS-Studio). sys/dev/cxgbe/t4_main.c: PVS-Studio: Expression is Always True (CWE-571) (3) r315920: cxgbe/iw_cxgbe: c4iw_connect should always returns a -ve errno on failure. r315921: cxgbe/iw_cxgbe: alloc_ep expects a gfp_t, and it's always ok to sleep during alloc_ep. r315922: cxgbe/iw_cxgbe: allocations that use GFP_KERNEL (which is M_WAITOK on FreeBSD) cannot fail. r316008: cxgbe/iw_cxgbe: Remove unused code. r316062: cxgbe/iw_cxgbe: Defer the handling of error CQEs and RDMA_TERMINATE to the thread that deals with socket state changes. This eliminates various bad races with the ithread. Modified: stable/10/sys/dev/cxgbe/iw_cxgbe/cm.c stable/10/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h stable/10/sys/dev/cxgbe/t4_main.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/cxgbe/iw_cxgbe/cm.c ============================================================================== --- stable/10/sys/dev/cxgbe/iw_cxgbe/cm.c Wed Mar 29 02:20:07 2017 (r316122) +++ stable/10/sys/dev/cxgbe/iw_cxgbe/cm.c Wed Mar 29 02:21:05 2017 (r316123) @@ -74,20 +74,19 @@ static spinlock_t req_lock; static TAILQ_HEAD(c4iw_ep_list, c4iw_ep_common) req_list; static struct work_struct c4iw_task; static struct workqueue_struct *c4iw_taskq; -static LIST_HEAD(timeout_list); -static spinlock_t timeout_lock; +static LIST_HEAD(err_cqe_list); +static spinlock_t err_cqe_lock; static void process_req(struct work_struct *ctx); static void start_ep_timer(struct c4iw_ep *ep); static int stop_ep_timer(struct c4iw_ep *ep); static int set_tcpinfo(struct c4iw_ep *ep); static void process_timeout(struct c4iw_ep *ep); -static void process_timedout_eps(void); +static void process_err_cqes(void); static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc); static void __state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state tostate); static void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state tostate); static void *alloc_ep(int size, gfp_t flags); -void __free_ep(struct c4iw_ep_common *epc); static struct rtentry * find_route(__be32 local_ip, __be32 peer_ip, __be16 local_port, __be16 peer_port, u8 tos); static void close_socket(struct socket *so); @@ -114,7 +113,10 @@ static void process_connected(struct c4i static int c4iw_so_upcall(struct socket *so, void *arg, int waitflag); static void process_socket_event(struct c4iw_ep *ep); static void release_ep_resources(struct c4iw_ep *ep); - +static int process_terminate(struct c4iw_ep *ep); +static int terminate(struct sge_iq *iq, const struct rss_header *rss, + struct mbuf *m); +static int add_ep_to_req_list(struct c4iw_ep *ep, int ep_events); #define START_EP_TIMER(ep) \ do { \ CTR3(KTR_IW_CXGBE, "start_ep_timer (%s:%d) ep %p", \ @@ -223,22 +225,32 @@ static void process_timeout(struct c4iw_ return; } -static void process_timedout_eps(void) +struct cqe_list_entry { + struct list_head entry; + struct c4iw_dev *rhp; + struct t4_cqe err_cqe; +}; + +static void +process_err_cqes(void) { - struct c4iw_ep *ep; + unsigned long flag; + struct cqe_list_entry *cle; - spin_lock(&timeout_lock); - while (!list_empty(&timeout_list)) { + spin_lock_irqsave(&err_cqe_lock, flag); + while (!list_empty(&err_cqe_list)) { struct list_head *tmp; - tmp = timeout_list.next; + tmp = err_cqe_list.next; list_del(tmp); tmp->next = tmp->prev = NULL; - spin_unlock(&timeout_lock); - ep = list_entry(tmp, struct c4iw_ep, entry); - process_timeout(ep); - spin_lock(&timeout_lock); + spin_unlock_irqrestore(&err_cqe_lock, flag); + cle = list_entry(tmp, struct cqe_list_entry, entry); + c4iw_ev_dispatch(cle->rhp, &cle->err_cqe); + free(cle, M_CXGBE); + spin_lock_irqsave(&err_cqe_lock, flag); } - spin_unlock(&timeout_lock); + spin_unlock_irqrestore(&err_cqe_lock, flag); + return; } @@ -246,23 +258,31 @@ static void process_req(struct work_struct *ctx) { struct c4iw_ep_common *epc; + unsigned long flag; + int ep_events; - process_timedout_eps(); - spin_lock(&req_lock); + process_err_cqes(); + spin_lock_irqsave(&req_lock, flag); while (!TAILQ_EMPTY(&req_list)) { epc = TAILQ_FIRST(&req_list); TAILQ_REMOVE(&req_list, epc, entry); epc->entry.tqe_prev = NULL; - spin_unlock(&req_lock); - CTR3(KTR_IW_CXGBE, "%s so :%p, ep:%p", __func__, - epc->so, epc); - if (epc->so) + ep_events = epc->ep_events; + epc->ep_events = 0; + spin_unlock_irqrestore(&req_lock, flag); + CTR4(KTR_IW_CXGBE, "%s: so %p, ep %p, events 0x%x", __func__, + epc->so, epc, ep_events); + if (ep_events & C4IW_EVENT_TERM) + process_terminate((struct c4iw_ep *)epc); + if (ep_events & C4IW_EVENT_TIMEOUT) + process_timeout((struct c4iw_ep *)epc); + if (ep_events & C4IW_EVENT_SOCKET) process_socket_event((struct c4iw_ep *)epc); c4iw_put_ep(epc); - process_timedout_eps(); - spin_lock(&req_lock); + process_err_cqes(); + spin_lock_irqsave(&req_lock, flag); } - spin_unlock(&req_lock); + spin_unlock_irqrestore(&req_lock, flag); } /* @@ -695,7 +715,7 @@ process_newconn(struct iw_cm_id *parent_ MPASS(child_so != NULL); - child_ep = alloc_ep(sizeof(*child_ep), M_WAITOK); + child_ep = alloc_ep(sizeof(*child_ep), GFP_KERNEL); CTR5(KTR_IW_CXGBE, "%s: parent so %p, parent ep %p, child so %p, child ep %p", @@ -734,28 +754,62 @@ process_newconn(struct iw_cm_id *parent_ } static int +add_ep_to_req_list(struct c4iw_ep *ep, int new_ep_event) +{ + unsigned long flag; + + spin_lock_irqsave(&req_lock, flag); + if (ep && ep->com.so) { + ep->com.ep_events |= new_ep_event; + if (!ep->com.entry.tqe_prev) { + c4iw_get_ep(&ep->com); + TAILQ_INSERT_TAIL(&req_list, &ep->com, entry); + queue_work(c4iw_taskq, &c4iw_task); + } + } + spin_unlock_irqrestore(&req_lock, flag); + + return (0); +} + +static int c4iw_so_upcall(struct socket *so, void *arg, int waitflag) { struct c4iw_ep *ep = arg; - spin_lock(&req_lock); - CTR6(KTR_IW_CXGBE, "%s: so %p, so_state 0x%x, ep %p, ep_state %s, tqe_prev %p", __func__, so, so->so_state, ep, states[ep->com.state], ep->com.entry.tqe_prev); - if (ep && ep->com.so && !ep->com.entry.tqe_prev) { - KASSERT(ep->com.so == so, ("%s: XXX review.", __func__)); - c4iw_get_ep(&ep->com); - TAILQ_INSERT_TAIL(&req_list, &ep->com, entry); - queue_work(c4iw_taskq, &c4iw_task); - } + MPASS(ep->com.so == so); + add_ep_to_req_list(ep, C4IW_EVENT_SOCKET); - spin_unlock(&req_lock); return (SU_OK); } + +static int +terminate(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) +{ + struct adapter *sc = iq->adapter; + const struct cpl_rdma_terminate *cpl = mtod(m, const void *); + unsigned int tid = GET_TID(cpl); + struct toepcb *toep = lookup_tid(sc, tid); + struct socket *so; + struct c4iw_ep *ep; + + INP_WLOCK(toep->inp); + so = inp_inpcbtosocket(toep->inp); + ep = so->so_rcv.sb_upcallarg; + INP_WUNLOCK(toep->inp); + + CTR3(KTR_IW_CXGBE, "%s: so %p, ep %p", __func__, so, ep); + add_ep_to_req_list(ep, C4IW_EVENT_TERM); + + return 0; +} + static void process_socket_event(struct c4iw_ep *ep) { @@ -952,16 +1006,6 @@ alloc_ep(int size, gfp_t gfp) return (epc); } -void -__free_ep(struct c4iw_ep_common *epc) -{ - CTR2(KTR_IW_CXGBE, "%s:feB %p", __func__, epc); - KASSERT(!epc->so, ("%s warning ep->so %p \n", __func__, epc->so)); - KASSERT(!epc->entry.tqe_prev, ("%s epc %p still on req list!\n", __func__, epc)); - free(epc, M_DEVBUF); - CTR2(KTR_IW_CXGBE, "%s:feE %p", __func__, epc); -} - void _c4iw_free_ep(struct kref *kref) { struct c4iw_ep *ep; @@ -2148,15 +2192,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, err = -EINVAL; goto out; } - ep = alloc_ep(sizeof(*ep), M_NOWAIT); - - if (!ep) { - - CTR2(KTR_IW_CXGBE, "%s:cc2 %p", __func__, cm_id); - printk(KERN_ERR MOD "%s - cannot alloc ep.\n", __func__); - err = -ENOMEM; - goto out; - } + ep = alloc_ep(sizeof(*ep), GFP_KERNEL); init_timer(&ep->timer); ep->plen = conn_param->private_data_len; @@ -2216,7 +2252,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, ep->tos = 0; ep->com.local_addr = cm_id->local_addr; ep->com.remote_addr = cm_id->remote_addr; - err = soconnect(ep->com.so, (struct sockaddr *)&ep->com.remote_addr, + err = -soconnect(ep->com.so, (struct sockaddr *)&ep->com.remote_addr, ep->com.thread); if (!err) { @@ -2243,21 +2279,11 @@ out: int c4iw_create_listen_ep(struct iw_cm_id *cm_id, int backlog) { - int rc; struct c4iw_dev *dev = to_c4iw_dev(cm_id->device); struct c4iw_listen_ep *ep; struct socket *so = cm_id->so; ep = alloc_ep(sizeof(*ep), GFP_KERNEL); - CTR5(KTR_IW_CXGBE, "%s: cm_id %p, lso %p, ep %p, inp %p", __func__, - cm_id, so, ep, so->so_pcb); - if (ep == NULL) { - log(LOG_ERR, "%s: failed to alloc memory for endpoint\n", - __func__); - rc = ENOMEM; - goto failed; - } - ep->com.cm_id = cm_id; ref_cm_id(&ep->com); ep->com.dev = dev; @@ -2269,10 +2295,6 @@ c4iw_create_listen_ep(struct iw_cm_id *c cm_id->provider_data = ep; return (0); - -failed: - CTR3(KTR_IW_CXGBE, "%s: cm_id %p, FAILED (%d)", __func__, cm_id, rc); - return (-rc); } void @@ -2435,29 +2457,17 @@ int c4iw_ep_redirect(void *ctx, struct d static void ep_timeout(unsigned long arg) { struct c4iw_ep *ep = (struct c4iw_ep *)arg; - int kickit = 0; - - CTR2(KTR_IW_CXGBE, "%s:etB %p", __func__, ep); - spin_lock(&timeout_lock); if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) { /* * Only insert if it is not already on the list. */ - if (!ep->entry.next) { - list_add_tail(&ep->entry, &timeout_list); - kickit = 1; + if (!(ep->com.ep_events & C4IW_EVENT_TIMEOUT)) { + CTR2(KTR_IW_CXGBE, "%s:et1 %p", __func__, ep); + add_ep_to_req_list(ep, C4IW_EVENT_TIMEOUT); } } - spin_unlock(&timeout_lock); - - if (kickit) { - - CTR2(KTR_IW_CXGBE, "%s:et1 %p", __func__, ep); - queue_work(c4iw_taskq, &c4iw_task); - } - CTR2(KTR_IW_CXGBE, "%s:etE %p", __func__, ep); } static int fw6_wr_rpl(struct adapter *sc, const __be64 *rpl) @@ -2477,40 +2487,38 @@ static int fw6_wr_rpl(struct adapter *sc static int fw6_cqe_handler(struct adapter *sc, const __be64 *rpl) { - struct t4_cqe cqe =*(const struct t4_cqe *)(&rpl[0]); + struct cqe_list_entry *cle; + unsigned long flag; - CTR2(KTR_IW_CXGBE, "%s rpl %p", __func__, rpl); - c4iw_ev_dispatch(sc->iwarp_softc, &cqe); + cle = malloc(sizeof(*cle), M_CXGBE, M_NOWAIT); + cle->rhp = sc->iwarp_softc; + cle->err_cqe = *(const struct t4_cqe *)(&rpl[0]); + + spin_lock_irqsave(&err_cqe_lock, flag); + list_add_tail(&cle->entry, &err_cqe_list); + queue_work(c4iw_taskq, &c4iw_task); + spin_unlock_irqrestore(&err_cqe_lock, flag); return (0); } -static int terminate(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) +static int +process_terminate(struct c4iw_ep *ep) { - struct adapter *sc = iq->adapter; - const struct cpl_rdma_terminate *cpl = mtod(m, const void *); - unsigned int tid = GET_TID(cpl); struct c4iw_qp_attributes attrs; - struct toepcb *toep = lookup_tid(sc, tid); - struct socket *so; - struct c4iw_ep *ep; - - INP_WLOCK(toep->inp); - so = inp_inpcbtosocket(toep->inp); - ep = so->so_rcv.sb_upcallarg; - INP_WUNLOCK(toep->inp); CTR2(KTR_IW_CXGBE, "%s:tB %p %d", __func__, ep); if (ep && ep->com.qp) { - printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid, - ep->com.qp->wq.sq.qid); + printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", + ep->hwtid, ep->com.qp->wq.sq.qid); attrs.next_state = C4IW_QP_STATE_TERMINATE; c4iw_modify_qp(ep->com.dev, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); } else - printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid); + printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", + ep->hwtid); CTR2(KTR_IW_CXGBE, "%s:tE %p %d", __func__, ep); return 0; @@ -2526,8 +2534,8 @@ int __init c4iw_cm_init(void) TAILQ_INIT(&req_list); spin_lock_init(&req_lock); - INIT_LIST_HEAD(&timeout_list); - spin_lock_init(&timeout_lock); + INIT_LIST_HEAD(&err_cqe_list); + spin_lock_init(&err_cqe_lock); INIT_WORK(&c4iw_task, process_req); @@ -2541,7 +2549,7 @@ int __init c4iw_cm_init(void) void __exit c4iw_cm_term(void) { WARN_ON(!TAILQ_EMPTY(&req_list)); - WARN_ON(!list_empty(&timeout_list)); + WARN_ON(!list_empty(&err_cqe_list)); flush_workqueue(c4iw_taskq); destroy_workqueue(c4iw_taskq); Modified: stable/10/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h ============================================================================== --- stable/10/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h Wed Mar 29 02:20:07 2017 (r316122) +++ stable/10/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h Wed Mar 29 02:21:05 2017 (r316123) @@ -523,6 +523,14 @@ enum c4iw_qp_state { C4IW_QP_STATE_TOT }; +/* + * IW_CXGBE event bits. + * These bits are used for handling all events for a particular 'ep' serially. + */ +#define C4IW_EVENT_SOCKET 0x0001 +#define C4IW_EVENT_TIMEOUT 0x0002 +#define C4IW_EVENT_TERM 0x0004 + static inline int c4iw_convert_state(enum ib_qp_state ib_state) { switch (ib_state) { @@ -756,6 +764,7 @@ struct c4iw_ep_common { int rpl_done; struct thread *thread; struct socket *so; + int ep_events; }; struct c4iw_listen_ep { @@ -768,7 +777,6 @@ struct c4iw_ep { struct c4iw_ep_common com; struct c4iw_ep *parent_ep; struct timer_list timer; - struct list_head entry; unsigned int atid; u32 hwtid; u32 snd_seq; Modified: stable/10/sys/dev/cxgbe/t4_main.c ============================================================================== --- stable/10/sys/dev/cxgbe/t4_main.c Wed Mar 29 02:20:07 2017 (r316122) +++ stable/10/sys/dev/cxgbe/t4_main.c Wed Mar 29 02:21:05 2017 (r316123) @@ -7850,9 +7850,9 @@ sysctl_tp_timer(SYSCTL_HANDLER_ARGS) u_int cclk_ps = 1000000000 / sc->params.vpd.cclk; MPASS(reg == A_TP_RXT_MIN || reg == A_TP_RXT_MAX || - reg == A_TP_PERS_MIN || reg == A_TP_PERS_MAX || - reg == A_TP_KEEP_IDLE || A_TP_KEEP_INTVL || reg == A_TP_INIT_SRTT || - reg == A_TP_FINWAIT2_TIMER); + reg == A_TP_PERS_MIN || reg == A_TP_PERS_MAX || + reg == A_TP_KEEP_IDLE || reg == A_TP_KEEP_INTVL || + reg == A_TP_INIT_SRTT || reg == A_TP_FINWAIT2_TIMER); tre = G_TIMERRESOLUTION(t4_read_reg(sc, A_TP_TIMER_RESOLUTION)); tp_tick_us = (cclk_ps << tre) / 1000000;