Module: Mesa
Branch: main
Commit: ae3b022fa0568e048ce2013affbd2ca60cc42ec6
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=ae3b022fa0568e048ce2013affbd2ca60cc42ec6

Author: Yiwei Zhang <zzyi...@chromium.org>
Date:   Wed Nov  1 01:14:00 2023 -0700

venus: fix query feedback batch leak and race upon submission

Summary:
- fixed the combined query batches leak
- fixed the race condition of accessing feedback cmd pool
- very scoped code refactor

Cc: 23.3 <mesa-stable>
Fixes: 5b24ab91e43 ("venus: switch to unconditionally deferred query feedback")
Signed-off-by: Yiwei Zhang <zzyi...@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25988>

---

 src/virtio/vulkan/vn_queue.c | 135 +++++++++++++++++++++++--------------------
 1 file changed, 73 insertions(+), 62 deletions(-)

diff --git a/src/virtio/vulkan/vn_queue.c b/src/virtio/vulkan/vn_queue.c
index 031366f0163..fd1ad4e23ae 100644
--- a/src/virtio/vulkan/vn_queue.c
+++ b/src/virtio/vulkan/vn_queue.c
@@ -510,61 +510,83 @@ vn_get_feedback_cmd_handle(struct vn_queue_submission 
*submit,
 }
 
 static VkResult
