Hi

The drm code uses 'struct mtx' as DRM_SPINTYPE on FreeBSD 5.x.  The
kernel expects such mutices to be freed after use by calling
mtx_destroy(), which the current code fails to do.  Quitting X and
restarting it thus results in this kernel panic:

%%
[...]
panic: mutex vblsig 0xc65fa234 already initialized
cpuid = 1; lapic.id = 01000000
boot() called on cpu#1
[...]
#12 0xc02003e7 in panic () at /freebsd/current/src/sys/kern/kern_shutdown.c:531
#13 0xc01f714f in mtx_init (m=0xc65fa234, name=0xc67d652c "vblsig", type=0x0, 
    opts=0) at /freebsd/current/src/sys/kern/kern_mutex.c:914
#14 0xc67cb50f in ?? ()
#15 0xc67cb7ef in ?? ()
#16 0xc67ccd0e in ?? ()
#17 0xc01c8a0e in spec_ioctl (ap=0xc65fa000)
    at /freebsd/current/src/sys/fs/specfs/spec_vnops.c:349
[...]
%%

The attached patch does these things:

- Create a new macro DRM_SPINDESTROY which releases the lock on FreeBSD
  5.x by calling mtx_destroy(), on 4.x and NetBSD it does nothing.  I
  also removed the trailing ';' from the DRM_SPINUNLOCK macro.

- Move the lock creation for getmagic() into the attach routing and make
  the mutex a member of drm_device (otherwise, the static lock could not
  be released).  The vbl_lock which caused my panic is also created in
  attach().

- Create mem_cleanup() as counterpart to mem_init().  Mem_clean() just
  releases DRM(mem_lock).
  
- Add code to release all locks in the detach function.  The waitlist
  mutex is released in waitlist_destroy().

- Fix an occurence of p->p_pid, which doesn't compile on FreeBSD 5.x
  because p is a struct thread, not a struct proc.


Regards,
Stefan Farfeleder
Index: drmP.h
===================================================================
RCS file: 
/cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drmP.h,v
retrieving revision 1.11
diff -c -r1.11 drmP.h
*** drmP.h      6 Dec 2002 02:27:30 -0000       1.11
--- drmP.h      4 Feb 2003 17:10:58 -0000
***************
*** 419,424 ****
--- 419,425 ----
  
                                /* Locks */
        DRM_SPINTYPE      count_lock;   /* For inuse, open_count, buf_use  */
+       DRM_SPINTYPE      getmagic_lock;        /* For the getmagic ioctl  */
        struct lock       dev_lock;     /* For others                      */
                                /* Usage Counters */
        int               open_count;   /* Outstanding files open          */
***************
*** 530,535 ****
--- 531,537 ----
  
                                /* Memory management support (drm_memory.h) */
  extern void        DRM(mem_init)(void);
+ extern void        DRM(mem_cleanup)(void);
  extern void        *DRM(alloc)(size_t size, int area);
  extern void        *DRM(realloc)(void *oldpt, size_t oldsize, size_t size,
                                   int area);
