Blame view

net/rds/ib_rdma.c 16.2 KB
08b48a1ed   Andy Grover   RDS/IB: Implement...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  /*
   * Copyright (c) 2006 Oracle.  All rights reserved.
   *
   * This software is available to you under a choice of one of two
   * licenses.  You may choose to be licensed under the terms of the GNU
   * General Public License (GPL) Version 2, available from the file
   * COPYING in the main directory of this source tree, or the
   * OpenIB.org BSD license below:
   *
   *     Redistribution and use in source and binary forms, with or
   *     without modification, are permitted provided that the following
   *     conditions are met:
   *
   *      - Redistributions of source code must retain the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer.
   *
   *      - Redistributions in binary form must reproduce the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer in the documentation and/or other materials
   *        provided with the distribution.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   *
   */
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
34
  #include <linux/slab.h>
764f2dd92   Chris Mason   rds: rcu-ize rds_...
35
  #include <linux/rculist.h>
1bc144b62   Huang Ying   net, rds, Replace...
36
  #include <linux/llist.h>
08b48a1ed   Andy Grover   RDS/IB: Implement...
37

0cb43965d   Sowmini Varadhan   RDS: split out co...
38
  #include "rds_single_path.h"
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
39
40
41
  #include "ib_mr.h"
  
  struct workqueue_struct *rds_ib_mr_wq;
08b48a1ed   Andy Grover   RDS/IB: Implement...
42

6fa70da60   Chris Mason   rds: recycle FMRs...
43
44
  static DEFINE_PER_CPU(unsigned long, clean_list_grace);
  #define CLEAN_LIST_BUSY_BIT 0
08b48a1ed   Andy Grover   RDS/IB: Implement...
45

08b48a1ed   Andy Grover   RDS/IB: Implement...
46
47
48
49
  static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
  {
  	struct rds_ib_device *rds_ibdev;
  	struct rds_ib_ipaddr *i_ipaddr;
ea819867b   Zach Brown   RDS/IB: protect t...
50
51
  	rcu_read_lock();
  	list_for_each_entry_rcu(rds_ibdev, &rds_ib_devices, list) {
764f2dd92   Chris Mason   rds: rcu-ize rds_...
52
  		list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
08b48a1ed   Andy Grover   RDS/IB: Implement...
53
  			if (i_ipaddr->ipaddr == ipaddr) {
50d61ff78   Reshetova, Elena   net, rds: convert...
54
  				refcount_inc(&rds_ibdev->refcount);
764f2dd92   Chris Mason   rds: rcu-ize rds_...
55
  				rcu_read_unlock();
08b48a1ed   Andy Grover   RDS/IB: Implement...
56
57
58
  				return rds_ibdev;
  			}
  		}
08b48a1ed   Andy Grover   RDS/IB: Implement...
59
  	}
ea819867b   Zach Brown   RDS/IB: protect t...
60
  	rcu_read_unlock();
08b48a1ed   Andy Grover   RDS/IB: Implement...
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  
  	return NULL;
  }
  
  static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
  {
  	struct rds_ib_ipaddr *i_ipaddr;
  
  	i_ipaddr = kmalloc(sizeof *i_ipaddr, GFP_KERNEL);
  	if (!i_ipaddr)
  		return -ENOMEM;
  
  	i_ipaddr->ipaddr = ipaddr;
  
  	spin_lock_irq(&rds_ibdev->spinlock);
764f2dd92   Chris Mason   rds: rcu-ize rds_...
76
  	list_add_tail_rcu(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
08b48a1ed   Andy Grover   RDS/IB: Implement...
77
78
79
80
81
82
83
  	spin_unlock_irq(&rds_ibdev->spinlock);
  
  	return 0;
  }
  
  static void rds_ib_remove_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
  {
4a81802b5   Andy Grover   RDS/IB: Remove un...
84
  	struct rds_ib_ipaddr *i_ipaddr;
764f2dd92   Chris Mason   rds: rcu-ize rds_...
85
  	struct rds_ib_ipaddr *to_free = NULL;
08b48a1ed   Andy Grover   RDS/IB: Implement...
86
87
  
  	spin_lock_irq(&rds_ibdev->spinlock);
764f2dd92   Chris Mason   rds: rcu-ize rds_...
88
  	list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
08b48a1ed   Andy Grover   RDS/IB: Implement...
89
  		if (i_ipaddr->ipaddr == ipaddr) {
764f2dd92   Chris Mason   rds: rcu-ize rds_...
90
91
  			list_del_rcu(&i_ipaddr->list);
  			to_free = i_ipaddr;
08b48a1ed   Andy Grover   RDS/IB: Implement...
92
93
94
95
  			break;
  		}
  	}
  	spin_unlock_irq(&rds_ibdev->spinlock);
764f2dd92   Chris Mason   rds: rcu-ize rds_...
96

59fe46067   Santosh Shilimkar   RDS: use kfree_rc...
97
98
  	if (to_free)
  		kfree_rcu(to_free, rcu);
08b48a1ed   Andy Grover   RDS/IB: Implement...
99
100
101
102
103
104
105
  }
  
  int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
  {
  	struct rds_ib_device *rds_ibdev_old;
  
  	rds_ibdev_old = rds_ib_get_device(ipaddr);
e1f475a73   santosh.shilimkar@oracle.com   RDS: don't update...
106
107
108
109
  	if (!rds_ibdev_old)
  		return rds_ib_add_ipaddr(rds_ibdev, ipaddr);
  
  	if (rds_ibdev_old != rds_ibdev) {
08b48a1ed   Andy Grover   RDS/IB: Implement...
110
  		rds_ib_remove_ipaddr(rds_ibdev_old, ipaddr);
3e0249f9c   Zach Brown   RDS/IB: add refco...
111
  		rds_ib_dev_put(rds_ibdev_old);
e1f475a73   santosh.shilimkar@oracle.com   RDS: don't update...
112
  		return rds_ib_add_ipaddr(rds_ibdev, ipaddr);
3e0249f9c   Zach Brown   RDS/IB: add refco...
113
  	}
e1f475a73   santosh.shilimkar@oracle.com   RDS: don't update...
114
  	rds_ib_dev_put(rds_ibdev_old);
08b48a1ed   Andy Grover   RDS/IB: Implement...
115

e1f475a73   santosh.shilimkar@oracle.com   RDS: don't update...
116
  	return 0;
08b48a1ed   Andy Grover   RDS/IB: Implement...
117
  }
