]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/viro/bdev
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Oct 2008 17:23:07 +0000 (10:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Oct 2008 17:23:07 +0000 (10:23 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/viro/bdev: (66 commits)
  [PATCH] kill the rest of struct file propagation in block ioctls
  [PATCH] get rid of struct file use in blkdev_ioctl() BLKBSZSET
  [PATCH] get rid of blkdev_locked_ioctl()
  [PATCH] get rid of blkdev_driver_ioctl()
  [PATCH] sanitize blkdev_get() and friends
  [PATCH] remember mode of reiserfs journal
  [PATCH] propagate mode through swsusp_close()
  [PATCH] propagate mode through open_bdev_excl/close_bdev_excl
  [PATCH] pass fmode_t to blkdev_put()
  [PATCH] kill the unused bsize on the send side of /dev/loop
  [PATCH] trim file propagation in block/compat_ioctl.c
  [PATCH] end of methods switch: remove the old ones
  [PATCH] switch sr
  [PATCH] switch sd
  [PATCH] switch ide-scsi
  [PATCH] switch tape_block
  [PATCH] switch dcssblk
  [PATCH] switch dasd
  [PATCH] switch mtd_blkdevs
  [PATCH] switch mmc
  ...

1  2 
drivers/md/dm-linear.c
drivers/md/dm-mpath.c
drivers/md/dm-table.c
drivers/md/dm.c
fs/block_dev.c
fs/ext3/super.c
fs/ext4/super.c
fs/super.c
include/linux/device-mapper.h
include/linux/fs.h

diff --combined drivers/md/dm-linear.c
index 1b29e9136758523edcc8925018fda84056d8be4b,373442b1e98fb8d1cd29c460c6062db3d8b0b8b1..44042becad8adea2e53af2af8bdf2589f070d91e
@@@ -5,12 -5,12 +5,12 @@@
   */
  
  #include "dm.h"
 -
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/blkdev.h>
  #include <linux/bio.h>
  #include <linux/slab.h>
 +#include <linux/device-mapper.h>
  
  #define DM_MSG_PREFIX "linear"
  
@@@ -110,20 -110,11 +110,11 @@@ static int linear_status(struct dm_targ
        return 0;
  }
  
- static int linear_ioctl(struct dm_target *ti, struct inode *inode,
-                       struct file *filp, unsigned int cmd,
+ static int linear_ioctl(struct dm_target *ti, unsigned int cmd,
                        unsigned long arg)
  {
        struct linear_c *lc = (struct linear_c *) ti->private;
-       struct block_device *bdev = lc->dev->bdev;
-       struct file fake_file = {};
-       struct dentry fake_dentry = {};
-       fake_file.f_mode = lc->dev->mode;
-       fake_file.f_path.dentry = &fake_dentry;
-       fake_dentry.d_inode = bdev->bd_inode;
-       return blkdev_driver_ioctl(bdev->bd_inode, &fake_file, bdev->bd_disk, cmd, arg);
+       return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg);
  }
  
  static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
diff --combined drivers/md/dm-mpath.c
index abf6e8cfaedbaba1a5535da6c8157748200bf0f9,d85c65a46433ce4c37b54aa906421008faf63f56..4840733cd9032c48a1253a8fae8ebdea2d4c09cd
@@@ -5,8 -5,7 +5,8 @@@
   * This file is released under the GPL.
   */
  
 -#include "dm.h"
 +#include <linux/device-mapper.h>
 +
  #include "dm-path-selector.h"
  #include "dm-bio-list.h"
  #include "dm-bio-record.h"
@@@ -1396,19 -1395,15 +1396,15 @@@ error
        return -EINVAL;
  }
  
- static int multipath_ioctl(struct dm_target *ti, struct inode *inode,
-                          struct file *filp, unsigned int cmd,
+ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
                           unsigned long arg)
  {
        struct multipath *m = (struct multipath *) ti->private;
        struct block_device *bdev = NULL;
+       fmode_t mode = 0;
        unsigned long flags;
-       struct file fake_file = {};
-       struct dentry fake_dentry = {};
        int r = 0;
  
-       fake_file.f_path.dentry = &fake_dentry;
        spin_lock_irqsave(&m->lock, flags);
  
        if (!m->current_pgpath)
  
        if (m->current_pgpath) {
                bdev = m->current_pgpath->path.dev->bdev;
-               fake_dentry.d_inode = bdev->bd_inode;
-               fake_file.f_mode = m->current_pgpath->path.dev->mode;
+               mode = m->current_pgpath->path.dev->mode;
        }
  
        if (m->queue_io)
  
        spin_unlock_irqrestore(&m->lock, flags);
  
-       return r ? : blkdev_driver_ioctl(bdev->bd_inode, &fake_file,
-                                        bdev->bd_disk, cmd, arg);
+       return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
  }
  
  /*-----------------------------------------------------------------
diff --combined drivers/md/dm-table.c
index 1407eb96f1a4388b1432c3ef386f370331b5c760,dd8bd2e867cdd7c09783ccf0e1653a6a9808d43c..a63161aec48750ef51feb6e6e506c7ff83044dc0
@@@ -43,7 -43,7 +43,7 @@@ struct dm_table 
         * device.  This should be a combination of FMODE_READ
         * and FMODE_WRITE.
         */
-       int mode;
+       fmode_t mode;
  
        /* a list of devices used by this table */
        struct list_head devices;
@@@ -217,7 -217,7 +217,7 @@@ static int alloc_targets(struct dm_tabl
        return 0;
  }
  
- int dm_table_create(struct dm_table **result, int mode,
+ int dm_table_create(struct dm_table **result, fmode_t mode,
                    unsigned num_targets, struct mapped_device *md)
  {
        struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
@@@ -312,6 -312,19 +312,6 @@@ static inline int check_space(struct dm
        return 0;
  }
  
 -/*
 - * Convert a device path to a dev_t.
 - */
 -static int lookup_device(const char *path, dev_t *dev)
 -{
 -      struct block_device *bdev = lookup_bdev(path);
 -      if (IS_ERR(bdev))
 -              return PTR_ERR(bdev);
 -      *dev = bdev->bd_dev;
 -      bdput(bdev);
 -      return 0;
 -}
 -
  /*
   * See if we've already got a device in the list.
   */
@@@ -344,7 -357,7 +344,7 @@@ static int open_dev(struct dm_dev_inter
                return PTR_ERR(bdev);
        r = bd_claim_by_disk(bdev, _claim_ptr, dm_disk(md));
        if (r)
-               blkdev_put(bdev);
+               blkdev_put(bdev, d->dm_dev.mode);
        else
                d->dm_dev.bdev = bdev;
        return r;
@@@ -359,7 -372,7 +359,7 @@@ static void close_dev(struct dm_dev_int
                return;
  
        bd_release_from_disk(d->dm_dev.bdev, dm_disk(md));
-       blkdev_put(d->dm_dev.bdev);
+       blkdev_put(d->dm_dev.bdev, d->dm_dev.mode);
        d->dm_dev.bdev = NULL;
  }
  
@@@ -382,7 -395,7 +382,7 @@@ static int check_device_area(struct dm_
   * careful to leave things as they were if we fail to reopen the
   * device.
   */
- static int upgrade_mode(struct dm_dev_internal *dd, int new_mode,
+ static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
                        struct mapped_device *md)
  {
        int r;
   */
  static int __table_get_device(struct dm_table *t, struct dm_target *ti,
                              const char *path, sector_t start, sector_t len,
-                             int mode, struct dm_dev **result)
+                             fmode_t mode, struct dm_dev **result)
  {
        int r;
        dev_t uninitialized_var(dev);
                        return -EOVERFLOW;
        } else {
                /* convert the path to a device */
 -              if ((r = lookup_device(path, &dev)))
 -                      return r;
 +              struct block_device *bdev = lookup_bdev(path);
 +
 +              if (IS_ERR(bdev))
 +                      return PTR_ERR(bdev);
 +              dev = bdev->bd_dev;
 +              bdput(bdev);
        }
  
        dd = find_device(&t->devices, dev);
@@@ -528,7 -537,7 +528,7 @@@ void dm_set_device_limits(struct dm_tar
  EXPORT_SYMBOL_GPL(dm_set_device_limits);
  
  int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
-                 sector_t len, int mode, struct dm_dev **result)
+                 sector_t len, fmode_t mode, struct dm_dev **result)
  {
        int r = __table_get_device(ti->table, ti, path,
                                   start, len, mode, result);
@@@ -878,7 -887,7 +878,7 @@@ struct list_head *dm_table_get_devices(
        return &t->devices;
  }
  
int dm_table_get_mode(struct dm_table *t)
fmode_t dm_table_get_mode(struct dm_table *t)
  {
        return t->mode;
  }
diff --combined drivers/md/dm.c
index d1d0cd0f5750a2693f29cdf7bf5e5d99cbbfa2c0,dc48c2585feb9442b902a6634bfd1870cd315b68..6963ad1484082bf5d0f8009c60aa1db18eb980c1
@@@ -21,7 -21,6 +21,6 @@@
  #include <linux/idr.h>
  #include <linux/hdreg.h>
  #include <linux/blktrace_api.h>
- #include <linux/smp_lock.h>
  
  #define DM_MSG_PREFIX "core"
  
@@@ -76,6 -75,7 +75,6 @@@ union map_info *dm_get_mapinfo(struct b
   */
  struct dm_wq_req {
        enum {
 -              DM_WQ_FLUSH_ALL,
                DM_WQ_FLUSH_DEFERRED,
        } type;
        struct work_struct work;
@@@ -150,40 -150,40 +149,40 @@@ static struct kmem_cache *_tio_cache
  
  static int __init local_init(void)
  {
 -      int r;
 +      int r = -ENOMEM;
  
        /* allocate a slab for the dm_ios */
        _io_cache = KMEM_CACHE(dm_io, 0);
        if (!_io_cache)
 -              return -ENOMEM;
 +              return r;
  
        /* allocate a slab for the target ios */
        _tio_cache = KMEM_CACHE(dm_target_io, 0);
 -      if (!_tio_cache) {
 -              kmem_cache_destroy(_io_cache);
 -              return -ENOMEM;
 -      }
 +      if (!_tio_cache)
 +              goto out_free_io_cache;
  
        r = dm_uevent_init();
 -      if (r) {
 -              kmem_cache_destroy(_tio_cache);
 -              kmem_cache_destroy(_io_cache);
 -              return r;
 -      }
 +      if (r)
 +              goto out_free_tio_cache;
  
        _major = major;
        r = register_blkdev(_major, _name);
 -      if (r < 0) {
 -              kmem_cache_destroy(_tio_cache);
 -              kmem_cache_destroy(_io_cache);
 -              dm_uevent_exit();
 -              return r;
 -      }
 +      if (r < 0)
 +              goto out_uevent_exit;
  
        if (!_major)
                _major = r;
  
        return 0;
 +
 +out_uevent_exit:
 +      dm_uevent_exit();
 +out_free_tio_cache:
 +      kmem_cache_destroy(_tio_cache);
 +out_free_io_cache:
 +      kmem_cache_destroy(_io_cache);
 +
 +      return r;
  }
  
  static void local_exit(void)
@@@ -248,13 -248,13 +247,13 @@@ static void __exit dm_exit(void
  /*
   * Block device functions
   */
- static int dm_blk_open(struct inode *inode, struct file *file)
+ static int dm_blk_open(struct block_device *bdev, fmode_t mode)
  {
        struct mapped_device *md;
  
        spin_lock(&_minor_lock);
  
-       md = inode->i_bdev->bd_disk->private_data;
+       md = bdev->bd_disk->private_data;
        if (!md)
                goto out;
  
@@@ -273,11 -273,9 +272,9 @@@ out
        return md ? 0 : -ENXIO;
  }
  
- static int dm_blk_close(struct inode *inode, struct file *file)
+ static int dm_blk_close(struct gendisk *disk, fmode_t mode)
  {
-       struct mapped_device *md;
-       md = inode->i_bdev->bd_disk->private_data;
+       struct mapped_device *md = disk->private_data;
        atomic_dec(&md->open_count);
        dm_put(md);
        return 0;
@@@ -314,21 -312,14 +311,14 @@@ static int dm_blk_getgeo(struct block_d
        return dm_get_geometry(md, geo);
  }
  
- static int dm_blk_ioctl(struct inode *inode, struct file *file,
+ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
                        unsigned int cmd, unsigned long arg)
  {
-       struct mapped_device *md;
-       struct dm_table *map;
+       struct mapped_device *md = bdev->bd_disk->private_data;
+       struct dm_table *map = dm_get_table(md);
        struct dm_target *tgt;
        int r = -ENOTTY;
  
-       /* We don't really need this lock, but we do need 'inode'. */
-       unlock_kernel();
-       md = inode->i_bdev->bd_disk->private_data;
-       map = dm_get_table(md);
        if (!map || !dm_table_get_size(map))
                goto out;
  
        }
  
        if (tgt->type->ioctl)
-               r = tgt->type->ioctl(tgt, inode, file, cmd, arg);
+               r = tgt->type->ioctl(tgt, cmd, arg);
  
  out:
        dm_table_put(map);
  
-       lock_kernel();
        return r;
  }
  
@@@ -668,7 -658,6 +657,7 @@@ static struct bio *split_bvec(struct bi
        clone->bi_size = to_bytes(len);
        clone->bi_io_vec->bv_offset = offset;
        clone->bi_io_vec->bv_len = clone->bi_size;
 +      clone->bi_flags |= 1 << BIO_CLONED;
  
        return clone;
  }
@@@ -1394,6 -1383,9 +1383,6 @@@ static void dm_wq_work(struct work_stru
  
        down_write(&md->io_lock);
        switch (req->type) {
 -      case DM_WQ_FLUSH_ALL:
 -              __merge_pushback_list(md);
 -              /* pass through */
        case DM_WQ_FLUSH_DEFERRED:
                __flush_deferred_io(md);
                break;
@@@ -1523,7 -1515,7 +1512,7 @@@ int dm_suspend(struct mapped_device *md
                if (!md->suspended_bdev) {
                        DMWARN("bdget failed in dm_suspend");
                        r = -ENOMEM;
 -                      goto flush_and_out;
 +                      goto out;
                }
  
                /*
  
        set_bit(DMF_SUSPENDED, &md->flags);
  
 -flush_and_out:
 -      if (r && noflush)
 -              /*
 -               * Because there may be already I/Os in the pushback list,
 -               * flush them before return.
 -               */
 -              dm_queue_flush(md, DM_WQ_FLUSH_ALL, NULL);
 -
  out:
        if (r && md->suspended_bdev) {
                bdput(md->suspended_bdev);
diff --combined fs/block_dev.c
index d06fe3c3dd3f55751c381adc3a68cc2a25dadc61,05865b93f7e1cd32112e04aface1f649e550c6ab..88a776fa0ef6e29bc67322f3184cb04f31b2248d
@@@ -840,13 -840,12 +840,12 @@@ EXPORT_SYMBOL_GPL(bd_release_from_disk)
   * to be used for internal purposes.  If you ever need it - reconsider
   * your API.
   */
- struct block_device *open_by_devnum(dev_t dev, unsigned mode)
+ struct block_device *open_by_devnum(dev_t dev, fmode_t mode)
  {
        struct block_device *bdev = bdget(dev);
        int err = -ENOMEM;
-       int flags = mode & FMODE_WRITE ? O_RDWR : O_RDONLY;
        if (bdev)
-               err = blkdev_get(bdev, mode, flags);
+               err = blkdev_get(bdev, mode);
        return err ? ERR_PTR(err) : bdev;
  }
  
@@@ -975,9 -974,7 +974,7 @@@ void bd_set_size(struct block_device *b
  }
  EXPORT_SYMBOL(bd_set_size);
  
- static int __blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags,
-                       int for_part);
- static int __blkdev_put(struct block_device *bdev, int for_part);
+ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part);
  
  /*
   * bd_mutex locking:
   *    mutex_lock_nested(whole->bd_mutex, 1)
   */
  
- static int do_open(struct block_device *bdev, struct file *file, int for_part)
+ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
  {
        struct gendisk *disk;
        struct hd_struct *part = NULL;
        int partno;
        int perm = 0;
  
-       if (file->f_mode & FMODE_READ)
+       if (mode & FMODE_READ)
                perm |= MAY_READ;
-       if (file->f_mode & FMODE_WRITE)
+       if (mode & FMODE_WRITE)
                perm |= MAY_WRITE;
        /*
         * hooks: /n/, see "layering violations".
        }
  
        ret = -ENXIO;
-       file->f_mapping = bdev->bd_inode->i_mapping;
  
        lock_kernel();
  
                if (!partno) {
                        struct backing_dev_info *bdi;
                        if (disk->fops->open) {
-                               ret = disk->fops->open(bdev->bd_inode, file);
+                               ret = disk->fops->open(bdev, mode);
                                if (ret)
                                        goto out_clear;
                        }
                        if (!whole)
                                goto out_clear;
                        BUG_ON(for_part);
-                       ret = __blkdev_get(whole, file->f_mode, file->f_flags, 1);
+                       ret = __blkdev_get(whole, mode, 1);
                        if (ret)
                                goto out_clear;
                        bdev->bd_contains = whole;
                disk = NULL;
                if (bdev->bd_contains == bdev) {
                        if (bdev->bd_disk->fops->open) {
-                               ret = bdev->bd_disk->fops->open(bdev->bd_inode, file);
+                               ret = bdev->bd_disk->fops->open(bdev, mode);
                                if (ret)
                                        goto out_unlock_bdev;
                        }
        bdev->bd_part = NULL;
        bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
        if (bdev != bdev->bd_contains)
-               __blkdev_put(bdev->bd_contains, 1);
+               __blkdev_put(bdev->bd_contains, mode, 1);
        bdev->bd_contains = NULL;
   out_unlock_bdev:
        mutex_unlock(&bdev->bd_mutex);
        return ret;
  }
  
- static int __blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags,
-                       int for_part)
+ int blkdev_get(struct block_device *bdev, fmode_t mode)
  {
-       /*
-        * This crockload is due to bad choice of ->open() type.
-        * It will go away.
-        * For now, block device ->open() routine must _not_
-        * examine anything in 'inode' argument except ->i_rdev.
-        */
-       struct file fake_file = {};
-       struct dentry fake_dentry = {};
-       fake_file.f_mode = mode;
-       fake_file.f_flags = flags;
-       fake_file.f_path.dentry = &fake_dentry;
-       fake_dentry.d_inode = bdev->bd_inode;
-       return do_open(bdev, &fake_file, for_part);
- }
- int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags)
- {
-       return __blkdev_get(bdev, mode, flags, 0);
+       return __blkdev_get(bdev, mode, 0);
  }
  EXPORT_SYMBOL(blkdev_get);
  
@@@ -1142,28 -1119,36 +1119,36 @@@ static int blkdev_open(struct inode * i
         */
        filp->f_flags |= O_LARGEFILE;
  
+       if (filp->f_flags & O_NDELAY)
+               filp->f_mode |= FMODE_NDELAY;
+       if (filp->f_flags & O_EXCL)
+               filp->f_mode |= FMODE_EXCL;
+       if ((filp->f_flags & O_ACCMODE) == 3)
+               filp->f_mode |= FMODE_WRITE_IOCTL;
        bdev = bd_acquire(inode);
        if (bdev == NULL)
                return -ENOMEM;
  
-       res = do_open(bdev, filp, 0);
+       filp->f_mapping = bdev->bd_inode->i_mapping;
+       res = blkdev_get(bdev, filp->f_mode);
        if (res)
                return res;
  
-       if (!(filp->f_flags & O_EXCL) )
+       if (!(filp->f_mode & FMODE_EXCL))
                return 0;
  
        if (!(res = bd_claim(bdev, filp)))
                return 0;
  
-       blkdev_put(bdev);
+       blkdev_put(bdev, filp->f_mode);
        return res;
  }
  
- static int __blkdev_put(struct block_device *bdev, int for_part)
+ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
  {
        int ret = 0;
-       struct inode *bd_inode = bdev->bd_inode;
        struct gendisk *disk = bdev->bd_disk;
        struct block_device *victim = NULL;
  
        }
        if (bdev->bd_contains == bdev) {
                if (disk->fops->release)
-                       ret = disk->fops->release(bd_inode, NULL);
+                       ret = disk->fops->release(disk, mode);
        }
        if (!bdev->bd_openers) {
                struct module *owner = disk->fops->owner;
        mutex_unlock(&bdev->bd_mutex);
        bdput(bdev);
        if (victim)
-               __blkdev_put(victim, 1);
+               __blkdev_put(victim, mode, 1);
        return ret;
  }
  
- int blkdev_put(struct block_device *bdev)
+ int blkdev_put(struct block_device *bdev, fmode_t mode)
  {
-       return __blkdev_put(bdev, 0);
+       return __blkdev_put(bdev, mode, 0);
  }
  EXPORT_SYMBOL(blkdev_put);
  
@@@ -1212,12 -1197,16 +1197,16 @@@ static int blkdev_close(struct inode * 
        struct block_device *bdev = I_BDEV(filp->f_mapping->host);
        if (bdev->bd_holder == filp)
                bd_release(bdev);
-       return blkdev_put(bdev);
+       return blkdev_put(bdev, filp->f_mode);
  }
  
  static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
  {
-       return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
+       struct block_device *bdev = I_BDEV(file->f_mapping->host);
+       fmode_t mode = file->f_mode;
+       if (file->f_flags & O_NDELAY)
+               mode |= FMODE_NDELAY_NOW;
+       return blkdev_ioctl(bdev, mode, cmd, arg);
  }
  
  static const struct address_space_operations def_blk_aops = {
@@@ -1253,7 -1242,7 +1242,7 @@@ int ioctl_by_bdev(struct block_device *
        int res;
        mm_segment_t old_fs = get_fs();
        set_fs(KERNEL_DS);
-       res = blkdev_ioctl(bdev->bd_inode, NULL, cmd, arg);
+       res = blkdev_ioctl(bdev, 0, cmd, arg);
        set_fs(old_fs);
        return res;
  }
@@@ -1268,33 -1257,33 +1257,33 @@@ EXPORT_SYMBOL(ioctl_by_bdev)
   * namespace if possible and return it.  Return ERR_PTR(error)
   * otherwise.
   */
 -struct block_device *lookup_bdev(const char *path)
 +struct block_device *lookup_bdev(const char *pathname)
  {
        struct block_device *bdev;
        struct inode *inode;
 -      struct nameidata nd;
 +      struct path path;
        int error;
  
 -      if (!path || !*path)
 +      if (!pathname || !*pathname)
                return ERR_PTR(-EINVAL);
  
 -      error = path_lookup(path, LOOKUP_FOLLOW, &nd);
 +      error = kern_path(pathname, LOOKUP_FOLLOW, &path);
        if (error)
                return ERR_PTR(error);
  
 -      inode = nd.path.dentry->d_inode;
 +      inode = path.dentry->d_inode;
        error = -ENOTBLK;
        if (!S_ISBLK(inode->i_mode))
                goto fail;
        error = -EACCES;
 -      if (nd.path.mnt->mnt_flags & MNT_NODEV)
 +      if (path.mnt->mnt_flags & MNT_NODEV)
                goto fail;
        error = -ENOMEM;
        bdev = bd_acquire(inode);
        if (!bdev)
                goto fail;
  out:
 -      path_put(&nd.path);
 +      path_put(&path);
        return bdev;
  fail:
        bdev = ERR_PTR(error);
  EXPORT_SYMBOL(lookup_bdev);
  
  /**
-  * open_bdev_excl  -  open a block device by name and set it up for use
+  * open_bdev_exclusive  -  open a block device by name and set it up for use
   *
   * @path:     special file representing the block device
-  * @flags:    %MS_RDONLY for opening read-only
+  * @mode:     FMODE_... combination to pass be used
   * @holder:   owner for exclusion
   *
   * Open the blockdevice described by the special file at @path, claim it
   * for the @holder.
   */
- struct block_device *open_bdev_excl(const char *path, int flags, void *holder)
+ struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder)
  {
        struct block_device *bdev;
-       mode_t mode = FMODE_READ;
        int error = 0;
  
        bdev = lookup_bdev(path);
        if (IS_ERR(bdev))
                return bdev;
  
-       if (!(flags & MS_RDONLY))
-               mode |= FMODE_WRITE;
-       error = blkdev_get(bdev, mode, 0);
+       error = blkdev_get(bdev, mode);
        if (error)
                return ERR_PTR(error);
        error = -EACCES;
-       if (!(flags & MS_RDONLY) && bdev_read_only(bdev))
+       if ((mode & FMODE_WRITE) && bdev_read_only(bdev))
                goto blkdev_put;
        error = bd_claim(bdev, holder);
        if (error)
        return bdev;
        
  blkdev_put:
-       blkdev_put(bdev);
+       blkdev_put(bdev, mode);
        return ERR_PTR(error);
  }
  
- EXPORT_SYMBOL(open_bdev_excl);
+ EXPORT_SYMBOL(open_bdev_exclusive);
  
  /**
-  * close_bdev_excl  -  release a blockdevice openen by open_bdev_excl()
+  * close_bdev_exclusive  -  close a blockdevice opened by open_bdev_exclusive()
   *
   * @bdev:     blockdevice to close
+  * @mode:     mode, must match that used to open.
   *
-  * This is the counterpart to open_bdev_excl().
+  * This is the counterpart to open_bdev_exclusive().
   */
- void close_bdev_excl(struct block_device *bdev)
+ void close_bdev_exclusive(struct block_device *bdev, fmode_t mode)
  {
        bd_release(bdev);
-       blkdev_put(bdev);
+       blkdev_put(bdev, mode);
  }
  
- EXPORT_SYMBOL(close_bdev_excl);
+ EXPORT_SYMBOL(close_bdev_exclusive);
  
  int __invalidate_device(struct block_device *bdev)
  {
diff --combined fs/ext3/super.c
index 34b6fca765d725fdf60f0d0ee7e924a0927f39c4,15c38e69b69428c86680b7c0af2e71866971ca11..8147dd44cedea34fe51004505766ec23e06c169d
@@@ -347,7 -347,7 +347,7 @@@ fail
  static int ext3_blkdev_put(struct block_device *bdev)
  {
        bd_release(bdev);
-       return blkdev_put(bdev);
+       return blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
  }
  
  static int ext3_blkdev_remove(struct ext3_sb_info *sbi)
@@@ -393,8 -393,7 +393,8 @@@ static void ext3_put_super (struct supe
        int i;
  
        ext3_xattr_put_super(sb);
 -      journal_destroy(sbi->s_journal);
 +      if (journal_destroy(sbi->s_journal) < 0)
 +              ext3_abort(sb, __func__, "Couldn't clean up the journal");
        if (!(sb->s_flags & MS_RDONLY)) {
                EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
@@@ -2067,7 -2066,7 +2067,7 @@@ static journal_t *ext3_get_dev_journal(
        if (bd_claim(bdev, sb)) {
                printk(KERN_ERR
                        "EXT3: failed to claim external journal device.\n");
-               blkdev_put(bdev);
+               blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
                return NULL;
        }
  
@@@ -2297,9 -2296,7 +2297,9 @@@ static void ext3_mark_recovery_complete
        journal_t *journal = EXT3_SB(sb)->s_journal;
  
        journal_lock_updates(journal);
 -      journal_flush(journal);
 +      if (journal_flush(journal) < 0)
 +              goto out;
 +
        lock_super(sb);
        if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
            sb->s_flags & MS_RDONLY) {
                ext3_commit_super(sb, es, 1);
        }
        unlock_super(sb);
 +
 +out:
        journal_unlock_updates(journal);
  }
  
@@@ -2409,13 -2404,7 +2409,13 @@@ static void ext3_write_super_lockfs(str
  
                /* Now we set up the journal barrier. */
                journal_lock_updates(journal);
 -              journal_flush(journal);
 +
 +              /*
 +               * We don't want to clear needs_recovery flag when we failed
 +               * to flush the journal.
 +               */
 +              if (journal_flush(journal) < 0)
 +                      return;
  
                /* Journal blocked and flushed, clear needs_recovery flag. */
                EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
@@@ -2794,30 -2783,30 +2794,30 @@@ static int ext3_quota_on_mount(struct s
   * Standard function to be called on quota_on
   */
  static int ext3_quota_on(struct super_block *sb, int type, int format_id,
 -                       char *path, int remount)
 +                       char *name, int remount)
  {
        int err;
 -      struct nameidata nd;
 +      struct path path;
  
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
 -      /* When remounting, no checks are needed and in fact, path is NULL */
 +      /* When remounting, no checks are needed and in fact, name is NULL */
        if (remount)
 -              return vfs_quota_on(sb, type, format_id, path, remount);
 +              return vfs_quota_on(sb, type, format_id, name, remount);
  
 -      err = path_lookup(path, LOOKUP_FOLLOW, &nd);
 +      err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
                return err;
  
        /* Quotafile not on the same filesystem? */
 -      if (nd.path.mnt->mnt_sb != sb) {
 -              path_put(&nd.path);
 +      if (path.mnt->mnt_sb != sb) {
 +              path_put(&path);
                return -EXDEV;
        }
        /* Journaling quota? */
        if (EXT3_SB(sb)->s_qf_names[type]) {
                /* Quotafile not of fs root? */
 -              if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
 +              if (path.dentry->d_parent != sb->s_root)
                        printk(KERN_WARNING
                                "EXT3-fs: Quota file not on filesystem root. "
                                "Journaled quota will not work.\n");
         * When we journal data on quota file, we have to flush journal to see
         * all updates to the file when we bypass pagecache...
         */
 -      if (ext3_should_journal_data(nd.path.dentry->d_inode)) {
 +      if (ext3_should_journal_data(path.dentry->d_inode)) {
                /*
                 * We don't need to lock updates but journal_flush() could
                 * otherwise be livelocked...
                 */
                journal_lock_updates(EXT3_SB(sb)->s_journal);
 -              journal_flush(EXT3_SB(sb)->s_journal);
 +              err = journal_flush(EXT3_SB(sb)->s_journal);
                journal_unlock_updates(EXT3_SB(sb)->s_journal);
 +              if (err) {
 +                      path_put(&nd.path);
 +                      return err;
 +              }
        }
  
 -      err = vfs_quota_on_path(sb, type, format_id, &nd.path);
 -      path_put(&nd.path);
 +      err = vfs_quota_on_path(sb, type, format_id, &path);
 +      path_put(&path);
        return err;
  }
  
diff --combined fs/ext4/super.c
index ae35f176b69770e4bda4439c18439fc25352586e,c12cf7a657a91ee0a35a7f35f889720513d548a4..bdddea14e782f041381837d1488506fd951cbc99
@@@ -399,7 -399,7 +399,7 @@@ fail
  static int ext4_blkdev_put(struct block_device *bdev)
  {
        bd_release(bdev);
-       return blkdev_put(bdev);
+       return blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
  }
  
  static int ext4_blkdev_remove(struct ext4_sb_info *sbi)
@@@ -2553,7 -2553,7 +2553,7 @@@ static journal_t *ext4_get_dev_journal(
        if (bd_claim(bdev, sb)) {
                printk(KERN_ERR
                        "EXT4: failed to claim external journal device.\n");
-               blkdev_put(bdev);
+               blkdev_put(bdev, FMODE_READ|FMODE_WRITE);
                return NULL;
        }
  
@@@ -3328,30 -3328,30 +3328,30 @@@ static int ext4_quota_on_mount(struct s
   * Standard function to be called on quota_on
   */
  static int ext4_quota_on(struct super_block *sb, int type, int format_id,
 -                       char *path, int remount)
 +                       char *name, int remount)
  {
        int err;
 -      struct nameidata nd;
 +      struct path path;
  
        if (!test_opt(sb, QUOTA))
                return -EINVAL;
 -      /* When remounting, no checks are needed and in fact, path is NULL */
 +      /* When remounting, no checks are needed and in fact, name is NULL */
        if (remount)
 -              return vfs_quota_on(sb, type, format_id, path, remount);
 +              return vfs_quota_on(sb, type, format_id, name, remount);
  
 -      err = path_lookup(path, LOOKUP_FOLLOW, &nd);
 +      err = kern_path(name, LOOKUP_FOLLOW, &path);
        if (err)
                return err;
  
        /* Quotafile not on the same filesystem? */
 -      if (nd.path.mnt->mnt_sb != sb) {
 -              path_put(&nd.path);
 +      if (path.mnt->mnt_sb != sb) {
 +              path_put(&path);
                return -EXDEV;
        }
        /* Journaling quota? */
        if (EXT4_SB(sb)->s_qf_names[type]) {
                /* Quotafile not in fs root? */
 -              if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode)
 +              if (path.dentry->d_parent != sb->s_root)
                        printk(KERN_WARNING
                                "EXT4-fs: Quota file not on filesystem root. "
                                "Journaled quota will not work.\n");
         * When we journal data on quota file, we have to flush journal to see
         * all updates to the file when we bypass pagecache...
         */
 -      if (ext4_should_journal_data(nd.path.dentry->d_inode)) {
 +      if (ext4_should_journal_data(path.dentry->d_inode)) {
                /*
                 * We don't need to lock updates but journal_flush() could
                 * otherwise be livelocked...
                err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
                jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
                if (err) {
 -                      path_put(&nd.path);
 +                      path_put(&path);
                        return err;
                }
        }
  
 -      err = vfs_quota_on_path(sb, type, format_id, &nd.path);
 -      path_put(&nd.path);
 +      err = vfs_quota_on_path(sb, type, format_id, &path);
 +      path_put(&path);
        return err;
  }
  
diff --combined fs/super.c
index f31ef824d0691050139d83978df22b47b53820fb,0d77ac20d03e45548bee75be8ac1ef556315fe5e..400a7608f15e7ea7b84837b106db1765c3efff4c
@@@ -682,7 -682,7 +682,7 @@@ void emergency_remount(void
   * filesystems which don't use real block-devices.  -- jrs
   */
  
 -static struct idr unnamed_dev_idr;
 +static DEFINE_IDA(unnamed_dev_ida);
  static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */
  
  int set_anon_super(struct super_block *s, void *data)
        int error;
  
   retry:
 -      if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0)
 +      if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)
                return -ENOMEM;
        spin_lock(&unnamed_dev_lock);
 -      error = idr_get_new(&unnamed_dev_idr, NULL, &dev);
 +      error = ida_get_new(&unnamed_dev_ida, &dev);
        spin_unlock(&unnamed_dev_lock);
        if (error == -EAGAIN)
                /* We raced and lost with another CPU. */
  
        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
                spin_lock(&unnamed_dev_lock);
 -              idr_remove(&unnamed_dev_idr, dev);
 +              ida_remove(&unnamed_dev_ida, dev);
                spin_unlock(&unnamed_dev_lock);
                return -EMFILE;
        }
@@@ -720,12 -720,17 +720,12 @@@ void kill_anon_super(struct super_bloc
  
        generic_shutdown_super(sb);
        spin_lock(&unnamed_dev_lock);
 -      idr_remove(&unnamed_dev_idr, slot);
 +      ida_remove(&unnamed_dev_ida, slot);
        spin_unlock(&unnamed_dev_lock);
  }
  
  EXPORT_SYMBOL(kill_anon_super);
  
 -void __init unnamed_dev_init(void)
 -{
 -      idr_init(&unnamed_dev_idr);
 -}
 -
  void kill_litter_super(struct super_block *sb)
  {
        if (sb->s_root)
@@@ -755,9 -760,13 +755,13 @@@ int get_sb_bdev(struct file_system_typ
  {
        struct block_device *bdev;
        struct super_block *s;
+       fmode_t mode = FMODE_READ;
        int error = 0;
  
-       bdev = open_bdev_excl(dev_name, flags, fs_type);
+       if (!(flags & MS_RDONLY))
+               mode |= FMODE_WRITE;
+       bdev = open_bdev_exclusive(dev_name, mode, fs_type);
        if (IS_ERR(bdev))
                return PTR_ERR(bdev);
  
                        goto error_bdev;
                }
  
-               close_bdev_excl(bdev);
+               close_bdev_exclusive(bdev, mode);
        } else {
                char b[BDEVNAME_SIZE];
  
                s->s_flags = flags;
+               s->s_mode = mode;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
                sb_set_blocksize(s, block_size(bdev));
                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
  error_s:
        error = PTR_ERR(s);
  error_bdev:
-       close_bdev_excl(bdev);
+       close_bdev_exclusive(bdev, mode);
  error:
        return error;
  }
@@@ -812,10 -822,11 +817,11 @@@ EXPORT_SYMBOL(get_sb_bdev)
  void kill_block_super(struct super_block *sb)
  {
        struct block_device *bdev = sb->s_bdev;
+       fmode_t mode = sb->s_mode;
  
        generic_shutdown_super(sb);
        sync_blockdev(bdev);
-       close_bdev_excl(bdev);
+       close_bdev_exclusive(bdev, mode);
  }
  
  EXPORT_SYMBOL(kill_block_super);
index dfb30db475ed61c2c5562952c3e8add25a1754a2,a567bbc5293a79fcc3c5a9c65c324a49d776f7dc..c17fd334e574ec759285c892616ab01108ec0e13
@@@ -69,8 -69,7 +69,7 @@@ typedef int (*dm_status_fn) (struct dm_
  
  typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
  
- typedef int (*dm_ioctl_fn) (struct dm_target *ti, struct inode *inode,
-                           struct file *filp, unsigned int cmd,
+ typedef int (*dm_ioctl_fn) (struct dm_target *ti, unsigned int cmd,
                            unsigned long arg);
  
  typedef int (*dm_merge_fn) (struct dm_target *ti, struct bvec_merge_data *bvm,
@@@ -85,7 -84,7 +84,7 @@@ void dm_set_device_limits(struct dm_tar
  
  struct dm_dev {
        struct block_device *bdev;
-       int mode;
+       fmode_t mode;
        char name[16];
  };
  
@@@ -95,7 -94,7 +94,7 @@@
   * FIXME: too many arguments.
   */
  int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
-                 sector_t len, int mode, struct dm_dev **result);
+                 sector_t len, fmode_t mode, struct dm_dev **result);
  void dm_put_device(struct dm_target *ti, struct dm_dev *d);
  
  /*
@@@ -223,7 -222,7 +222,7 @@@ int dm_set_geometry(struct mapped_devic
  /*
   * First create an empty table.
   */
- int dm_table_create(struct dm_table **result, int mode,
+ int dm_table_create(struct dm_table **result, fmode_t mode,
                    unsigned num_targets, struct mapped_device *md);
  
  /*
@@@ -254,7 -253,7 +253,7 @@@ void dm_table_put(struct dm_table *t)
   */
  sector_t dm_table_get_size(struct dm_table *t);
  unsigned int dm_table_get_num_targets(struct dm_table *t);
int dm_table_get_mode(struct dm_table *t);
fmode_t dm_table_get_mode(struct dm_table *t);
  struct mapped_device *dm_table_get_md(struct dm_table *t);
  
  /*
@@@ -354,9 -353,6 +353,9 @@@ void *dm_vcalloc(unsigned long nmemb, u
   */
  #define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
  
 +#define dm_array_too_big(fixed, obj, num) \
 +      ((num) > (UINT_MAX - (fixed)) / (obj))
 +
  static inline sector_t to_sector(unsigned long n)
  {
        return (n >> SECTOR_SHIFT);
diff --combined include/linux/fs.h
index 7d719c1a18e3d855a662912d9c2998d83a89bae2,ff536e106b4e929a80b74a46c70ee0bd5fcbca32..43659ae52e4d22dec1d90e8db1f61a920414d5f6
@@@ -63,18 -63,23 +63,23 @@@ extern int dir_notify_enable
  #define MAY_ACCESS 16
  #define MAY_OPEN 32
  
- #define FMODE_READ 1
- #define FMODE_WRITE 2
+ #define FMODE_READ ((__force fmode_t)1)
+ #define FMODE_WRITE ((__force fmode_t)2)
  
  /* Internal kernel extensions */
- #define FMODE_LSEEK   4
- #define FMODE_PREAD   8
+ #define FMODE_LSEEK   ((__force fmode_t)4)
+ #define FMODE_PREAD   ((__force fmode_t)8)
  #define FMODE_PWRITE  FMODE_PREAD     /* These go hand in hand */
  
  /* File is being opened for execution. Primary users of this flag are
     distributed filesystems that can use it to achieve correct ETXTBUSY
     behavior for cross-node execution/opening_for_writing of files */
- #define FMODE_EXEC    16
+ #define FMODE_EXEC    ((__force fmode_t)16)
+ #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
  /*
   * Superblock flags that can be altered by MS_REMOUNT
   */
 -#define MS_RMT_MASK   (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK)
 +#define MS_RMT_MASK   (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION)
  
  /*
   * Old magic mount flag and mask
@@@ -825,7 -830,7 +830,7 @@@ struct file 
        const struct file_operations    *f_op;
        atomic_long_t           f_count;
        unsigned int            f_flags;
-       mode_t                  f_mode;
+       fmode_t                 f_mode;
        loff_t                  f_pos;
        struct fown_struct      f_owner;
        unsigned int            f_uid, f_gid;
@@@ -1152,6 -1157,7 +1157,7 @@@ struct super_block 
        char s_id[32];                          /* Informational name */
  
        void                    *s_fs_info;     /* Filesystem private info */
+       fmode_t                 s_mode;
  
        /*
         * The next field is for VFS *only*. No filesystems have any business
@@@ -1266,20 -1272,7 +1272,7 @@@ int generic_osync_inode(struct inode *
   * to have different dirent layouts depending on the binary type.
   */
  typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
- 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 (*direct_access) (struct block_device *, sector_t,
-                                               void **, unsigned long *);
-       int (*media_changed) (struct gendisk *);
-       int (*revalidate_disk) (struct gendisk *);
-       int (*getgeo)(struct block_device *, struct hd_geometry *);
-       struct module *owner;
- };
+ struct block_device_operations;
  
  /* These macros are for out of kernel modules to test that
   * the kernel supports the unlocked_ioctl and compat_ioctl
@@@ -1593,6 -1586,7 +1586,6 @@@ extern int get_sb_pseudo(struct file_sy
        struct vfsmount *mnt);
  extern int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
  int __put_super_and_need_restart(struct super_block *sb);
 -void unnamed_dev_init(void);
  
  /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
  #define fops_get(fops) \
@@@ -1713,7 -1707,7 +1706,7 @@@ extern struct block_device *bdget(dev_t
  extern void bd_set_size(struct block_device *, loff_t size);
  extern void bd_forget(struct inode *inode);
  extern void bdput(struct block_device *);
- extern struct block_device *open_by_devnum(dev_t, unsigned);
+ extern struct block_device *open_by_devnum(dev_t, fmode_t);
  #else
  static inline void bd_forget(struct inode *inode) {}
  #endif
@@@ -1723,13 -1717,10 +1716,10 @@@ extern const struct file_operations bad
  extern const struct file_operations def_fifo_fops;
  #ifdef CONFIG_BLOCK
  extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
- extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long);
- extern int blkdev_driver_ioctl(struct inode *inode, struct file *file,
-                              struct gendisk *disk, unsigned cmd,
-                              unsigned long arg);
+ extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
  extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
- extern int blkdev_get(struct block_device *, mode_t, unsigned);
- extern int blkdev_put(struct block_device *);
+ extern int blkdev_get(struct block_device *, fmode_t);
+ extern int blkdev_put(struct block_device *, fmode_t);
  extern int bd_claim(struct block_device *, void *);
  extern void bd_release(struct block_device *);
  #ifdef CONFIG_SYSFS
@@@ -1760,9 -1751,10 +1750,10 @@@ extern void chrdev_show(struct seq_fil
  extern const char *__bdevname(dev_t, char *buffer);
  extern const char *bdevname(struct block_device *bdev, char *buffer);
  extern struct block_device *lookup_bdev(const char *);
- extern struct block_device *open_bdev_excl(const char *, int, void *);
- extern void close_bdev_excl(struct block_device *);
+ extern struct block_device *open_bdev_exclusive(const char *, fmode_t, void *);
+ extern void close_bdev_exclusive(struct block_device *, fmode_t);
  extern void blkdev_show(struct seq_file *,off_t);
  #else
  #define BLKDEV_MAJOR_HASH_SIZE        0
  #endif
@@@ -1851,11 -1843,6 +1842,11 @@@ extern int inode_permission(struct inod
  extern int generic_permission(struct inode *, int,
                int (*check_acl)(struct inode *, int));
  
 +static inline bool execute_ok(struct inode *inode)
 +{
 +      return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode);
 +}
 +
  extern int get_write_access(struct inode *);
  extern int deny_write_access(struct file *);
  static inline void put_write_access(struct inode * inode)