Commit 6e9624b8 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Jens Axboe

block: push down BKL into .open and .release

The open and release block_device_operations are currently
called with the BKL held. In order to change that, we must
first make sure that all drivers that currently rely
on this have no regressions.

This blindly pushes the BKL into all .open and .release
operations for all block drivers to prepare for the
next step. The drivers can subsequently replace the BKL
with their own locks or remove it completely when it can
be shown that it is not needed.

The functions blkdev_get and blkdev_put are the only
remaining users of the big kernel lock in the block
layer, besides a few uses in the ioctl code, none
of which need to serialize with blkdev_{get,put}.

Most of these two functions is also under the protection
of bdev->bd_mutex, including the actual calls to
->open and ->release, and the common code does not
access any global data structures that need the BKL.
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Acked-by: default avatarChristoph Hellwig <hch@infradead.org>
Signed-off-by: default avatarJens Axboe <jaxboe@fusionio.com>
parent 8a6cfeb6
......@@ -33,6 +33,7 @@
#include "linux/mm.h"
#include "linux/slab.h"
#include "linux/vmalloc.h"
#include "linux/smp_lock.h"
#include "linux/blkpg.h"
#include "linux/genhd.h"
#include "linux/spinlock.h"
......@@ -1098,6 +1099,7 @@ static int ubd_open(struct block_device *bdev, fmode_t mode)
struct ubd *ubd_dev = disk->private_data;
int err = 0;
lock_kernel();
if(ubd_dev->count == 0){
err = ubd_open_dev(ubd_dev);
if(err){
......@@ -1115,7 +1117,8 @@ static int ubd_open(struct block_device *bdev, fmode_t mode)
if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
err = -EROFS;
}*/
out:
out:
unlock_kernel();
return err;
}
......@@ -1123,8 +1126,10 @@ static int ubd_release(struct gendisk *disk, fmode_t mode)
{
struct ubd *ubd_dev = disk->private_data;
lock_kernel();
if(--ubd_dev->count == 0)
ubd_close_dev(ubd_dev);
unlock_kernel();
return 0;
}
......
......@@ -79,23 +79,28 @@ static int DAC960_open(struct block_device *bdev, fmode_t mode)
struct gendisk *disk = bdev->bd_disk;
DAC960_Controller_T *p = disk->queue->queuedata;
int drive_nr = (long)disk->private_data;
int ret = -ENXIO;
lock_kernel();
if (p->FirmwareType == DAC960_V1_Controller) {
if (p->V1.LogicalDriveInformation[drive_nr].
LogicalDriveState == DAC960_V1_LogicalDrive_Offline)
return -ENXIO;
goto out;
} else {
DAC960_V2_LogicalDeviceInfo_T *i =
p->V2.LogicalDeviceInformation[drive_nr];
if (!i || i->LogicalDeviceState == DAC960_V2_LogicalDevice_Offline)
return -ENXIO;
goto out;
}
check_disk_change(bdev);
if (!get_capacity(p->disks[drive_nr]))
return -ENXIO;
return 0;
goto out;
ret = 0;
out:
unlock_kernel();
return ret;
}
static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo)
......
......@@ -1555,10 +1555,13 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
int old_dev;
unsigned long flags;
lock_kernel();
old_dev = fd_device[drive];
if (fd_ref[drive] && old_dev != system)
if (fd_ref[drive] && old_dev != system) {
unlock_kernel();
return -EBUSY;
}
if (mode & (FMODE_READ|FMODE_WRITE)) {
check_disk_change(bdev);
......@@ -1571,8 +1574,10 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
fd_deselect (drive);
rel_fdc();
if (wrprot)
if (wrprot) {
unlock_kernel();
return -EROFS;
}
}
}
......@@ -1589,6 +1594,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
unit[drive].type->name, data_types[system].name);
unlock_kernel();
return 0;
}
......@@ -1597,6 +1603,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
struct amiga_floppy_struct *p = disk->private_data;
int drive = p - unit;
lock_kernel();
if (unit[drive].dirty == 1) {
del_timer (flush_track_timer + drive);
non_int_flush_track (drive);
......@@ -1610,6 +1617,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
/* the mod_use counter is handled this way */
floppy_off (drive | 0x40000000);
#endif
unlock_kernel();
return 0;
}
......
......@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/genhd.h>
#include <linux/netdevice.h>
#include <linux/smp_lock.h>
#include "aoe.h"
static struct kmem_cache *buf_pool_cache;
......@@ -124,13 +125,16 @@ aoeblk_open(struct block_device *bdev, fmode_t mode)
struct aoedev *d = bdev->bd_disk->private_data;
ulong flags;
lock_kernel();
spin_lock_irqsave(&d->lock, flags);
if (d->flags & DEVFL_UP) {
d->nopen++;
spin_unlock_irqrestore(&d->lock, flags);
unlock_kernel();
return 0;
}
spin_unlock_irqrestore(&d->lock, flags);
unlock_kernel();
return -ENODEV;
}
......
......@@ -1850,22 +1850,34 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
return 0;
}
static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode)
{
int ret;
lock_kernel();
ret = floppy_open(bdev, mode);
unlock_kernel();
return ret;
}
static int floppy_release(struct gendisk *disk, fmode_t mode)
{
struct atari_floppy_struct *p = disk->private_data;
lock_kernel();
if (p->ref < 0)
p->ref = 0;
else if (!p->ref--) {
printk(KERN_ERR "floppy_release with fd_ref == 0");
p->ref = 0;
}
unlock_kernel();
return 0;
}
static const struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.open = floppy_unlocked_open,
.release = floppy_release,
.ioctl = fd_ioctl,
.media_changed = check_floppy_change,
......
......@@ -178,6 +178,7 @@ static void do_cciss_request(struct request_queue *q);
static irqreturn_t do_cciss_intx(int irq, void *dev_id);
static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id);
static int cciss_open(struct block_device *bdev, fmode_t mode);
static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode);
static int cciss_release(struct gendisk *disk, fmode_t mode);
static int do_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg);
......@@ -237,7 +238,7 @@ static int cciss_compat_ioctl(struct block_device *, fmode_t,
static const struct block_device_operations cciss_fops = {
.owner = THIS_MODULE,
.open = cciss_open,
.open = cciss_unlocked_open,
.release = cciss_release,
.ioctl = do_ioctl,
.getgeo = cciss_getgeo,
......@@ -1042,13 +1043,28 @@ static int cciss_open(struct block_device *bdev, fmode_t mode)
return 0;
}
static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode)
{
int ret;
lock_kernel();
ret = cciss_open(bdev, mode);
unlock_kernel();
return ret;
}
/*
* Close. Sync first.
*/
static int cciss_release(struct gendisk *disk, fmode_t mode)
{
ctlr_info_t *host = get_host(disk);
drive_info_struct *drv = get_drv(disk);
ctlr_info_t *host;
drive_info_struct *drv;
lock_kernel();
host = get_host(disk);
drv = get_drv(disk);
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_release %s\n", disk->disk_name);
......@@ -1056,6 +1072,7 @@ static int cciss_release(struct gendisk *disk, fmode_t mode)
drv->usage_count--;
host->usage_count--;
unlock_kernel();
return 0;
}
......
......@@ -158,7 +158,7 @@ static int sendcmd(
unsigned int blkcnt,
unsigned int log_unit );
static int ida_open(struct block_device *bdev, fmode_t mode);
static int ida_unlocked_open(struct block_device *bdev, fmode_t mode);
static int ida_release(struct gendisk *disk, fmode_t mode);
static int ida_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg);
static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo);
......@@ -196,7 +196,7 @@ static inline ctlr_info_t *get_host(struct gendisk *disk)
static const struct block_device_operations ida_fops = {
.owner = THIS_MODULE,
.open = ida_open,
.open = ida_unlocked_open,
.release = ida_release,
.ioctl = ida_ioctl,
.getgeo = ida_getgeo,
......@@ -841,13 +841,29 @@ static int ida_open(struct block_device *bdev, fmode_t mode)
return 0;
}
static int ida_unlocked_open(struct block_device *bdev, fmode_t mode)
{
int ret;
lock_kernel();
ret = ida_open(bdev, mode);
unlock_kernel();
return ret;
}
/*
* Close. Sync first.
*/
static int ida_release(struct gendisk *disk, fmode_t mode)
{
ctlr_info_t *host = get_host(disk);
ctlr_info_t *host;
lock_kernel();
host = get_host(disk);
host->usage_count--;
unlock_kernel();
return 0;
}
......
......@@ -2604,6 +2604,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
unsigned long flags;
int rv = 0;
lock_kernel();
spin_lock_irqsave(&mdev->req_lock, flags);
/* to have a stable mdev->state.role
* and no race with updating open_cnt */
......@@ -2618,6 +2619,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
if (!rv)
mdev->open_cnt++;
spin_unlock_irqrestore(&mdev->req_lock, flags);
unlock_kernel();
return rv;
}
......@@ -2625,7 +2627,9 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
static int drbd_release(struct gendisk *gd, fmode_t mode)
{
struct drbd_conf *mdev = gd->private_data;
lock_kernel();
mdev->open_cnt--;
unlock_kernel();
return 0;
}
......
......@@ -3616,6 +3616,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
{
int drive = (long)disk->private_data;
lock_kernel();
mutex_lock(&open_lock);
if (UDRS->fd_ref < 0)
UDRS->fd_ref = 0;
......@@ -3626,6 +3627,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
if (!UDRS->fd_ref)
opened_bdev[drive] = NULL;
mutex_unlock(&open_lock);
unlock_kernel();
return 0;
}
......@@ -3643,6 +3645,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
int res = -EBUSY;
char *tmp;
lock_kernel();
mutex_lock(&open_lock);
old_dev = UDRS->fd_device;
if (opened_bdev[drive] && opened_bdev[drive] != bdev)
......@@ -3719,6 +3722,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
goto out;
}
mutex_unlock(&open_lock);
unlock_kernel();
return 0;
out:
if (UDRS->fd_ref < 0)
......@@ -3729,6 +3733,7 @@ out:
opened_bdev[drive] = NULL;
out2:
mutex_unlock(&open_lock);
unlock_kernel();
return res;
}
......
......@@ -67,6 +67,7 @@
#include <linux/compat.h>
#include <linux/suspend.h>
#include <linux/freezer.h>
#include <linux/smp_lock.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h> /* for invalidate_bdev() */
#include <linux/completion.h>
......@@ -1408,9 +1409,11 @@ static int lo_open(struct block_device *bdev, fmode_t mode)
{
struct loop_device *lo = bdev->bd_disk->private_data;
lock_kernel();
mutex_lock(&lo->lo_ctl_mutex);
lo->lo_refcnt++;
mutex_unlock(&lo->lo_ctl_mutex);
unlock_kernel();
return 0;
}
......@@ -1420,6 +1423,7 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
struct loop_device *lo = disk->private_data;
int err;
lock_kernel();
mutex_lock(&lo->lo_ctl_mutex);
if (--lo->lo_refcnt)
......@@ -1444,6 +1448,7 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
out:
mutex_unlock(&lo->lo_ctl_mutex);
out_unlocked:
lock_kernel();
return 0;
}
......
......@@ -225,13 +225,21 @@ static char *pcd_buf; /* buffer for request in progress */
static int pcd_block_open(struct block_device *bdev, fmode_t mode)
{
struct pcd_unit *cd = bdev->bd_disk->private_data;
return cdrom_open(&cd->info, bdev, mode);
int ret;
lock_kernel();
ret = cdrom_open(&cd->info, bdev, mode);
unlock_kernel();
return ret;
}
static int pcd_block_release(struct gendisk *disk, fmode_t mode)
{
struct pcd_unit *cd = disk->private_data;
lock_kernel();
cdrom_release(&cd->info, mode);
unlock_kernel();
return 0;
}
......
......@@ -736,12 +736,14 @@ static int pd_open(struct block_device *bdev, fmode_t mode)
{
struct pd_unit *disk = bdev->bd_disk->private_data;
lock_kernel();
disk->access++;
if (disk->removable) {
pd_special_command(disk, pd_media_check);
pd_special_command(disk, pd_door_lock);
}
unlock_kernel();
return 0;
}
......@@ -783,8 +785,10 @@ static int pd_release(struct gendisk *p, fmode_t mode)
{
struct pd_unit *disk = p->private_data;
lock_kernel();
if (!--disk->access && disk->removable)
pd_special_command(disk, pd_door_unlock);
unlock_kernel();
return 0;
}
......
......@@ -300,20 +300,26 @@ static void __init pf_init_units(void)
static int pf_open(struct block_device *bdev, fmode_t mode)
{
struct pf_unit *pf = bdev->bd_disk->private_data;
int ret;
lock_kernel();
pf_identify(pf);
ret = -ENODEV;
if (pf->media_status == PF_NM)
return -ENODEV;
goto out;
ret = -EROFS;
if ((pf->media_status == PF_RO) && (mode & FMODE_WRITE))
return -EROFS;
goto out;
ret = 0;
pf->access++;
if (pf->removable)
pf_lock(pf, 1);
return 0;
out:
unlock_kernel();
return ret;
}
static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo)
......@@ -354,14 +360,18 @@ static int pf_release(struct gendisk *disk, fmode_t mode)
{
struct pf_unit *pf = disk->private_data;
if (pf->access <= 0)
lock_kernel();
if (pf->access <= 0) {
unlock_kernel();
return -EINVAL;
}
pf->access--;
if (!pf->access && pf->removable)
pf_lock(pf, 0);
unlock_kernel();
return 0;
}
......
......@@ -2383,6 +2383,7 @@ static int pkt_open(struct block_device *bdev, fmode_t mode)
VPRINTK(DRIVER_NAME": entering open\n");
lock_kernel();
mutex_lock(&ctl_mutex);
pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev));
if (!pd) {
......@@ -2410,6 +2411,7 @@ static int pkt_open(struct block_device *bdev, fmode_t mode)
}
mutex_unlock(&ctl_mutex);
unlock_kernel();
return 0;
out_dec:
......@@ -2417,6 +2419,7 @@ out_dec:
out:
VPRINTK(DRIVER_NAME": failed open (%d)\n", ret);
mutex_unlock(&ctl_mutex);
unlock_kernel();
return ret;
}
......@@ -2425,6 +2428,7 @@ static int pkt_close(struct gendisk *disk, fmode_t mode)
struct pktcdvd_device *pd = disk->private_data;
int ret = 0;
lock_kernel();
mutex_lock(&ctl_mutex);
pd->refcnt--;
BUG_ON(pd->refcnt < 0);
......@@ -2433,6 +2437,7 @@ static int pkt_close(struct gendisk *disk, fmode_t mode)
pkt_release_dev(pd, flush);
}
mutex_unlock(&ctl_mutex);
unlock_kernel();
return ret;
}
......
......@@ -662,11 +662,23 @@ out:
return err;
}
static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode)
{
int ret;
lock_kernel();
ret = floppy_open(bdev, mode);
unlock_kernel();
return ret;
}
static int floppy_release(struct gendisk *disk, fmode_t mode)
{
struct floppy_state *fs = disk->private_data;
struct swim __iomem *base = fs->swd->base;
lock_kernel();
if (fs->ref_count < 0)
fs->ref_count = 0;
else if (fs->ref_count > 0)
......@@ -674,6 +686,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode)
if (fs->ref_count == 0)
swim_motor(base, OFF);
unlock_kernel();
return 0;
}
......@@ -754,7 +767,7 @@ static int floppy_revalidate(struct gendisk *disk)
static const struct block_device_operations floppy_fops = {
.owner = THIS_MODULE,
.open = floppy_open,
.open = floppy_unlocked_open,
.release = floppy_release,
.ioctl = floppy_ioctl,
.getgeo = floppy_getgeo,
......
......@@ -949,15 +949,28 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
return 0;
}
static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode)
{
int ret;
lock_kernel();
ret = floppy_open(bdev, mode);
unlock_kernel();
return ret;
}
static int floppy_release(struct gendisk *disk, fmode_t mode)
{
struct floppy_state *fs = disk->private_data;
struct swim3 __iomem *sw = fs->swim3;
lock_kernel();
if (fs->ref_count > 0 && --fs->ref_count == 0) {
swim3_action(fs, MOTOR_OFF);
out_8(&sw->control_bic, 0xff);
swim3_select(fs, RELAX);
}
unlock_kernel();
return 0;
}
......@@ -1008,7 +1021,7 @@ static int floppy_revalidate(struct gendisk *disk)
}
static const struct block_device_operations floppy_fops = {
.open = floppy_open,
.open = floppy_unlocked_open,
.release = floppy_release,
.ioctl = floppy_ioctl,
.media_changed = floppy_check_change,
......
......@@ -1711,6 +1711,18 @@ err_open:
return rc;
}
static int ub_bd_unlocked_open(struct block_device *bdev, fmode_t mode)
{
int ret;
lock_kernel();
ret = ub_bd_open(bdev, mode);
unlock_kernel();
return ret;
}
/*