745cbccac   Andy Grover   RDS: Rewrite conn...
118
  void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
08b48a1ed   Andy Grover   RDS/IB: Implement...
119
120
121
122
123
124
125
126
  {
  	struct rds_ib_connection *ic = conn->c_transport_data;
  
  	/* conn was previously on the nodev_conns_list */
  	spin_lock_irq(&ib_nodev_conns_lock);
  	BUG_ON(list_empty(&ib_nodev_conns));
  	BUG_ON(list_empty(&ic->ib_node));
  	list_del(&ic->ib_node);
08b48a1ed   Andy Grover   RDS/IB: Implement...
127

aef3ea33e   Dan Carpenter   rds: spin_lock_ir...
128
  	spin_lock(&rds_ibdev->spinlock);
08b48a1ed   Andy Grover   RDS/IB: Implement...
129
  	list_add_tail(&ic->ib_node, &rds_ibdev->conn_list);
aef3ea33e   Dan Carpenter   rds: spin_lock_ir...
130
  	spin_unlock(&rds_ibdev->spinlock);
745cbccac   Andy Grover   RDS: Rewrite conn...
131
  	spin_unlock_irq(&ib_nodev_conns_lock);
08b48a1ed   Andy Grover   RDS/IB: Implement...
132
133
  
  	ic->rds_ibdev = rds_ibdev;
50d61ff78   Reshetova, Elena   net, rds: convert...
134
  	refcount_inc(&rds_ibdev->refcount);
08b48a1ed   Andy Grover   RDS/IB: Implement...
135
  }
745cbccac   Andy Grover   RDS: Rewrite conn...
136
  void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
08b48a1ed   Andy Grover   RDS/IB: Implement...
137
  {
745cbccac   Andy Grover   RDS: Rewrite conn...
138
  	struct rds_ib_connection *ic = conn->c_transport_data;
08b48a1ed   Andy Grover   RDS/IB: Implement...
139

745cbccac   Andy Grover   RDS: Rewrite conn...
140
141
  	/* place conn on nodev_conns_list */
  	spin_lock(&ib_nodev_conns_lock);
08b48a1ed   Andy Grover   RDS/IB: Implement...
142

745cbccac   Andy Grover   RDS: Rewrite conn...
143
144
145
146
147
148
149
150
151
152
  	spin_lock_irq(&rds_ibdev->spinlock);
  	BUG_ON(list_empty(&ic->ib_node));
  	list_del(&ic->ib_node);
  	spin_unlock_irq(&rds_ibdev->spinlock);
  
  	list_add_tail(&ic->ib_node, &ib_nodev_conns);
  
  	spin_unlock(&ib_nodev_conns_lock);
  
  	ic->rds_ibdev = NULL;
3e0249f9c   Zach Brown   RDS/IB: add refco...
153
  	rds_ib_dev_put(rds_ibdev);
08b48a1ed   Andy Grover   RDS/IB: Implement...
154
  }
