summaryrefslogtreecommitdiff
path: root/bsd
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2003-10-20 05:09:21 +0000
committerEric Anholt <anholt@freebsd.org>2003-10-20 05:09:21 +0000
commitea7b4fdc225ebbbfd77f875fd3bfcfbdcfa9a1f7 (patch)
treea37f442a37d9e577110812486410c4c023bf43e6 /bsd
parent6b0424fdcdec9d12943718e4542659c8bca019da (diff)
Fix the possibility of sleeping with locks held in sysctls by copying the
data into temporary variables with the lock held then outputting to sysctls with the lock released. Rearranged a little extra code to aid this. Note that drm_memory_debug.h hasn't had this fix applied, but I consider that code to be just about dead anyway.
Diffstat (limited to 'bsd')
-rw-r--r--bsd/drm_drv.h18
-rw-r--r--bsd/drm_memory_debug.h8
-rw-r--r--bsd/drm_os_freebsd.h8
-rw-r--r--bsd/drm_os_netbsd.h6
-rw-r--r--bsd/drm_sysctl.h206
5 files changed, 142 insertions, 104 deletions
diff --git a/bsd/drm_drv.h b/bsd/drm_drv.h
index 269f4225..7d753836 100644
--- a/bsd/drm_drv.h
+++ b/bsd/drm_drv.h
@@ -472,11 +472,6 @@ static int DRM(setup)( drm_device_t *dev )
dev->magiclist[i].tail = NULL;
}
- dev->maplist = DRM(calloc)(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
- if (dev->maplist == NULL)
- return DRM_ERR(ENOMEM);
- TAILQ_INIT(dev->maplist);
-
dev->lock.hw_lock = NULL;
dev->lock.lock_queue = 0;
dev->irq = 0;
@@ -591,8 +586,6 @@ static int DRM(takedown)( drm_device_t *dev )
DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
}
- DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
- dev->maplist = NULL;
}
#if __HAVE_DMA
@@ -647,6 +640,14 @@ static int DRM(init)( device_t nbdev )
#elif defined(__NetBSD__)
unit = minor(dev->device.dv_unit);
#endif
+
+ dev->maplist = DRM(calloc)(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
+ if (dev->maplist == NULL) {
+ retcode = ENOMEM;
+ goto error;
+ }
+ TAILQ_INIT(dev->maplist);
+
dev->name = DRIVER_NAME;
DRM(mem_init)();
DRM(sysctl_init)(dev);
@@ -680,6 +681,7 @@ static int DRM(init)( device_t nbdev )
goto error;
}
#endif
+
DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n",
DRIVER_NAME,
DRIVER_MAJOR,
@@ -703,6 +705,7 @@ error:
mtx_destroy(&dev->dev_lock);
#endif
#endif
+ DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
return retcode;
}
@@ -749,6 +752,7 @@ static void DRM(cleanup)(drm_device_t *dev)
#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
mtx_destroy(&dev->dev_lock);
#endif
+ DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
}
diff --git a/bsd/drm_memory_debug.h b/bsd/drm_memory_debug.h
index c4bad089..d211b76b 100644
--- a/bsd/drm_memory_debug.h
+++ b/bsd/drm_memory_debug.h
@@ -32,6 +32,14 @@
#include "drmP.h"
+#define DRM_SYSCTL_PRINT(fmt, arg...) \
+do { \
+ snprintf(buf, sizeof(buf), fmt, ##arg); \
+ error = SYSCTL_OUT(req, buf, strlen(buf)); \
+ if (error) \
+ return error; \
+} while (0)
+
typedef struct drm_mem_stats {
const char *name;
int succeed_count;
diff --git a/bsd/drm_os_freebsd.h b/bsd/drm_os_freebsd.h
index 33bdcd20..42385137 100644
--- a/bsd/drm_os_freebsd.h
+++ b/bsd/drm_os_freebsd.h
@@ -413,14 +413,6 @@ find_first_zero_bit(volatile void *p, int max)
#define DRM_SYSCTL_HANDLER_ARGS SYSCTL_HANDLER_ARGS
#endif
-#define DRM_SYSCTL_PRINT(fmt, arg...) \
-do { \
- snprintf(buf, sizeof(buf), fmt, ##arg); \
- error = SYSCTL_OUT(req, buf, strlen(buf)); \
- if (error) return error; \
-} while (0)
-
-
#define DRM_FIND_MAP(dest, o) \
do { \
drm_map_list_entry_t *listentry; \
diff --git a/bsd/drm_os_netbsd.h b/bsd/drm_os_netbsd.h
index 1554d24d..b03399d8 100644
--- a/bsd/drm_os_netbsd.h
+++ b/bsd/drm_os_netbsd.h
@@ -342,12 +342,6 @@ do { \
#define DRM_DEBUG(fmt, arg...) do { } while (0)
#endif
-#define DRM_SYSCTL_PRINT(fmt, arg...) \
- snprintf(buf, sizeof(buf), fmt, ##arg); \
- error = SYSCTL_OUT(req, buf, strlen(buf)); \
- if (error) return error;
-
-
#define DRM_FIND_MAP(dest, o) \
do { \
drm_map_list_entry_t *listentry; \
diff --git a/bsd/drm_sysctl.h b/bsd/drm_sysctl.h
index fe586d4c..98bcc1ce 100644
--- a/bsd/drm_sysctl.h
+++ b/bsd/drm_sysctl.h
@@ -41,7 +41,9 @@ struct DRM(sysctl_list) {
#endif
{ "vm", DRM(vm_info) },
{ "clients", DRM(clients_info) },
+#if __HAVE_DMA
{ "bufs", DRM(bufs_info) },
+#endif
};
#define DRM_SYSCTL_ENTRIES (sizeof(DRM(sysctl_list))/sizeof(DRM(sysctl_list)[0]))
@@ -112,90 +114,128 @@ int DRM(sysctl_cleanup)(drm_device_t *dev)
return error;
}
+#define DRM_SYSCTL_PRINT(fmt, arg...) \
+do { \
+ snprintf(buf, sizeof(buf), fmt, ##arg); \
+ retcode = SYSCTL_OUT(req, buf, strlen(buf)); \
+ if (retcode) \
+ goto done; \
+} while (0)
+
static int DRM(name_info)DRM_SYSCTL_HANDLER_ARGS
{
drm_device_t *dev = arg1;
char buf[128];
- int error;
+ int retcode;
+ int hasunique = 0;
+ DRM_SYSCTL_PRINT("%s 0x%x", dev->name, dev2udev(dev->devnode));
+
+ DRM_LOCK();
if (dev->unique) {
- DRM_SYSCTL_PRINT("%s 0x%x %s",
- dev->name, dev2udev(dev->devnode), dev->unique);
- } else {
- DRM_SYSCTL_PRINT("%s 0x%x", dev->name, dev2udev(dev->devnode));
+ snprintf(buf, sizeof(buf), " %s", dev->unique);
+ hasunique = 1;
}
+ DRM_UNLOCK();
+
+ if (hasunique)
+ SYSCTL_OUT(req, buf, strlen(buf));
SYSCTL_OUT(req, "", 1);
- return 0;
+done:
+ return retcode;
}
-static int DRM(_vm_info)DRM_SYSCTL_HANDLER_ARGS
+static int DRM(vm_info)DRM_SYSCTL_HANDLER_ARGS
{
drm_device_t *dev = arg1;
- drm_local_map_t *map;
+ drm_local_map_t *map, *tempmaps;
drm_map_list_entry_t *listentry;
const char *types[] = { "FB", "REG", "SHM", "AGP", "SG" };
- const char *type;
- int i=0;
- char buf[128];
- int error;
+ const char *type, *yesno;
+ int i, mapcount;
+ char buf[128];
+ int retcode;
- DRM_SYSCTL_PRINT("\nslot offset size type flags "
- "address mtrr\n");
+ /* We can't hold the lock while doing SYSCTL_OUTs, so allocate a
+ * temporary copy of all the map entries and then SYSCTL_OUT that.
+ */
+ DRM_LOCK();
- if (dev->maplist != NULL) {
- TAILQ_FOREACH(listentry, dev->maplist, link) {
- map = listentry->map;
- if (map->type < 0 || map->type > 4)
- type = "??";
- else
- type = types[map->type];
- DRM_SYSCTL_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
- i,
- map->offset,
- map->size,
- type,
- map->flags,
- (unsigned long)map->handle);
- if (map->mtrr < 0) {
- DRM_SYSCTL_PRINT("no\n");
- } else {
- DRM_SYSCTL_PRINT("yes\n");
- }
- i++;
- }
- }
- SYSCTL_OUT(req, "", 1);
+ mapcount = 0;
+ TAILQ_FOREACH(listentry, dev->maplist, link)
+ mapcount++;
- return 0;
-}
+ tempmaps = DRM(alloc)(sizeof(drm_local_map_t) * mapcount, DRM_MEM_MAPS);
+ if (tempmaps == NULL) {
+ DRM_UNLOCK();
+ return ENOMEM;
+ }
-static int DRM(vm_info)DRM_SYSCTL_HANDLER_ARGS
-{
- drm_device_t __unused *dev = arg1;
- int ret;
+ i = 0;
+ TAILQ_FOREACH(listentry, dev->maplist, link)
+ tempmaps[i++] = *listentry->map;
- DRM_LOCK();
- ret = DRM(_vm_info)(oidp, arg1, arg2, req);
DRM_UNLOCK();
- return ret;
-}
+ DRM_SYSCTL_PRINT("\nslot offset size type flags "
+ "address mtrr\n");
+
+ for (i = 0; i < mapcount; i++) {
+ map = &tempmaps[i];
+
+ if (map->type < 0 || map->type > 4)
+ type = "??";
+ else
+ type = types[map->type];
+ if (map->mtrr <= 0)
+ yesno = "no";
+ else
+ yesno = "yes";
+
+ DRM_SYSCTL_PRINT(
+ "%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx %s\n", i,
+ map->offset, map->size, type, map->flags,
+ (unsigned long)map->handle, yesno);
+ }
+ SYSCTL_OUT(req, "", 1);
-/* drm_bufs_info is called whenever a process reads
- hw.dri.0.bufs. */
+done:
+ DRM(free)(tempmaps, sizeof(drm_local_map_t) * mapcount, DRM_MEM_MAPS);
+ return retcode;
+}
-static int DRM(_bufs_info) DRM_SYSCTL_HANDLER_ARGS
+#if __HAVE_DMA
+static int DRM(bufs_info) DRM_SYSCTL_HANDLER_ARGS
{
drm_device_t *dev = arg1;
drm_device_dma_t *dma = dev->dma;
- int i;
- char buf[128];
- int error;
+ drm_device_dma_t tempdma;
+ int *templists;
+ int i;
+ char buf[128];
+ int retcode;
+
+ /* We can't hold the locks around DRM_SYSCTL_PRINT, so make a temporary
+ * copy of the whole structure and the relevant data from buflist.
+ */
+ DRM_LOCK();
+ DRM_SPINLOCK(&dev->dma_lock);
+ if (dma == NULL) {
+ DRM_SPINUNLOCK(&dev->dma_lock);
+ DRM_UNLOCK();
+ return 0;
+ }
+ tempdma = *dma;
+ templists = DRM(alloc)(sizeof(int) * dma->buf_count, DRM_MEM_BUFS);
+ for (i = 0; i < dma->buf_count; i++)
+ templists[i] = dma->buflist[i]->list;
+ dma = &tempdma;
+ DRM_SPINUNLOCK(&dev->dma_lock);
+ DRM_UNLOCK();
- if (!dma) return 0;
DRM_SYSCTL_PRINT("\n o size count free segs pages kB\n");
for (i = 0; i <= DRM_MAX_ORDER; i++) {
if (dma->bufs[i].buf_count)
@@ -215,35 +255,45 @@ static int DRM(_bufs_info) DRM_SYSCTL_HANDLER_ARGS
DRM_SYSCTL_PRINT("\n");
for (i = 0; i < dma->buf_count; i++) {
if (i && !(i%32)) DRM_SYSCTL_PRINT("\n");
- DRM_SYSCTL_PRINT(" %d", dma->buflist[i]->list);
+ DRM_SYSCTL_PRINT(" %d", templists[i]);
}
DRM_SYSCTL_PRINT("\n");
SYSCTL_OUT(req, "", 1);
- return 0;
+done:
+ DRM(free)(templists, sizeof(int) * dma->buf_count, DRM_MEM_BUFS);
+ return retcode;
}
+#endif
-static int DRM(bufs_info) DRM_SYSCTL_HANDLER_ARGS
+static int DRM(clients_info)DRM_SYSCTL_HANDLER_ARGS
{
- drm_device_t __unused *dev = arg1;
- int ret;
+ drm_device_t *dev = arg1;
+ drm_file_t *priv, *tempprivs;
+ char buf[128];
+ int retcode;
+ int privcount, i;
DRM_LOCK();
- ret = DRM(_bufs_info)(oidp, arg1, arg2, req);
- DRM_UNLOCK();
- return ret;
-}
+ privcount = 0;
+ TAILQ_FOREACH(priv, &dev->files, link)
+ privcount++;
-static int DRM(_clients_info) DRM_SYSCTL_HANDLER_ARGS
-{
- drm_device_t *dev = arg1;
- drm_file_t *priv;
- char buf[128];
- int error;
+ tempprivs = DRM(alloc)(sizeof(drm_file_t) * privcount, DRM_MEM_FILES);
+ if (tempprivs == NULL) {
+ DRM_UNLOCK();
+ return ENOMEM;
+ }
+ i = 0;
+ TAILQ_FOREACH(priv, &dev->files, link)
+ tempprivs[i++] = *priv;
+
+ DRM_UNLOCK();
DRM_SYSCTL_PRINT("\na dev pid uid magic ioctls\n");
- TAILQ_FOREACH(priv, &dev->files, link) {
+ for (i = 0; i < privcount; i++) {
+ priv = &tempprivs[i];
DRM_SYSCTL_PRINT("%c %3d %5d %5d %10u %10lu\n",
priv->authenticated ? 'y' : 'n',
priv->minor,
@@ -254,21 +304,11 @@ static int DRM(_clients_info) DRM_SYSCTL_HANDLER_ARGS
}
SYSCTL_OUT(req, "", 1);
- return 0;
+done:
+ DRM(free)(tempprivs, sizeof(drm_file_t) * privcount, DRM_MEM_FILES);
+ return retcode;
}
-static int DRM(clients_info)DRM_SYSCTL_HANDLER_ARGS
-{
- drm_device_t __unused *dev = arg1;
- int ret;
-
- DRM_LOCK();
- ret = DRM(_clients_info)(oidp, arg1, arg2, req);
- DRM_UNLOCK();
- return ret;
-}
-
-
#elif defined(__NetBSD__)
/* stub it out for now, sysctl is only for debugging */
int DRM(sysctl_init)(drm_device_t *dev)