Merge branch 'for-linus' of git://neil.brown.name/md
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Feb 2011 19:13:26 +0000 (11:13 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Feb 2011 19:13:26 +0000 (11:13 -0800)
* 'for-linus' of git://neil.brown.name/md:
  md: Fix - again - partition detection when array becomes active
  Fix over-zealous flush_disk when changing device size.
  md: avoid spinlock problem in blk_throtl_exit
  md: correctly handle probe of an 'mdp' device.
  md: don't set_capacity before array is active.
  md: Fix raid1->raid0 takeover

1  2 
fs/block_dev.c
fs/inode.c
include/linux/fs.h

diff --combined fs/block_dev.c
@@@ -873,11 -873,6 +873,11 @@@ int bd_link_disk_holder(struct block_de
        ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
        if (ret)
                goto out_del;
 +      /*
 +       * bdev could be deleted beneath us which would implicitly destroy
 +       * the holder directory.  Hold on to it.
 +       */
 +      kobject_get(bdev->bd_part->holder_dir);
  
        list_add(&holder->list, &bdev->bd_holder_disks);
        goto out_unlock;
@@@ -914,7 -909,6 +914,7 @@@ void bd_unlink_disk_holder(struct block
                del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
                del_symlink(bdev->bd_part->holder_dir,
                            &disk_to_dev(disk)->kobj);
 +              kobject_put(bdev->bd_part->holder_dir);
                list_del_init(&holder->list);
                kfree(holder);
        }
@@@ -933,9 -927,9 +933,9 @@@ EXPORT_SYMBOL_GPL(bd_unlink_disk_holder
   * when a disk has been changed -- either by a media change or online
   * resize.
   */
- static void flush_disk(struct block_device *bdev)
+ static void flush_disk(struct block_device *bdev, bool kill_dirty)
  {
-       if (__invalidate_device(bdev)) {
+       if (__invalidate_device(bdev, kill_dirty)) {
                char name[BDEVNAME_SIZE] = "";
  
                if (bdev->bd_disk)
@@@ -972,7 -966,7 +972,7 @@@ void check_disk_size_change(struct gend
                       "%s: detected capacity change from %lld to %lld\n",
                       name, bdev_size, disk_size);
                i_size_write(bdev->bd_inode, disk_size);
-               flush_disk(bdev);
+               flush_disk(bdev, false);
        }
  }
  EXPORT_SYMBOL(check_disk_size_change);
@@@ -1025,7 -1019,7 +1025,7 @@@ int check_disk_change(struct block_devi
        if (!(events & DISK_EVENT_MEDIA_CHANGE))
                return 0;
  
-       flush_disk(bdev);
+       flush_disk(bdev, true);
        if (bdops->revalidate_disk)
                bdops->revalidate_disk(bdev->bd_disk);
        return 1;
@@@ -1221,6 -1215,12 +1221,6 @@@ int blkdev_get(struct block_device *bde
  
        res = __blkdev_get(bdev, mode, 0);
  
 -      /* __blkdev_get() may alter read only status, check it afterwards */
 -      if (!res && (mode & FMODE_WRITE) && bdev_read_only(bdev)) {
 -              __blkdev_put(bdev, mode, 0);
 -              res = -EACCES;
 -      }
 -
        if (whole) {
                /* finish claiming */
                mutex_lock(&bdev->bd_mutex);
@@@ -1298,11 -1298,6 +1298,11 @@@ struct block_device *blkdev_get_by_path
        if (err)
                return ERR_PTR(err);
  
 +      if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) {
 +              blkdev_put(bdev, mode);
 +              return ERR_PTR(-EACCES);
 +      }
 +
        return bdev;
  }
  EXPORT_SYMBOL(blkdev_get_by_path);
@@@ -1606,7 -1601,7 +1606,7 @@@ fail
  }
  EXPORT_SYMBOL(lookup_bdev);
  
- int __invalidate_device(struct block_device *bdev)
+ int __invalidate_device(struct block_device *bdev, bool kill_dirty)
  {
        struct super_block *sb = get_super(bdev);
        int res = 0;
                 * hold).
                 */
                shrink_dcache_sb(sb);
-               res = invalidate_inodes(sb);
+               res = invalidate_inodes(sb, kill_dirty);
                drop_super(sb);
        }
        invalidate_bdev(bdev);
diff --combined fs/inode.c
@@@ -295,20 -295,6 +295,20 @@@ static void destroy_inode(struct inode 
                call_rcu(&inode->i_rcu, i_callback);
  }
  
 +void address_space_init_once(struct address_space *mapping)
 +{
 +      memset(mapping, 0, sizeof(*mapping));
 +      INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
 +      spin_lock_init(&mapping->tree_lock);
 +      spin_lock_init(&mapping->i_mmap_lock);
 +      INIT_LIST_HEAD(&mapping->private_list);
 +      spin_lock_init(&mapping->private_lock);
 +      INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
 +      INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
 +      mutex_init(&mapping->unmap_mutex);
 +}
 +EXPORT_SYMBOL(address_space_init_once);
 +
  /*
   * These are initializations that only need to be done
   * once, because the fields are idempotent across use
@@@ -322,7 -308,13 +322,7 @@@ void inode_init_once(struct inode *inod
        INIT_LIST_HEAD(&inode->i_devices);
        INIT_LIST_HEAD(&inode->i_wb_list);
        INIT_LIST_HEAD(&inode->i_lru);
 -      INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
 -      spin_lock_init(&inode->i_data.tree_lock);
 -      spin_lock_init(&inode->i_data.i_mmap_lock);
 -      INIT_LIST_HEAD(&inode->i_data.private_list);
 -      spin_lock_init(&inode->i_data.private_lock);
 -      INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
 -      INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
 +      address_space_init_once(&inode->i_data);
        i_size_ordered_init(inode);
  #ifdef CONFIG_FSNOTIFY
        INIT_HLIST_HEAD(&inode->i_fsnotify_marks);
@@@ -548,11 -540,14 +548,14 @@@ void evict_inodes(struct super_block *s
  /**
   * invalidate_inodes  - attempt to free all inodes on a superblock
   * @sb:               superblock to operate on
+  * @kill_dirty: flag to guide handling of dirty inodes
   *
   * Attempts to free all inodes for a given superblock.  If there were any
   * busy inodes return a non-zero value, else zero.
+  * If @kill_dirty is set, discard dirty inodes too, otherwise treat
+  * them as busy.
   */
- int invalidate_inodes(struct super_block *sb)
+ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
  {
        int busy = 0;
        struct inode *inode, *next;
        list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
                if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE))
                        continue;
+               if (inode->i_state & I_DIRTY && !kill_dirty) {
+                       busy = 1;
+                       continue;
+               }
                if (atomic_read(&inode->i_count)) {
                        busy = 1;
                        continue;
diff --combined include/linux/fs.h
@@@ -649,7 -649,6 +649,7 @@@ struct address_space 
        spinlock_t              private_lock;   /* for use by the address_space */
        struct list_head        private_list;   /* ditto */
        struct address_space    *assoc_mapping; /* ditto */
 +      struct mutex            unmap_mutex;    /* to protect unmapping */
  } __attribute__((aligned(sizeof(long))));
        /*
         * On most architectures that alignment is already the case; but
@@@ -2140,7 -2139,7 +2140,7 @@@ extern void check_disk_size_change(stru
                                   struct block_device *bdev);
  extern int revalidate_disk(struct gendisk *);
  extern int check_disk_change(struct block_device *);
- extern int __invalidate_device(struct block_device *);
+ extern int __invalidate_device(struct block_device *, bool);
  extern int invalidate_partition(struct gendisk *, int);
  #endif
  unsigned long invalidate_mapping_pages(struct address_space *mapping,
@@@ -2226,7 -2225,6 +2226,7 @@@ extern loff_t vfs_llseek(struct file *f
  
  extern int inode_init_always(struct super_block *, struct inode *);
  extern void inode_init_once(struct inode *);
 +extern void address_space_init_once(struct address_space *mapping);
  extern void ihold(struct inode * inode);
  extern void iput(struct inode *);
  extern struct inode * igrab(struct inode *);
@@@ -2557,12 -2555,9 +2557,12 @@@ int proc_nr_inodes(struct ctl_table *ta
                   void __user *buffer, size_t *lenp, loff_t *ppos);
  int __init get_filesystem_list(char *buf);
  
 +#define __FMODE_EXEC          ((__force int) FMODE_EXEC)
 +#define __FMODE_NONOTIFY      ((__force int) FMODE_NONOTIFY)
 +
  #define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
  #define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
 -                                          (flag & FMODE_NONOTIFY)))
 +                                          (flag & __FMODE_NONOTIFY)))
  
  #endif /* __KERNEL__ */
  #endif /* _LINUX_FS_H */