8aeb1ba66   Zach Brown   RDS/IB: destroy c...
155
  void rds_ib_destroy_nodev_conns(void)
08b48a1ed   Andy Grover   RDS/IB: Implement...
156
157
158
159
160
  {
  	struct rds_ib_connection *ic, *_ic;
  	LIST_HEAD(tmp_list);
  
  	/* avoid calling conn_destroy with irqs off */
8aeb1ba66   Zach Brown   RDS/IB: destroy c...
161
162
163
  	spin_lock_irq(&ib_nodev_conns_lock);
  	list_splice(&ib_nodev_conns, &tmp_list);
  	spin_unlock_irq(&ib_nodev_conns_lock);
08b48a1ed   Andy Grover   RDS/IB: Implement...
164

433d308dd   Andy Grover   RDS: Fix panic on...
165
  	list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node)
08b48a1ed   Andy Grover   RDS/IB: Implement...
166
  		rds_conn_destroy(ic->conn);
08b48a1ed   Andy Grover   RDS/IB: Implement...
167
  }
08b48a1ed   Andy Grover   RDS/IB: Implement...
168
169
  void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo)
  {
067665132   Santosh Shilimkar   RDS: IB: split mr...
170
  	struct rds_ib_mr_pool *pool_1m = rds_ibdev->mr_1m_pool;
08b48a1ed   Andy Grover   RDS/IB: Implement...
171

067665132   Santosh Shilimkar   RDS: IB: split mr...
172
173
  	iinfo->rdma_mr_max = pool_1m->max_items;
  	iinfo->rdma_mr_size = pool_1m->fmr_attr.max_pages;
08b48a1ed   Andy Grover   RDS/IB: Implement...
174
  }
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
175
  struct rds_ib_mr *rds_ib_reuse_mr(struct rds_ib_mr_pool *pool)
08b48a1ed   Andy Grover   RDS/IB: Implement...
176
177
  {
  	struct rds_ib_mr *ibmr = NULL;
1bc144b62   Huang Ying   net, rds, Replace...
178
  	struct llist_node *ret;
6fa70da60   Chris Mason   rds: recycle FMRs...
179
  	unsigned long *flag;
08b48a1ed   Andy Grover   RDS/IB: Implement...
180

6fa70da60   Chris Mason   rds: recycle FMRs...
181
  	preempt_disable();
903ceff7c   Christoph Lameter   net: Replace get_...
182
  	flag = this_cpu_ptr(&clean_list_grace);
6fa70da60   Chris Mason   rds: recycle FMRs...
183
  	set_bit(CLEAN_LIST_BUSY_BIT, flag);
1bc144b62   Huang Ying   net, rds, Replace...
184
  	ret = llist_del_first(&pool->clean_list);
db42753ad   santosh.shilimkar@oracle.com   RDS: IB: add mr r...
185
  	if (ret) {
1bc144b62   Huang Ying   net, rds, Replace...
186
  		ibmr = llist_entry(ret, struct rds_ib_mr, llnode);
db42753ad   santosh.shilimkar@oracle.com   RDS: IB: add mr r...
187
188
189
190
191
  		if (pool->pool_type == RDS_IB_MR_8K_POOL)
  			rds_ib_stats_inc(s_ib_rdma_mr_8k_reused);
  		else
  			rds_ib_stats_inc(s_ib_rdma_mr_1m_reused);
  	}
08b48a1ed   Andy Grover   RDS/IB: Implement...
192

6fa70da60   Chris Mason   rds: recycle FMRs...
193
194
  	clear_bit(CLEAN_LIST_BUSY_BIT, flag);
  	preempt_enable();
08b48a1ed   Andy Grover   RDS/IB: Implement...
195
196
  	return ibmr;
  }
6fa70da60   Chris Mason   rds: recycle FMRs...
197
198
199
200
201
202
203
204
205
206
207
  static inline void wait_clean_list_grace(void)
  {
  	int cpu;
  	unsigned long *flag;
  
  	for_each_online_cpu(cpu) {
  		flag = &per_cpu(clean_list_grace, cpu);
  		while (test_bit(CLEAN_LIST_BUSY_BIT, flag))
  			cpu_relax();
  	}
  }
08b48a1ed   Andy Grover   RDS/IB: Implement...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  void rds_ib_sync_mr(void *trans_private, int direction)
  {
  	struct rds_ib_mr *ibmr = trans_private;
  	struct rds_ib_device *rds_ibdev = ibmr->device;
  
  	switch (direction) {
  	case DMA_FROM_DEVICE:
  		ib_dma_sync_sg_for_cpu(rds_ibdev->dev, ibmr->sg,
  			ibmr->sg_dma_len, DMA_BIDIRECTIONAL);
  		break;
  	case DMA_TO_DEVICE:
  		ib_dma_sync_sg_for_device(rds_ibdev->dev, ibmr->sg,
  			ibmr->sg_dma_len, DMA_BIDIRECTIONAL);
  		break;
  	}
  }
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
224
  void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
