--- a/sys/dev/drm/drm_sysctl.c +++ b/sys/dev/drm/drm_sysctl.c @@ -265,23 +265,34 @@ int retcode; int privcount, i; - DRM_LOCK(dev); + /* + * dev->filelist is protected by dev->filelist_mutex + * (drm_device.h:88), NOT by dev->struct_mutex: drm_open() and + * drm_close() mutate it under filelist_mutex only + * (drm_file.c:514-516, drm_file.c:380-382). The copy walk below + * is bounded by the list, not by privcount, so opens that land + * between the two walks (e.g. during the M_WAITOK sleep) write + * sizeof(struct drm_file) chunks past tempprivs. Hold the lock + * the mutators actually take. + */ + mutex_lock(&dev->filelist_mutex); privcount = 0; list_for_each_entry(priv, &dev->filelist, lhead) privcount++; + /* M_WAITOK under the sleepable filelist_mutex is fine. */ tempprivs = kmalloc(sizeof(struct drm_file) * privcount, M_DRM, M_WAITOK | M_NULLOK); if (tempprivs == NULL) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->filelist_mutex); return ENOMEM; } i = 0; list_for_each_entry(priv, &dev->filelist, lhead) tempprivs[i++] = *priv; - DRM_UNLOCK(dev); + mutex_unlock(&dev->filelist_mutex); DRM_SYSCTL_PRINT( "\na pid magic ioctls\n");