Skip to content

Commit 5837471

Browse files
arndbairlied
authored andcommitted
drm: kill BKL from common code
This restricts the use of the big kernel lock to the i830 and i810 device drivers. The three remaining users in common code (open, ioctl and release) get converted to a new mutex, the drm_global_mutex, making the locking stricter than the big kernel lock. This may have a performance impact, but only in those cases that currently don't use DRM_UNLOCKED flag in the ioctl list and would benefit from that anyway. The reason why i810 and i830 cannot use drm_global_mutex in their mmap functions is a lock-order inversion problem between the current use of the BKL and mmap_sem in these drivers. Since the BKL has release-on-sleep semantics, it's harmless but it would cause trouble if we replace the BKL with a mutex. Instead, these drivers get their own ioctl wrappers that take the BKL around every ioctl call and then set their own handlers as DRM_UNLOCKED. Signed-off-by: Arnd Bergmann <[email protected]> Cc: David Airlie <[email protected]> Cc: [email protected] Signed-off-by: Dave Airlie <[email protected]>
1 parent a1e09b6 commit 5837471

File tree

9 files changed

+75
-46
lines changed

9 files changed

+75
-46
lines changed

drivers/gpu/drm/drm_drv.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,9 +481,9 @@ long drm_ioctl(struct file *filp,
481481
if (ioctl->flags & DRM_UNLOCKED)
482482
retcode = func(dev, kdata, file_priv);
483483
else {
484-
lock_kernel();
484+
mutex_lock(&drm_global_mutex);
485485
retcode = func(dev, kdata, file_priv);
486-
unlock_kernel();
486+
mutex_unlock(&drm_global_mutex);
487487
}
488488

489489
if (cmd & IOC_OUT) {

drivers/gpu/drm/drm_fops.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
#include <linux/slab.h>
4040
#include <linux/smp_lock.h>
4141

42+
/* from BKL pushdown: note that nothing else serializes idr_find() */
43+
DEFINE_MUTEX(drm_global_mutex);
44+
4245
static int drm_open_helper(struct inode *inode, struct file *filp,
4346
struct drm_device * dev);
4447

@@ -175,8 +178,7 @@ int drm_stub_open(struct inode *inode, struct file *filp)
175178

176179
DRM_DEBUG("\n");
177180

178-
/* BKL pushdown: note that nothing else serializes idr_find() */
179-
lock_kernel();
181+
mutex_lock(&drm_global_mutex);
180182
minor = idr_find(&drm_minors_idr, minor_id);
181183
if (!minor)
182184
goto out;
@@ -197,7 +199,7 @@ int drm_stub_open(struct inode *inode, struct file *filp)
197199
fops_put(old_fops);
198200

199201
out:
200-
unlock_kernel();
202+
mutex_unlock(&drm_global_mutex);
201203
return err;
202204
}
203205

@@ -472,7 +474,7 @@ int drm_release(struct inode *inode, struct file *filp)
472474
struct drm_device *dev = file_priv->minor->dev;
473475
int retcode = 0;
474476

475-
lock_kernel();
477+
mutex_lock(&drm_global_mutex);
476478

477479
DRM_DEBUG("open_count = %d\n", dev->open_count);
478480

@@ -573,17 +575,14 @@ int drm_release(struct inode *inode, struct file *filp)
573575
if (atomic_read(&dev->ioctl_count)) {
574576
DRM_ERROR("Device busy: %d\n",
575577
atomic_read(&dev->ioctl_count));
576-
spin_unlock(&dev->count_lock);
577-
unlock_kernel();
578-
return -EBUSY;
578+
retcode = -EBUSY;
579+
goto out;
579580
}
580-
spin_unlock(&dev->count_lock);
581-
unlock_kernel();
582-
return drm_lastclose(dev);
581+
retcode = drm_lastclose(dev);
583582
}
583+
out:
584584
spin_unlock(&dev->count_lock);
585-
586-
unlock_kernel();
585+
mutex_unlock(&drm_global_mutex);
587586

588587
return retcode;
589588
}

drivers/gpu/drm/i810/i810_dma.c

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/interrupt.h> /* For task queue support */
3838
#include <linux/delay.h>
3939
#include <linux/slab.h>
40+
#include <linux/smp_lock.h>
4041
#include <linux/pagemap.h>
4142

4243
#define I810_BUF_FREE 2
@@ -1240,22 +1241,35 @@ int i810_driver_dma_quiescent(struct drm_device *dev)
12401241
return 0;
12411242
}
12421243