08b48a1ed   Andy Grover   RDS/IB: Implement...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  {
  	struct rds_ib_device *rds_ibdev = ibmr->device;
  
  	if (ibmr->sg_dma_len) {
  		ib_dma_unmap_sg(rds_ibdev->dev,
  				ibmr->sg, ibmr->sg_len,
  				DMA_BIDIRECTIONAL);
  		ibmr->sg_dma_len = 0;
  	}
  
  	/* Release the s/g list */
  	if (ibmr->sg_len) {
  		unsigned int i;
  
  		for (i = 0; i < ibmr->sg_len; ++i) {
  			struct page *page = sg_page(&ibmr->sg[i]);
  
  			/* FIXME we need a way to tell a r/w MR
  			 * from a r/o MR */
5c240fa2a   santosh.shilimkar@oracle.com   RDS: Fix assertio...
244
  			WARN_ON(!page->mapping && irqs_disabled());
08b48a1ed   Andy Grover   RDS/IB: Implement...
245
246
247
248
249
250
251
252
253
  			set_page_dirty(page);
  			put_page(page);
  		}
  		kfree(ibmr->sg);
  
  		ibmr->sg = NULL;
  		ibmr->sg_len = 0;
  	}
  }
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
254
  void rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
08b48a1ed   Andy Grover   RDS/IB: Implement...
255
256
257
258
259
  {
  	unsigned int pinned = ibmr->sg_len;
  
  	__rds_ib_teardown_mr(ibmr);
  	if (pinned) {
26139dc1d   Santosh Shilimkar   RDS: IB: use alre...
260
  		struct rds_ib_mr_pool *pool = ibmr->pool;
08b48a1ed   Andy Grover   RDS/IB: Implement...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  
  		atomic_sub(pinned, &pool->free_pinned);
  	}
  }
  
  static inline unsigned int rds_ib_flush_goal(struct rds_ib_mr_pool *pool, int free_all)
  {
  	unsigned int item_count;
  
  	item_count = atomic_read(&pool->item_count);
  	if (free_all)
  		return item_count;
  
  	return 0;
  }
  
  /*
1bc144b62   Huang Ying   net, rds, Replace...
278
   * given an llist of mrs, put them all into the list_head for more processing
6fa70da60   Chris Mason   rds: recycle FMRs...
279
   */
6116c2030   Wengang Wang   RDS: fix fmr pool...
280
281
  static unsigned int llist_append_to_list(struct llist_head *llist,
  					 struct list_head *list)
6fa70da60   Chris Mason   rds: recycle FMRs...
282
283
  {
  	struct rds_ib_mr *ibmr;
1bc144b62   Huang Ying   net, rds, Replace...
284
285
  	struct llist_node *node;
  	struct llist_node *next;
6116c2030   Wengang Wang   RDS: fix fmr pool...
286
  	unsigned int count = 0;
1bc144b62   Huang Ying   net, rds, Replace...
287
288
289
290
291
  
  	node = llist_del_all(llist);
  	while (node) {
  		next = node->next;
  		ibmr = llist_entry(node, struct rds_ib_mr, llnode);
6fa70da60   Chris Mason   rds: recycle FMRs...
292
  		list_add_tail(&ibmr->unmap_list, list);
1bc144b62   Huang Ying   net, rds, Replace...
293
  		node = next;
6116c2030   Wengang Wang   RDS: fix fmr pool...
294
  		count++;
6fa70da60   Chris Mason   rds: recycle FMRs...
295
  	}
6116c2030   Wengang Wang   RDS: fix fmr pool...
296
  	return count;
6fa70da60   Chris Mason   rds: recycle FMRs...
297
298
299
  }
  
  /*
1bc144b62   Huang Ying   net, rds, Replace...
300
301
302
   * this takes a list head of mrs and turns it into linked llist nodes
   * of clusters.  Each cluster has linked llist nodes of
   * MR_CLUSTER_SIZE mrs that are ready for reuse.
6fa70da60   Chris Mason   rds: recycle FMRs...
303
   */
1bc144b62   Huang Ying   net, rds, Replace...
304
305
306
307
  static void list_to_llist_nodes(struct rds_ib_mr_pool *pool,
  				struct list_head *list,
  				struct llist_node **nodes_head,
  				struct llist_node **nodes_tail)
