Merge branch 'master' into for-2.6.35
authorJens Axboe <jens.axboe@oracle.com>
Thu, 29 Apr 2010 07:36:24 +0000 (09:36 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Thu, 29 Apr 2010 07:36:24 +0000 (09:36 +0200)
Conflicts:
fs/block_dev.c

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
1  2 
drivers/block/drbd/drbd_receiver.c
fs/block_dev.c
include/linux/backing-dev.h
include/linux/fs.h

@@@ -899,7 -899,8 +899,8 @@@ retry
  
        drbd_thread_start(&mdev->asender);
  
-       drbd_send_protocol(mdev);
+       if (!drbd_send_protocol(mdev))
+               return -1;
        drbd_send_sync_param(mdev, &mdev->sync_conf);
        drbd_send_sizes(mdev, 0);
        drbd_send_uuids(mdev);
@@@ -945,8 -946,7 +946,8 @@@ static enum finish_epoch drbd_flush_aft
        int rv;
  
        if (mdev->write_ordering >= WO_bdev_flush && get_ldev(mdev)) {
 -              rv = blkdev_issue_flush(mdev->ldev->backing_bdev, NULL);
 +              rv = blkdev_issue_flush(mdev->ldev->backing_bdev, GFP_KERNEL,
 +                                      NULL, BLKDEV_IFL_WAIT);
                if (rv) {
                        dev_err(DEV, "local disk flush failed with status %d\n", rv);
                        /* would rather check on EOPNOTSUPP, but that is not reliable.
diff --combined fs/block_dev.c
@@@ -406,17 -406,23 +406,23 @@@ static loff_t block_llseek(struct file 
   
  int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync)
  {
-       struct block_device *bdev = I_BDEV(filp->f_mapping->host);
+       struct inode *bd_inode = filp->f_mapping->host;
+       struct block_device *bdev = I_BDEV(bd_inode);
        int error;
  
-       error = sync_blockdev(bdev);
-       if (error)
-               return error;
-       
-       error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL,
-                               (BLKDEV_IFL_WAIT));
+       /*
+        * There is no need to serialise calls to blkdev_issue_flush with
+        * i_mutex and doing so causes performance issues with concurrent
+        * O_SYNC writers to a block device.
+        */
+       mutex_unlock(&bd_inode->i_mutex);
 -      error = blkdev_issue_flush(bdev, NULL);
++      error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL, BLKDEV_IFL_WAIT);
        if (error == -EOPNOTSUPP)
                error = 0;
+       mutex_lock(&bd_inode->i_mutex);
        return error;
  }
  EXPORT_SYMBOL(blkdev_fsync);
@@@ -662,209 -668,41 +668,209 @@@ void bd_forget(struct inode *inode
                iput(bdev->bd_inode);
  }
  
 -int bd_claim(struct block_device *bdev, void *holder)
 +/**
 + * bd_may_claim - test whether a block device can be claimed
 + * @bdev: block device of interest
 + * @whole: whole block device containing @bdev, may equal @bdev
 + * @holder: holder trying to claim @bdev
 + *
 + * Test whther @bdev can be claimed by @holder.
 + *
 + * CONTEXT:
 + * spin_lock(&bdev_lock).
 + *
 + * RETURNS:
 + * %true if @bdev can be claimed, %false otherwise.
 + */
 +static bool bd_may_claim(struct block_device *bdev, struct block_device *whole,
 +                       void *holder)
  {
 -      int res;
 -      spin_lock(&bdev_lock);
 -
 -      /* first decide result */
        if (bdev->bd_holder == holder)
 -              res = 0;         /* already a holder */
 +              return true;     /* already a holder */
        else if (bdev->bd_holder != NULL)
 -              res = -EBUSY;    /* held by someone else */
 +              return false;    /* held by someone else */
        else if (bdev->bd_contains == bdev)
 -              res = 0;         /* is a whole device which isn't held */
 +              return true;     /* is a whole device which isn't held */
  
 -      else if (bdev->bd_contains->bd_holder == bd_claim)
 -              res = 0;         /* is a partition of a device that is being partitioned */
 -      else if (bdev->bd_contains->bd_holder != NULL)
 -              res = -EBUSY;    /* is a partition of a held device */
 +      else if (whole->bd_holder == bd_claim)
 +              return true;     /* is a partition of a device that is being partitioned */
 +      else if (whole->bd_holder != NULL)
 +              return false;    /* is a partition of a held device */
        else
 -              res = 0;         /* is a partition of an un-held device */
 +              return true;     /* is a partition of an un-held device */
 +}
 +
 +/**
 + * bd_prepare_to_claim - prepare to claim a block device
 + * @bdev: block device of interest
 + * @whole: the whole device containing @bdev, may equal @bdev
 + * @holder: holder trying to claim @bdev
 + *
 + * Prepare to claim @bdev.  This function fails if @bdev is already
 + * claimed by another holder and waits if another claiming is in
 + * progress.  This function doesn't actually claim.  On successful
 + * return, the caller has ownership of bd_claiming and bd_holder[s].
 + *
 + * CONTEXT:
 + * spin_lock(&bdev_lock).  Might release bdev_lock, sleep and regrab
 + * it multiple times.
 + *
 + * RETURNS:
 + * 0 if @bdev can be claimed, -EBUSY otherwise.
 + */
 +static int bd_prepare_to_claim(struct block_device *bdev,
 +                             struct block_device *whole, void *holder)
 +{
 +retry:
 +      /* if someone else claimed, fail */
 +      if (!bd_may_claim(bdev, whole, holder))
 +              return -EBUSY;
 +
 +      /* if someone else is claiming, wait for it to finish */
 +      if (whole->bd_claiming && whole->bd_claiming != holder) {
 +              wait_queue_head_t *wq = bit_waitqueue(&whole->bd_claiming, 0);
 +              DEFINE_WAIT(wait);
 +
 +              prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
 +              spin_unlock(&bdev_lock);
 +              schedule();
 +              finish_wait(wq, &wait);
 +              spin_lock(&bdev_lock);
 +              goto retry;
 +      }
 +
 +      /* yay, all mine */
 +      return 0;
 +}
 +
 +/**
 + * bd_start_claiming - start claiming a block device
 + * @bdev: block device of interest
 + * @holder: holder trying to claim @bdev
 + *
 + * @bdev is about to be opened exclusively.  Check @bdev can be opened
 + * exclusively and mark that an exclusive open is in progress.  Each
 + * successful call to this function must be matched with a call to
 + * either bd_claim() or bd_abort_claiming().  If this function
 + * succeeds, the matching bd_claim() is guaranteed to succeed.
 + *
 + * CONTEXT:
 + * Might sleep.
 + *
 + * RETURNS:
 + * Pointer to the block device containing @bdev on success, ERR_PTR()
 + * value on failure.
 + */
 +static struct block_device *bd_start_claiming(struct block_device *bdev,
 +                                            void *holder)
 +{
 +      struct gendisk *disk;
 +      struct block_device *whole;
 +      int partno, err;
 +
 +      might_sleep();
 +
 +      /*
 +       * @bdev might not have been initialized properly yet, look up
 +       * and grab the outer block device the hard way.
 +       */
 +      disk = get_gendisk(bdev->bd_dev, &partno);
 +      if (!disk)
 +              return ERR_PTR(-ENXIO);
 +
 +      whole = bdget_disk(disk, 0);
 +      put_disk(disk);
 +      if (!whole)
 +              return ERR_PTR(-ENOMEM);
 +
 +      /* prepare to claim, if successful, mark claiming in progress */
 +      spin_lock(&bdev_lock);
 +
 +      err = bd_prepare_to_claim(bdev, whole, holder);
 +      if (err == 0) {
 +              whole->bd_claiming = holder;
 +              spin_unlock(&bdev_lock);
 +              return whole;
 +      } else {
 +              spin_unlock(&bdev_lock);
 +              bdput(whole);
 +              return ERR_PTR(err);
 +      }
 +}
  
 -      /* now impose change */
 -      if (res==0) {
 +/* releases bdev_lock */
 +static void __bd_abort_claiming(struct block_device *whole, void *holder)
 +{
 +      BUG_ON(whole->bd_claiming != holder);
 +      whole->bd_claiming = NULL;
 +      wake_up_bit(&whole->bd_claiming, 0);
 +
 +      spin_unlock(&bdev_lock);
 +      bdput(whole);
 +}
 +
 +/**
 + * bd_abort_claiming - abort claiming a block device
 + * @whole: whole block device returned by bd_start_claiming()
 + * @holder: holder trying to claim @bdev
 + *
 + * Abort a claiming block started by bd_start_claiming().  Note that
 + * @whole is not the block device to be claimed but the whole device
 + * returned by bd_start_claiming().
 + *
 + * CONTEXT:
 + * Grabs and releases bdev_lock.
 + */
 +static void bd_abort_claiming(struct block_device *whole, void *holder)
 +{
 +      spin_lock(&bdev_lock);
 +      __bd_abort_claiming(whole, holder);             /* releases bdev_lock */
 +}
 +
 +/**
 + * bd_claim - claim a block device
 + * @bdev: block device to claim
 + * @holder: holder trying to claim @bdev
 + *
 + * Try to claim @bdev which must have been opened successfully.  This
 + * function may be called with or without preceding
 + * blk_start_claiming().  In the former case, this function is always
 + * successful and terminates the claiming block.
 + *
 + * CONTEXT:
 + * Might sleep.
 + *
 + * RETURNS:
 + * 0 if successful, -EBUSY if @bdev is already claimed.
 + */
 +int bd_claim(struct block_device *bdev, void *holder)
 +{
 +      struct block_device *whole = bdev->bd_contains;
 +      int res;
 +
 +      might_sleep();
 +
 +      spin_lock(&bdev_lock);
 +
 +      res = bd_prepare_to_claim(bdev, whole, holder);
 +      if (res == 0) {
                /* note that for a whole device bd_holders
                 * will be incremented twice, and bd_holder will
                 * be set to bd_claim before being set to holder
                 */
 -              bdev->bd_contains->bd_holders ++;
 -              bdev->bd_contains->bd_holder = bd_claim;
 +              whole->bd_holders++;
 +              whole->bd_holder = bd_claim;
                bdev->bd_holders++;
                bdev->bd_holder = holder;
        }
 -      spin_unlock(&bdev_lock);
 +
 +      if (whole->bd_claiming)
 +              __bd_abort_claiming(whole, holder);     /* releases bdev_lock */
 +      else
 +              spin_unlock(&bdev_lock);
 +
        return res;
  }
 -
  EXPORT_SYMBOL(bd_claim);
  
  void bd_release(struct block_device *bdev)
@@@ -1478,7 -1316,6 +1484,7 @@@ EXPORT_SYMBOL(blkdev_get)
  
  static int blkdev_open(struct inode * inode, struct file * filp)
  {
 +      struct block_device *whole = NULL;
        struct block_device *bdev;
        int res;
  
        if (bdev == NULL)
                return -ENOMEM;
  
 +      if (filp->f_mode & FMODE_EXCL) {
 +              whole = bd_start_claiming(bdev, filp);
 +              if (IS_ERR(whole)) {
 +                      bdput(bdev);
 +                      return PTR_ERR(whole);
 +              }
 +      }
 +
        filp->f_mapping = bdev->bd_inode->i_mapping;
  
        res = blkdev_get(bdev, filp->f_mode);
 -      if (res)
 -              return res;
  
 -      if (filp->f_mode & FMODE_EXCL) {
 -              res = bd_claim(bdev, filp);
 -              if (res)
 -                      goto out_blkdev_put;
 +      if (whole) {
 +              if (res == 0)
 +                      BUG_ON(bd_claim(bdev, filp) != 0);
 +              else
 +                      bd_abort_claiming(whole, filp);
        }
  
 -      return 0;
 -
 - out_blkdev_put:
 -      blkdev_put(bdev, filp->f_mode);
        return res;
  }
  
@@@ -1730,34 -1564,27 +1736,34 @@@ EXPORT_SYMBOL(lookup_bdev)
   */
  struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder)
  {
 -      struct block_device *bdev;
 -      int error = 0;
 +      struct block_device *bdev, *whole;
 +      int error;
  
        bdev = lookup_bdev(path);
        if (IS_ERR(bdev))
                return bdev;
  
 +      whole = bd_start_claiming(bdev, holder);
 +      if (IS_ERR(whole)) {
 +              bdput(bdev);
 +              return whole;
 +      }
 +
        error = blkdev_get(bdev, mode);
        if (error)
 -              return ERR_PTR(error);
 +              goto out_abort_claiming;
 +
        error = -EACCES;
        if ((mode & FMODE_WRITE) && bdev_read_only(bdev))
 -              goto blkdev_put;
 -      error = bd_claim(bdev, holder);
 -      if (error)
 -              goto blkdev_put;
 +              goto out_blkdev_put;
  
 +      BUG_ON(bd_claim(bdev, holder) != 0);
        return bdev;
 -      
 -blkdev_put:
 +
 +out_blkdev_put:
        blkdev_put(bdev, mode);
 +out_abort_claiming:
 +      bd_abort_claiming(whole, holder);
        return ERR_PTR(error);
  }
  
@@@ -14,7 -14,6 +14,7 @@@
  #include <linux/kernel.h>
  #include <linux/fs.h>
  #include <linux/sched.h>
 +#include <linux/timer.h>
  #include <linux/writeback.h>
  #include <asm/atomic.h>
  
@@@ -89,8 -88,6 +89,8 @@@ struct backing_dev_info 
  
        struct device *dev;
  
 +      struct timer_list laptop_mode_wb_timer;
 +
  #ifdef CONFIG_DEBUG_FS
        struct dentry *debug_dir;
        struct dentry *debug_stats;
@@@ -104,6 -101,7 +104,7 @@@ int bdi_register(struct backing_dev_inf
                const char *fmt, ...);
  int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
  void bdi_unregister(struct backing_dev_info *bdi);
+ int bdi_setup_and_register(struct backing_dev_info *, char *, unsigned int);
  void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb,
                                long nr_pages);
  int bdi_writeback_task(struct bdi_writeback *wb);
@@@ -249,6 -247,7 +250,7 @@@ int bdi_set_max_ratio(struct backing_de
  #endif
  
  extern struct backing_dev_info default_backing_dev_info;
+ extern struct backing_dev_info noop_backing_dev_info;
  void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page);
  
  int writeback_in_progress(struct backing_dev_info *bdi);
diff --combined include/linux/fs.h
@@@ -651,7 -651,6 +651,7 @@@ struct block_device 
        int                     bd_openers;
        struct mutex            bd_mutex;       /* open/close mutex */
        struct list_head        bd_inodes;
 +      void *                  bd_claiming;
        void *                  bd_holder;
        int                     bd_holders;
  #ifdef CONFIG_SYSFS
@@@ -2316,8 -2315,9 +2316,9 @@@ extern int vfs_fstatat(int , char __use
  extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
                    unsigned long arg);
  extern int __generic_block_fiemap(struct inode *inode,
-                                 struct fiemap_extent_info *fieinfo, u64 start,
-                                 u64 len, get_block_t *get_block);
+                                 struct fiemap_extent_info *fieinfo,
+                                 loff_t start, loff_t len,
+                                 get_block_t *get_block);
  extern int generic_block_fiemap(struct inode *inode,
                                struct fiemap_extent_info *fieinfo, u64 start,
                                u64 len, get_block_t *get_block);