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; /**