6fa70da60   Chris Mason   rds: recycle FMRs...
308
309
  {
  	struct rds_ib_mr *ibmr;
1bc144b62   Huang Ying   net, rds, Replace...
310
311
  	struct llist_node *cur = NULL;
  	struct llist_node **next = nodes_head;
6fa70da60   Chris Mason   rds: recycle FMRs...
312
313
  
  	list_for_each_entry(ibmr, list, unmap_list) {
1bc144b62   Huang Ying   net, rds, Replace...
314
315
316
  		cur = &ibmr->llnode;
  		*next = cur;
  		next = &cur->next;
6fa70da60   Chris Mason   rds: recycle FMRs...
317
  	}
1bc144b62   Huang Ying   net, rds, Replace...
318
319
  	*next = NULL;
  	*nodes_tail = cur;
6fa70da60   Chris Mason   rds: recycle FMRs...
320
321
322
  }
  
  /*
08b48a1ed   Andy Grover   RDS/IB: Implement...
323
324
325
326
327
   * Flush our pool of MRs.
   * At a minimum, all currently unused MRs are unmapped.
   * If the number of MRs allocated exceeds the limit, we also try
   * to free as many MRs as needed to get back to this limit.
   */
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
328
329
  int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
  			 int free_all, struct rds_ib_mr **ibmr_ret)
08b48a1ed   Andy Grover   RDS/IB: Implement...
330
  {
490ea5967   santosh.shilimkar@oracle.com   RDS: IB: move FMR...
331
  	struct rds_ib_mr *ibmr;
1bc144b62   Huang Ying   net, rds, Replace...
332
333
  	struct llist_node *clean_nodes;
  	struct llist_node *clean_tail;
08b48a1ed   Andy Grover   RDS/IB: Implement...
334
  	LIST_HEAD(unmap_list);
08b48a1ed   Andy Grover   RDS/IB: Implement...
335
  	unsigned long unpinned = 0;
6116c2030   Wengang Wang   RDS: fix fmr pool...
336
  	unsigned int nfreed = 0, dirty_to_clean = 0, free_goal;
08b48a1ed   Andy Grover   RDS/IB: Implement...
337

067665132   Santosh Shilimkar   RDS: IB: split mr...
338
339
340
341
  	if (pool->pool_type == RDS_IB_MR_8K_POOL)
  		rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_flush);
  	else
  		rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_flush);
08b48a1ed   Andy Grover   RDS/IB: Implement...
342

6fa70da60   Chris Mason   rds: recycle FMRs...
343
344
  	if (ibmr_ret) {
  		DEFINE_WAIT(wait);
067665132   Santosh Shilimkar   RDS: IB: split mr...
345
  		while (!mutex_trylock(&pool->flush_lock)) {
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
346
  			ibmr = rds_ib_reuse_mr(pool);
6fa70da60   Chris Mason   rds: recycle FMRs...
347
348
349
350
351
352
353
354
  			if (ibmr) {
  				*ibmr_ret = ibmr;
  				finish_wait(&pool->flush_wait, &wait);
  				goto out_nolock;
  			}
  
  			prepare_to_wait(&pool->flush_wait, &wait,
  					TASK_UNINTERRUPTIBLE);
1bc144b62   Huang Ying   net, rds, Replace...
355
  			if (llist_empty(&pool->clean_list))
6fa70da60   Chris Mason   rds: recycle FMRs...
356
  				schedule();
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
357
  			ibmr = rds_ib_reuse_mr(pool);
6fa70da60   Chris Mason   rds: recycle FMRs...
358
359
360
361
362
363
364
365
366
367
368
  			if (ibmr) {
  				*ibmr_ret = ibmr;
  				finish_wait(&pool->flush_wait, &wait);
  				goto out_nolock;
  			}
  		}
  		finish_wait(&pool->flush_wait, &wait);
  	} else
  		mutex_lock(&pool->flush_lock);
  
  	if (ibmr_ret) {
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
369
  		ibmr = rds_ib_reuse_mr(pool);
6fa70da60   Chris Mason   rds: recycle FMRs...
370
371
372
373
374
  		if (ibmr) {
  			*ibmr_ret = ibmr;
  			goto out;
  		}
  	}
08b48a1ed   Andy Grover   RDS/IB: Implement...
375

08b48a1ed   Andy Grover   RDS/IB: Implement...
376
  	/* Get the list of all MRs to be dropped. Ordering matters -
6fa70da60   Chris Mason   rds: recycle FMRs...
377
378
  	 * we want to put drop_list ahead of free_list.
  	 */
6116c2030   Wengang Wang   RDS: fix fmr pool...
379
380
  	dirty_to_clean = llist_append_to_list(&pool->drop_list, &unmap_list);
  	dirty_to_clean += llist_append_to_list(&pool->free_list, &unmap_list);
08b48a1ed   Andy Grover   RDS/IB: Implement...
381
  	if (free_all)