Index: drm_auth.h
===================================================================
RCS file: 
/cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_auth.h,v
retrieving revision 1.3
diff -c -r1.3 drm_auth.h
*** drm_auth.h  5 Jul 2002 08:31:07 -0000       1.3
--- drm_auth.h  4 Feb 2003 17:10:58 -0000
***************
*** 116,140 ****
  {
        static drm_magic_t sequence = 0;
        drm_auth_t         auth;
-       static DRM_SPINTYPE lock;
-       static int         first = 1;
        DRM_DEVICE;
        DRM_PRIV;
  
-       if (first) {
-               DRM_SPININIT(lock, "drm getmagic");
-               first = 0;
-       }
- 
                                /* Find unique magic */
        if (priv->magic) {
                auth.magic = priv->magic;
        } else {
                do {
!                       DRM_SPINLOCK(&lock);
                        if (!sequence) ++sequence; /* reserve 0 */
                        auth.magic = sequence++;
!                       DRM_SPINUNLOCK(&lock);
                } while (DRM(find_file)(dev, auth.magic));
                priv->magic = auth.magic;
                DRM(add_magic)(dev, priv, auth.magic);
--- 116,133 ----
  {
        static drm_magic_t sequence = 0;
        drm_auth_t         auth;
        DRM_DEVICE;
        DRM_PRIV;
  
                                /* Find unique magic */
        if (priv->magic) {
                auth.magic = priv->magic;
        } else {
                do {
!                       DRM_SPINLOCK(&dev->getmagic_lock);
                        if (!sequence) ++sequence; /* reserve 0 */
                        auth.magic = sequence++;
!                       DRM_SPINUNLOCK(&dev->getmagic_lock);
                } while (DRM(find_file)(dev, auth.magic));
                priv->magic = auth.magic;
                DRM(add_magic)(dev, priv, auth.magic);
Index: drm_dma.h
===================================================================
RCS file: 
/cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_dma.h,v
retrieving revision 1.10
diff -c -r1.10 drm_dma.h
*** drm_dma.h   2 Feb 2003 03:06:47 -0000       1.10
--- drm_dma.h   4 Feb 2003 17:11:01 -0000
***************
*** 525,531 ****
  #endif
  
  #if __HAVE_VBL_IRQ
-       DRM_SPININIT( dev->vbl_lock, "vblsig" );
        TAILQ_INIT( &dev->vbl_sig_list );
  #endif
  
--- 525,530 ----
Index: drm_drv.h
===================================================================
RCS file: 
/cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_drv.h,v
retrieving revision 1.8
diff -c -r1.8 drm_drv.h
*** drm_drv.h   27 Oct 2002 05:24:33 -0000      1.8
--- drm_drv.h   4 Feb 2003 17:11:02 -0000
***************
*** 701,706 ****
--- 701,707 ----
        if ( dev->agp == NULL ) {
                DRM_ERROR( "Cannot initialize the agpgart module.\n" );
                DRM(sysctl_cleanup)( dev );
+               DRM(mem_cleanup)();
  #ifdef __FreeBSD__
                destroy_dev(dev->devnode);
  #endif
***************
*** 739,744 ****
--- 740,746 ----
        if( retcode ) {
                DRM_ERROR( "Cannot allocate memory for context bitmap.\n" );
                DRM(sysctl_cleanup)( dev );
+               DRM(mem_cleanup)();
  #ifdef __FreeBSD__
                destroy_dev(dev->devnode);
  #endif
***************
*** 754,759 ****
--- 756,766 ----
                DRIVER_DATE,
                unit );
  
+       DRM_SPININIT(dev->getmagic_lock, "drm getmagic");
+ #if __HAVE_VBL_IRQ
+       DRM_SPININIT(dev->vbl_lock, "vblsig");
+ #endif
+ 
        DRIVER_POSTINIT();
  
        return 0;
***************
*** 785,790 ****
--- 792,798 ----
        dev = device_get_softc(nbdev);
  #endif
        DRM(sysctl_cleanup)( dev );
+       DRM(mem_cleanup)();
  #ifdef __FreeBSD__
        destroy_dev(dev->devnode);
  #endif
***************
*** 813,818 ****
--- 821,833 ----
                dev->agp = NULL;
        }
  #endif
+ 
+       DRM_SPINDESTROY(&dev->count_lock);
+       DRM_SPINDESTROY(&dev->getmagic_lock);
+ #if __HAVE_VBL_IRQ
+       DRM_SPINDESTROY(&dev->vbl_lock);
+ #endif
+ 
        DRIVER_POSTCLEANUP();
  }
  
***************
*** 926,932 ****
--- 941,951 ----
                        }
                        if ( DRM(lock_take)( &dev->lock.hw_lock->lock,
                                             DRM_KERNEL_CONTEXT ) ) {
+ #if defined (__FreeBSD__) && (__FreeBSD_version >= 500000)
+                               dev->lock.pid       = p->td_proc->p_pid;
+ #else
                                dev->lock.pid       = p->p_pid;
+ #endif
                                dev->lock.lock_time = jiffies;
                                  atomic_inc( &dev->counts[_DRM_STAT_LOCKS] );
                                break;  /* Got lock */
Index: drm_lists.h
===================================================================
RCS file: 
/cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_lists.h,v
retrieving revision 1.3
diff -c -r1.3 drm_lists.h
*** drm_lists.h 5 Jul 2002 08:31:07 -0000       1.3
--- drm_lists.h 4 Feb 2003 17:11:03 -0000
***************
*** 66,71 ****
--- 66,73 ----
        bl->rp    = NULL;
        bl->wp    = NULL;
        bl->end   = NULL;
+       DRM_SPINDESTROY( &bl->write_lock );
+       DRM_SPINDESTROY( &bl->read_lock );
        return 0;
  }
  
Index: drm_memory.h
===================================================================
RCS file: 
/cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_memory.h,v
retrieving revision 1.3
diff -c -r1.3 drm_memory.h
*** drm_memory.h        5 Jul 2002 08:31:07 -0000       1.3
--- drm_memory.h        4 Feb 2003 17:11:03 -0000
***************
*** 95,100 ****
--- 95,105 ----
        DRM(ram_used)      = 0;
  }
  
+ void DRM(mem_cleanup)(void)
+ {
+       DRM_SPINDESTROY(&DRM(mem_lock));
+ }
+ 
  #ifdef __FreeBSD__
  /* drm_mem_info is called whenever a process reads /dev/drm/mem. */
  static int DRM(_mem_info) DRM_SYSCTL_HANDLER_ARGS
Index: drm_os_freebsd.h
===================================================================
RCS file: 
/cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_freebsd.h,v
retrieving revision 1.11
diff -c -r1.11 drm_os_freebsd.h
*** drm_os_freebsd.h    24 Jan 2003 00:49:15 -0000      1.11
--- drm_os_freebsd.h    4 Feb 2003 17:11:05 -0000
***************
*** 80,86 ****
  #define DRM_SPINTYPE          struct mtx
  #define DRM_SPININIT(l,name)  mtx_init(&l, name, NULL, MTX_DEF)
  #define DRM_SPINLOCK(l)               mtx_lock(l)
! #define DRM_SPINUNLOCK(u)     mtx_unlock(u);
  #define DRM_CURRENTPID                curthread->td_proc->p_pid
  #else
  #define DRM_CURPROC           curproc
--- 80,87 ----
  #define DRM_SPINTYPE          struct mtx
  #define DRM_SPININIT(l,name)  mtx_init(&l, name, NULL, MTX_DEF)
  #define DRM_SPINLOCK(l)               mtx_lock(l)
! #define DRM_SPINUNLOCK(u)     mtx_unlock(u)
! #define DRM_SPINDESTROY(l)    mtx_destroy(l)
  #define DRM_CURRENTPID                curthread->td_proc->p_pid
  #else
  #define DRM_CURPROC           curproc
***************
*** 88,94 ****
  #define DRM_SPINTYPE          struct simplelock
  #define DRM_SPININIT(l,name)  simple_lock_init(&l)
  #define DRM_SPINLOCK(l)               simple_lock(l)
! #define DRM_SPINUNLOCK(u)     simple_unlock(u);
  #define DRM_CURRENTPID                curproc->p_pid
  #endif
  
--- 89,96 ----
  #define DRM_SPINTYPE          struct simplelock
  #define DRM_SPININIT(l,name)  simple_lock_init(&l)
  #define DRM_SPINLOCK(l)               simple_lock(l)
! #define DRM_SPINUNLOCK(u)     simple_unlock(u)
! #define DRM_SPINDESTROY(l)    (void)0
  #define DRM_CURRENTPID                curproc->p_pid
  #endif
  
Index: drm_os_netbsd.h
===================================================================
RCS file: 
/cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_netbsd.h,v
retrieving revision 1.2
diff -c -r1.2 drm_os_netbsd.h
*** drm_os_netbsd.h     5 Jul 2002 08:31:07 -0000       1.2
--- drm_os_netbsd.h     4 Feb 2003 17:11:06 -0000
***************
*** 64,70 ****
  #define DRM_SPINTYPE          struct simplelock
  #define DRM_SPININIT(l,name)  simple_lock_init(&l)
  #define DRM_SPINLOCK(l)       simple_lock(l)
! #define DRM_SPINUNLOCK(u)     simple_unlock(u);
  #define DRM_CURRENTPID       curproc->p_pid
  
  #define DRM_IOCTL_ARGS                dev_t kdev, u_long cmd, caddr_t data, int 
flags, DRM_STRUCTPROC *p
--- 64,71 ----
  #define DRM_SPINTYPE          struct simplelock
  #define DRM_SPININIT(l,name)  simple_lock_init(&l)
  #define DRM_SPINLOCK(l)       simple_lock(l)
! #define DRM_SPINUNLOCK(u)     simple_unlock(u)
! #define DRM_SPINDESTROY(l)    (void)0
  #define DRM_CURRENTPID       curproc->p_pid
  
  #define DRM_IOCTL_ARGS                dev_t kdev, u_long cmd, caddr_t data, int 
flags, DRM_STRUCTPROC *p

Reply via email to