1244+
/*
1245+
* call the drm_ioctl under the big kernel lock because
1246+
* to lock against the i810_mmap_buffers function.
1247+
*/
1248+
long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1249+
{
1250+
int ret;
1251+
lock_kernel();
1252+
ret = drm_ioctl(file, cmd, arg);
1253+
unlock_kernel();
1254+
return ret;
1255+
}
1256+
12431257
struct drm_ioctl_desc i810_ioctls[] = {
1244-
DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1245-
DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH),
1246-
DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH),
1247-
DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH),
1248-
DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH),
1249-
DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH),
1250-
DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH),
1251-
DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH),
1252-
DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH),
1253-
DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH),
1254-
DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH),
1255-
DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH),
1256-
DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1257-
DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH),
1258-
DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH)
1258+
DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
1259+
DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED),
1260+
DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED),
1261+
DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED),
1262+
DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED),
1263+
DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED),
1264+
DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED),
1265+
DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED),
1266+
DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED),
1267+
DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED),
1268+
DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED),
1269+
DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED),
1270+
DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
1271+
DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED),
1272+
DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED),
12591273
};
12601274

12611275
int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);

drivers/gpu/drm/i810/i810_drv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static struct drm_driver driver = {
5959
.owner = THIS_MODULE,
6060
.open = drm_open,
6161
.release = drm_release,
62-
.unlocked_ioctl = drm_ioctl,
62+
.unlocked_ioctl = i810_ioctl,
6363
.mmap = drm_mmap,
6464
.poll = drm_poll,
6565
.fasync = drm_fasync,

drivers/gpu/drm/i810/i810_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ extern void i810_driver_reclaim_buffers_locked(struct drm_device *dev,
126126
struct drm_file *file_priv);
127127
extern int i810_driver_device_is_agp(struct drm_device *dev);
128128

129+
extern long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
129130
extern struct drm_ioctl_desc i810_ioctls[];
130131
extern int i810_max_ioctl;
131132

drivers/gpu/drm/i830/i830_dma.c

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "i830_drm.h"
3737
#include "i830_drv.h"
3838
#include <linux/interrupt.h> /* For task queue support */
39+
#include <linux/smp_lock.h>
3940
#include <linux/pagemap.h>
4041
#include <linux/delay.h>
4142
#include <linux/slab.h>
@@ -1509,21 +1510,34 @@ int i830_driver_dma_quiescent(struct drm_device *dev)
15091510
return 0;
15101511
}
15111512

1513+
/*
1514+
* call the drm_ioctl under the big kernel lock because
1515+
* to lock against the i830_mmap_buffers function.
1516+
*/
1517+
long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1518+
{
1519+
int ret;
1520+
lock_kernel();
1521+
ret = drm_ioctl(file, cmd, arg);
1522+
unlock_kernel();
1523+
return ret;
1524+
}
1525+
15121526
struct drm_ioctl_desc i830_ioctls[] = {
1513-
DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
1514-
DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH),
1515-
DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH),
1516-
DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH),
1517-
DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH),
1518-
DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH),
1519-
DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH),
1520-
DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH),
1521-
DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH),
1522-
DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH),
1523-
DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH),
1524-
DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH),
1525-
DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH),
1526-
DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH)
1527+
DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
1528+
DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH|DRM_UNLOCKED),
1529+
DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH|DRM_UNLOCKED),
1530+
DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH|DRM_UNLOCKED),
1531+
DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH|DRM_UNLOCKED),
1532+
DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH|DRM_UNLOCKED),
1533+
DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH|DRM_UNLOCKED),
1534+
DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH|DRM_UNLOCKED),
1535+
DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH|DRM_UNLOCKED),
1536+
DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH|DRM_UNLOCKED),
1537+
DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH|DRM_UNLOCKED),
1538+
DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH|DRM_UNLOCKED),
1539+
DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH|DRM_UNLOCKED),
1540+
DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH|DRM_UNLOCKED),
15271541
};
15281542

15291543
int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);

drivers/gpu/drm/i830/i830_drv.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static struct drm_driver driver = {
7070
.owner = THIS_MODULE,
7171
.open = drm_open,
7272
.release = drm_release,
73-
.unlocked_ioctl = drm_ioctl,
73+
.unlocked_ioctl = i830_ioctl,
7474
.mmap = drm_mmap,
7575
.poll = drm_poll,
7676
.fasync = drm_fasync,

drivers/gpu/drm/i830/i830_drv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ typedef struct drm_i830_private {
122122

123123
} drm_i830_private_t;
124124

125+
long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
125126
extern struct drm_ioctl_desc i830_ioctls[];
126127
extern int i830_max_ioctl;
127128

include/drm/drmP.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
#include <linux/platform_device.h>
5353
#include <linux/pci.h>
5454
#include <linux/jiffies.h>
55-
#include <linux/smp_lock.h> /* For (un)lock_kernel */
5655
#include <linux/dma-mapping.h>
5756
#include <linux/mm.h>
5857
#include <linux/cdev.h>
@@ -1152,6 +1151,7 @@ extern long drm_compat_ioctl(struct file *filp,
11521151
extern int drm_lastclose(struct drm_device *dev);
11531152

11541153
/* Device support (drm_fops.h) */
1154+
extern struct mutex drm_global_mutex;
11551155
extern int drm_open(struct inode *inode, struct file *filp);
11561156
extern int drm_stub_open(struct inode *inode, struct file *filp);
11571157
extern int drm_fasync(int fd, struct file *filp, int on);

0 commit comments

Comments
 (0)