1bc144b62   Huang Ying   net, rds, Replace...
382
  		llist_append_to_list(&pool->clean_list, &unmap_list);
08b48a1ed   Andy Grover   RDS/IB: Implement...
383
384
385
386
387
  
  	free_goal = rds_ib_flush_goal(pool, free_all);
  
  	if (list_empty(&unmap_list))
  		goto out;
1659185fb   Avinash Repaka   RDS: IB: Support ...
388
389
390
391
  	if (pool->use_fastreg)
  		rds_ib_unreg_frmr(&unmap_list, &nfreed, &unpinned, free_goal);
  	else
  		rds_ib_unreg_fmr(&unmap_list, &nfreed, &unpinned, free_goal);
08b48a1ed   Andy Grover   RDS/IB: Implement...
392

6fa70da60   Chris Mason   rds: recycle FMRs...
393
394
395
  	if (!list_empty(&unmap_list)) {
  		/* we have to make sure that none of the things we're about
  		 * to put on the clean list would race with other cpus trying
1bc144b62   Huang Ying   net, rds, Replace...
396
  		 * to pull items off.  The llist would explode if we managed to
6fa70da60   Chris Mason   rds: recycle FMRs...
397
  		 * remove something from the clean list and then add it back again
1bc144b62   Huang Ying   net, rds, Replace...
398
  		 * while another CPU was spinning on that same item in llist_del_first.
6fa70da60   Chris Mason   rds: recycle FMRs...
399
  		 *
1bc144b62   Huang Ying   net, rds, Replace...
400
  		 * This is pretty unlikely, but just in case  wait for an llist grace period
6fa70da60   Chris Mason   rds: recycle FMRs...
401
402
403
  		 * here before adding anything back into the clean list.
  		 */
  		wait_clean_list_grace();
1bc144b62   Huang Ying   net, rds, Replace...
404
  		list_to_llist_nodes(pool, &unmap_list, &clean_nodes, &clean_tail);
6fa70da60   Chris Mason   rds: recycle FMRs...
405
  		if (ibmr_ret)
1bc144b62   Huang Ying   net, rds, Replace...
406
  			*ibmr_ret = llist_entry(clean_nodes, struct rds_ib_mr, llnode);
6fa70da60   Chris Mason   rds: recycle FMRs...
407

1bc144b62   Huang Ying   net, rds, Replace...
408
409
410
  		/* more than one entry in llist nodes */
  		if (clean_nodes->next)
  			llist_add_batch(clean_nodes->next, clean_tail, &pool->clean_list);
6fa70da60   Chris Mason   rds: recycle FMRs...
411
412
  
  	}
08b48a1ed   Andy Grover   RDS/IB: Implement...
413
414
  
  	atomic_sub(unpinned, &pool->free_pinned);
6116c2030   Wengang Wang   RDS: fix fmr pool...
415
  	atomic_sub(dirty_to_clean, &pool->dirty_count);
08b48a1ed   Andy Grover   RDS/IB: Implement...
416
417
418
419
  	atomic_sub(nfreed, &pool->item_count);
  
  out:
  	mutex_unlock(&pool->flush_lock);
6fa70da60   Chris Mason   rds: recycle FMRs...
420
421
422
  	if (waitqueue_active(&pool->flush_wait))
  		wake_up(&pool->flush_wait);
  out_nolock:
490ea5967   santosh.shilimkar@oracle.com   RDS: IB: move FMR...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
  	return 0;
  }
  
  struct rds_ib_mr *rds_ib_try_reuse_ibmr(struct rds_ib_mr_pool *pool)
  {
  	struct rds_ib_mr *ibmr = NULL;
  	int iter = 0;
  
  	if (atomic_read(&pool->dirty_count) >= pool->max_items_soft / 10)
  		queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10);
  
  	while (1) {
  		ibmr = rds_ib_reuse_mr(pool);
  		if (ibmr)
  			return ibmr;
  
  		if (atomic_inc_return(&pool->item_count) <= pool->max_items)
  			break;
  
  		atomic_dec(&pool->item_count);
  
  		if (++iter > 2) {
  			if (pool->pool_type == RDS_IB_MR_8K_POOL)
  				rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_depleted);
  			else
  				rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_depleted);
  			return ERR_PTR(-EAGAIN);
  		}
  
  		/* We do have some empty MRs. Flush them out. */
  		if (pool->pool_type == RDS_IB_MR_8K_POOL)
  			rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_wait);
  		else
  			rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_wait);
  
  		rds_ib_flush_mr_pool(pool, 0, &ibmr);
  		if (ibmr)
  			return ibmr;
  	}
  
  	return ibmr;
