[RFC PATCH 8/9] drm/rustgem: implement timeout to prevent hangs

Maíra Canal mcanal at igalia.com
Fri Mar 17 12:12:12 UTC 2023


In order to prevent possible hangs, if the fence is not signaled for
more than 10 seconds, force the fence to expire by being signaled.

Signed-off-by: Maíra Canal <mcanal at igalia.com>
---
 drivers/gpu/drm/rustgem/fence.rs | 31 +++++++++++++++++++++++++++++--
 drivers/gpu/drm/rustgem/file.rs  |  7 +++++++
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rustgem/fence.rs b/drivers/gpu/drm/rustgem/fence.rs
index 9ef1399548e2..eb1d7faa7e8e 100644
--- a/drivers/gpu/drm/rustgem/fence.rs
+++ b/drivers/gpu/drm/rustgem/fence.rs
@@ -2,10 +2,13 @@
 
 use core::fmt::Write;
 use core::ops::Deref;
-use kernel::c_str;
+use core::time::Duration;
 use kernel::dma_fence::*;
 use kernel::prelude::*;
 use kernel::sync::Arc;
+use kernel::time::timer::*;
+use kernel::time::*;
+use kernel::{bindings, c_str, timer_init};
 
 static QUEUE_NAME: &CStr = c_str!("vgem_fence");
 static QUEUE_CLASS_KEY: kernel::sync::LockClassKey = kernel::sync::LockClassKey::new();
@@ -36,6 +39,7 @@ impl FenceOps for Fence {
 
 pub(crate) struct VgemFence {
     fence: Arc<UniqueFence<Fence>>,
+    _timer: Box<FnTimer<Box<dyn FnMut() -> Result<Next> + Sync>>>,
 }
 
 impl VgemFence {
@@ -43,7 +47,30 @@ impl VgemFence {
         let fence_ctx = FenceContexts::new(1, QUEUE_NAME, &QUEUE_CLASS_KEY)?;
         let fence = Arc::try_new(fence_ctx.new_fence(0, Fence {})?)?;
 
-        Ok(Self { fence })
+        // SAFETY: The caller calls [`FnTimer::init_timer`] before using the timer.
+        let t = Box::try_new(unsafe {
+            FnTimer::new(Box::try_new({
+                let fence = fence.clone();
+                move || {
+                    let _ = fence.signal();
+                    Ok(Next::Done)
+                }
+            })? as Box<_>)
+        })?;
+
+        // SAFETY: As FnTimer is inside a Box, it won't be moved.
+        let ptr = unsafe { core::pin::Pin::new_unchecked(&*t) };
+
+        timer_init!(ptr, 0, "vgem_timer");
+
+        // SAFETY: Duration.as_millis() returns a valid total number of whole milliseconds.
+        let timeout =
+            unsafe { bindings::msecs_to_jiffies(Duration::from_secs(10).as_millis().try_into()?) };
+
+        // We force the fence to expire within 10s to prevent driver hangs
+        ptr.raw_timer().schedule_at(jiffies_later(timeout));
+
+        Ok(Self { fence, _timer: t })
     }
 }
 
diff --git a/drivers/gpu/drm/rustgem/file.rs b/drivers/gpu/drm/rustgem/file.rs
index 2552c7892b0e..a3714e8ca206 100644
--- a/drivers/gpu/drm/rustgem/file.rs
+++ b/drivers/gpu/drm/rustgem/file.rs
@@ -33,6 +33,10 @@ impl File {
     /// via the dma-buf reservation object and visible to consumers of the exported
     /// dma-buf.
     ///
+    /// This returns the handle for the new fence that must be signaled within 10
+    /// seconds (or otherwise it will automatically expire). See
+    /// signal (DRM_IOCTL_VGEM_FENCE_SIGNAL).
+    ///
     /// If the vGEM handle does not exist, attach returns -ENOENT.
     ///
     pub(crate) fn attach(
@@ -84,6 +88,9 @@ impl File {
     /// Signal and consume a fence earlier attached to a vGEM handle using
     /// attach (DRM_IOCTL_VGEM_FENCE_ATTACH).
     ///
+    /// All fences must be signaled within 10s of attachment or otherwise they
+    /// will automatically expire (and signal returns -ETIMEDOUT).
+    ///
     /// Signaling a fence indicates to all consumers of the dma-buf that the
     /// client has completed the operation associated with the fence, and that the
     /// buffer is then ready for consumption.
-- 
2.39.2



More information about the dri-devel mailing list