Skip to content

Commit efae6e2

Browse files
supercomputer7AtkinsSJ
authored andcommitted
Kernel/Graphics: Propagate errors properly around in the VirtIO driver
This happens to be a sad truth for the VirtIOGPU driver - it lacked any error propagation measures and generally relied on clunky assumptions that most operations with the GPU device are infallible, although in reality much of them could fail, so we do need to handle errors. To fix this, synchronous GPU commands no longer rely on the wait queue mechanism anymore, so instead we introduce a timeout-based mechanism, similar to how other Kernel drivers use a polling based mechanism with the assumption that hardware could get stuck in an error state and we could abort gracefully. Then, we change most of the VirtIOGraphicsAdapter methods to propagate errors properly to the original callers, to ensure that if a synchronous GPU command failed, either the Kernel or userspace could do something meaningful about this situation.
1 parent 12d4bbb commit efae6e2

File tree

5 files changed

+177
-152
lines changed

5 files changed

+177
-152
lines changed

Kernel/Graphics/VirtIOGPU/DisplayConnector.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ ErrorOr<void> VirtIODisplayConnector::flush_rectangle(size_t buffer_index, FBRec
122122
.height = rect.height
123123
};
124124

125-
m_graphics_adapter->transfer_framebuffer_data_to_host({}, *this, dirty_rect, true);
125+
TRY(m_graphics_adapter->transfer_framebuffer_data_to_host({}, *this, dirty_rect, true));
126126
// Flushing directly to screen
127-
flush_displayed_image(dirty_rect, true);
127+
TRY(flush_displayed_image(dirty_rect, true));
128128
return {};
129129
}
130130

@@ -139,9 +139,9 @@ ErrorOr<void> VirtIODisplayConnector::flush_first_surface()
139139
.height = m_display_info.rect.height
140140
};
141141

142-
m_graphics_adapter->transfer_framebuffer_data_to_host({}, *this, dirty_rect, true);
142+
TRY(m_graphics_adapter->transfer_framebuffer_data_to_host({}, *this, dirty_rect, true));
143143
// Flushing directly to screen
144-
flush_displayed_image(dirty_rect, true);
144+
TRY(flush_displayed_image(dirty_rect, true));
145145
return {};
146146
}
147147

@@ -241,10 +241,11 @@ void VirtIODisplayConnector::draw_ntsc_test_pattern(Badge<VirtIOGraphicsAdapter>
241241
dbgln_if(VIRTIO_DEBUG, "Finish drawing the pattern");
242242
}
243243

244-
void VirtIODisplayConnector::flush_displayed_image(Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect, bool main_buffer)
244+
ErrorOr<void> VirtIODisplayConnector::flush_displayed_image(Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect, bool main_buffer)
245245
{
246246
VERIFY(m_graphics_adapter->operation_lock().is_locked());
247-
m_graphics_adapter->flush_displayed_image({}, *this, dirty_rect, main_buffer);
247+
TRY(m_graphics_adapter->flush_displayed_image({}, *this, dirty_rect, main_buffer));
248+
return {};
248249
}
249250

250251
void VirtIODisplayConnector::set_dirty_displayed_rect(Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect, bool main_buffer)

Kernel/Graphics/VirtIOGPU/DisplayConnector.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class VirtIODisplayConnector final : public DisplayConnector {
6868
private:
6969
VirtIODisplayConnector(VirtIOGraphicsAdapter& graphics_adapter, Graphics::VirtIOGPU::ScanoutID scanout_id);
7070

71-
void flush_displayed_image(Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect, bool main_buffer);
71+
ErrorOr<void> flush_displayed_image(Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect, bool main_buffer);
7272
void set_dirty_displayed_rect(Graphics::VirtIOGPU::Protocol::Rect const& dirty_rect, bool main_buffer);
7373

7474
void query_display_information();

Kernel/Graphics/VirtIOGPU/GPU3DDevice.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ ErrorOr<void> VirtIOGPU3DDevice::ioctl(OpenFileDescription& description, unsigne
9494
SpinlockLocker locker(m_graphics_adapter->operation_lock());
9595
auto user_command_buffer = static_ptr_cast<VirGLCommandBuffer const*>(arg);
9696
auto command_buffer = TRY(copy_typed_from_user(user_command_buffer));
97-
m_graphics_adapter->submit_command_buffer(context_id, [&](Bytes buffer) {
97+
TRY(m_graphics_adapter->submit_command_buffer(context_id, [&](Bytes buffer) {
9898
auto num_bytes = command_buffer.num_elems * sizeof(u32);
9999
VERIFY(num_bytes <= buffer.size());
100100
MUST(copy_from_user(buffer.data(), command_buffer.data, num_bytes));
101101
return num_bytes;
102-
});
102+
}));
103103
return {};
104104
}
105105
case VIRGL_IOCTL_CREATE_RESOURCE: {
@@ -121,10 +121,12 @@ ErrorOr<void> VirtIOGPU3DDevice::ioctl(OpenFileDescription& description, unsigne
121121
.padding = 0,
122122
};
123123
SpinlockLocker locker(m_graphics_adapter->operation_lock());
124-
auto resource_id = m_graphics_adapter->create_3d_resource(resource_spec).value();
125-
m_graphics_adapter->attach_resource_to_context(resource_id, per_context_state->context_id());
126-
m_graphics_adapter->ensure_backing_storage(resource_id, per_context_state->transfer_buffer_region(), 0, NUM_TRANSFER_REGION_PAGES * PAGE_SIZE);
127-
spec.created_resource_id = resource_id;
124+
// FIXME: What would be an appropriate resource free-ing mechanism to use in case anything
125+
// after this fails?
126+
auto resource_id = TRY(m_graphics_adapter->create_3d_resource(resource_spec));
127+
TRY(m_graphics_adapter->attach_resource_to_context(resource_id, per_context_state->context_id()));
128+
TRY(m_graphics_adapter->ensure_backing_storage(resource_id, per_context_state->transfer_buffer_region(), 0, NUM_TRANSFER_REGION_PAGES * PAGE_SIZE));
129+
spec.created_resource_id = resource_id.value();
128130
// FIXME: We should delete the resource we just created if we fail to copy the resource id out
129131
return copy_to_user(static_ptr_cast<VirGL3DResourceSpec*>(arg), &spec);
130132
}

0 commit comments

Comments
 (0)