On Wed, 2003-11-05 at 05:07, Felix Kühling wrote:
> Hi,
> 
> I get hard lockups when switching from a second Xserver (:1) started on
> vt8 back to the first one (:0) on vt7. It happens on  VT switches as
> well as when the second Xserver exits. Sysrq keys don't work, and the
> machine doesn't respond to ping any more. I had a look at the
> XFree86.1.log from the second Xserver. This looks surprising to me:
> 
> ...
> drmOpenDevice: node name is /dev/dri/card0
> drmOpenDevice: open result is 9, (OK)
> drmOpenDevice: node name is /dev/dri/card0
> drmOpenDevice: open result is 9, (OK)
> drmOpenByBusid: Searching for BusID pci:0000:01:00.0
> drmOpenDevice: node name is /dev/dri/card0
> drmOpenDevice: open result is 9, (OK)
> drmOpenByBusid: drmOpenMinor returns 9
> drmOpenByBusid: drmGetBusid reports pci:0000:01:00.0
> (II) RADEON(0): [drm] DRM interface version 1.1
> (II) RADEON(0): [drm] created "radeon" driver at busid "pci:0000:01:00.0"
> (II) RADEON(0): [drm] added 8192 byte SAREA at 0xd8f7e000
> (II) RADEON(0): [drm] mapped SAREA 0xd8f7e000 to 0x40012000
> (II) RADEON(0): [drm] framebuffer handle = 0xd0000000
> (II) RADEON(0): [drm] added 1 reserved context for kernel
> (WW) RADEON(0): [agp] AGP not available
> (II) RADEON(0): [drm] removed 1 reserved context for kernel
> (II) RADEON(0): [drm] unmapping 8192 bytes of SAREA 0xd8f7e000 at 0x40012000
> ...
> 
> IIRC the old behaviour was that the second Xserver couldn't open the DRM
> in the first place. Now it opens the DRM but fails because AGP is not
> available (it was available to the first Xserver, though). Does anyone
> know for sure? Eric, could this be related to your latest DRM changes?

Ahh, here we go.  The 2nd X Server's adding of the SAREA was changing
the kernel's lock pointer, so when the 1st server was switched to it was
looping with lock errors.  The attached patch causes the addition of a
2nd lock-containing DRM_SHM map to return EBUSY, along with adding of
additional maps of the same offset/size doing the same (not necessary,
it was my first attempt).  When I get back from class I'll try to clean
it up, port, and commit unless there are issues.

This makes me wonder how difficult it would be to get two servers to
cooperatively share a DRM instance (both of them holding the DRM open,
rather than the reinit thing done before).

-- 
Eric Anholt                                [EMAIL PROTECTED]          
http://people.freebsd.org/~anholt/         [EMAIL PROTECTED]

Index: drm_bufs.h
===================================================================
RCS file: /home/ncvs/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_bufs.h,v
retrieving revision 1.24
diff -u -r1.24 drm_bufs.h
--- drm_bufs.h	19 Jun 2003 00:09:52 -0000	1.24
+++ drm_bufs.h	6 Nov 2003 01:12:25 -0000
@@ -99,6 +99,7 @@
 	drm_device_t *dev = priv->dev;
 	drm_map_t *map;
 	drm_map_list_t *list;
+	struct list_head *lh;
 
 	if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */
 
@@ -111,6 +112,22 @@
 		return -EFAULT;
 	}
 
+	/* Check if this map has already been added.  If so, then a second X
+	 * Server is trying to initialize the DRM.
+	 */
+	down(&dev->struct_sem);
+	list_for_each(lh, &dev->maplist->head) {
+		drm_map_list_t *r_list = list_entry(lh, drm_map_list_t, head);
+
+		if (r_list->map->offset == map->offset &&
+		    r_list->map->size == map->size) {
+			up(&dev->struct_sem);
+			DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+			return DRM_ERR(EBUSY);
+		}
+	}
+ 	up(&dev->struct_sem);
+
 	/* Only allow shared memory to be removable since we only keep enough
 	 * book keeping information about shared memory to allow for removal
 	 * when processes fork.
@@ -161,6 +178,11 @@
 		}
 		map->offset = (unsigned long)map->handle;
 		if ( map->flags & _DRM_CONTAINS_LOCK ) {
+			/* Prevent a 2nd X Server from creating a 2nd lock */
+			if (dev->lock.hw_lock != NULL) {
+				DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
+				return DRM_ERR(EBUSY);
+			}
 			dev->sigdata.lock =
 			dev->lock.hw_lock = map->handle; /* Pointer to lock */
 		}

Reply via email to