aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/rds/message.c51
-rw-r--r--net/rds/rds.h7
-rw-r--r--net/rds/send.c31
3 files changed, 62 insertions, 27 deletions
diff --git a/net/rds/message.c b/net/rds/message.c
index 4421d160b1a4..3498cbcc7542 100644
--- a/net/rds/message.c
+++ b/net/rds/message.c
@@ -214,17 +214,22 @@ int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 o
214} 214}
215EXPORT_SYMBOL_GPL(rds_message_add_rdma_dest_extension); 215EXPORT_SYMBOL_GPL(rds_message_add_rdma_dest_extension);
216 216
217struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp) 217/*
218 * Each rds_message is allocated with extra space for the scatterlist entries
219 * rds ops will need. This is to minimize memory allocation count. Then, each rds op
220 * can grab SGs when initializing its part of the rds_message.
221 */
222struct rds_message *rds_message_alloc(unsigned int extra_len, gfp_t gfp)
218{ 223{
219 struct rds_message *rm; 224 struct rds_message *rm;
220 225
221 rm = kzalloc(sizeof(struct rds_message) + 226 rm = kzalloc(sizeof(struct rds_message) + extra_len, gfp);
222 (nents * sizeof(struct scatterlist)), gfp);
223 if (!rm) 227 if (!rm)
224 goto out; 228 goto out;
225 229
226 if (nents) 230 rm->m_used_sgs = 0;
227 sg_init_table(rm->data.m_sg, nents); 231 rm->m_total_sgs = extra_len / sizeof(struct scatterlist);
232
228 atomic_set(&rm->m_refcount, 1); 233 atomic_set(&rm->m_refcount, 1);
229 INIT_LIST_HEAD(&rm->m_sock_item); 234 INIT_LIST_HEAD(&rm->m_sock_item);
230 INIT_LIST_HEAD(&rm->m_conn_item); 235 INIT_LIST_HEAD(&rm->m_conn_item);
@@ -234,6 +239,23 @@ out:
234 return rm; 239 return rm;
235} 240}
236 241
242/*
243 * RDS ops use this to grab SG entries from the rm's sg pool.
244 */
245struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents)
246{
247 struct scatterlist *sg_first = (struct scatterlist *) &rm[1];
248 struct scatterlist *sg_ret;
249
250 WARN_ON(rm->m_used_sgs + nents > rm->m_total_sgs);
251
252 sg_ret = &sg_first[rm->m_used_sgs];
253
254 rm->m_used_sgs += nents;
255
256 return sg_ret;
257}
258
237struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len) 259struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len)
238{ 260{
239 struct rds_message *rm; 261 struct rds_message *rm;
@@ -256,22 +278,15 @@ struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned in
256 return rm; 278 return rm;
257} 279}
258 280
259struct rds_message *rds_message_copy_from_user(struct iovec *first_iov, 281int rds_message_copy_from_user(struct rds_message *rm, struct iovec *first_iov,
260 size_t total_len) 282 size_t total_len)
261{ 283{
262 unsigned long to_copy; 284 unsigned long to_copy;
263 unsigned long iov_off; 285 unsigned long iov_off;
264 unsigned long sg_off; 286 unsigned long sg_off;
265 struct rds_message *rm;
266 struct iovec *iov; 287 struct iovec *iov;
267 struct scatterlist *sg; 288 struct scatterlist *sg;
268 int ret; 289 int ret = 0;
269
270 rm = rds_message_alloc(ceil(total_len, PAGE_SIZE), GFP_KERNEL);
271 if (rm == NULL) {
272 ret = -ENOMEM;
273 goto out;
274 }
275 290
276 rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len); 291 rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
277 292
@@ -320,14 +335,8 @@ struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
320 sg++; 335 sg++;
321 } 336 }
322 337
323 ret = 0;
324out: 338out:
325 if (ret) { 339 return ret;
326 if (rm)
327 rds_message_put(rm);
328 rm = ERR_PTR(ret);
329 }
330 return rm;
331} 340}
332 341
333int rds_message_inc_copy_to_user(struct rds_incoming *inc, 342int rds_message_inc_copy_to_user(struct rds_incoming *inc,
diff --git a/net/rds/rds.h b/net/rds/rds.h
index 07a750b3fb31..d29c71aabbd4 100644
--- a/net/rds/rds.h
+++ b/net/rds/rds.h
@@ -268,9 +268,11 @@ struct rds_message {
268 struct { 268 struct {
269 unsigned int m_nents; 269 unsigned int m_nents;
270 unsigned int m_count; 270 unsigned int m_count;
271 struct scatterlist m_sg[0]; 271 struct scatterlist *m_sg;
272 } data; 272 } data;
273 }; 273 };
274 unsigned int m_used_sgs;
275 unsigned int m_total_sgs;
274}; 276};
275 277
276/* 278/*
@@ -573,7 +575,8 @@ rds_conn_connecting(struct rds_connection *conn)
573 575
574/* message.c */ 576/* message.c */
575struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp); 577struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp);
576struct rds_message *rds_message_copy_from_user(struct iovec *first_iov, 578struct scatterlist *rds_message_alloc_sgs(struct rds_message *rm, int nents);
579int rds_message_copy_from_user(struct rds_message *rm, struct iovec *first_iov,
577 size_t total_len); 580 size_t total_len);
578struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len); 581struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len);
579void rds_message_populate_header(struct rds_header *hdr, __be16 sport, 582void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
diff --git a/net/rds/send.c b/net/rds/send.c
index 19dfd025498e..28d09447207b 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -758,6 +758,19 @@ out:
758 return *queued; 758 return *queued;
759} 759}
760 760
761/*
762 * rds_message is getting to be quite complicated, and we'd like to allocate
763 * it all in one go. This figures out how big it needs to be up front.
764 */
765static int rds_rm_size(struct msghdr *msg, int data_len)
766{
767 int size = 0;
768
769 size += ceil(data_len, PAGE_SIZE) * sizeof(struct scatterlist);
770
771 return size;
772}
773
761static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm, 774static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
762 struct msghdr *msg, int *allocated_mr) 775 struct msghdr *msg, int *allocated_mr)
763{ 776{
@@ -845,13 +858,23 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
845 goto out; 858 goto out;
846 } 859 }
847 860
848 rm = rds_message_copy_from_user(msg->msg_iov, payload_len); 861 /* size of rm including all sgs */
849 if (IS_ERR(rm)) { 862 ret = rds_rm_size(msg, payload_len);
850 ret = PTR_ERR(rm); 863 if (ret < 0)
851 rm = NULL; 864 goto out;
865
866 rm = rds_message_alloc(ret, GFP_KERNEL);
867 if (!rm) {
868 ret = -ENOMEM;
852 goto out; 869 goto out;
853 } 870 }
854 871
872 rm->data.m_sg = rds_message_alloc_sgs(rm, ceil(payload_len, PAGE_SIZE));
873 /* XXX fix this to not allocate memory */
874 ret = rds_message_copy_from_user(rm, msg->msg_iov, payload_len);
875 if (ret)
876 goto out;
877
855 rm->m_daddr = daddr; 878 rm->m_daddr = daddr;
856 879
857 /* rds_conn_create has a spinlock that runs with IRQ off. 880 /* rds_conn_create has a spinlock that runs with IRQ off.