diff options
Diffstat (limited to 'net/smc')
| -rw-r--r-- | net/smc/af_smc.c | 2 | ||||
| -rw-r--r-- | net/smc/smc_core.c | 35 | ||||
| -rw-r--r-- | net/smc/smc_core.h | 4 | ||||
| -rw-r--r-- | net/smc/smc_ib.c | 3 | ||||
| -rw-r--r-- | net/smc/smc_llc.c | 10 | ||||
| -rw-r--r-- | net/smc/smc_pnet.c | 3 | ||||
| -rw-r--r-- | net/smc/smc_tx.c | 18 | ||||
| -rw-r--r-- | net/smc/smc_wr.c | 10 | 
8 files changed, 56 insertions, 29 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 898389611ae8..c038efc23ce3 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -795,7 +795,7 @@ static int smc_connect_rdma(struct smc_sock *smc,  			reason_code = SMC_CLC_DECL_NOSRVLINK;  			goto connect_abort;  		} -		smc->conn.lnk = link; +		smc_switch_link_and_count(&smc->conn, link);  	}  	/* create send buffer and rmb */ diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c index cd0d7c908b2a..af227b65669e 100644 --- a/net/smc/smc_core.c +++ b/net/smc/smc_core.c @@ -917,8 +917,8 @@ static int smc_switch_cursor(struct smc_sock *smc, struct smc_cdc_tx_pend *pend,  	return rc;  } -static void smc_switch_link_and_count(struct smc_connection *conn, -				      struct smc_link *to_lnk) +void smc_switch_link_and_count(struct smc_connection *conn, +			       struct smc_link *to_lnk)  {  	atomic_dec(&conn->lnk->conn_cnt);  	conn->lnk = to_lnk; @@ -1752,21 +1752,30 @@ out:  	return rc;  } -/* convert the RMB size into the compressed notation - minimum 16K. +#define SMCD_DMBE_SIZES		6 /* 0 -> 16KB, 1 -> 32KB, .. 6 -> 1MB */ +#define SMCR_RMBE_SIZES		5 /* 0 -> 16KB, 1 -> 32KB, .. 5 -> 512KB */ + +/* convert the RMB size into the compressed notation (minimum 16K, see + * SMCD/R_DMBE_SIZES.   * In contrast to plain ilog2, this rounds towards the next power of 2,   * so the socket application gets at least its desired sndbuf / rcvbuf size.   */ -static u8 smc_compress_bufsize(int size) +static u8 smc_compress_bufsize(int size, bool is_smcd, bool is_rmb)  { +	const unsigned int max_scat = SG_MAX_SINGLE_ALLOC * PAGE_SIZE;  	u8 compressed;  	if (size <= SMC_BUF_MIN_SIZE)  		return 0; -	size = (size - 1) >> 14; -	compressed = ilog2(size) + 1; -	if (compressed >= SMC_RMBE_SIZES) -		compressed = SMC_RMBE_SIZES - 1; +	size = (size - 1) >> 14;  /* convert to 16K multiple */ +	compressed = min_t(u8, ilog2(size) + 1, +			   is_smcd ? SMCD_DMBE_SIZES : SMCR_RMBE_SIZES); + +	if (!is_smcd && is_rmb) +		/* RMBs are backed by & limited to max size of scatterlists */ +		compressed = min_t(u8, compressed, ilog2(max_scat >> 14)); +  	return compressed;  } @@ -1982,17 +1991,12 @@ out:  	return rc;  } -#define SMCD_DMBE_SIZES		6 /* 0 -> 16KB, 1 -> 32KB, .. 6 -> 1MB */ -  static struct smc_buf_desc *smcd_new_buf_create(struct smc_link_group *lgr,  						bool is_dmb, int bufsize)  {  	struct smc_buf_desc *buf_desc;  	int rc; -	if (smc_compress_bufsize(bufsize) > SMCD_DMBE_SIZES) -		return ERR_PTR(-EAGAIN); -  	/* try to alloc a new DMB */  	buf_desc = kzalloc(sizeof(*buf_desc), GFP_KERNEL);  	if (!buf_desc) @@ -2041,9 +2045,8 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb)  		/* use socket send buffer size (w/o overhead) as start value */  		sk_buf_size = smc->sk.sk_sndbuf / 2; -	for (bufsize_short = smc_compress_bufsize(sk_buf_size); +	for (bufsize_short = smc_compress_bufsize(sk_buf_size, is_smcd, is_rmb);  	     bufsize_short >= 0; bufsize_short--) { -  		if (is_rmb) {  			lock = &lgr->rmbs_lock;  			buf_list = &lgr->rmbs[bufsize_short]; @@ -2052,8 +2055,6 @@ static int __smc_buf_create(struct smc_sock *smc, bool is_smcd, bool is_rmb)  			buf_list = &lgr->sndbufs[bufsize_short];  		}  		bufsize = smc_uncompress_bufsize(bufsize_short); -		if ((1 << get_order(bufsize)) > SG_MAX_SINGLE_ALLOC) -			continue;  		/* check for reusable slot in the link group */  		buf_desc = smc_buf_get_slot(bufsize_short, lock, buf_list); diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h index 6d6fd1397c87..c043ecdca5c4 100644 --- a/net/smc/smc_core.h +++ b/net/smc/smc_core.h @@ -97,6 +97,7 @@ struct smc_link {  	unsigned long		*wr_tx_mask;	/* bit mask of used indexes */  	u32			wr_tx_cnt;	/* number of WR send buffers */  	wait_queue_head_t	wr_tx_wait;	/* wait for free WR send buf */ +	atomic_t		wr_tx_refcnt;	/* tx refs to link */  	struct smc_wr_buf	*wr_rx_bufs;	/* WR recv payload buffers */  	struct ib_recv_wr	*wr_rx_ibs;	/* WR recv meta data */ @@ -109,6 +110,7 @@ struct smc_link {  	struct ib_reg_wr	wr_reg;		/* WR register memory region */  	wait_queue_head_t	wr_reg_wait;	/* wait for wr_reg result */ +	atomic_t		wr_reg_refcnt;	/* reg refs to link */  	enum smc_wr_reg_state	wr_reg_state;	/* state of wr_reg request */  	u8			gid[SMC_GID_SIZE];/* gid matching used vlan id*/ @@ -444,6 +446,8 @@ void smc_core_exit(void);  int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk,  		   u8 link_idx, struct smc_init_info *ini);  void smcr_link_clear(struct smc_link *lnk, bool log); +void smc_switch_link_and_count(struct smc_connection *conn, +			       struct smc_link *to_lnk);  int smcr_buf_map_lgr(struct smc_link *lnk);  int smcr_buf_reg_lgr(struct smc_link *lnk);  void smcr_lgr_set_type(struct smc_link_group *lgr, enum smc_lgr_type new_type); diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c index 7d7ba0320d5a..a8845343d183 100644 --- a/net/smc/smc_ib.c +++ b/net/smc/smc_ib.c @@ -753,8 +753,7 @@ void smc_ib_ndev_change(struct net_device *ndev, unsigned long event)  			if (!libdev->ops.get_netdev)  				continue;  			lndev = libdev->ops.get_netdev(libdev, i + 1); -			if (lndev) -				dev_put(lndev); +			dev_put(lndev);  			if (lndev != ndev)  				continue;  			if (event == NETDEV_REGISTER) diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c index 273eaf1bfe49..2e7560eba981 100644 --- a/net/smc/smc_llc.c +++ b/net/smc/smc_llc.c @@ -888,6 +888,7 @@ int smc_llc_cli_add_link(struct smc_link *link, struct smc_llc_qentry *qentry)  	if (!rc)  		goto out;  out_clear_lnk: +	lnk_new->state = SMC_LNK_INACTIVE;  	smcr_link_clear(lnk_new, false);  out_reject:  	smc_llc_cli_add_link_reject(qentry); @@ -1184,6 +1185,7 @@ int smc_llc_srv_add_link(struct smc_link *link)  		goto out_err;  	return 0;  out_err: +	link_new->state = SMC_LNK_INACTIVE;  	smcr_link_clear(link_new, false);  	return rc;  } @@ -1286,10 +1288,8 @@ static void smc_llc_process_cli_delete_link(struct smc_link_group *lgr)  	del_llc->reason = 0;  	smc_llc_send_message(lnk, &qentry->msg); /* response */ -	if (smc_link_downing(&lnk_del->state)) { -		if (smc_switch_conns(lgr, lnk_del, false)) -			smc_wr_tx_wait_no_pending_sends(lnk_del); -	} +	if (smc_link_downing(&lnk_del->state)) +		smc_switch_conns(lgr, lnk_del, false);  	smcr_link_clear(lnk_del, true);  	active_links = smc_llc_active_link_count(lgr); @@ -1805,8 +1805,6 @@ void smc_llc_link_clear(struct smc_link *link, bool log)  				    link->smcibdev->ibdev->name, link->ibport);  	complete(&link->llc_testlink_resp);  	cancel_delayed_work_sync(&link->llc_testlink_wrk); -	smc_wr_wakeup_reg_wait(link); -	smc_wr_wakeup_tx_wait(link);  }  /* register a new rtoken at the remote peer (for all links) */ diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 6f6d33edb135..4a964e9190b0 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c @@ -394,8 +394,7 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,  	return 0;  out_put: -	if (ndev) -		dev_put(ndev); +	dev_put(ndev);  	return rc;  } diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index 289025cd545a..c79361dfcdfb 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c @@ -496,7 +496,7 @@ static int smc_tx_rdma_writes(struct smc_connection *conn,  /* Wakeup sndbuf consumers from any context (IRQ or process)   * since there is more data to transmit; usable snd_wnd as max transmit   */ -static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn) +static int _smcr_tx_sndbuf_nonempty(struct smc_connection *conn)  {  	struct smc_cdc_producer_flags *pflags = &conn->local_tx_ctrl.prod_flags;  	struct smc_link *link = conn->lnk; @@ -550,6 +550,22 @@ out_unlock:  	return rc;  } +static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn) +{ +	struct smc_link *link = conn->lnk; +	int rc = -ENOLINK; + +	if (!link) +		return rc; + +	atomic_inc(&link->wr_tx_refcnt); +	if (smc_link_usable(link)) +		rc = _smcr_tx_sndbuf_nonempty(conn); +	if (atomic_dec_and_test(&link->wr_tx_refcnt)) +		wake_up_all(&link->wr_tx_wait); +	return rc; +} +  static int smcd_tx_sndbuf_nonempty(struct smc_connection *conn)  {  	struct smc_cdc_producer_flags *pflags = &conn->local_tx_ctrl.prod_flags; diff --git a/net/smc/smc_wr.c b/net/smc/smc_wr.c index cbc73a7e4d59..a419e9af36b9 100644 --- a/net/smc/smc_wr.c +++ b/net/smc/smc_wr.c @@ -322,9 +322,12 @@ int smc_wr_reg_send(struct smc_link *link, struct ib_mr *mr)  	if (rc)  		return rc; +	atomic_inc(&link->wr_reg_refcnt);  	rc = wait_event_interruptible_timeout(link->wr_reg_wait,  					      (link->wr_reg_state != POSTED),  					      SMC_WR_REG_MR_WAIT_TIME); +	if (atomic_dec_and_test(&link->wr_reg_refcnt)) +		wake_up_all(&link->wr_reg_wait);  	if (!rc) {  		/* timeout - terminate link */  		smcr_link_down_cond_sched(link); @@ -566,10 +569,15 @@ void smc_wr_free_link(struct smc_link *lnk)  		return;  	ibdev = lnk->smcibdev->ibdev; +	smc_wr_wakeup_reg_wait(lnk); +	smc_wr_wakeup_tx_wait(lnk); +  	if (smc_wr_tx_wait_no_pending_sends(lnk))  		memset(lnk->wr_tx_mask, 0,  		       BITS_TO_LONGS(SMC_WR_BUF_CNT) *  						sizeof(*lnk->wr_tx_mask)); +	wait_event(lnk->wr_reg_wait, (!atomic_read(&lnk->wr_reg_refcnt))); +	wait_event(lnk->wr_tx_wait, (!atomic_read(&lnk->wr_tx_refcnt)));  	if (lnk->wr_rx_dma_addr) {  		ib_dma_unmap_single(ibdev, lnk->wr_rx_dma_addr, @@ -728,7 +736,9 @@ int smc_wr_create_link(struct smc_link *lnk)  	memset(lnk->wr_tx_mask, 0,  	       BITS_TO_LONGS(SMC_WR_BUF_CNT) * sizeof(*lnk->wr_tx_mask));  	init_waitqueue_head(&lnk->wr_tx_wait); +	atomic_set(&lnk->wr_tx_refcnt, 0);  	init_waitqueue_head(&lnk->wr_reg_wait); +	atomic_set(&lnk->wr_reg_refcnt, 0);  	return rc;  dma_unmap:  |