08b48a1ed   Andy Grover   RDS/IB: Implement...
464
465
466
467
  }
  
  static void rds_ib_mr_pool_flush_worker(struct work_struct *work)
  {
7a0ff5dbd   Chris Mason   RDS: use delayed ...
468
  	struct rds_ib_mr_pool *pool = container_of(work, struct rds_ib_mr_pool, flush_worker.work);
08b48a1ed   Andy Grover   RDS/IB: Implement...
469

6fa70da60   Chris Mason   rds: recycle FMRs...
470
  	rds_ib_flush_mr_pool(pool, 0, NULL);
08b48a1ed   Andy Grover   RDS/IB: Implement...
471
472
473
474
475
  }
  
  void rds_ib_free_mr(void *trans_private, int invalidate)
  {
  	struct rds_ib_mr *ibmr = trans_private;
26139dc1d   Santosh Shilimkar   RDS: IB: use alre...
476
  	struct rds_ib_mr_pool *pool = ibmr->pool;
08b48a1ed   Andy Grover   RDS/IB: Implement...
477
  	struct rds_ib_device *rds_ibdev = ibmr->device;
08b48a1ed   Andy Grover   RDS/IB: Implement...
478
479
480
481
482
  
  	rdsdebug("RDS/IB: free_mr nents %u
  ", ibmr->sg_len);
  
  	/* Return it to the pool's free list */
1659185fb   Avinash Repaka   RDS: IB: Support ...
483
484
485
486
  	if (rds_ibdev->use_fastreg)
  		rds_ib_free_frmr_list(ibmr);
  	else
  		rds_ib_free_fmr_list(ibmr);
08b48a1ed   Andy Grover   RDS/IB: Implement...
487
488
489
  
  	atomic_add(ibmr->sg_len, &pool->free_pinned);
  	atomic_inc(&pool->dirty_count);
08b48a1ed   Andy Grover   RDS/IB: Implement...
490
491
  
  	/* If we've pinned too many pages, request a flush */
f64f9e719   Joe Perches   net: Move && and ...
492
  	if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
ef5217a6e   santosh.shilimkar@oracle.com   RDS: flush the FM...
493
  	    atomic_read(&pool->dirty_count) >= pool->max_items / 5)
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
494
  		queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10);
08b48a1ed   Andy Grover   RDS/IB: Implement...
495
496
497
  
  	if (invalidate) {
  		if (likely(!in_interrupt())) {
6fa70da60   Chris Mason   rds: recycle FMRs...
498
  			rds_ib_flush_mr_pool(pool, 0, NULL);
08b48a1ed   Andy Grover   RDS/IB: Implement...
499
500
  		} else {
  			/* We get here if the user created a MR marked
ad1d7dc0d   santosh.shilimkar@oracle.com   RDS: push FMR poo...
501
502
  			 * as use_once and invalidate at the same time.
  			 */
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
503
  			queue_delayed_work(rds_ib_mr_wq,
ad1d7dc0d   santosh.shilimkar@oracle.com   RDS: push FMR poo...
504
  					   &pool->flush_worker, 10);
08b48a1ed   Andy Grover   RDS/IB: Implement...
505
506
  		}
  	}
3e0249f9c   Zach Brown   RDS/IB: add refco...
507
508
  
  	rds_ib_dev_put(rds_ibdev);
08b48a1ed   Andy Grover   RDS/IB: Implement...
509
510
511
512
513
  }
  
  void rds_ib_flush_mrs(void)
  {
  	struct rds_ib_device *rds_ibdev;
ea819867b   Zach Brown   RDS/IB: protect t...
514
  	down_read(&rds_ib_devices_lock);
08b48a1ed   Andy Grover   RDS/IB: Implement...
515
  	list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
067665132   Santosh Shilimkar   RDS: IB: split mr...
516
517
  		if (rds_ibdev->mr_8k_pool)
  			rds_ib_flush_mr_pool(rds_ibdev->mr_8k_pool, 0, NULL);
08b48a1ed   Andy Grover   RDS/IB: Implement...
518

067665132   Santosh Shilimkar   RDS: IB: split mr...
519
520
  		if (rds_ibdev->mr_1m_pool)
  			rds_ib_flush_mr_pool(rds_ibdev->mr_1m_pool, 0, NULL);
08b48a1ed   Andy Grover   RDS/IB: Implement...
521
  	}
ea819867b   Zach Brown   RDS/IB: protect t...
522
  	up_read(&rds_ib_devices_lock);
