Skip to content

Commit c3a910f

Browse files
Wen GuPaolo Abeni
authored andcommitted
net/smc: implement DMB-merged operations of loopback-ism
This implements operations related to merging sndbuf with peer DMB in loopback-ism. The DMB won't be freed until no sndbuf is attached to it. Signed-off-by: Wen Gu <guwen@linux.alibaba.com> Reviewed-by: Wenjia Zhang <wenjia@linux.ibm.com> Reviewed-and-tested-by: Jan Karcher <jaka@linux.ibm.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent cc0ab80 commit c3a910f

File tree

2 files changed

+108
-15
lines changed

2 files changed

+108
-15
lines changed

net/smc/smc_loopback.c

Lines changed: 105 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "smc_loopback.h"
2121

2222
#define SMC_LO_V2_CAPABLE 0x1 /* loopback-ism acts as ISMv2 */
23+
#define SMC_LO_SUPPORT_NOCOPY 0x1
2324
#define SMC_DMA_ADDR_INVALID (~(dma_addr_t)0)
2425

2526
static const char smc_lo_dev_name[] = "loopback-ism";
@@ -81,6 +82,7 @@ static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
8182
goto err_node;
8283
}
8384
dmb_node->dma_addr = SMC_DMA_ADDR_INVALID;
85+
refcount_set(&dmb_node->refcnt, 1);
8486

8587
again:
8688
/* add new dmb into hash table */
@@ -94,6 +96,7 @@ static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
9496
}
9597
hash_add(ldev->dmb_ht, &dmb_node->list, dmb_node->token);
9698
write_unlock_bh(&ldev->dmb_ht_lock);
99+
atomic_inc(&ldev->dmb_cnt);
97100

98101
dmb->sba_idx = dmb_node->sba_idx;
99102
dmb->dmb_tok = dmb_node->token;
@@ -110,30 +113,106 @@ static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
110113
return rc;
111114
}
112115

116+
static void __smc_lo_unregister_dmb(struct smc_lo_dev *ldev,
117+
struct smc_lo_dmb_node *dmb_node)
118+
{
119+
/* remove dmb from hash table */
120+
write_lock_bh(&ldev->dmb_ht_lock);
121+
hash_del(&dmb_node->list);
122+
write_unlock_bh(&ldev->dmb_ht_lock);
123+
124+
clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
125+
kvfree(dmb_node->cpu_addr);
126+
kfree(dmb_node);
127+
128+
if (atomic_dec_and_test(&ldev->dmb_cnt))
129+
wake_up(&ldev->ldev_release);
130+
}
131+
113132
static int smc_lo_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
114133
{
115134
struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node;
116135
struct smc_lo_dev *ldev = smcd->priv;
117136

118-
/* remove dmb from hash table */
119-
write_lock_bh(&ldev->dmb_ht_lock);
137+
/* find dmb from hash table */
138+
read_lock_bh(&ldev->dmb_ht_lock);
120139
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
121140
if (tmp_node->token == dmb->dmb_tok) {
122141
dmb_node = tmp_node;
123142
break;
124143
}
125144
}
126145
if (!dmb_node) {
127-
write_unlock_bh(&ldev->dmb_ht_lock);
146+
read_unlock_bh(&ldev->dmb_ht_lock);
128147
return -EINVAL;
129148
}
130-
hash_del(&dmb_node->list);
131-
write_unlock_bh(&ldev->dmb_ht_lock);
149+
read_unlock_bh(&ldev->dmb_ht_lock);
132150

133-
clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
134-
kfree(dmb_node->cpu_addr);
135-
kfree(dmb_node);
151+
if (refcount_dec_and_test(&dmb_node->refcnt))
152+
__smc_lo_unregister_dmb(ldev, dmb_node);
153+
return 0;
154+
}
155+
156+
static int smc_lo_support_dmb_nocopy(struct smcd_dev *smcd)
157+
{
158+
return SMC_LO_SUPPORT_NOCOPY;
159+
}
160+
161+
static int smc_lo_attach_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
162+
{
163+
struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node;
164+
struct smc_lo_dev *ldev = smcd->priv;
165+
166+
/* find dmb_node according to dmb->dmb_tok */
167+
read_lock_bh(&ldev->dmb_ht_lock);
168+
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
169+
if (tmp_node->token == dmb->dmb_tok) {
170+
dmb_node = tmp_node;
171+
break;
172+
}
173+
}
174+
if (!dmb_node) {
175+
read_unlock_bh(&ldev->dmb_ht_lock);
176+
return -EINVAL;
177+
}
178+
read_unlock_bh(&ldev->dmb_ht_lock);
179+
180+
if (!refcount_inc_not_zero(&dmb_node->refcnt))
181+
/* the dmb is being unregistered, but has
182+
* not been removed from the hash table.
183+
*/
184+
return -EINVAL;
136185

