virt: haven: rm_core: Always allocate a connection for notifications

Currently, there is an optimized path to directly use the message queue
buffer when a received notification fits within a single message and
there aren't any fragments. This greatly complicates buffer management
and might not provide any measurable benefit.
Suppose Linux receives a notification with one fragment then a
notification with 3 fragments. In current flow, there is 1 alloc for the
first notification and 4 allocations for the 2nd notification (1 for
each message + 1 for overall combined buffer). In the new flow, we could
optimize this to 0 allocations for each message because we can re-use
the same message buffer for each fragment and then a single alloc for
the entire payload.
There is, however, a slightly increased cost for single-message
notifications in the form of an extra memcpy from the message buffer to
notification buffer. Under the code optimizations and simplifications
that come with this cost, it is a worthy cost.

Change-Id: Ib52bd332f59b108d7dab9121c0beefed0aa66994
Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
Signed-off-by: Srinivasarao Pathipati <quic_c_spathi@quicinc.com>
This commit is contained in:
Srinivasarao Pathipati 2022-10-10 14:30:57 +05:30
commit faf7c82fab

View file

@ -132,73 +132,36 @@ int hh_rm_unregister_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL(hh_rm_unregister_notifier);
static struct hh_rm_connection *
hh_rm_wait_for_notif_fragments(void *recv_buff, size_t recv_buff_size)
static int hh_rm_process_notif(void *msg, size_t msg_size)
{
struct hh_rm_rpc_hdr *hdr = recv_buff;
struct hh_rm_rpc_hdr *hdr = msg;
struct hh_rm_connection *connection;
u32 notification;
size_t payload_size;
void *payload;
int ret = 0;
connection = hh_rm_alloc_connection(hdr->msg_id);
if (IS_ERR_OR_NULL(connection))
return connection;
payload_size = recv_buff_size - sizeof(*hdr);
curr_connection = connection;
ret = hh_rm_init_connection_buff(connection, recv_buff,
sizeof(*hdr), payload_size);
if (ret < 0)
goto out;
if (wait_for_completion_interruptible(&connection->seq_done)) {
ret = -ERESTARTSYS;
goto out;
}
return connection;
out:
kfree(connection);
return ERR_PTR(ret);
}
static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size)
{
struct hh_rm_connection *connection = NULL;
struct hh_rm_rpc_hdr *hdr = recv_buff;
u32 notification = hdr->msg_id;
void *payload = NULL;
size_t payload_size;
int ret = 0;
pr_debug("Notification received from RM-VM: %x\n", notification);
if (curr_connection) {
pr_err("Received new notification from RM-VM before completing last connection\n");
return -EINVAL;
}
if (recv_buff_size > sizeof(*hdr))
payload = recv_buff + sizeof(*hdr);
connection = hh_rm_alloc_connection(hdr->msg_id);
if (!connection)
return -EINVAL;
/* If the notification payload is split-up into
* fragments, wait until all them arrive.
*/
if (hdr->fragments) {
connection = hh_rm_wait_for_notif_fragments(recv_buff,
recv_buff_size);
if (IS_ERR_OR_NULL(connection))
return PTR_ERR(connection);
/* In the case of fragments, the complete payload
* is contained under connection->recv_buff
*/
payload = connection->recv_buff;
recv_buff_size = connection->recv_buff_size;
if (hh_rm_init_connection_buff(connection, msg, sizeof(*hdr), msg_size - sizeof(*hdr))) {
kfree(connection);
return -EINVAL;
}
payload_size = recv_buff_size - sizeof(*hdr);
if (hdr->fragments)
return PTR_ERR(connection);
payload = connection->recv_buff;
payload_size = connection->recv_buff_size;
notification = connection->msg_id;
pr_debug("Notification received from RM-VM: %x\n", notification);
switch (notification) {
case HH_RM_NOTIF_VM_STATUS:
@ -297,7 +260,7 @@ static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size)
err:
if (connection) {
kfree(connection->recv_buff);
kfree(payload);
kfree(connection);
}