-vn_combine_query_feedback_batches(VkCommandBuffer *src_cmd_handles,
-                                  uint32_t cmd_buffer_count,
-                                  uint32_t stride,
-                                  struct vn_feedback_cmd_pool *feedback_pool,
-                                  struct list_head *combined_query_batches)
+vn_combine_query_feedback_batches_and_record(
+   VkDevice dev_handle,
+   VkCommandBuffer *cmd_handles,
+   uint32_t cmd_count,
+   uint32_t stride,
+   struct vn_feedback_cmd_pool *feedback_cmd_pool,
+   VkCommandBuffer *out_feedback_cmd_handle)
 {
    struct vn_command_pool *cmd_pool =
-      vn_command_pool_from_handle(feedback_pool->pool);
+      vn_command_pool_from_handle(feedback_cmd_pool->pool);
+   VkResult result = VK_SUCCESS;
 
-   uintptr_t cmd_handle_ptr = (uintptr_t)src_cmd_handles;
-   for (uint32_t i = 0; i < cmd_buffer_count; i++) {
-      struct vn_command_buffer *cmd_buffer =
-         vn_command_buffer_from_handle(*(VkCommandBuffer *)cmd_handle_ptr);
+   struct list_head combined_batches;
+   list_inithead(&combined_batches);
 
-      list_for_each_entry_safe(struct vn_feedback_query_batch, new_batch,
-                               &cmd_buffer->builder.query_batches, head) {
+   uintptr_t cmd_handle_ptr = (uintptr_t)cmd_handles;
+   for (uint32_t i = 0; i < cmd_count; i++) {
+      struct vn_command_buffer *cmd =
+         vn_command_buffer_from_handle(*(VkCommandBuffer *)cmd_handle_ptr);
 
-         if (!new_batch->copy) {
+      list_for_each_entry(struct vn_feedback_query_batch, batch,
+                          &cmd->builder.query_batches, head) {
+         if (!batch->copy) {
             list_for_each_entry_safe(struct vn_feedback_query_batch,
-                                     combined_batch, combined_query_batches,
-                                     head) {
+                                     batch_clone, &combined_batches, head) {
                /* If we previously added a query feedback that is now getting
                 * reset, remove it since it is now a no-op and the deferred
                 * feedback copy will cause a hang waiting for the reset query
                 * to become available.
                 */
-               if (combined_batch->copy &&
-                   (vn_query_pool_to_handle(combined_batch->query_pool) ==
-                    vn_query_pool_to_handle(new_batch->query_pool)) &&
-                   combined_batch->query >= new_batch->query &&
-                   combined_batch->query <=
-                      new_batch->query + new_batch->query_count) {
-                  list_move_to(&combined_batch->head,
+               if (batch_clone->copy &&
+                   (vn_query_pool_to_handle(batch_clone->query_pool) ==
+                    vn_query_pool_to_handle(batch->query_pool)) &&
+                   batch_clone->query >= batch->query &&
+                   batch_clone->query <= batch->query + batch->query_count) {
+                  simple_mtx_lock(&feedback_cmd_pool->mutex);
+                  list_move_to(&batch_clone->head,
                                &cmd_pool->free_query_batches);
+                  simple_mtx_unlock(&feedback_cmd_pool->mutex);
                }
             }
          }
-         struct vn_feedback_query_batch *batch = vn_cmd_query_batch_alloc(
-            cmd_pool, new_batch->query_pool, new_batch->query,
-            new_batch->query_count, new_batch->copy);
-         if (!batch)
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
 
-         list_addtail(&batch->head, combined_query_batches);
+         simple_mtx_lock(&feedback_cmd_pool->mutex);
+         struct vn_feedback_query_batch *batch_clone =
+            vn_cmd_query_batch_alloc(cmd_pool, batch->query_pool,
+                                     batch->query, batch->query_count,
+                                     batch->copy);
+         simple_mtx_unlock(&feedback_cmd_pool->mutex);
+         if (!batch_clone) {
+            result = VK_ERROR_OUT_OF_HOST_MEMORY;
+            goto recycle_combined_batches;
+         }
+
+         list_addtail(&batch_clone->head, &combined_batches);
       }
 
       cmd_handle_ptr += stride;
    }
 
-   return VK_SUCCESS;
+   result = vn_feedback_query_batch_record(dev_handle, feedback_cmd_pool,
+                                           &combined_batches,
+                                           out_feedback_cmd_handle);
+
+recycle_combined_batches:
+   simple_mtx_lock(&feedback_cmd_pool->mutex);
+   list_for_each_entry_safe(struct vn_feedback_query_batch, batch_clone,
+                            &combined_batches, head)
+      list_move_to(&batch_clone->head, &cmd_pool->free_query_batches);
+   simple_mtx_unlock(&feedback_cmd_pool->mutex);
+
+   return result;
 }
 
 static VkResult
 vn_queue_submission_add_query_feedback(struct vn_queue_submission *submit,
-                                       uint32_t cmd_buffer_count,
+                                       uint32_t cmd_count,
                                        struct vn_feedback_cmds *feedback_cmds)
 {
    struct vk_queue *queue_vk = vk_queue_from_handle(submit->queue_handle);
@@ -573,32 +595,22 @@ vn_queue_submission_add_query_feedback(struct 
vn_queue_submission *submit,
    VkCommandBuffer *src_cmd_handles =
       vn_get_feedback_cmd_handle(submit, feedback_cmds, 0);
    VkCommandBuffer *feedback_cmd_handle =
-      vn_get_feedback_cmd_handle(submit, feedback_cmds, cmd_buffer_count);
-   uint32_t stride = (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO)
-                        ? sizeof(VkCommandBuffer *)
-                        : sizeof(VkCommandBufferSubmitInfo);
-   VkResult result;
+      vn_get_feedback_cmd_handle(submit, feedback_cmds, cmd_count);
+   const uint32_t stride = submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO
+                              ? sizeof(VkCommandBuffer *)
+                              : sizeof(VkCommandBufferSubmitInfo);
 
-   uint32_t pool_index;
-   for (pool_index = 0; pool_index < dev->queue_family_count; pool_index++) {
-      if (dev->queue_families[pool_index] == queue_vk->queue_family_index)
+   struct vn_feedback_cmd_pool *feedback_cmd_pool = NULL;
+   for (uint32_t i = 0; i < dev->queue_family_count; i++) {
+      if (dev->queue_families[i] == queue_vk->queue_family_index) {
+         feedback_cmd_pool = &dev->cmd_pools[i];
          break;
+      }
    }
-   struct vn_feedback_cmd_pool *feedback_cmd_pool =
-      &dev->cmd_pools[pool_index];
-
-   struct list_head combined_query_batches;
-   list_inithead(&combined_query_batches);
-
-   result = vn_combine_query_feedback_batches(
-      src_cmd_handles, cmd_buffer_count, stride, feedback_cmd_pool,
-      &combined_query_batches);
-   if (result != VK_SUCCESS)
-      return result;
 
-   result = vn_feedback_query_batch_record(dev_handle, feedback_cmd_pool,
-                                           &combined_query_batches,
-                                           feedback_cmd_handle);
+   VkResult result = vn_combine_query_feedback_batches_and_record(
+      dev_handle, src_cmd_handles, cmd_count, stride, feedback_cmd_pool,
+      feedback_cmd_handle);
    if (result != VK_SUCCESS)
       return result;
 
@@ -610,20 +622,19 @@ vn_queue_submission_add_query_feedback(struct 
vn_queue_submission *submit,
     * since we don't know if all its instances have completed execution.
     * Should be rare enough to just log and leak the feedback cmd.
     */
-   struct vn_command_buffer *linked_cmd_buffer = NULL;
-   for (uint32_t i = cmd_buffer_count - 1; i >= 0; i--) {
+   struct vn_command_buffer *linked_cmd = NULL;
+   for (uint32_t i = 0; i < cmd_count; i++) {
       VkCommandBuffer *cmd_handle =
          vn_get_feedback_cmd_handle(submit, feedback_cmds, i);
-      struct vn_command_buffer *cmd_buffer =
+      struct vn_command_buffer *cmd =
          vn_command_buffer_from_handle(*cmd_handle);
-
-      if (!cmd_buffer->builder.is_simultaneous) {
-         linked_cmd_buffer = cmd_buffer;
+      if (!cmd->builder.is_simultaneous) {
+         linked_cmd = cmd;
          break;
       }
    }
 
-   if (!linked_cmd_buffer) {
+   if (!linked_cmd) {
       vn_log(dev->instance,
              "Could not find non simultaneous cmd to link query feedback\n");
       return VK_SUCCESS;
@@ -636,11 +647,11 @@ vn_queue_submission_add_query_feedback(struct 
vn_queue_submission *submit,
     * linking a new one. Defer the actual recycle operation to
     * vn_queue_submission_cleanup.
     */
-   if (linked_cmd_buffer->linked_query_feedback_cmd)
+   if (linked_cmd->linked_query_feedback_cmd)
       submit->recycle_query_feedback_cmd =
-         linked_cmd_buffer->linked_query_feedback_cmd;
+         linked_cmd->linked_query_feedback_cmd;
 
-   linked_cmd_buffer->linked_query_feedback_cmd =
+   linked_cmd->linked_query_feedback_cmd =
       vn_command_buffer_from_handle(*feedback_cmd_handle);
 
    return VK_SUCCESS;

Reply via email to