08b48a1ed   Andy Grover   RDS/IB: Implement...
523
524
525
526
527
528
529
  }
  
  void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
  		    struct rds_sock *rs, u32 *key_ret)
  {
  	struct rds_ib_device *rds_ibdev;
  	struct rds_ib_mr *ibmr = NULL;
1659185fb   Avinash Repaka   RDS: IB: Support ...
530
  	struct rds_ib_connection *ic = rs->rs_conn->c_transport_data;
08b48a1ed   Andy Grover   RDS/IB: Implement...
531
532
533
534
535
536
537
  	int ret;
  
  	rds_ibdev = rds_ib_get_device(rs->rs_bound_addr);
  	if (!rds_ibdev) {
  		ret = -ENODEV;
  		goto out;
  	}
067665132   Santosh Shilimkar   RDS: IB: split mr...
538
  	if (!rds_ibdev->mr_8k_pool || !rds_ibdev->mr_1m_pool) {
08b48a1ed   Andy Grover   RDS/IB: Implement...
539
540
541
  		ret = -ENODEV;
  		goto out;
  	}
1659185fb   Avinash Repaka   RDS: IB: Support ...
542
543
544
545
  	if (rds_ibdev->use_fastreg)
  		ibmr = rds_ib_reg_frmr(rds_ibdev, ic, sg, nents, key_ret);
  	else
  		ibmr = rds_ib_reg_fmr(rds_ibdev, sg, nents, key_ret);
490ea5967   santosh.shilimkar@oracle.com   RDS: IB: move FMR...
546
547
  	if (ibmr)
  		rds_ibdev = NULL;
08b48a1ed   Andy Grover   RDS/IB: Implement...
548
549
  
   out:
490ea5967   santosh.shilimkar@oracle.com   RDS: IB: move FMR...
550
551
552
  	if (!ibmr)
  		pr_warn("RDS/IB: rds_ib_get_mr failed (errno=%d)
  ", ret);
3e0249f9c   Zach Brown   RDS/IB: add refco...
553
554
  	if (rds_ibdev)
  		rds_ib_dev_put(rds_ibdev);
490ea5967   santosh.shilimkar@oracle.com   RDS: IB: move FMR...
555

08b48a1ed   Andy Grover   RDS/IB: Implement...
556
557
  	return ibmr;
  }
6fa70da60   Chris Mason   rds: recycle FMRs...
558

f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
  void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
  {
  	cancel_delayed_work_sync(&pool->flush_worker);
  	rds_ib_flush_mr_pool(pool, 1, NULL);
  	WARN_ON(atomic_read(&pool->item_count));
  	WARN_ON(atomic_read(&pool->free_pinned));
  	kfree(pool);
  }
  
  struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev,
  					     int pool_type)
  {
  	struct rds_ib_mr_pool *pool;
  
  	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
  	if (!pool)
  		return ERR_PTR(-ENOMEM);
  
  	pool->pool_type = pool_type;
  	init_llist_head(&pool->free_list);
  	init_llist_head(&pool->drop_list);
  	init_llist_head(&pool->clean_list);
  	mutex_init(&pool->flush_lock);
  	init_waitqueue_head(&pool->flush_wait);
  	INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
  
  	if (pool_type == RDS_IB_MR_1M_POOL) {
  		/* +1 allows for unaligned MRs */
  		pool->fmr_attr.max_pages = RDS_MR_1M_MSG_SIZE + 1;
  		pool->max_items = RDS_MR_1M_POOL_SIZE;
  	} else {
  		/* pool_type == RDS_IB_MR_8K_POOL */
  		pool->fmr_attr.max_pages = RDS_MR_8K_MSG_SIZE + 1;
  		pool->max_items = RDS_MR_8K_POOL_SIZE;
  	}
  
  	pool->max_free_pinned = pool->max_items * pool->fmr_attr.max_pages / 4;
  	pool->fmr_attr.max_maps = rds_ibdev->fmr_max_remaps;
  	pool->fmr_attr.page_shift = PAGE_SHIFT;
  	pool->max_items_soft = rds_ibdev->max_mrs * 3 / 4;
1659185fb   Avinash Repaka   RDS: IB: Support ...
599
  	pool->use_fastreg = rds_ibdev->use_fastreg;
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
600
601
602
603
604
605
  
  	return pool;
  }
  
  int rds_ib_mr_init(void)
  {
231edca97   Bhaktipriya Shridhar   RDS: IB: Remove d...
606
  	rds_ib_mr_wq = alloc_workqueue("rds_mr_flushd", WQ_MEM_RECLAIM, 0);
f6df683f3   santosh.shilimkar@oracle.com   RDS: IB: Re-organ...
607
608
609
610
611
612
613
614
615
616
617
618
619
  	if (!rds_ib_mr_wq)
  		return -ENOMEM;
  	return 0;
  }
  
  /* By the time this is called all the IB devices should have been torn down and
   * had their pools freed.  As each pool is freed its work struct is waited on,
   * so the pool flushing work queue should be idle by the time we get here.
   */
  void rds_ib_mr_exit(void)
  {
  	destroy_workqueue(rds_ib_mr_wq);
  }