3535#include "rdma_core.h"
3636#include "uverbs.h"
3737
38+ struct bundle_alloc_head {
39+ struct bundle_alloc_head * next ;
40+ u8 data [];
41+ };
42+
3843struct bundle_priv {
44+ /* Must be first */
45+ struct bundle_alloc_head alloc_head ;
46+ struct bundle_alloc_head * allocated_mem ;
47+ size_t internal_avail ;
48+ size_t internal_used ;
49+
3950 struct ib_uverbs_attr __user * user_attrs ;
4051 struct ib_uverbs_attr * uattrs ;
4152 struct uverbs_obj_attr * destroy_attr ;
@@ -45,8 +56,53 @@ struct bundle_priv {
4556 * internal_buffer.
4657 */
4758 struct uverbs_attr_bundle bundle ;
59+ u64 internal_buffer [32 ];
4860};
4961
62+ /**
63+ * uverbs_alloc() - Quickly allocate memory for use with a bundle
64+ * @bundle: The bundle
65+ * @size: Number of bytes to allocate
66+ * @flags: Allocator flags
67+ *
68+ * The bundle allocator is intended for allocations that are connected with
69+ * processing the system call related to the bundle. The allocated memory is
70+ * always freed once the system call completes, and cannot be freed any other
71+ * way.
72+ *
73+ * This tries to use a small pool of pre-allocated memory for performance.
74+ */
75+ __malloc void * _uverbs_alloc (struct uverbs_attr_bundle * bundle , size_t size ,
76+ gfp_t flags )
77+ {
78+ struct bundle_priv * pbundle =
79+ container_of (bundle , struct bundle_priv , bundle );
80+ size_t new_used ;
81+ void * res ;
82+
83+ if (check_add_overflow (size , pbundle -> internal_used , & new_used ))
84+ return ERR_PTR (- EINVAL );
85+
86+ if (new_used > pbundle -> internal_avail ) {
87+ struct bundle_alloc_head * buf ;
88+
89+ buf = kvmalloc (struct_size (buf , data , size ), flags );
90+ if (!buf )
91+ return ERR_PTR (- ENOMEM );
92+ buf -> next = pbundle -> allocated_mem ;
93+ pbundle -> allocated_mem = buf ;
94+ return buf -> data ;
95+ }
96+
97+ res = (void * )pbundle -> internal_buffer + pbundle -> internal_used ;
98+ pbundle -> internal_used =
99+ ALIGN (new_used , sizeof (* pbundle -> internal_buffer ));
100+ if (flags & __GFP_ZERO )
101+ memset (res , 0 , size );
102+ return res ;
103+ }
104+ EXPORT_SYMBOL (_uverbs_alloc );
105+
50106static bool uverbs_is_attr_cleared (const struct ib_uverbs_attr * uattr ,
51107 u16 len )
52108{
@@ -129,17 +185,15 @@ static int uverbs_process_attr(struct bundle_priv *pbundle,
129185 if (val_spec -> alloc_and_copy && !uverbs_attr_ptr_is_inline (e )) {
130186 void * p ;
131187
132- p = kvmalloc ( uattr -> len , GFP_KERNEL );
133- if (! p )
134- return - ENOMEM ;
188+ p = uverbs_alloc ( & pbundle -> bundle , uattr -> len );
189+ if (IS_ERR ( p ) )
190+ return PTR_ERR ( p ) ;
135191
136192 e -> ptr_attr .ptr = p ;
137193
138194 if (copy_from_user (p , u64_to_user_ptr (uattr -> data ),
139- uattr -> len )) {
140- kvfree (p );
195+ uattr -> len ))
141196 return - EFAULT ;
142- }
143197 } else {
144198 e -> ptr_attr .data = uattr -> data ;
145199 }
@@ -234,10 +288,6 @@ static int uverbs_finalize_attrs(struct bundle_priv *pbundle,
234288 spec -> u .obj .access , commit );
235289 if (!ret )
236290 ret = current_ret ;
237- } else if (spec -> type == UVERBS_ATTR_TYPE_PTR_IN &&
238- spec -> alloc_and_copy &&
239- !uverbs_attr_ptr_is_inline (attr )) {
240- kvfree (attr -> ptr_attr .ptr );
241291 }
242292 }
243293 }
@@ -372,7 +422,18 @@ static int uverbs_handle_method(size_t num_uattrs,
372422 return ret ? ret : finalize_ret ;
373423}
374424
375- #define UVERBS_OPTIMIZE_USING_STACK_SZ 256
425+ static void bundle_destroy (struct bundle_priv * pbundle )
426+ {
427+ struct bundle_alloc_head * memblock ;
428+
429+ for (memblock = pbundle -> allocated_mem ; memblock ;) {
430+ struct bundle_alloc_head * tmp = memblock ;
431+
432+ memblock = memblock -> next ;
433+ kvfree (tmp );
434+ }
435+ }
436+
376437static long ib_uverbs_cmd_verbs (struct ib_device * ib_dev ,
377438 struct ib_uverbs_file * file ,
378439 struct ib_uverbs_ioctl_hdr * hdr ,
@@ -382,11 +443,11 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev,
382443 const struct uverbs_method_spec * method_spec ;
383444 long err = 0 ;
384445 unsigned int i ;
446+ struct bundle_priv onstack_pbundle ;
385447 struct bundle_priv * ctx ;
386448 struct uverbs_attr * curr_attr ;
387449 unsigned long * curr_bitmap ;
388450 size_t ctx_size ;
389- uintptr_t data [UVERBS_OPTIMIZE_USING_STACK_SZ / sizeof (uintptr_t )];
390451
391452 if (hdr -> driver_id != ib_dev -> driver_id )
392453 return - EINVAL ;
@@ -399,7 +460,7 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev,
399460 if (!method_spec )
400461 return - EPROTONOSUPPORT ;
401462
402- ctx_size = sizeof (* ctx ) +
463+ ctx_size = sizeof (* ctx ) - sizeof ( ctx -> internal_buffer ) +
403464 sizeof (struct uverbs_attr_bundle_hash ) * method_spec -> num_buckets +
404465 sizeof (* ctx -> uattrs ) * hdr -> num_attrs +
405466 sizeof (* ctx -> bundle .hash [0 ].attrs ) *
@@ -408,17 +469,26 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev,
408469 (method_spec -> num_child_attrs / BITS_PER_LONG +
409470 method_spec -> num_buckets );
410471
411- if (ctx_size <= UVERBS_OPTIMIZE_USING_STACK_SZ )
412- ctx = (void * )data ;
413- if (!ctx )
472+ if (ctx_size <= sizeof (onstack_pbundle )) {
473+ ctx = & onstack_pbundle ;
474+ ctx -> internal_avail =
475+ sizeof (onstack_pbundle ) -
476+ offsetof(struct bundle_priv , internal_buffer );
477+ ctx -> allocated_mem = NULL ;
478+ } else {
414479 ctx = kmalloc (ctx_size , GFP_KERNEL );
415- if (!ctx )
416- return - ENOMEM ;
480+ if (!ctx )
481+ return - ENOMEM ;
482+ ctx -> internal_avail = 0 ;
483+ ctx -> alloc_head .next = NULL ;
484+ ctx -> allocated_mem = & ctx -> alloc_head ;
485+ }
417486
418487 ctx -> uattrs = (void * )(ctx + 1 ) +
419488 (sizeof (ctx -> bundle .hash [0 ]) * method_spec -> num_buckets );
420489 curr_attr = (void * )(ctx -> uattrs + hdr -> num_attrs );
421490 curr_bitmap = (void * )(curr_attr + method_spec -> num_child_attrs );
491+ ctx -> internal_used = ALIGN (ctx_size , sizeof (* ctx -> internal_buffer ));
422492
423493 /*
424494 * We just fill the pointers and num_attrs here. The data itself will be
@@ -462,8 +532,7 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev,
462532 err = - EINVAL ;
463533 }
464534out :
465- if (ctx != (void * )data )
466- kfree (ctx );
535+ bundle_destroy (ctx );
467536 return err ;
468537}
469538
0 commit comments