Petr Tesarik 0cbe94
From: Petr Tesarik <ptesarik@suse.com>
Petr Tesarik 0cbe94
Subject: net/smc: kABI workarounds for struct smc_link
Petr Tesarik 0cbe94
Patch-mainline: Never, kABI workaround
Petr Tesarik 0cbe94
References: git-fixes
Petr Tesarik 0cbe94
Petr Tesarik 0cbe94
Commit e9b1a4f867ae9c1dbd1d71cd09cbdb3239fb4968 adds two new fields
Petr Tesarik 0cbe94
to struct smc_link, which breaks kABI. It is not possible to mask
Petr Tesarik 0cbe94
the change by moving the fields to the end of the structure, because
Petr Tesarik 0cbe94
struct smc_link itself is embedded in struct smc_link_group.
Petr Tesarik 0cbe94
Petr Tesarik 0cbe94
However, struct smc_link is never allocated outside of struct
Petr Tesarik 0cbe94
smc_link_group; it even contains its index in the lnk[] array
Petr Tesarik 0cbe94
(link_idx), so it is possible to move those fields to another array
Petr Tesarik 0cbe94
in struct smc_link_group, and use the backpointer plus the index
Petr Tesarik 0cbe94
to access the corresponding fields.
Petr Tesarik 0cbe94
Petr Tesarik 0cbe94
It is safe to enlarge struct smc_link_group, because it is only ever
Petr Tesarik 0cbe94
allocated by smc_lgr_create() and never embedded in another data
Petr Tesarik 0cbe94
structure.
Petr Tesarik 0cbe94
Petr Tesarik 0cbe94
Signed-off-by: Petr Tesarik <ptesarik@suse.com>
Petr Tesarik 0cbe94
---
Petr Tesarik 0cbe94
 net/smc/smc_core.c |    2 +-
Petr Tesarik 0cbe94
 net/smc/smc_core.h |   12 ++++++++++--
Petr Tesarik 0cbe94
 net/smc/smc_wr.c   |   10 ++++++----
Petr Tesarik 0cbe94
 net/smc/smc_wr.h   |    5 ++++-
Petr Tesarik 0cbe94
 4 files changed, 21 insertions(+), 8 deletions(-)
