quake3-smp is OK

drmCommandWrite: -22
drmRadeonCmdBuffer: -22 (exiting)

Seems to be fixed.

Latest DRI and DRM CVS.

Yesterday's DRI CVS was fine (textures).

DRM reset works.

See attached patch.

More to come, I'm in hurry.

-Dieter
diff -ru drm.orig/linux/drm_drv.h drm/linux/drm_drv.h
--- drm.orig/linux/drm_drv.h	2004-09-23 17:56:18.000000000 +0200
+++ drm/linux/drm_drv.h	2004-09-23 17:58:09.562593427 +0200
@@ -158,6 +158,8 @@
 
 #define DRIVER_IOCTL_COUNT	DRM_ARRAY_SIZE( DRM(ioctls) )
 
+static void drm_lock_watchdog( unsigned long __data );
+
 static int DRM(setup)( drm_device_t *dev )
 {
 	int i;
@@ -261,6 +263,7 @@
 
 	down( &dev->struct_sem );
 	del_timer( &dev->timer );
+	del_timer_sync( &dev->lock.watchdog );
 
 	if ( dev->devname ) {
 		DRM(free)( dev->devname, strlen( dev->devname ) + 1,
@@ -371,6 +374,7 @@
 	if ( dev->lock.hw_lock ) {
 		dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
 		dev->lock.filp = NULL;
+		dev->lock.dontbreak = 1;
 		wake_up_interruptible( &dev->lock.lock_queue );
 	}
 	up( &dev->struct_sem );
@@ -463,6 +467,10 @@
 		goto error_out_unreg;
 	}
 
+	init_timer( &dev->lock.watchdog );
+	dev->lock.watchdog.data = (unsigned long) dev;
+	dev->lock.watchdog.function = drm_lock_watchdog;
+
 	dev->device = MKDEV(DRM_MAJOR, dev->minor );
 
 	DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d: %s\n",
@@ -810,6 +818,11 @@
 		if (dev->fn_tbl.release)
 			dev->fn_tbl.release(dev, filp);
 
+		/* Avoid potential race where the watchdog callback is still
+		 * running when filp is freed.
+		 */
+                del_timer_sync( &dev->lock.watchdog );
+
 		DRM(lock_free)( dev, &dev->lock.hw_lock->lock,
 				_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) );
 
@@ -832,6 +845,7 @@
 			}
 			if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
 					     DRM_KERNEL_CONTEXT ) ) {
+				dev->lock.dontbreak = 1;
 				dev->lock.filp	    = filp;
 				dev->lock.lock_time = jiffies;
                                 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
@@ -983,6 +997,40 @@
 	return retcode;
 }
 
+
+/**
+ * Lock watchdog callback function.
+ *
+ * Whenever a privileged client must sleep on the lock waitqueue
+ * in the LOCK ioctl, the watchdog timer is started.
+ * When the UNLOCK ioctl is called, the timer is stopped.
+ *
+ * When the watchdog timer expires, the process holding the lock
+ * is killed. Privileged clients set lock.dontbreak and are exempt
+ * from this rule.
+ */
+static void drm_lock_watchdog( unsigned long __data )
+{
+	drm_device_t *dev = (drm_device_t *)__data;
+	drm_file_t *priv;
+	
+	if ( !dev->lock.filp ) {
+		DRM_DEBUG( "held by kernel\n" );
+		return;
+	}
+	
+	if ( dev->lock.dontbreak ) {
+		DRM_DEBUG( "privileged lock\n" );
+		return;
+	}
+	
+	priv = dev->lock.filp->private_data;
+	DRM_DEBUG( "Kill pid=%d\n", priv->pid );
+	
+	kill_proc( priv->pid, SIGKILL, 1 );
+}
+
+
 /** 
  * Lock ioctl.
  *
@@ -1002,6 +1050,7 @@
         DECLARE_WAITQUEUE( entry, current );
         drm_lock_t lock;
         int ret = 0;
+	int privileged = capable( CAP_SYS_ADMIN );
 
 	++priv->lock_count;
 
@@ -1032,6 +1081,7 @@
 		}
 		if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
 				     lock.context ) ) {
+			dev->lock.dontbreak = privileged;
 			dev->lock.filp      = filp;
 			dev->lock.lock_time = jiffies;
 			atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
@@ -1039,6 +1089,14 @@
 		}
 		
 		/* Contention */
+
+		if ( privileged ) {
+			if ( !timer_pending( &dev->lock.watchdog ) ) {
+				DRM_DEBUG( "Starting lock watchdog\n" );
+				mod_timer( &dev->lock.watchdog, jiffies + 5 * HZ );
+			}
+		}
+
 		schedule();
 		if ( signal_pending( current ) ) {
 			ret = -ERESTARTSYS;
@@ -1103,8 +1161,12 @@
 		return -EINVAL;
 	}
 
+	DRM_DEBUG( "\n" );
+
 	atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
 
+	del_timer_sync( &dev->lock.watchdog );
+
 	if (dev->fn_tbl.kernel_context_switch_unlock)
 		dev->fn_tbl.kernel_context_switch_unlock(dev);
 	else
diff -ru drm.orig/linux/drmP.h drm/linux/drmP.h
--- drm.orig/linux/drmP.h	2004-09-23 17:56:18.000000000 +0200
+++ drm/linux/drmP.h	2004-09-23 17:58:09.565592833 +0200
@@ -406,6 +406,8 @@
 	struct file       *filp;	/**< File descr of lock holder (0=kernel) */
 	wait_queue_head_t lock_queue;	/**< Queue of blocked processes */
 	unsigned long	  lock_time;	/**< Time of last lock in jiffies */
+	struct timer_list watchdog;	/**< Watchdog timer to kill runaway processes */
+	int               dontbreak;	/**< Even watchdog honours the current lock */
 } drm_lock_data_t;
 
 /**

Reply via email to