]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 6 Sep 2015 03:34:28 +0000 (20:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 6 Sep 2015 03:34:28 +0000 (20:34 -0700)
Pull vfs updates from Al Viro:
 "In this one:

   - d_move fixes (Eric Biederman)

   - UFS fixes (me; locking is mostly sane now, a bunch of bugs in error
     handling ought to be fixed)

   - switch of sb_writers to percpu rwsem (Oleg Nesterov)

   - superblock scalability (Josef Bacik and Dave Chinner)

   - swapon(2) race fix (Hugh Dickins)"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (65 commits)
  vfs: Test for and handle paths that are unreachable from their mnt_root
  dcache: Reduce the scope of i_lock in d_splice_alias
  dcache: Handle escaped paths in prepend_path
  mm: fix potential data race in SyS_swapon
  inode: don't softlockup when evicting inodes
  inode: rename i_wb_list to i_io_list
  sync: serialise per-superblock sync operations
  inode: convert inode_sb_list_lock to per-sb
  inode: add hlist_fake to avoid the inode hash lock in evict
  writeback: plug writeback at a high level
  change sb_writers to use percpu_rw_semaphore
  shift percpu_counter_destroy() into destroy_super_work()
  percpu-rwsem: kill CONFIG_PERCPU_RWSEM
  percpu-rwsem: introduce percpu_rwsem_release() and percpu_rwsem_acquire()
  percpu-rwsem: introduce percpu_down_read_trylock()
  document rwsem_release() in sb_wait_write()
  fix the broken lockdep logic in __sb_start_write()
  introduce __sb_writers_{acquired,release}() helpers
  ufs_inode_get{frag,block}(): get rid of 'phys' argument
  ufs_getfrag_block(): tidy up a bit
  ...

1  2 
arch/Kconfig
fs/btrfs/transaction.c
fs/fs-writeback.c
fs/notify/inode_mark.c
fs/quota/dquot.c
fs/xfs/xfs_aops.c
include/linux/fs.h
include/linux/fsnotify_backend.h
init/Kconfig
kernel/locking/Makefile
lib/Kconfig

diff --combined arch/Kconfig
index a71cdbe2a04d7c5f4c581c485d4a71724275810a,8f3638674e05ac642484712b5e347ebdf7212665..8f35649305804c913efe1501e486ddb465e12810
@@@ -71,12 -71,6 +71,12 @@@ config JUMP_LABE
         ( On 32-bit x86, the necessary options added to the compiler
           flags may increase the size of the kernel slightly. )
  
 +config STATIC_KEYS_SELFTEST
 +      bool "Static key selftest"
 +      depends on JUMP_LABEL
 +      help
 +        Boot time self-test of the branch patching code.
 +
  config OPTPROBES
        def_bool y
        depends on KPROBES && HAVE_OPTPROBES
@@@ -93,7 -87,6 +93,6 @@@ config KPROBES_ON_FTRAC
  
  config UPROBES
        def_bool n
-       select PERCPU_RWSEM
        help
          Uprobes is the user-space counterpart to kprobes: they
          enable instrumentation applications (such as 'perf probe')
diff --combined fs/btrfs/transaction.c
index 68ad89e237132c9e6b3bceed8ad0bba7d67357c6,a8ab8f5ef38e1954244b7be4651694569b469238..8f259b3a66b366d6e90393d4b3f15e91d23fd2b0
@@@ -258,8 -258,6 +258,8 @@@ loop
        mutex_init(&cur_trans->cache_write_mutex);
        cur_trans->num_dirty_bgs = 0;
        spin_lock_init(&cur_trans->dirty_bgs_lock);
 +      INIT_LIST_HEAD(&cur_trans->deleted_bgs);
 +      spin_lock_init(&cur_trans->deleted_bgs_lock);
        list_add_tail(&cur_trans->list, &fs_info->trans_list);
        extent_io_tree_init(&cur_trans->dirty_pages,
                             fs_info->btree_inode->i_mapping);
@@@ -1303,7 -1301,7 +1303,7 @@@ static noinline int create_pending_snap
         */
        btrfs_set_skip_qgroup(trans, objectid);
  
 -      btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
 +      btrfs_reloc_pre_snapshot(pending, &to_reserve);
  
        if (to_reserve > 0) {
                pending->error = btrfs_block_rsv_add(root,
@@@ -1640,9 -1638,7 +1640,7 @@@ static void do_async_commit(struct work
         * Tell lockdep about it.
         */
        if (ac->newtrans->type & __TRANS_FREEZABLE)
-               rwsem_acquire_read(
-                    &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
-                    0, 1, _THIS_IP_);
+               __sb_writers_acquired(ac->root->fs_info->sb, SB_FREEZE_FS);
  
        current->journal_info = ac->newtrans;
  
@@@ -1681,9 -1677,7 +1679,7 @@@ int btrfs_commit_transaction_async(stru
         * async commit thread will be the one to unlock it.
         */
        if (ac->newtrans->type & __TRANS_FREEZABLE)
-               rwsem_release(
-                       &root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
-                       1, _THIS_IP_);
+               __sb_writers_release(root->fs_info->sb, SB_FREEZE_FS);
  
        schedule_work(&ac->work);
  
@@@ -1895,11 -1889,8 +1891,11 @@@ int btrfs_commit_transaction(struct btr
                        spin_unlock(&root->fs_info->trans_lock);
  
                        wait_for_commit(root, prev_trans);
 +                      ret = prev_trans->aborted;
  
                        btrfs_put_transaction(prev_trans);
 +                      if (ret)
 +                              goto cleanup_transaction;
                } else {
                        spin_unlock(&root->fs_info->trans_lock);
                }
diff --combined fs/fs-writeback.c
index 5fa588e933d5eaeb72f1ac1b4bd97e7dce785612,63e00f11022e446a1dd4e0160402d9f95a24c004..ae0f438c2ee68f59e4f8f4ebc17aeaae9c250ff9
@@@ -88,7 -88,7 +88,7 @@@ unsigned int dirtytime_expire_interval 
  
  static inline struct inode *wb_inode(struct list_head *head)
  {
-       return list_entry(head, struct inode, i_wb_list);
+       return list_entry(head, struct inode, i_io_list);
  }
  
  /*
@@@ -125,22 -125,22 +125,22 @@@ static void wb_io_lists_depopulated(str
  }
  
  /**
-  * inode_wb_list_move_locked - move an inode onto a bdi_writeback IO list
+  * inode_io_list_move_locked - move an inode onto a bdi_writeback IO list
   * @inode: inode to be moved
   * @wb: target bdi_writeback
   * @head: one of @wb->b_{dirty|io|more_io}
   *
-  * Move @inode->i_wb_list to @list of @wb and set %WB_has_dirty_io.
+  * Move @inode->i_io_list to @list of @wb and set %WB_has_dirty_io.
   * Returns %true if @inode is the first occupant of the !dirty_time IO
   * lists; otherwise, %false.
   */
- static bool inode_wb_list_move_locked(struct inode *inode,
+ static bool inode_io_list_move_locked(struct inode *inode,
                                      struct bdi_writeback *wb,
                                      struct list_head *head)
  {
        assert_spin_locked(&wb->list_lock);
  
-       list_move(&inode->i_wb_list, head);
+       list_move(&inode->i_io_list, head);
  
        /* dirty_time doesn't count as dirty_io until expiration */
        if (head != &wb->b_dirty_time)
  }
  
  /**
-  * inode_wb_list_del_locked - remove an inode from its bdi_writeback IO list
+  * inode_io_list_del_locked - remove an inode from its bdi_writeback IO list
   * @inode: inode to be removed
   * @wb: bdi_writeback @inode is being removed from
   *
   * Remove @inode which may be on one of @wb->b_{dirty|io|more_io} lists and
   * clear %WB_has_dirty_io if all are empty afterwards.
   */
- static void inode_wb_list_del_locked(struct inode *inode,
+ static void inode_io_list_del_locked(struct inode *inode,
                                     struct bdi_writeback *wb)
  {
        assert_spin_locked(&wb->list_lock);
  
-       list_del_init(&inode->i_wb_list);
+       list_del_init(&inode->i_io_list);
        wb_io_lists_depopulated(wb);
  }
  
@@@ -351,7 -351,7 +351,7 @@@ static void inode_switch_wbs_work_fn(st
  
        /*
         * Once I_FREEING is visible under i_lock, the eviction path owns
-        * the inode and we shouldn't modify ->i_wb_list.
+        * the inode and we shouldn't modify ->i_io_list.
         */
        if (unlikely(inode->i_state & I_FREEING))
                goto skip_switch;
         * is always correct including from ->b_dirty_time.  The transfer
         * preserves @inode->dirtied_when ordering.
         */
-       if (!list_empty(&inode->i_wb_list)) {
+       if (!list_empty(&inode->i_io_list)) {
                struct inode *pos;
  
-               inode_wb_list_del_locked(inode, old_wb);
+               inode_io_list_del_locked(inode, old_wb);
                inode->i_wb = new_wb;
-               list_for_each_entry(pos, &new_wb->b_dirty, i_wb_list)
+               list_for_each_entry(pos, &new_wb->b_dirty, i_io_list)
                        if (time_after_eq(inode->dirtied_when,
                                          pos->dirtied_when))
                                break;
-               inode_wb_list_move_locked(inode, new_wb, pos->i_wb_list.prev);
+               inode_io_list_move_locked(inode, new_wb, pos->i_io_list.prev);
        } else {
                inode->i_wb = new_wb;
        }
@@@ -844,15 -844,14 +844,15 @@@ static void bdi_split_work_to_wbs(struc
        struct wb_iter iter;
  
        might_sleep();
 -
 -      if (!bdi_has_dirty_io(bdi))
 -              return;
  restart:
        rcu_read_lock();
        bdi_for_each_wb(wb, bdi, &iter, next_blkcg_id) {
 -              if (!wb_has_dirty_io(wb) ||
 -                  (skip_if_busy && writeback_in_progress(wb)))
 +              /* SYNC_ALL writes out I_DIRTY_TIME too */
 +              if (!wb_has_dirty_io(wb) &&
 +                  (base_work->sync_mode == WB_SYNC_NONE ||
 +                   list_empty(&wb->b_dirty_time)))
 +                      continue;
 +              if (skip_if_busy && writeback_in_progress(wb))
                        continue;
  
                base_work->nr_pages = wb_split_bdi_pages(wb, nr_pages);
@@@ -900,7 -899,8 +900,7 @@@ static void bdi_split_work_to_wbs(struc
  {
        might_sleep();
  
 -      if (bdi_has_dirty_io(bdi) &&
 -          (!skip_if_busy || !writeback_in_progress(&bdi->wb))) {
 +      if (!skip_if_busy || !writeback_in_progress(&bdi->wb)) {
                base_work->auto_free = 0;
                base_work->single_wait = 0;
                base_work->single_done = 0;
@@@ -961,12 -961,12 +961,12 @@@ void wb_start_background_writeback(stru
  /*
   * Remove the inode from the writeback list it is on.
   */
- void inode_wb_list_del(struct inode *inode)
+ void inode_io_list_del(struct inode *inode)
  {
        struct bdi_writeback *wb;
  
        wb = inode_to_wb_and_lock_list(inode);
-       inode_wb_list_del_locked(inode, wb);
+       inode_io_list_del_locked(inode, wb);
        spin_unlock(&wb->list_lock);
  }
  
@@@ -988,7 -988,7 +988,7 @@@ static void redirty_tail(struct inode *
                if (time_before(inode->dirtied_when, tail->dirtied_when))
                        inode->dirtied_when = jiffies;
        }
-       inode_wb_list_move_locked(inode, wb, &wb->b_dirty);
+       inode_io_list_move_locked(inode, wb, &wb->b_dirty);
  }
  
  /*
   */
  static void requeue_io(struct inode *inode, struct bdi_writeback *wb)
  {
-       inode_wb_list_move_locked(inode, wb, &wb->b_more_io);
+       inode_io_list_move_locked(inode, wb, &wb->b_more_io);
  }
  
  static void inode_sync_complete(struct inode *inode)
@@@ -1055,7 -1055,7 +1055,7 @@@ static int move_expired_inodes(struct l
                if (older_than_this &&
                    inode_dirtied_after(inode, *older_than_this))
                        break;
-               list_move(&inode->i_wb_list, &tmp);
+               list_move(&inode->i_io_list, &tmp);
                moved++;
                if (flags & EXPIRE_DIRTY_ATIME)
                        set_bit(__I_DIRTY_TIME_EXPIRED, &inode->i_state);
                list_for_each_prev_safe(pos, node, &tmp) {
                        inode = wb_inode(pos);
                        if (inode->i_sb == sb)
-                               list_move(&inode->i_wb_list, dispatch_queue);
+                               list_move(&inode->i_io_list, dispatch_queue);
                }
        }
  out:
@@@ -1232,10 -1232,10 +1232,10 @@@ static void requeue_inode(struct inode 
                redirty_tail(inode, wb);
        } else if (inode->i_state & I_DIRTY_TIME) {
                inode->dirtied_when = jiffies;
-               inode_wb_list_move_locked(inode, wb, &wb->b_dirty_time);
+               inode_io_list_move_locked(inode, wb, &wb->b_dirty_time);
        } else {
                /* The inode is clean. Remove from writeback lists. */
-               inode_wb_list_del_locked(inode, wb);
+               inode_io_list_del_locked(inode, wb);
        }
  }
  
@@@ -1378,7 -1378,7 +1378,7 @@@ writeback_single_inode(struct inode *in
         * touch it. See comment above for explanation.
         */
        if (!(inode->i_state & I_DIRTY_ALL))
-               inode_wb_list_del_locked(inode, wb);
+               inode_io_list_del_locked(inode, wb);
        spin_unlock(&wb->list_lock);
        inode_sync_complete(inode);
  out:
@@@ -1439,7 -1439,9 +1439,9 @@@ static long writeback_sb_inodes(struct 
        unsigned long start_time = jiffies;
        long write_chunk;
        long wrote = 0;  /* count both pages and inodes */
+       struct blk_plug plug;
  
+       blk_start_plug(&plug);
        while (!list_empty(&wb->b_io)) {
                struct inode *inode = wb_inode(wb->b_io.prev);
  
                                break;
                }
        }
+       blk_finish_plug(&plug);
        return wrote;
  }
  
@@@ -2088,7 -2091,7 +2091,7 @@@ void __mark_inode_dirty(struct inode *i
                        else
                                dirty_list = &wb->b_dirty_time;
  
-                       wakeup_bdi = inode_wb_list_move_locked(inode, wb,
+                       wakeup_bdi = inode_io_list_move_locked(inode, wb,
                                                               dirty_list);
  
                        spin_unlock(&wb->list_lock);
@@@ -2111,6 -2114,15 +2114,15 @@@ out_unlock_inode
  }
  EXPORT_SYMBOL(__mark_inode_dirty);
  
+ /*
+  * The @s_sync_lock is used to serialise concurrent sync operations
+  * to avoid lock contention problems with concurrent wait_sb_inodes() calls.
+  * Concurrent callers will block on the s_sync_lock rather than doing contending
+  * walks. The queueing maintains sync(2) required behaviour as all the IO that
+  * has been issued up to the time this function is enter is guaranteed to be
+  * completed by the time we have gained the lock and waited for all IO that is
+  * in progress regardless of the order callers are granted the lock.
+  */
  static void wait_sb_inodes(struct super_block *sb)
  {
        struct inode *inode, *old_inode = NULL;
         */
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
  
-       spin_lock(&inode_sb_list_lock);
+       mutex_lock(&sb->s_sync_lock);
+       spin_lock(&sb->s_inode_list_lock);
  
        /*
         * Data integrity sync. Must wait for all pages under writeback,
                }
                __iget(inode);
                spin_unlock(&inode->i_lock);
-               spin_unlock(&inode_sb_list_lock);
+               spin_unlock(&sb->s_inode_list_lock);
  
                /*
                 * We hold a reference to 'inode' so it couldn't have been
                 * removed from s_inodes list while we dropped the
-                * inode_sb_list_lock.  We cannot iput the inode now as we can
+                * s_inode_list_lock.  We cannot iput the inode now as we can
                 * be holding the last reference and we cannot iput it under
-                * inode_sb_list_lock. So we keep the reference and iput it
+                * s_inode_list_lock. So we keep the reference and iput it
                 * later.
                 */
                iput(old_inode);
  
                cond_resched();
  
-               spin_lock(&inode_sb_list_lock);
+               spin_lock(&sb->s_inode_list_lock);
        }
-       spin_unlock(&inode_sb_list_lock);
+       spin_unlock(&sb->s_inode_list_lock);
        iput(old_inode);
+       mutex_unlock(&sb->s_sync_lock);
  }
  
  static void __writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr,
@@@ -2275,12 -2289,8 +2289,12 @@@ void sync_inodes_sb(struct super_block 
        };
        struct backing_dev_info *bdi = sb->s_bdi;
  
 -      /* Nothing to do? */
 -      if (!bdi_has_dirty_io(bdi) || bdi == &noop_backing_dev_info)
 +      /*
 +       * Can't skip on !bdi_has_dirty() because we should wait for !dirty
 +       * inodes under writeback and I_DIRTY_TIME inodes ignored by
 +       * bdi_has_dirty() need to be written out too.
 +       */
 +      if (bdi == &noop_backing_dev_info)
                return;
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
  
diff --combined fs/notify/inode_mark.c
index 474a3ce1b5e104ccf5c73f6acbfb1e044e147d1d,a4e1a8f6c329e42e10d705864bb0e75c09212265..e785fd954c30731e8f8a5dd676f903f84f0df70c
@@@ -64,6 -64,26 +64,6 @@@ void fsnotify_destroy_inode_mark(struc
        spin_unlock(&inode->i_lock);
  }
  
 -/*
 - * Given an inode, destroy all of the marks associated with that inode.
 - */
 -void fsnotify_clear_marks_by_inode(struct inode *inode)
 -{
 -      struct fsnotify_mark *mark;
 -      struct hlist_node *n;
 -      LIST_HEAD(free_list);
 -
 -      spin_lock(&inode->i_lock);
 -      hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, obj_list) {
 -              list_add(&mark->free_list, &free_list);
 -              hlist_del_init_rcu(&mark->obj_list);
 -              fsnotify_get_mark(mark);
 -      }
 -      spin_unlock(&inode->i_lock);
 -
 -      fsnotify_destroy_marks(&free_list);
 -}
 -
  /*
   * Given a group clear all of the inode marks associated with that group.
   */
@@@ -143,17 -163,17 +143,17 @@@ int fsnotify_add_inode_mark(struct fsno
  
  /**
   * fsnotify_unmount_inodes - an sb is unmounting.  handle any watched inodes.
-  * @list: list of inodes being unmounted (sb->s_inodes)
+  * @sb: superblock being unmounted.
   *
   * Called during unmount with no locks held, so needs to be safe against
-  * concurrent modifiers. We temporarily drop inode_sb_list_lock and CAN block.
+  * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block.
   */
- void fsnotify_unmount_inodes(struct list_head *list)
+ void fsnotify_unmount_inodes(struct super_block *sb)
  {
        struct inode *inode, *next_i, *need_iput = NULL;
  
-       spin_lock(&inode_sb_list_lock);
-       list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
+       spin_lock(&sb->s_inode_list_lock);
+       list_for_each_entry_safe(inode, next_i, &sb->s_inodes, i_sb_list) {
                struct inode *need_iput_tmp;
  
                /*
                spin_unlock(&inode->i_lock);
  
                /* In case the dropping of a reference would nuke next_i. */
-               while (&next_i->i_sb_list != list) {
+               while (&next_i->i_sb_list != &sb->s_inodes) {
                        spin_lock(&next_i->i_lock);
                        if (!(next_i->i_state & (I_FREEING | I_WILL_FREE)) &&
                                                atomic_read(&next_i->i_count)) {
                }
  
                /*
-                * We can safely drop inode_sb_list_lock here because either
+                * We can safely drop s_inode_list_lock here because either
                 * we actually hold references on both inode and next_i or
                 * end of list.  Also no new inodes will be added since the
                 * umount has begun.
                 */
-               spin_unlock(&inode_sb_list_lock);
+               spin_unlock(&sb->s_inode_list_lock);
  
                if (need_iput_tmp)
                        iput(need_iput_tmp);
  
                iput(inode);
  
-               spin_lock(&inode_sb_list_lock);
+               spin_lock(&sb->s_inode_list_lock);
        }
-       spin_unlock(&inode_sb_list_lock);
+       spin_unlock(&sb->s_inode_list_lock);
  }
diff --combined fs/quota/dquot.c
index fed66e2c9fe8430d04b8086202773770a5dba7a8,2863ec6cbadf384464c6ffee73e1b57c1285e561..ef0d64b2a6d947a0879a36fe4599f70d8cb925e5
@@@ -247,7 -247,7 +247,7 @@@ struct dqstats dqstats
  EXPORT_SYMBOL(dqstats);
  
  static qsize_t inode_get_rsv_space(struct inode *inode);
 -static void __dquot_initialize(struct inode *inode, int type);
 +static int __dquot_initialize(struct inode *inode, int type);
  
  static inline unsigned int
  hashfn(const struct super_block *sb, struct kqid qid)
@@@ -832,17 -832,16 +832,17 @@@ static struct dquot *get_empty_dquot(st
  struct dquot *dqget(struct super_block *sb, struct kqid qid)
  {
        unsigned int hashent = hashfn(sb, qid);
 -      struct dquot *dquot = NULL, *empty = NULL;
 +      struct dquot *dquot, *empty = NULL;
  
          if (!sb_has_quota_active(sb, qid.type))
 -              return NULL;
 +              return ERR_PTR(-ESRCH);
  we_slept:
        spin_lock(&dq_list_lock);
        spin_lock(&dq_state_lock);
        if (!sb_has_quota_active(sb, qid.type)) {
                spin_unlock(&dq_state_lock);
                spin_unlock(&dq_list_lock);
 +              dquot = ERR_PTR(-ESRCH);
                goto out;
        }
        spin_unlock(&dq_state_lock);
         * already finished or it will be canceled due to dq_count > 1 test */
        wait_on_dquot(dquot);
        /* Read the dquot / allocate space in quota file */
 -      if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) &&
 -          sb->dq_op->acquire_dquot(dquot) < 0) {
 -              dqput(dquot);
 -              dquot = NULL;
 -              goto out;
 +      if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
 +              int err;
 +
 +              err = sb->dq_op->acquire_dquot(dquot);
 +              if (err < 0) {
 +                      dqput(dquot);
 +                      dquot = ERR_PTR(err);
 +                      goto out;
 +              }
        }
  #ifdef CONFIG_QUOTA_DEBUG
        BUG_ON(!dquot->dq_sb);  /* Has somebody invalidated entry under us? */
@@@ -928,7 -923,7 +928,7 @@@ static void add_dquot_ref(struct super_
        int reserved = 0;
  #endif
  
-       spin_lock(&inode_sb_list_lock);
+       spin_lock(&sb->s_inode_list_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                spin_lock(&inode->i_lock);
                if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
                }
                __iget(inode);
                spin_unlock(&inode->i_lock);
-               spin_unlock(&inode_sb_list_lock);
+               spin_unlock(&sb->s_inode_list_lock);
  
  #ifdef CONFIG_QUOTA_DEBUG
                if (unlikely(inode_get_rsv_space(inode) > 0))
                /*
                 * We hold a reference to 'inode' so it couldn't have been
                 * removed from s_inodes list while we dropped the
-                * inode_sb_list_lock We cannot iput the inode now as we can be
+                * s_inode_list_lock. We cannot iput the inode now as we can be
                 * holding the last reference and we cannot iput it under
-                * inode_sb_list_lock. So we keep the reference and iput it
+                * s_inode_list_lock. So we keep the reference and iput it
                 * later.
                 */
                old_inode = inode;
-               spin_lock(&inode_sb_list_lock);
+               spin_lock(&sb->s_inode_list_lock);
        }
-       spin_unlock(&inode_sb_list_lock);
+       spin_unlock(&sb->s_inode_list_lock);
        iput(old_inode);
  
  #ifdef CONFIG_QUOTA_DEBUG
@@@ -1028,7 -1023,7 +1028,7 @@@ static void remove_dquot_ref(struct sup
        struct inode *inode;
        int reserved = 0;
  
-       spin_lock(&inode_sb_list_lock);
+       spin_lock(&sb->s_inode_list_lock);
        list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
                /*
                 *  We have to scan also I_NEW inodes because they can already
                }
                spin_unlock(&dq_data_lock);
        }
-       spin_unlock(&inode_sb_list_lock);
+       spin_unlock(&sb->s_inode_list_lock);
  #ifdef CONFIG_QUOTA_DEBUG
        if (reserved) {
                printk(KERN_WARNING "VFS (%s): Writes happened after quota"
@@@ -1395,16 -1390,15 +1395,16 @@@ static int dquot_active(const struct in
   * It is better to call this function outside of any transaction as it
   * might need a lot of space in journal for dquot structure allocation.
   */
 -static void __dquot_initialize(struct inode *inode, int type)
 +static int __dquot_initialize(struct inode *inode, int type)
  {
        int cnt, init_needed = 0;
        struct dquot **dquots, *got[MAXQUOTAS];
        struct super_block *sb = inode->i_sb;
        qsize_t rsv;
 +      int ret = 0;
  
        if (!dquot_active(inode))
 -              return;
 +              return 0;
  
        dquots = i_dquot(inode);
  
                struct kqid qid;
                kprojid_t projid;
                int rc;
 +              struct dquot *dquot;
  
                got[cnt] = NULL;
                if (type != -1 && cnt != type)
                        qid = make_kqid_projid(projid);
                        break;
                }
 -              got[cnt] = dqget(sb, qid);
 +              dquot = dqget(sb, qid);
 +              if (IS_ERR(dquot)) {
 +                      /* We raced with somebody turning quotas off... */
 +                      if (PTR_ERR(dquot) != -ESRCH) {
 +                              ret = PTR_ERR(dquot);
 +                              goto out_put;
 +                      }
 +                      dquot = NULL;
 +              }
 +              got[cnt] = dquot;
        }
  
        /* All required i_dquot has been initialized */
        if (!init_needed)
 -              return;
 +              return 0;
  
        spin_lock(&dq_data_lock);
        if (IS_NOQUOTA(inode))
 -              goto out_err;
 +              goto out_lock;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (type != -1 && cnt != type)
                        continue;
                                dquot_resv_space(dquots[cnt], rsv);
                }
        }
 -out_err:
 +out_lock:
        spin_unlock(&dq_data_lock);
 +out_put:
        /* Drop unused references */
        dqput_all(got);
 +
 +      return ret;
  }
  
 -void dquot_initialize(struct inode *inode)
 +int dquot_initialize(struct inode *inode)
  {
 -      __dquot_initialize(inode, -1);
 +      return __dquot_initialize(inode, -1);
  }
  EXPORT_SYMBOL(dquot_initialize);
  
@@@ -1980,37 -1961,18 +1980,37 @@@ EXPORT_SYMBOL(__dquot_transfer)
  int dquot_transfer(struct inode *inode, struct iattr *iattr)
  {
        struct dquot *transfer_to[MAXQUOTAS] = {};
 +      struct dquot *dquot;
        struct super_block *sb = inode->i_sb;
        int ret;
  
        if (!dquot_active(inode))
                return 0;
  
 -      if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
 -              transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(iattr->ia_uid));
 -      if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
 -              transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(iattr->ia_gid));
 -
 +      if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)){
 +              dquot = dqget(sb, make_kqid_uid(iattr->ia_uid));
 +              if (IS_ERR(dquot)) {
 +                      if (PTR_ERR(dquot) != -ESRCH) {
 +                              ret = PTR_ERR(dquot);
 +                              goto out_put;
 +                      }
 +                      dquot = NULL;
 +              }
 +              transfer_to[USRQUOTA] = dquot;
 +      }
 +      if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid)){
 +              dquot = dqget(sb, make_kqid_gid(iattr->ia_gid));
 +              if (IS_ERR(dquot)) {
 +                      if (PTR_ERR(dquot) != -ESRCH) {
 +                              ret = PTR_ERR(dquot);
 +                              goto out_put;
 +                      }
 +                      dquot = NULL;
 +              }
 +              transfer_to[GRPQUOTA] = dquot;
 +      }
        ret = __dquot_transfer(inode, transfer_to);
 +out_put:
        dqput_all(transfer_to);
        return ret;
  }
@@@ -2556,8 -2518,8 +2556,8 @@@ int dquot_get_dqblk(struct super_block 
        struct dquot *dquot;
  
        dquot = dqget(sb, qid);
 -      if (!dquot)
 -              return -ESRCH;
 +      if (IS_ERR(dquot))
 +              return PTR_ERR(dquot);
        do_get_dqblk(dquot, di);
        dqput(dquot);
  
@@@ -2669,8 -2631,8 +2669,8 @@@ int dquot_set_dqblk(struct super_block 
        int rc;
  
        dquot = dqget(sb, qid);
 -      if (!dquot) {
 -              rc = -ESRCH;
 +      if (IS_ERR(dquot)) {
 +              rc = PTR_ERR(dquot);
                goto out;
        }
        rc = do_set_dqblk(dquot, di);
diff --combined fs/xfs/xfs_aops.c
index c77499bcbd7a22807e6840ebd314e2a3efbd71e3,9bbb3507376a7503ece35508c765e6929fb9fbd6..cc2a321f774b204de565db643483ce4c48518bbf
@@@ -119,8 -119,7 +119,7 @@@ xfs_setfilesize_trans_alloc
         * We may pass freeze protection with a transaction.  So tell lockdep
         * we released it.
         */
-       rwsem_release(&ioend->io_inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
-                     1, _THIS_IP_);
+       __sb_writers_release(ioend->io_inode->i_sb, SB_FREEZE_FS);
        /*
         * We hand off the transaction to the completion thread now, so
         * clear the flag here.
@@@ -171,8 -170,7 +170,7 @@@ xfs_setfilesize_ioend
         * Similarly for freeze protection.
         */
        current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
-       rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
-                          0, 1, _THIS_IP_);
+       __sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS);
  
        return xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size);
  }
@@@ -351,11 -349,12 +349,11 @@@ xfs_imap_valid
   */
  STATIC void
  xfs_end_bio(
 -      struct bio              *bio,
 -      int                     error)
 +      struct bio              *bio)
  {
        xfs_ioend_t             *ioend = bio->bi_private;
  
 -      ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error;
 +      ioend->io_error = bio->bi_error;
  
        /* Toss bio and pass work off to an xfsdatad thread */
        bio->bi_private = NULL;
@@@ -381,7 -380,8 +379,7 @@@ STATIC struct bio 
  xfs_alloc_ioend_bio(
        struct buffer_head      *bh)
  {
 -      int                     nvecs = bio_get_nr_vecs(bh->b_bdev);
 -      struct bio              *bio = bio_alloc(GFP_NOIO, nvecs);
 +      struct bio              *bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES);
  
        ASSERT(bio->bi_private == NULL);
        bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
diff --combined include/linux/fs.h
index dc634a55163be60a95379970403c998d2b663e7c,9b85aa5c7a701e5704919d286dcd08275f84bf05..b2f9b9c25e419255a08ece5031315b62db3ecd82
@@@ -1,7 -1,6 +1,6 @@@
  #ifndef _LINUX_FS_H
  #define _LINUX_FS_H
  
  #include <linux/linkage.h>
  #include <linux/wait.h>
  #include <linux/kdev_t.h>
@@@ -30,6 -29,8 +29,8 @@@
  #include <linux/lockdep.h>
  #include <linux/percpu-rwsem.h>
  #include <linux/blk_types.h>
+ #include <linux/workqueue.h>
+ #include <linux/percpu-rwsem.h>
  
  #include <asm/byteorder.h>
  #include <uapi/linux/fs.h>
@@@ -636,7 -637,7 +637,7 @@@ struct inode 
        unsigned long           dirtied_time_when;
  
        struct hlist_node       i_hash;
-       struct list_head        i_wb_list;      /* backing dev IO list */
+       struct list_head        i_io_list;      /* backing dev IO list */
  #ifdef CONFIG_CGROUP_WRITEBACK
        struct bdi_writeback    *i_wb;          /* the associated cgroup wb */
  
@@@ -943,18 -944,12 +944,18 @@@ struct lock_manager_operations 
  
  struct lock_manager {
        struct list_head list;
 +      /*
 +       * NFSv4 and up also want opens blocked during the grace period;
 +       * NLM doesn't care:
 +       */
 +      bool block_opens;
  };
  
  struct net;
  void locks_start_grace(struct net *, struct lock_manager *);
  void locks_end_grace(struct lock_manager *);
  int locks_in_grace(struct net *);
 +int opens_in_grace(struct net *);
  
  /* that will die - we need it for nfs_lock_info */
  #include <linux/nfs_fs_i.h>
@@@ -1266,7 -1261,6 +1267,7 @@@ struct mm_struct
  
  /* sb->s_iflags */
  #define SB_I_CGROUPWB 0x00000001      /* cgroup-aware writeback enabled */
 +#define SB_I_NOEXEC   0x00000002      /* Ignore executables on this fs */
  
  /* Possible states of 'frozen' field */
  enum {
  #define SB_FREEZE_LEVELS (SB_FREEZE_COMPLETE - 1)
  
  struct sb_writers {
-       /* Counters for counting writers at each level */
-       struct percpu_counter   counter[SB_FREEZE_LEVELS];
-       wait_queue_head_t       wait;           /* queue for waiting for
-                                                  writers / faults to finish */
-       int                     frozen;         /* Is sb frozen? */
-       wait_queue_head_t       wait_unfrozen;  /* queue for waiting for
-                                                  sb to be thawed */
- #ifdef CONFIG_DEBUG_LOCK_ALLOC
-       struct lockdep_map      lock_map[SB_FREEZE_LEVELS];
- #endif
+       int                             frozen;         /* Is sb frozen? */
+       wait_queue_head_t               wait_unfrozen;  /* for get_super_thawed() */
+       struct percpu_rw_semaphore      rw_sem[SB_FREEZE_LEVELS];
  };
  
  struct super_block {
  #endif
        const struct xattr_handler **s_xattr;
  
-       struct list_head        s_inodes;       /* all inodes */
        struct hlist_bl_head    s_anon;         /* anonymous dentries for (nfs) exporting */
        struct list_head        s_mounts;       /* list of mounts; _not_ for fs use */
        struct block_device     *s_bdev;
        struct list_lru         s_dentry_lru ____cacheline_aligned_in_smp;
        struct list_lru         s_inode_lru ____cacheline_aligned_in_smp;
        struct rcu_head         rcu;
+       struct work_struct      destroy_work;
+       struct mutex            s_sync_lock;    /* sync serialisation lock */
  
        /*
         * Indicates how deep in a filesystem stack this SB is
         */
        int s_stack_depth;
+       /* s_inode_list_lock protects s_inodes */
+       spinlock_t              s_inode_list_lock ____cacheline_aligned_in_smp;
+       struct list_head        s_inodes;       /* all inodes */
  };
  
  extern struct timespec current_fs_time(struct super_block *sb);
  void __sb_end_write(struct super_block *sb, int level);
  int __sb_start_write(struct super_block *sb, int level, bool wait);
  
+ #define __sb_writers_acquired(sb, lev)        \
+       percpu_rwsem_acquire(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
+ #define __sb_writers_release(sb, lev) \
+       percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_)
  /**
   * sb_end_write - drop write access to a superblock
   * @sb: the super we wrote to
@@@ -1618,6 -1616,7 +1623,6 @@@ struct file_operations 
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
 -      int (*mremap)(struct file *, struct vm_area_struct *);
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
@@@ -2614,7 -2613,7 +2619,7 @@@ static inline void insert_inode_hash(st
  extern void __remove_inode_hash(struct inode *);
  static inline void remove_inode_hash(struct inode *inode)
  {
-       if (!inode_unhashed(inode))
+       if (!inode_unhashed(inode) && !hlist_fake(&inode->i_hash))
                __remove_inode_hash(inode);
  }
  
@@@ -3047,6 -3046,4 +3052,6 @@@ static inline bool dir_relax(struct ino
        return !IS_DEADDIR(inode);
  }
  
 +extern bool path_noexec(const struct path *path);
 +
  #endif /* _LINUX_FS_H */
index e0727d77feafb92747f8fc5fd040fc508b3b5d80,0390ee69c4391b0a747a0772d388549fd247eaf0..533c4408529a19819570c5dc40d917aa10ac2d26
@@@ -195,49 -195,40 +195,49 @@@ struct fsnotify_group 
  #define FSNOTIFY_EVENT_INODE  2
  
  /*
 - * a mark is simply an object attached to an in core inode which allows an
 + * A mark is simply an object attached to an in core inode which allows an
   * fsnotify listener to indicate they are either no longer interested in events
   * of a type matching mask or only interested in those events.
   *
 - * these are flushed when an inode is evicted from core and may be flushed
 - * when the inode is modified (as seen by fsnotify_access).  Some fsnotify users
 - * (such as dnotify) will flush these when the open fd is closed and not at
 - * inode eviction or modification.
 + * These are flushed when an inode is evicted from core and may be flushed
 + * when the inode is modified (as seen by fsnotify_access).  Some fsnotify
 + * users (such as dnotify) will flush these when the open fd is closed and not
 + * at inode eviction or modification.
 + *
 + * Text in brackets is showing the lock(s) protecting modifications of a
 + * particular entry. obj_lock means either inode->i_lock or
 + * mnt->mnt_root->d_lock depending on the mark type.
   */
  struct fsnotify_mark {
 -      __u32 mask;                     /* mask this mark is for */
 -      /* we hold ref for each i_list and g_list.  also one ref for each 'thing'
 +      /* Mask this mark is for [mark->lock, group->mark_mutex] */
 +      __u32 mask;
 +      /* We hold one for presence in g_list. Also one ref for each 'thing'
         * in kernel that found and may be using this mark. */
 -      atomic_t refcnt;                /* active things looking at this mark */
 -      struct fsnotify_group *group;   /* group this mark is for */
 -      struct list_head g_list;        /* list of marks by group->i_fsnotify_marks
 -                                       * Also reused for queueing mark into
 -                                       * destroy_list when it's waiting for
 -                                       * the end of SRCU period before it can
 -                                       * be freed */
 -      spinlock_t lock;                /* protect group and inode */
 -      struct hlist_node obj_list;     /* list of marks for inode / vfsmount */
 -      struct list_head free_list;     /* tmp list used when freeing this mark */
 -      union {
 +      atomic_t refcnt;
 +      /* Group this mark is for. Set on mark creation, stable until last ref
 +       * is dropped */
 +      struct fsnotify_group *group;
 +      /* List of marks by group->i_fsnotify_marks. Also reused for queueing
 +       * mark into destroy_list when it's waiting for the end of SRCU period
 +       * before it can be freed. [group->mark_mutex] */
 +      struct list_head g_list;
 +      /* Protects inode / mnt pointers, flags, masks */
 +      spinlock_t lock;
 +      /* List of marks for inode / vfsmount [obj_lock] */
 +      struct hlist_node obj_list;
 +      union { /* Object pointer [mark->lock, group->mark_mutex] */
                struct inode *inode;    /* inode this mark is associated with */
                struct vfsmount *mnt;   /* vfsmount this mark is associated with */
        };
 -      __u32 ignored_mask;             /* events types to ignore */
 +      /* Events types to ignore [mark->lock, group->mark_mutex] */
 +      __u32 ignored_mask;
  #define FSNOTIFY_MARK_FLAG_INODE              0x01
  #define FSNOTIFY_MARK_FLAG_VFSMOUNT           0x02
  #define FSNOTIFY_MARK_FLAG_OBJECT_PINNED      0x04
  #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY        0x08
  #define FSNOTIFY_MARK_FLAG_ALIVE              0x10
 -      unsigned int flags;             /* vfsmount or inode mark? */
 +#define FSNOTIFY_MARK_FLAG_ATTACHED           0x20
 +      unsigned int flags;             /* flags [mark->lock] */
        void (*free_mark)(struct fsnotify_mark *mark); /* called on final put+free */
  };
  
@@@ -354,10 -345,8 +354,10 @@@ extern int fsnotify_add_mark_locked(str
  /* given a group and a mark, flag mark to be freed when all references are dropped */
  extern void fsnotify_destroy_mark(struct fsnotify_mark *mark,
                                  struct fsnotify_group *group);
 -extern void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
 -                                       struct fsnotify_group *group);
 +/* detach mark from inode / mount list, group list, drop inode reference */
 +extern void fsnotify_detach_mark(struct fsnotify_mark *mark);
 +/* free mark */
 +extern void fsnotify_free_mark(struct fsnotify_mark *mark);
  /* run all the marks in a group, and clear all of the vfsmount marks */
  extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group);
  /* run all the marks in a group, and clear all of the inode marks */
@@@ -368,7 -357,7 +368,7 @@@ extern void fsnotify_clear_marks_by_gro
  extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group);
  extern void fsnotify_get_mark(struct fsnotify_mark *mark);
  extern void fsnotify_put_mark(struct fsnotify_mark *mark);
- extern void fsnotify_unmount_inodes(struct list_head *list);
+ extern void fsnotify_unmount_inodes(struct super_block *sb);
  
  /* put here because inotify does some weird stuff when destroying watches */
  extern void fsnotify_init_event(struct fsnotify_event *event,
@@@ -404,7 -393,7 +404,7 @@@ static inline u32 fsnotify_get_cookie(v
        return 0;
  }
  
- static inline void fsnotify_unmount_inodes(struct list_head *list)
+ static inline void fsnotify_unmount_inodes(struct super_block *sb)
  {}
  
  #endif        /* CONFIG_FSNOTIFY */
diff --combined init/Kconfig
index 2c0e50ef554a39c1a4ebb20bb4494968271733e1,288c0122c2a53851e4114e0918581c3fdce160cd..9cabd866b34b7432ce877538e6c4f50904d4150d
@@@ -538,6 -538,15 +538,6 @@@ config RCU_STALL_COMMO
  config CONTEXT_TRACKING
         bool
  
 -config RCU_USER_QS
 -      bool
 -      help
 -        This option sets hooks on kernel / userspace boundaries and
 -        puts RCU in extended quiescent state when the CPU runs in
 -        userspace. It means that when a CPU runs in userspace, it is
 -        excluded from the global RCU state machine and thus doesn't
 -        try to keep the timer tick on for RCU.
 -
  config CONTEXT_TRACKING_FORCE
        bool "Force context tracking"
        depends on CONTEXT_TRACKING
@@@ -698,7 -707,6 +698,7 @@@ config RCU_BOOST_DELA
  config RCU_NOCB_CPU
        bool "Offload RCU callback processing from boot-selected CPUs"
        depends on TREE_RCU || PREEMPT_RCU
 +      depends on RCU_EXPERT || NO_HZ_FULL
        default n
        help
          Use this option to reduce OS jitter for aggressive HPC or
@@@ -882,16 -890,6 +882,16 @@@ config GENERIC_SCHED_CLOC
  config ARCH_SUPPORTS_NUMA_BALANCING
        bool
  
 +#
 +# For architectures that prefer to flush all TLBs after a number of pages
 +# are unmapped instead of sending one IPI per page to flush. The architecture
 +# must provide guarantees on what happens if a clean TLB cache entry is
 +# written after the unmap. Details are in mm/rmap.c near the check for
 +# should_defer_flush. The architecture should also consider if the full flush
 +# and the refill costs are offset by the savings of sending fewer IPIs.
 +config ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
 +      bool
 +
  #
  # For architectures that know their GCC __int128 support is sound
  #
@@@ -927,7 -925,6 +927,6 @@@ config NUMA_BALANCING_DEFAULT_ENABLE
  menuconfig CGROUPS
        bool "Control Group support"
        select KERNFS
-       select PERCPU_RWSEM
        help
          This option adds support for grouping sets of processes together, for
          use with process control subsystems such as Cpusets, CFS, memory
@@@ -957,22 -954,6 +956,22 @@@ config CGROUP_FREEZE
          Provides a way to freeze and unfreeze all tasks in a
          cgroup.
  
 +config CGROUP_PIDS
 +      bool "PIDs cgroup subsystem"
 +      help
 +        Provides enforcement of process number limits in the scope of a
 +        cgroup. Any attempt to fork more processes than is allowed in the
 +        cgroup will fail. PIDs are fundamentally a global resource because it
 +        is fairly trivial to reach PID exhaustion before you reach even a
 +        conservative kmemcg limit. As a result, it is possible to grind a
 +        system to halt without being limited by other cgroup policies. The
 +        PIDs cgroup subsystem is designed to stop this from happening.
 +
 +        It should be noted that organisational operations (such as attaching
 +        to a cgroup hierarchy will *not* be blocked by the PIDs subsystem),
 +        since the PIDs limit only affects a process's ability to fork, not to
 +        attach to a cgroup.
 +
  config CGROUP_DEVICE
        bool "Device controller for cgroups"
        help
@@@ -1586,14 -1567,6 +1585,14 @@@ config ADVISE_SYSCALL
          applications use these syscalls, you can disable this option to save
          space.
  
 +config USERFAULTFD
 +      bool "Enable userfaultfd() system call"
 +      select ANON_INODES
 +      depends on MMU
 +      help
 +        Enable the userfaultfd() system call that allows to intercept and
 +        handle page faults in userland.
 +
  config PCI_QUIRKS
        default y
        bool "Enable PCI quirk workarounds" if EXPERT
diff --combined kernel/locking/Makefile
index 36942047ffc080808388a302c6df9e1ac7a87bda,4c6a97e1a8493eaf922dd22b79f88dba1259cca8..8e96f6cc2a4a8aa139a691afed04b163e81b1e93
@@@ -1,5 -1,5 +1,5 @@@
  
- obj-y += mutex.o semaphore.o rwsem.o
+ obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o
  
  ifdef CONFIG_FUNCTION_TRACER
  CFLAGS_REMOVE_lockdep.o = $(CC_FLAGS_FTRACE)
@@@ -20,10 -20,10 +20,9 @@@ obj-$(CONFIG_PROVE_LOCKING) += spinlock
  obj-$(CONFIG_QUEUED_SPINLOCKS) += qspinlock.o
  obj-$(CONFIG_RT_MUTEXES) += rtmutex.o
  obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o
 -obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
  obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
  obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
  obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
  obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem-xadd.o
- obj-$(CONFIG_PERCPU_RWSEM) += percpu-rwsem.o
  obj-$(CONFIG_QUEUED_RWLOCKS) += qrwlock.o
  obj-$(CONFIG_LOCK_TORTURE_TEST) += locktorture.o
diff --combined lib/Kconfig
index a16555281d5361e9fd437bb5bb84a94177dc3e51,f6aa03dc15760745ec45475ebb17b058d63b90c1..8a49ff9d15027af8e0c60b40c56f56e4d54f8125
@@@ -52,9 -52,6 +52,6 @@@ config GENERIC_I
  
  config STMP_DEVICE
        bool
- config PERCPU_RWSEM
-       bool
  
  config ARCH_USE_CMPXCHG_LOCKREF
        bool
@@@ -460,6 -457,16 +457,6 @@@ config ARCH_HAS_ATOMIC64_DEC_IF_POSITIV
  config LRU_CACHE
        tristate
  
 -config AVERAGE
 -      bool "Averaging functions"
 -      help
 -        This option is provided for the case where no in-kernel-tree
 -        modules require averaging functions, but a module built outside
 -        the kernel tree does. Such modules that use library averaging
 -        functions require Y here.
 -
 -        If unsure, say N.
 -
  config CLZ_TAB
        bool
  
@@@ -511,13 -518,6 +508,13 @@@ config UCS2_STRIN
  
  source "lib/fonts/Kconfig"
  
 +config SG_SPLIT
 +      def_bool n
 +      help
 +       Provides a heler to split scatterlists into chunks, each chunk being a
 +       scatterlist. This should be selected by a driver or an API which
 +       whishes to split a scatterlist amongst multiple DMA channel.
 +
  #
  # sg chaining option
  #