Petr Tesarik 0cbe94
Petr Tesarik 0cbe94
--- a/net/smc/smc_core.c
Petr Tesarik 0cbe94
+++ b/net/smc/smc_core.c
Petr Tesarik 0cbe94
@@ -750,7 +750,7 @@ int smcr_link_init(struct smc_link_group
Petr Tesarik 0cbe94
 	lnk->link_id = smcr_next_link_id(lgr);
Petr Tesarik 0cbe94
 	lnk->lgr = lgr;
Petr Tesarik 0cbe94
 	lnk->link_idx = link_idx;
Petr Tesarik 0cbe94
-	lnk->wr_rx_id_compl = 0;
Petr Tesarik 0cbe94
+	lgr->lnk_kabi_fixup[link_idx].wr_rx_id_compl = 0;
Petr Tesarik 0cbe94
 	smc_ibdev_cnt_inc(lnk);
Petr Tesarik 0cbe94
 	smcr_copy_dev_info_to_link(lnk);
Petr Tesarik 0cbe94
 	atomic_set(&lnk->conn_cnt, 0);
Petr Tesarik 0cbe94
--- a/net/smc/smc_core.h
Petr Tesarik 0cbe94
+++ b/net/smc/smc_core.h
Petr Tesarik 0cbe94
@@ -115,10 +115,8 @@ struct smc_link {
Petr Tesarik 0cbe94
 	dma_addr_t		wr_rx_dma_addr;	/* DMA address of wr_rx_bufs */
Petr Tesarik 0cbe94
 	dma_addr_t		wr_rx_v2_dma_addr; /* DMA address of v2 rx buf*/
Petr Tesarik 0cbe94
 	u64			wr_rx_id;	/* seq # of last recv WR */
Petr Tesarik 0cbe94
-	u64			wr_rx_id_compl; /* seq # of last completed WR */
Petr Tesarik 0cbe94
 	u32			wr_rx_cnt;	/* number of WR recv buffers */
Petr Tesarik 0cbe94
 	unsigned long		wr_rx_tstamp;	/* jiffies when last buf rx */
Petr Tesarik 0cbe94
-	wait_queue_head_t       wr_rx_empty_wait; /* wait for RQ empty */
Petr Tesarik 0cbe94
 
Petr Tesarik 0cbe94
 	struct ib_reg_wr	wr_reg;		/* WR register memory region */
Petr Tesarik 0cbe94
 	wait_queue_head_t	wr_reg_wait;	/* wait for wr_reg result */
Petr Tesarik 0cbe94
@@ -151,6 +149,12 @@ struct smc_link {
Petr Tesarik 0cbe94
 	atomic_t		conn_cnt; /* connections on this link */
Petr Tesarik 0cbe94
 };
Petr Tesarik 0cbe94
 
Petr Tesarik 0cbe94
+/* Extra fields removed from struct smc_link to preserve kABI. */
Petr Tesarik 0cbe94
+struct smc_link_kabi_fixup {
Petr Tesarik 0cbe94
+	u64			wr_rx_id_compl; /* seq # of last completed WR */
Petr Tesarik 0cbe94
+	wait_queue_head_t       wr_rx_empty_wait; /* wait for RQ empty */
Petr Tesarik 0cbe94
+};
Petr Tesarik 0cbe94
+
Petr Tesarik 0cbe94
 /* For now we just allow one parallel link per link group. The SMC protocol
Petr Tesarik 0cbe94
  * allows more (up to 8).
Petr Tesarik 0cbe94
  */
Petr Tesarik 0cbe94
@@ -308,6 +312,10 @@ struct smc_link_group {
Petr Tesarik 0cbe94
 			u8			nexthop_mac[ETH_ALEN];
Petr Tesarik 0cbe94
 			u8			uses_gateway;
Petr Tesarik 0cbe94
 			__be32			saddr;
Petr Tesarik 0cbe94
+#ifndef __GENKSYMS__
Petr Tesarik 0cbe94
+			struct smc_link_kabi_fixup lnk_kabi_fixup[SMC_LINKS_PER_LGR_MAX];
Petr Tesarik 0cbe94
+						/* extra lnk fields */
Petr Tesarik 0cbe94
+#endif
Petr Tesarik 0cbe94
 		};
Petr Tesarik 0cbe94
 		struct { /* SMC-D */
Petr Tesarik 0cbe94
 			u64			peer_gid;
Petr Tesarik 0cbe94
--- a/net/smc/smc_wr.c
Petr Tesarik 0cbe94
+++ b/net/smc/smc_wr.c
Petr Tesarik 0cbe94
@@ -454,11 +454,13 @@ static inline void smc_wr_rx_demultiplex
Petr Tesarik 0cbe94
 static inline void smc_wr_rx_process_cqes(struct ib_wc wc[], int num)
Petr Tesarik 0cbe94
 {
Petr Tesarik 0cbe94
 	struct smc_link *link;
Petr Tesarik 0cbe94
+	struct smc_link_kabi_fixup *link_kabi_fixup;
Petr Tesarik 0cbe94
 	int i;
Petr Tesarik 0cbe94
 
Petr Tesarik 0cbe94
 	for (i = 0; i < num; i++) {
Petr Tesarik 0cbe94
 		link = wc[i].qp->qp_context;
Petr Tesarik 0cbe94
-		link->wr_rx_id_compl = wc[i].wr_id;
Petr Tesarik 0cbe94
+		link_kabi_fixup = &link->lgr->lnk_kabi_fixup[link->link_idx];
Petr Tesarik 0cbe94
+		link_kabi_fixup->wr_rx_id_compl = wc[i].wr_id;
Petr Tesarik 0cbe94
 		if (wc[i].status == IB_WC_SUCCESS) {
Petr Tesarik 0cbe94
 			link->wr_rx_tstamp = jiffies;
Petr Tesarik 0cbe94
 			smc_wr_rx_demultiplex(&wc[i]);
Petr Tesarik 0cbe94
@@ -470,8 +472,8 @@ static inline void smc_wr_rx_process_cqe
Petr Tesarik 0cbe94
 			case IB_WC_RNR_RETRY_EXC_ERR:
Petr Tesarik 0cbe94
 			case IB_WC_WR_FLUSH_ERR:
Petr Tesarik 0cbe94
 				smcr_link_down_cond_sched(link);
Petr Tesarik 0cbe94
-				if (link->wr_rx_id_compl == link->wr_rx_id)
Petr Tesarik 0cbe94
-					wake_up(&link->wr_rx_empty_wait);
Petr Tesarik 0cbe94
+				if (link_kabi_fixup->wr_rx_id_compl == link->wr_rx_id)
Petr Tesarik 0cbe94
+					wake_up(&link_kabi_fixup->wr_rx_empty_wait);
Petr Tesarik 0cbe94
 				break;
Petr Tesarik 0cbe94
 			default:
Petr Tesarik 0cbe94
 				smc_wr_rx_post(link); /* refill WR RX */
Petr Tesarik 0cbe94
@@ -897,7 +899,7 @@ int smc_wr_create_link(struct smc_link *
Petr Tesarik 0cbe94
 	atomic_set(&lnk->wr_tx_refcnt, 0);
Petr Tesarik 0cbe94
 	init_waitqueue_head(&lnk->wr_reg_wait);
Petr Tesarik 0cbe94
 	atomic_set(&lnk->wr_reg_refcnt, 0);
Petr Tesarik 0cbe94
-	init_waitqueue_head(&lnk->wr_rx_empty_wait);
Petr Tesarik 0cbe94
+	init_waitqueue_head(&lnk->lgr->lnk_kabi_fixup[lnk->link_idx].wr_rx_empty_wait);
Petr Tesarik 0cbe94
 	return rc;
Petr Tesarik 0cbe94
 
Petr Tesarik 0cbe94
 dma_unmap:
Petr Tesarik 0cbe94
--- a/net/smc/smc_wr.h
Petr Tesarik 0cbe94
+++ b/net/smc/smc_wr.h
Petr Tesarik 0cbe94
@@ -75,7 +75,10 @@ static inline void smc_wr_tx_link_put(st
Petr Tesarik 0cbe94
 
Petr Tesarik 0cbe94
 static inline void smc_wr_drain_cq(struct smc_link *lnk)
Petr Tesarik 0cbe94
 {
Petr Tesarik 0cbe94
-	wait_event(lnk->wr_rx_empty_wait, lnk->wr_rx_id_compl == lnk->wr_rx_id);
Petr Tesarik 0cbe94
+	struct smc_link_kabi_fixup *lnk_fixup =
Petr Tesarik 0cbe94
+		&lnk->lgr->lnk_kabi_fixup[lnk->link_idx];
Petr Tesarik 0cbe94
+	wait_event(lnk_fixup->wr_rx_empty_wait,
Petr Tesarik 0cbe94
+		   lnk_fixup->wr_rx_id_compl == lnk->wr_rx_id);
Petr Tesarik 0cbe94
 }
Petr Tesarik 0cbe94
 
Petr Tesarik 0cbe94
 static inline void smc_wr_wakeup_tx_wait(struct smc_link *lnk)