186+
/* provide dmb information */
187+
dmb->sba_idx = dmb_node->sba_idx;
188+
dmb->dmb_tok = dmb_node->token;
189+
dmb->cpu_addr = dmb_node->cpu_addr;
190+
dmb->dma_addr = dmb_node->dma_addr;
191+
dmb->dmb_len = dmb_node->len;
192+
return 0;
193+
}
194+
195+
static int smc_lo_detach_dmb(struct smcd_dev *smcd, u64 token)
196+
{
197+
struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node;
198+
struct smc_lo_dev *ldev = smcd->priv;
199+
200+
/* find dmb_node according to dmb->dmb_tok */
201+
read_lock_bh(&ldev->dmb_ht_lock);
202+
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
203+
if (tmp_node->token == token) {
204+
dmb_node = tmp_node;
205+
break;
206+
}
207+
}
208+
if (!dmb_node) {
209+
read_unlock_bh(&ldev->dmb_ht_lock);
210+
return -EINVAL;
211+
}
212+
read_unlock_bh(&ldev->dmb_ht_lock);
213+
214+
if (refcount_dec_and_test(&dmb_node->refcnt))
215+
__smc_lo_unregister_dmb(ldev, dmb_node);
137216
return 0;
138217
}
139218

@@ -145,6 +224,12 @@ static int smc_lo_move_data(struct smcd_dev *smcd, u64 dmb_tok,
145224
struct smc_lo_dev *ldev = smcd->priv;
146225
struct smc_connection *conn;
147226

227+
if (!sf)
228+
/* since sndbuf is merged with peer DMB, there is
229+
* no need to copy data from sndbuf to peer DMB.
230+
*/
231+
return 0;
232+
148233
read_lock_bh(&ldev->dmb_ht_lock);
149234
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_tok) {
150235
if (tmp_node->token == dmb_tok) {
@@ -159,13 +244,10 @@ static int smc_lo_move_data(struct smcd_dev *smcd, u64 dmb_tok,
159244
memcpy((char *)rmb_node->cpu_addr + offset, data, size);
160245
read_unlock_bh(&ldev->dmb_ht_lock);
161246

162-
if (sf) {
163-
conn = smcd->conn[rmb_node->sba_idx];
164-
if (conn && !conn->killed)
165-
tasklet_schedule(&conn->rx_tsklet);
166-
else
167-
return -EPIPE;
168-
}
247+
conn = smcd->conn[rmb_node->sba_idx];
248+
if (!conn || conn->killed)
249+
return -EPIPE;
250+
tasklet_schedule(&conn->rx_tsklet);
169251
return 0;
170252
}
171253

@@ -197,6 +279,9 @@ static const struct smcd_ops lo_ops = {
197279
.query_remote_gid = smc_lo_query_rgid,
198280
.register_dmb = smc_lo_register_dmb,
199281
.unregister_dmb = smc_lo_unregister_dmb,
282+
.support_dmb_nocopy = smc_lo_support_dmb_nocopy,
283+
.attach_dmb = smc_lo_attach_dmb,
284+
.detach_dmb = smc_lo_detach_dmb,
200285
.add_vlan_id = NULL,
201286
.del_vlan_id = NULL,
202287
.set_vlan_required = NULL,
@@ -275,12 +360,17 @@ static int smc_lo_dev_init(struct smc_lo_dev *ldev)
275360
smc_lo_generate_ids(ldev);
276361
rwlock_init(&ldev->dmb_ht_lock);
277362
hash_init(ldev->dmb_ht);
363+
atomic_set(&ldev->dmb_cnt, 0);
364+
init_waitqueue_head(&ldev->ldev_release);
365+
278366
return smcd_lo_register_dev(ldev);
279367
}
280368

281369
static void smc_lo_dev_exit(struct smc_lo_dev *ldev)
282370
{
283371
smcd_lo_unregister_dev(ldev);
372+
if (atomic_read(&ldev->dmb_cnt))
373+
wait_event(ldev->ldev_release, !atomic_read(&ldev->dmb_cnt));
284374
}
285375

286376
static void smc_lo_dev_release(struct device *dev)

net/smc/smc_loopback.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,19 @@ struct smc_lo_dmb_node {
3030
u32 sba_idx;
3131
void *cpu_addr;
3232
dma_addr_t dma_addr;
33+
refcount_t refcnt;
3334
};
3435

3536
struct smc_lo_dev {
3637
struct smcd_dev *smcd;
3738
struct device dev;
3839
u16 chid;
3940
struct smcd_gid local_gid;
41+
atomic_t dmb_cnt;
4042
rwlock_t dmb_ht_lock;
4143
DECLARE_BITMAP(sba_idx_mask, SMC_LO_MAX_DMBS);
4244
DECLARE_HASHTABLE(dmb_ht, SMC_LO_DMBS_HASH_BITS);
45+
wait_queue_head_t ldev_release;
4346
};
4447

4548
int smc_loopback_init(void);

0 commit comments

Comments
 (0)