greybus: create a slab cache for simple messages
A large number of request and response message types have no payload. Such "simple" messages have a known, fixed maximum size, so we can preallocate and use a pool (slab cache) of them. Here are two benefits to doing this: - There can be (small) performance and memory utilization benefits to using a slab cache. - Error responses can be sent with no payload; the cache is likely to have a free entry to use for an error response even in a low memory situation. The plan here is that an incoming request handler that has no response payload to fill will not need to allocate a response message. If no message has been allocated when a response is to be sent, one will be allocated from the cache by the core code. Signed-off-by: Alex Elder <elder@linaro.org> Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
This commit is contained in:
parent
835fb5e498
commit
0cffcac305
|
@ -28,6 +28,7 @@
|
|||
#define GB_OPERATION_MESSAGE_SIZE_MAX 4096
|
||||
|
||||
static struct kmem_cache *gb_operation_cache;
|
||||
static struct kmem_cache *gb_simple_message_cache;
|
||||
|
||||
/* Workqueue to handle Greybus operation completions. */
|
||||
static struct workqueue_struct *gb_operation_workqueue;
|
||||
|
@ -369,11 +370,19 @@ gb_operation_message_alloc(struct greybus_host_device *hd, u8 type,
|
|||
hd->buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX;
|
||||
}
|
||||
|
||||
if (message_size > hd->buffer_size_max)
|
||||
return NULL;
|
||||
/* Allocate the message. Use the slab cache for simple messages */
|
||||
if (payload_size) {
|
||||
if (message_size > hd->buffer_size_max) {
|
||||
pr_warn("requested message size too big (%zu > %zu)\n",
|
||||
message_size, hd->buffer_size_max);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = sizeof(*message) + hd->buffer_headroom + message_size;
|
||||
message = kzalloc(size, gfp_flags);
|
||||
size = sizeof(*message) + hd->buffer_headroom + message_size;
|
||||
message = kzalloc(size, gfp_flags);
|
||||
} else {
|
||||
message = kmem_cache_zalloc(gb_simple_message_cache, gfp_flags);
|
||||
}
|
||||
if (!message)
|
||||
return NULL;
|
||||
|
||||
|
@ -385,7 +394,10 @@ gb_operation_message_alloc(struct greybus_host_device *hd, u8 type,
|
|||
|
||||
static void gb_operation_message_free(struct gb_message *message)
|
||||
{
|
||||
kfree(message);
|
||||
if (message->size > sizeof(message->header))
|
||||
kfree(message);
|
||||
else
|
||||
kmem_cache_free(gb_simple_message_cache, message);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -836,22 +848,46 @@ int gb_operation_sync(struct gb_connection *connection, int type,
|
|||
|
||||
int gb_operation_init(void)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
BUILD_BUG_ON(GB_OPERATION_MESSAGE_SIZE_MAX >
|
||||
U16_MAX - sizeof(struct gb_operation_msg_hdr));
|
||||
|
||||
/*
|
||||
* A message structure with consists of:
|
||||
* - the message structure itself
|
||||
* - the headroom set aside for the host device
|
||||
* - the message header
|
||||
* - space for the message payload
|
||||
* Messages with no payload are a fairly common case and
|
||||
* have a known fixed maximum size, so we use a slab cache
|
||||
* for them.
|
||||
*/
|
||||
size = sizeof(struct gb_message) + GB_BUFFER_HEADROOM_MAX +
|
||||
sizeof(struct gb_operation_msg_hdr);
|
||||
gb_simple_message_cache = kmem_cache_create("gb_simple_message_cache",
|
||||
size, 0, 0, NULL);
|
||||
if (!gb_simple_message_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
gb_operation_cache = kmem_cache_create("gb_operation_cache",
|
||||
sizeof(struct gb_operation), 0, 0, NULL);
|
||||
if (!gb_operation_cache)
|
||||
return -ENOMEM;
|
||||
goto err_simple;
|
||||
|
||||
gb_operation_workqueue = alloc_workqueue("greybus_operation", 0, 1);
|
||||
if (!gb_operation_workqueue) {
|
||||
kmem_cache_destroy(gb_operation_cache);
|
||||
gb_operation_cache = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!gb_operation_workqueue)
|
||||
goto err_operation;
|
||||
|
||||
return 0;
|
||||
err_operation:
|
||||
kmem_cache_destroy(gb_operation_cache);
|
||||
gb_operation_cache = NULL;
|
||||
err_simple:
|
||||
kmem_cache_destroy(gb_simple_message_cache);
|
||||
gb_simple_message_cache = NULL;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void gb_operation_exit(void)
|
||||
|
@ -860,4 +896,6 @@ void gb_operation_exit(void)
|
|||
gb_operation_workqueue = NULL;
|
||||
kmem_cache_destroy(gb_operation_cache);
|
||||
gb_operation_cache = NULL;
|
||||
kmem_cache_destroy(gb_simple_message_cache);
|
||||
gb_simple_message_cache = NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue