static struct block_device_operations ubd_blops = {
         .owner         = THIS_MODULE,
-        .open          = ubd_open,
-        .release       = ubd_release,
-        .ioctl         = ubd_ioctl,
+        .__open                = ubd_open,
+        .__release     = ubd_release,
+        .__ioctl               = ubd_ioctl,
        .getgeo         = ubd_getgeo,
 };
 
 
                return -ENOIOCTLCMD;
        }
 
-       if (disk->fops->unlocked_ioctl)
-               return disk->fops->unlocked_ioctl(file, cmd, arg);
+       if (disk->fops->__unlocked_ioctl)
+               return disk->fops->__unlocked_ioctl(file, cmd, arg);
 
-       if (disk->fops->ioctl) {
+       if (disk->fops->__ioctl) {
                lock_kernel();
-               ret = disk->fops->ioctl(inode, file, cmd, arg);
+               ret = disk->fops->__ioctl(inode, file, cmd, arg);
                unlock_kernel();
                return ret;
        }
 
-       return -ENOTTY;
+       return __blkdev_driver_ioctl(inode->i_bdev, file->f_mode, cmd, arg);
 }
 
 static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
 
        lock_kernel();
        ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
-       /* FIXME: why do we assume -> compat_ioctl needs the BKL? */
-       if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
-               ret = disk->fops->compat_ioctl(file, cmd, arg);
+       if (ret == -ENOIOCTLCMD && disk->fops->__compat_ioctl)
+               ret = disk->fops->__compat_ioctl(file, cmd, arg);
        unlock_kernel();
+       if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
+               ret = disk->fops->compat_ioctl(bdev, file->f_mode, cmd, arg);
 
        if (ret != -ENOIOCTLCMD)
                return ret;
 
                        struct gendisk *disk, unsigned cmd, unsigned long arg)
 {
        int ret;
-       if (disk->fops->unlocked_ioctl)
-               return disk->fops->unlocked_ioctl(file, cmd, arg);
+       fmode_t mode = 0;
+       if (file) {
+               mode = file->f_mode;
+               if (file->f_flags & O_NDELAY)
+                       mode |= FMODE_NDELAY_NOW;
+       }
+
+       if (disk->fops->__unlocked_ioctl)
+               return disk->fops->__unlocked_ioctl(file, cmd, arg);
 
-       if (disk->fops->ioctl) {
+       if (disk->fops->__ioctl) {
                lock_kernel();
-               ret = disk->fops->ioctl(inode, file, cmd, arg);
+               ret = disk->fops->__ioctl(inode, file, cmd, arg);
                unlock_kernel();
                return ret;
        }
 
-       return -ENOTTY;
+       return __blkdev_driver_ioctl(inode->i_bdev, mode, cmd, arg);
 }
 EXPORT_SYMBOL_GPL(blkdev_driver_ioctl);
 
        fake_file.f_path.dentry = &fake_dentry;
        fake_dentry.d_inode = bdev->bd_inode;
 
-       if (disk->fops->unlocked_ioctl)
-               return disk->fops->unlocked_ioctl(&fake_file, cmd, arg);
+       if (disk->fops->__unlocked_ioctl)
+               return disk->fops->__unlocked_ioctl(&fake_file, cmd, arg);
+
+       if (disk->fops->__ioctl) {
+               lock_kernel();
+               ret = disk->fops->__ioctl(bdev->bd_inode, &fake_file, cmd, arg);
+               unlock_kernel();
+               return ret;
+       }
+
+       if (disk->fops->ioctl)
+               return disk->fops->ioctl(bdev, mode, cmd, arg);
 
-       if (disk->fops->ioctl) {
+       if (disk->fops->locked_ioctl) {
                lock_kernel();
-               ret = disk->fops->ioctl(bdev->bd_inode, &fake_file, cmd, arg);
+               ret = disk->fops->locked_ioctl(bdev, mode, cmd, arg);
                unlock_kernel();
                return ret;
        }
 
 
 static struct block_device_operations DAC960_BlockDeviceOperations = {
        .owner                  = THIS_MODULE,
-       .open                   = DAC960_open,
+       .__open                 = DAC960_open,
        .getgeo                 = DAC960_getgeo,
        .media_changed          = DAC960_media_changed,
        .revalidate_disk        = DAC960_revalidate_disk,
 
 
 static struct block_device_operations floppy_fops = {
        .owner          = THIS_MODULE,
-       .open           = floppy_open,
-       .release        = floppy_release,
-       .ioctl          = fd_ioctl,
+       .__open         = floppy_open,
+       .__release      = floppy_release,
+       .__ioctl                = fd_ioctl,
        .getgeo         = fd_getgeo,
        .media_changed  = amiga_floppy_change,
 };
 
 }
 
 static struct block_device_operations aoe_bdops = {
-       .open = aoeblk_open,
-       .release = aoeblk_release,
+       .__open = aoeblk_open,
+       .__release = aoeblk_release,
        .getgeo = aoeblk_getgeo,
        .owner = THIS_MODULE,
 };
 
 
 static struct block_device_operations floppy_fops = {
        .owner          = THIS_MODULE,
-       .open           = floppy_open,
-       .release        = floppy_release,
-       .ioctl          = fd_ioctl,
+       .__open         = floppy_open,
+       .__release      = floppy_release,
+       .__ioctl                = fd_ioctl,
        .media_changed  = check_floppy_change,
        .revalidate_disk= floppy_revalidate,
 };
 
 
 static struct block_device_operations brd_fops = {
        .owner =                THIS_MODULE,
-       .ioctl =                brd_ioctl,
+       .__ioctl =              brd_ioctl,
 #ifdef CONFIG_BLK_DEV_XIP
        .direct_access =        brd_direct_access,
 #endif
 
 
 static struct block_device_operations cciss_fops = {
        .owner = THIS_MODULE,
-       .open = cciss_open,
-       .release = cciss_release,
-       .ioctl = cciss_ioctl,
+       .__open = cciss_open,
+       .__release = cciss_release,
+       .__ioctl = cciss_ioctl,
        .getgeo = cciss_getgeo,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl = cciss_compat_ioctl,
+       .__compat_ioctl = cciss_compat_ioctl,
 #endif
        .revalidate_disk = cciss_revalidate,
 };
 
 
 static struct block_device_operations ida_fops  = {
        .owner          = THIS_MODULE,
-       .open           = ida_open,
-       .release        = ida_release,
-       .ioctl          = ida_ioctl,
+       .__open         = ida_open,
+       .__release      = ida_release,
+       .__ioctl                = ida_ioctl,
        .getgeo         = ida_getgeo,
        .revalidate_disk= ida_revalidate,
 };
 
 
 static struct block_device_operations floppy_fops = {
        .owner                  = THIS_MODULE,
-       .open                   = floppy_open,
-       .release                = floppy_release,
-       .ioctl                  = fd_ioctl,
+       .__open                 = floppy_open,
+       .__release              = floppy_release,
+       .__ioctl                        = fd_ioctl,
        .getgeo                 = fd_getgeo,
        .media_changed          = check_floppy_change,
        .revalidate_disk        = floppy_revalidate,
 
 
 static struct block_device_operations lo_fops = {
        .owner =        THIS_MODULE,
-       .open =         lo_open,
-       .release =      lo_release,
-       .ioctl =        lo_ioctl,
+       .__open =               lo_open,
+       .__release =    lo_release,
+       .__ioctl =      lo_ioctl,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl = lo_compat_ioctl,
+       .__compat_ioctl =       lo_compat_ioctl,
 #endif
 };
 
 
 static struct block_device_operations nbd_fops =
 {
        .owner =        THIS_MODULE,
-       .ioctl =        nbd_ioctl,
+       .__ioctl =      nbd_ioctl,
 };
 
 /*
 
 
 static struct block_device_operations pcd_bdops = {
        .owner          = THIS_MODULE,
-       .open           = pcd_block_open,
-       .release        = pcd_block_release,
-       .ioctl          = pcd_block_ioctl,
+       .__open         = pcd_block_open,
+       .__release      = pcd_block_release,
+       .__ioctl                = pcd_block_ioctl,
        .media_changed  = pcd_block_media_changed,
 };
 
 
 
 static struct block_device_operations pd_fops = {
        .owner          = THIS_MODULE,
-       .open           = pd_open,
-       .release        = pd_release,
-       .ioctl          = pd_ioctl,
+       .__open         = pd_open,
+       .__release      = pd_release,
+       .__ioctl                = pd_ioctl,
        .getgeo         = pd_getgeo,
        .media_changed  = pd_check_media,
        .revalidate_disk= pd_revalidate
 
 
 static struct block_device_operations pf_fops = {
        .owner          = THIS_MODULE,
-       .open           = pf_open,
-       .release        = pf_release,
-       .ioctl          = pf_ioctl,
+       .__open         = pf_open,
+       .__release      = pf_release,
+       .__ioctl                = pf_ioctl,
        .getgeo         = pf_getgeo,
        .media_changed  = pf_check_media,
 };
 
 
 static struct block_device_operations pktcdvd_ops = {
        .owner =                THIS_MODULE,
-       .open =                 pkt_open,
-       .release =              pkt_close,
-       .ioctl =                pkt_ioctl,
+       .__open =                       pkt_open,
+       .__release =            pkt_close,
+       .__ioctl =              pkt_ioctl,
        .media_changed =        pkt_media_changed,
 };
 
 
 }
 
 static struct block_device_operations floppy_fops = {
-       .open           = floppy_open,
-       .release        = floppy_release,
-       .ioctl          = floppy_ioctl,
+       .__open         = floppy_open,
+       .__release      = floppy_release,
+       .__ioctl                = floppy_ioctl,
        .media_changed  = floppy_check_change,
        .revalidate_disk= floppy_revalidate,
 };
 
 
 static struct block_device_operations ub_bd_fops = {
        .owner          = THIS_MODULE,
-       .open           = ub_bd_open,
-       .release        = ub_bd_release,
-       .ioctl          = ub_bd_ioctl,
+       .__open         = ub_bd_open,
+       .__release      = ub_bd_release,
+       .__ioctl                = ub_bd_ioctl,
        .media_changed  = ub_bd_media_changed,
        .revalidate_disk = ub_bd_revalidate,
 };
 
  */
 static struct block_device_operations viodasd_fops = {
        .owner = THIS_MODULE,
-       .open = viodasd_open,
-       .release = viodasd_release,
+       .__open = viodasd_open,
+       .__release = viodasd_release,
        .getgeo = viodasd_getgeo,
 };
 
 
 }
 
 static struct block_device_operations virtblk_fops = {
-       .ioctl  = virtblk_ioctl,
+       .__ioctl  = virtblk_ioctl,
        .owner  = THIS_MODULE,
        .getgeo = virtblk_getgeo,
 };
 
 
 static struct block_device_operations xd_fops = {
        .owner  = THIS_MODULE,
-       .ioctl  = xd_ioctl,
+       .__ioctl        = xd_ioctl,
        .getgeo = xd_getgeo,
 };
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
 
 static struct block_device_operations xlvbd_block_fops =
 {
        .owner = THIS_MODULE,
-       .open = blkif_open,
-       .release = blkif_release,
+       .__open = blkif_open,
+       .__release = blkif_release,
        .getgeo = blkif_getgeo,
        .ioctl = blkif_ioctl,
 };
 
 
 static struct block_device_operations ace_fops = {
        .owner = THIS_MODULE,
-       .open = ace_open,
-       .release = ace_release,
+       .__open = ace_open,
+       .__release = ace_release,
        .media_changed = ace_media_changed,
        .revalidate_disk = ace_revalidate_disk,
        .getgeo = ace_getgeo,
 
 static struct block_device_operations z2_fops =
 {
        .owner          = THIS_MODULE,
-       .open           = z2_open,
-       .release        = z2_release,
+       .__open         = z2_open,
+       .__release      = z2_release,
 };
 
 static struct kobject *z2_find(dev_t dev, int *part, void *data)
 
 
 static struct block_device_operations gdrom_bdops = {
        .owner                  = THIS_MODULE,
-       .open                   = gdrom_bdops_open,
-       .release                = gdrom_bdops_release,
+       .__open                 = gdrom_bdops_open,
+       .__release              = gdrom_bdops_release,
        .media_changed          = gdrom_bdops_mediachanged,
-       .ioctl                  = gdrom_bdops_ioctl,
+       .__ioctl                        = gdrom_bdops_ioctl,
 };
 
 static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
 
 
 struct block_device_operations viocd_fops = {
        .owner =                THIS_MODULE,
-       .open =                 viocd_blk_open,
-       .release =              viocd_blk_release,
-       .ioctl =                viocd_blk_ioctl,
+       .__open =                       viocd_blk_open,
+       .__release =            viocd_blk_release,
+       .__ioctl =              viocd_blk_ioctl,
        .media_changed =        viocd_blk_media_changed,
 };
 
 
 
 static struct block_device_operations idecd_ops = {
        .owner                  = THIS_MODULE,
-       .open                   = idecd_open,
-       .release                = idecd_release,
-       .ioctl                  = idecd_ioctl,
+       .__open                 = idecd_open,
+       .__release              = idecd_release,
+       .__ioctl                        = idecd_ioctl,
        .media_changed          = idecd_media_changed,
        .revalidate_disk        = idecd_revalidate_disk
 };
 
 
 static struct block_device_operations ide_gd_ops = {
        .owner                  = THIS_MODULE,
-       .open                   = ide_gd_open,
-       .release                = ide_gd_release,
-       .ioctl                  = ide_gd_ioctl,
+       .__open                 = ide_gd_open,
+       .__release              = ide_gd_release,
+       .__ioctl                        = ide_gd_ioctl,
        .getgeo                 = ide_gd_getgeo,
        .media_changed          = ide_gd_media_changed,
        .revalidate_disk        = ide_gd_revalidate_disk
 
 
 static struct block_device_operations idetape_block_ops = {
        .owner          = THIS_MODULE,
-       .open           = idetape_open,
-       .release        = idetape_release,
-       .ioctl          = idetape_ioctl,
+       .__open         = idetape_open,
+       .__release      = idetape_release,
+       .__ioctl                = idetape_ioctl,
 };
 
 static int ide_tape_probe(ide_drive_t *drive)
 
 EXPORT_SYMBOL_GPL(dm_noflush_suspending);
 
 static struct block_device_operations dm_blk_dops = {
-       .open = dm_blk_open,
-       .release = dm_blk_close,
-       .ioctl = dm_blk_ioctl,
+       .__open = dm_blk_open,
+       .__release = dm_blk_close,
+       .__ioctl = dm_blk_ioctl,
        .getgeo = dm_blk_getgeo,
        .owner = THIS_MODULE
 };
 
 static struct block_device_operations md_fops =
 {
        .owner          = THIS_MODULE,
-       .open           = md_open,
-       .release        = md_release,
-       .ioctl          = md_ioctl,
+       .__open         = md_open,
+       .__release      = md_release,
+       .__ioctl                = md_ioctl,
        .getgeo         = md_getgeo,
        .media_changed  = md_media_changed,
        .revalidate_disk= md_revalidate,
 
 }
 
 static struct block_device_operations ms_block_bdops = {
-       .open    = mspro_block_bd_open,
-       .release = mspro_block_bd_release,
+       .__open    = mspro_block_bd_open,
+       .__release = mspro_block_bd_release,
        .getgeo  = mspro_block_bd_getgeo,
        .owner   = THIS_MODULE
 };
 
 /* I2O Block device operations definition */
 static struct block_device_operations i2o_block_fops = {
        .owner = THIS_MODULE,
-       .open = i2o_block_open,
-       .release = i2o_block_release,
-       .ioctl = i2o_block_ioctl,
+       .__open = i2o_block_open,
+       .__release = i2o_block_release,
+       .__ioctl = i2o_block_ioctl,
        .getgeo = i2o_block_getgeo,
        .media_changed = i2o_block_media_changed
 };
 
 }
 
 static struct block_device_operations mmc_bdops = {
-       .open                   = mmc_blk_open,
-       .release                = mmc_blk_release,
+       .__open                 = mmc_blk_open,
+       .__release              = mmc_blk_release,
        .getgeo                 = mmc_blk_getgeo,
        .owner                  = THIS_MODULE,
 };
 
 
 static struct block_device_operations mtd_blktrans_ops = {
        .owner          = THIS_MODULE,
-       .open           = blktrans_open,
-       .release        = blktrans_release,
-       .ioctl          = blktrans_ioctl,
+       .__open         = blktrans_open,
+       .__release      = blktrans_release,
+       .__ioctl                = blktrans_ioctl,
        .getgeo         = blktrans_getgeo,
 };
 
 
 struct block_device_operations
 dasd_device_operations = {
        .owner          = THIS_MODULE,
-       .open           = dasd_open,
-       .release        = dasd_release,
-       .ioctl          = dasd_ioctl,
-       .compat_ioctl   = dasd_compat_ioctl,
+       .__open         = dasd_open,
+       .__release      = dasd_release,
+       .__ioctl                = dasd_ioctl,
+       .__compat_ioctl = dasd_compat_ioctl,
        .getgeo         = dasd_getgeo,
 };
 
 
 static int dcssblk_major;
 static struct block_device_operations dcssblk_devops = {
        .owner          = THIS_MODULE,
-       .open           = dcssblk_open,
-       .release        = dcssblk_release,
+       .__open         = dcssblk_open,
+       .__release      = dcssblk_release,
        .direct_access  = dcssblk_direct_access,
 };
 
 
 
 static struct block_device_operations tapeblock_fops = {
        .owner           = THIS_MODULE,
-       .open            = tapeblock_open,
-       .release         = tapeblock_release,
-       .ioctl           = tapeblock_ioctl,
+       .__open          = tapeblock_open,
+       .__release       = tapeblock_release,
+       .__ioctl           = tapeblock_ioctl,
        .media_changed   = tapeblock_medium_changed,
        .revalidate_disk = tapeblock_revalidate_disk,
 };
 
 
 static struct block_device_operations idescsi_ops = {
        .owner          = THIS_MODULE,
-       .open           = idescsi_ide_open,
-       .release        = idescsi_ide_release,
-       .ioctl          = idescsi_ide_ioctl,
+       .__open         = idescsi_ide_open,
+       .__release      = idescsi_ide_release,
+       .__ioctl                = idescsi_ide_ioctl,
 };
 
 static int idescsi_slave_configure(struct scsi_device * sdp)
 
 
 static struct block_device_operations sd_fops = {
        .owner                  = THIS_MODULE,
-       .open                   = sd_open,
-       .release                = sd_release,
-       .ioctl                  = sd_ioctl,
+       .__open                 = sd_open,
+       .__release              = sd_release,
+       .__ioctl                        = sd_ioctl,
        .getgeo                 = sd_getgeo,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl           = sd_compat_ioctl,
+       .__compat_ioctl         = sd_compat_ioctl,
 #endif
        .media_changed          = sd_media_changed,
        .revalidate_disk        = sd_revalidate_disk,
 
 static struct block_device_operations sr_bdops =
 {
        .owner          = THIS_MODULE,
-       .open           = sr_block_open,
-       .release        = sr_block_release,
-       .ioctl          = sr_block_ioctl,
+       .__open         = sr_block_open,
+       .__release      = sr_block_release,
+       .__ioctl                = sr_block_ioctl,
        .media_changed  = sr_block_media_changed,
        /* 
         * No compat_ioctl for now because sr_block_ioctl never
 
                bdev->bd_contains = bdev;
                if (!partno) {
                        struct backing_dev_info *bdi;
+                       if (disk->fops->__open) {
+                               ret = disk->fops->__open(bdev->bd_inode, file);
+                               if (ret)
+                                       goto out_first;
+                       }
                        if (disk->fops->open) {
-                               ret = disk->fops->open(bdev->bd_inode, file);
+                               ret = disk->fops->open(bdev, file->f_mode);
                                if (ret)
                                        goto out_clear;
                        }
                part = NULL;
                disk = NULL;
                if (bdev->bd_contains == bdev) {
+                       if (bdev->bd_disk->fops->__open) {
+                               ret = bdev->bd_disk->fops->__open(bdev->bd_inode, file);
+                               if (ret)
+                                       goto out;
+                       }
                        if (bdev->bd_disk->fops->open) {
-                               ret = bdev->bd_disk->fops->open(bdev->bd_inode, file);
+                               ret = bdev->bd_disk->fops->open(bdev, file->f_mode);
                                if (ret)
                                        goto out_unlock_bdev;
                        }
                kill_bdev(bdev);
        }
        if (bdev->bd_contains == bdev) {
+               if (disk->fops->__release)
+                       ret = disk->fops->__release(bd_inode, NULL);
                if (disk->fops->release)
-                       ret = disk->fops->release(bd_inode, NULL);
+                       ret = disk->fops->release(disk, 0);
        }
        if (!bdev->bd_openers) {
                struct module *owner = disk->fops->owner;
 
 struct inode;
 
 struct block_device_operations {
-       int (*open) (struct inode *, struct file *);
-       int (*release) (struct inode *, struct file *);
-       int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
-       long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
-       long (*compat_ioctl) (struct file *, unsigned, unsigned long);
+       int (*__open) (struct inode *, struct file *);
+       int (*__release) (struct inode *, struct file *);
+       int (*__ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+       long (*__unlocked_ioctl) (struct file *, unsigned, unsigned long);
+       long (*__compat_ioctl) (struct file *, unsigned, unsigned long);
+       int (*open) (struct block_device *, fmode_t);
+       int (*release) (struct gendisk *, fmode_t);
+       int (*locked_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+       int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+       int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*direct_access) (struct block_device *, sector_t,
                                                void **, unsigned long *);
        int (*media_changed) (struct gendisk *);
 
 #define FMODE_NDELAY   ((__force fmode_t)32)
 #define FMODE_EXCL     ((__force fmode_t)64)
 #define FMODE_WRITE_IOCTL      ((__force fmode_t)128)
+#define FMODE_NDELAY_NOW       ((__force fmode_t)256)
 
 #define RW_MASK                1
 #define RWA_MASK       2