OSDN Git Service

Merge branch 'work.const-qstr' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 6 Aug 2016 13:49:02 +0000 (09:49 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 6 Aug 2016 13:49:02 +0000 (09:49 -0400)
Pull qstr constification updates from Al Viro:
 "Fairly self-contained bunch - surprising lot of places passes struct
  qstr * as an argument when const struct qstr * would suffice; it
  complicates analysis for no good reason.

  I'd prefer to feed that separately from the assorted fixes (those are
  in #for-linus and with somewhat trickier topology)"

* 'work.const-qstr' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  qstr: constify instances in adfs
  qstr: constify instances in lustre
  qstr: constify instances in f2fs
  qstr: constify instances in ext2
  qstr: constify instances in vfat
  qstr: constify instances in procfs
  qstr: constify instances in fuse
  qstr constify instances in fs/dcache.c
  qstr: constify instances in nfs
  qstr: constify instances in ocfs2
  qstr: constify instances in autofs4
  qstr: constify instances in hfs
  qstr: constify instances in hfsplus
  qstr: constify instances in logfs
  qstr: constify dentry_init_security

21 files changed:
1  2 
drivers/staging/lustre/lustre/llite/statahead.c
fs/adfs/dir.c
fs/autofs4/waitq.c
fs/dcache.c
fs/ext2/ext2.h
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/fat/namei_vfat.c
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/hfs/inode.c
fs/hfsplus/hfsplus_fs.h
fs/logfs/dir.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/proc/proc_sysctl.c
include/linux/dcache.h
include/linux/nfs_xdr.h
security/security.c
security/selinux/hooks.c

   *
   * You should have received a copy of the GNU General Public License
   * version 2 along with this program; If not, see
 - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
 - *
 - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 - * CA 95054 USA or visit www.sun.com if you need additional information or
 - * have any questions.
 + * http://www.gnu.org/licenses/gpl-2.0.html
   *
   * GPL HEADER END
   */
@@@ -170,8 -174,7 +170,8 @@@ static inline int is_omitted_entry(stru
   * Insert it into sai_entries tail when init.
   */
  static struct ll_sa_entry *
 -ll_sa_entry_alloc(struct ll_statahead_info *sai, __u64 index,
 +ll_sa_entry_alloc(struct dentry *parent,
 +                struct ll_statahead_info *sai, __u64 index,
                  const char *name, int len)
  {
        struct ll_inode_info *lli;
        dname = (char *)entry + sizeof(struct ll_sa_entry);
        memcpy(dname, name, len);
        dname[len] = 0;
 -      entry->se_qstr.hash = full_name_hash(name, len);
 +
 +      entry->se_qstr.hash = full_name_hash(parent, name, len);
        entry->se_qstr.len = len;
        entry->se_qstr.name = dname;
  
@@@ -648,7 -650,7 +648,7 @@@ static void ll_post_statahead(struct ll
                }
        }
  
 -      it->d.lustre.it_lock_handle = entry->se_handle;
 +      it->it_lock_handle = entry->se_handle;
        rc = md_revalidate_lock(ll_i2mdexp(dir), it, ll_inode2fid(dir), NULL);
        if (rc != 1) {
                rc = -EAGAIN;
@@@ -702,7 -704,7 +702,7 @@@ static int ll_statahead_interpret(struc
                 * process enqueues lock on child with parent lock held, eg.
                 * unlink.
                 */
 -              handle = it->d.lustre.it_lock_handle;
 +              handle = it->it_lock_handle;
                ll_intent_drop_lock(it);
        }
  
@@@ -781,7 -783,7 +781,7 @@@ static int sa_args_init(struct inode *d
                        struct ll_sa_entry *entry, struct md_enqueue_info **pmi,
                        struct ldlm_enqueue_info **pei)
  {
-       struct qstr           *qstr = &entry->se_qstr;
+       const struct qstr      *qstr = &entry->se_qstr;
        struct ll_inode_info     *lli  = ll_i2info(dir);
        struct md_enqueue_info   *minfo;
        struct ldlm_enqueue_info *einfo;
@@@ -852,7 -854,7 +852,7 @@@ static int do_sa_revalidate(struct inod
  {
        struct inode         *inode = d_inode(dentry);
        struct lookup_intent      it = { .it_op = IT_GETATTR,
 -                                       .d.lustre.it_lock_handle = 0 };
 +                                       .it_lock_handle = 0 };
        struct md_enqueue_info   *minfo;
        struct ldlm_enqueue_info *einfo;
        int rc;
        rc = md_revalidate_lock(ll_i2mdexp(dir), &it, ll_inode2fid(inode),
                                NULL);
        if (rc == 1) {
 -              entry->se_handle = it.d.lustre.it_lock_handle;
 +              entry->se_handle = it.it_lock_handle;
                ll_intent_release(&it);
                return 1;
        }
@@@ -900,7 -902,7 +900,7 @@@ static void ll_statahead_one(struct den
        int                    rc;
        int                    rc1;
  
 -      entry = ll_sa_entry_alloc(sai, sai->sai_index, entry_name,
 +      entry = ll_sa_entry_alloc(parent, sai, sai->sai_index, entry_name,
                                  entry_name_len);
        if (IS_ERR(entry))
                return;
@@@ -1340,7 -1342,7 +1340,7 @@@ enum 
  static int is_first_dirent(struct inode *dir, struct dentry *dentry)
  {
        struct ll_dir_chain   chain;
-       struct qstr       *target = &dentry->d_name;
+       const struct qstr  *target = &dentry->d_name;
        struct page       *page;
        __u64            pos    = 0;
        int                dot_de;
@@@ -1571,7 -1573,7 +1571,7 @@@ int do_statahead_enter(struct inode *di
                if (entry->se_stat == SA_ENTRY_SUCC && entry->se_inode) {
                        struct inode *inode = entry->se_inode;
                        struct lookup_intent it = { .it_op = IT_GETATTR,
 -                                                  .d.lustre.it_lock_handle =
 +                                                  .it_lock_handle =
                                                     entry->se_handle };
                        __u64 bits;
  
diff --combined fs/adfs/dir.c
@@@ -101,7 -101,7 +101,7 @@@ out
  }
  
  static int
- adfs_match(struct qstr *name, struct object_info *obj)
+ adfs_match(const struct qstr *name, struct object_info *obj)
  {
        int i;
  
  }
  
  static int
- adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_info *obj)
+ adfs_dir_lookup_byname(struct inode *inode, const struct qstr *name, struct object_info *obj)
  {
        struct super_block *sb = inode->i_sb;
        const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
@@@ -207,7 -207,7 +207,7 @@@ adfs_hash(const struct dentry *parent, 
         */
        qstr->len = i = name_len;
        name = qstr->name;
 -      hash = init_name_hash();
 +      hash = init_name_hash(parent);
        while (i--) {
                char c;
  
diff --combined fs/autofs4/waitq.c
@@@ -225,7 -225,7 +225,7 @@@ rename_retry
  }
  
  static struct autofs_wait_queue *
- autofs4_find_wait(struct autofs_sb_info *sbi, struct qstr *qstr)
+ autofs4_find_wait(struct autofs_sb_info *sbi, const struct qstr *qstr)
  {
        struct autofs_wait_queue *wq;
  
   */
  static int validate_request(struct autofs_wait_queue **wait,
                            struct autofs_sb_info *sbi,
-                           struct qstr *qstr,
+                           const struct qstr *qstr,
                            struct dentry *dentry, enum autofs_notify notify)
  {
        struct autofs_wait_queue *wq;
@@@ -398,7 -398,7 +398,7 @@@ int autofs4_wait(struct autofs_sb_info 
                }
        }
        qstr.name = name;
 -      qstr.hash = full_name_hash(name, qstr.len);
 +      qstr.hash = full_name_hash(dentry, name, qstr.len);
  
        if (mutex_lock_interruptible(&sbi->wq_mutex)) {
                kfree(qstr.name);
diff --combined fs/dcache.c
@@@ -104,9 -104,11 +104,9 @@@ static unsigned int d_hash_shift __read
  
  static struct hlist_bl_head *dentry_hashtable __read_mostly;
  
 -static inline struct hlist_bl_head *d_hash(const struct dentry *parent,
 -                                      unsigned int hash)
 +static inline struct hlist_bl_head *d_hash(unsigned int hash)
  {
 -      hash += (unsigned long) parent / L1_CACHE_BYTES;
 -      return dentry_hashtable + hash_32(hash, d_hash_shift);
 +      return dentry_hashtable + (hash >> (32 - d_hash_shift));
  }
  
  #define IN_LOOKUP_SHIFT 10
@@@ -224,9 -226,10 +224,9 @@@ static inline int dentry_string_cmp(con
  
  static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount)
  {
 -      const unsigned char *cs;
        /*
         * Be careful about RCU walk racing with rename:
 -       * use ACCESS_ONCE to fetch the name pointer.
 +       * use 'lockless_dereference' to fetch the name pointer.
         *
         * NOTE! Even if a rename will mean that the length
         * was not loaded atomically, we don't care. The
         * early because the data cannot match (there can
         * be no NUL in the ct/tcount data)
         */
 -      cs = ACCESS_ONCE(dentry->d_name.name);
 -      smp_read_barrier_depends();
 +      const unsigned char *cs = lockless_dereference(dentry->d_name.name);
 +
        return dentry_string_cmp(cs, ct, tcount);
  }
  
@@@ -332,21 -335,44 +332,21 @@@ static inline void dentry_rcuwalk_inval
  
  /*
   * Release the dentry's inode, using the filesystem
 - * d_iput() operation if defined. Dentry has no refcount
 - * and is unhashed.
 - */
 -static void dentry_iput(struct dentry * dentry)
 -      __releases(dentry->d_lock)
 -      __releases(dentry->d_inode->i_lock)
 -{
 -      struct inode *inode = dentry->d_inode;
 -      if (inode) {
 -              __d_clear_type_and_inode(dentry);
 -              hlist_del_init(&dentry->d_u.d_alias);
 -              spin_unlock(&dentry->d_lock);
 -              spin_unlock(&inode->i_lock);
 -              if (!inode->i_nlink)
 -                      fsnotify_inoderemove(inode);
 -              if (dentry->d_op && dentry->d_op->d_iput)
 -                      dentry->d_op->d_iput(dentry, inode);
 -              else
 -                      iput(inode);
 -      } else {
 -              spin_unlock(&dentry->d_lock);
 -      }
 -}
 -
 -/*
 - * Release the dentry's inode, using the filesystem
 - * d_iput() operation if defined. dentry remains in-use.
 + * d_iput() operation if defined.
   */
  static void dentry_unlink_inode(struct dentry * dentry)
        __releases(dentry->d_lock)
        __releases(dentry->d_inode->i_lock)
  {
        struct inode *inode = dentry->d_inode;
 +      bool hashed = !d_unhashed(dentry);
  
 -      raw_write_seqcount_begin(&dentry->d_seq);
 +      if (hashed)
 +              raw_write_seqcount_begin(&dentry->d_seq);
        __d_clear_type_and_inode(dentry);
        hlist_del_init(&dentry->d_u.d_alias);
 -      raw_write_seqcount_end(&dentry->d_seq);
 +      if (hashed)
 +              raw_write_seqcount_end(&dentry->d_seq);
        spin_unlock(&dentry->d_lock);
        spin_unlock(&inode->i_lock);
        if (!inode->i_nlink)
@@@ -462,7 -488,7 +462,7 @@@ void __d_drop(struct dentry *dentry
                if (unlikely(IS_ROOT(dentry)))
                        b = &dentry->d_sb->s_anon;
                else
 -                      b = d_hash(dentry->d_parent, dentry->d_name.hash);
 +                      b = d_hash(dentry->d_name.hash);
  
                hlist_bl_lock(b);
                __hlist_bl_del(&dentry->d_hash);
@@@ -547,10 -573,12 +547,10 @@@ static void __dentry_kill(struct dentr
        dentry_unlist(dentry, parent);
        if (parent)
                spin_unlock(&parent->d_lock);
 -      dentry_iput(dentry);
 -      /*
 -       * dentry_iput drops the locks, at which point nobody (except
 -       * transient RCU lookups) can reach this dentry.
 -       */
 -      BUG_ON(dentry->d_lockref.count > 0);
 +      if (dentry->d_inode)
 +              dentry_unlink_inode(dentry);
 +      else
 +              spin_unlock(&dentry->d_lock);
        this_cpu_dec(nr_dentry);
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
@@@ -594,6 -622,7 +594,6 @@@ static struct dentry *dentry_kill(struc
  
  failed:
        spin_unlock(&dentry->d_lock);
 -      cpu_relax();
        return dentry; /* try again with same dentry */
  }
  
@@@ -767,8 -796,6 +767,8 @@@ void dput(struct dentry *dentry
                return;
  
  repeat:
 +      might_sleep();
 +
        rcu_read_lock();
        if (likely(fast_dput(dentry))) {
                rcu_read_unlock();
  
  kill_it:
        dentry = dentry_kill(dentry);
 -      if (dentry)
 +      if (dentry) {
 +              cond_resched();
                goto repeat;
 +      }
  }
  EXPORT_SYMBOL(dput);
  
@@@ -1570,7 -1595,6 +1570,7 @@@ struct dentry *__d_alloc(struct super_b
  {
        struct dentry *dentry;
        char *dname;
 +      int err;
  
        dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);
        if (!dentry)
        INIT_LIST_HEAD(&dentry->d_child);
        d_set_d_op(dentry, dentry->d_sb->s_d_op);
  
 +      if (dentry->d_op && dentry->d_op->d_init) {
 +              err = dentry->d_op->d_init(dentry);
 +              if (err) {
 +                      if (dname_external(dentry))
 +                              kfree(external_name(dentry));
 +                      kmem_cache_free(dentry_cache, dentry);
 +                      return NULL;
 +              }
 +      }
 +
        this_cpu_inc(nr_dentry);
  
        return dentry;
@@@ -1702,7 -1716,7 +1702,7 @@@ struct dentry *d_alloc_name(struct dent
        struct qstr q;
  
        q.name = name;
 -      q.hash_len = hashlen_string(name);
 +      q.hash_len = hashlen_string(parent, name);
        return d_alloc(parent, &q);
  }
  EXPORT_SYMBOL(d_alloc_name);
@@@ -1715,6 -1729,7 +1715,6 @@@ void d_set_d_op(struct dentry *dentry, 
                                DCACHE_OP_REVALIDATE    |
                                DCACHE_OP_WEAK_REVALIDATE       |
                                DCACHE_OP_DELETE        |
 -                              DCACHE_OP_SELECT_INODE  |
                                DCACHE_OP_REAL));
        dentry->d_op = op;
        if (!op)
                dentry->d_flags |= DCACHE_OP_DELETE;
        if (op->d_prune)
                dentry->d_flags |= DCACHE_OP_PRUNE;
 -      if (op->d_select_inode)
 -              dentry->d_flags |= DCACHE_OP_SELECT_INODE;
        if (op->d_real)
                dentry->d_flags |= DCACHE_OP_REAL;
  
@@@ -1798,7 -1815,7 +1798,7 @@@ static void __d_instantiate(struct dent
        raw_write_seqcount_begin(&dentry->d_seq);
        __d_set_inode_and_type(dentry, inode, add_flags);
        raw_write_seqcount_end(&dentry->d_seq);
 -      __fsnotify_d_instantiate(dentry);
 +      fsnotify_update_flags(dentry);
        spin_unlock(&dentry->d_lock);
  }
  
@@@ -2050,19 -2067,42 +2050,19 @@@ struct dentry *d_add_ci(struct dentry *
  }
  EXPORT_SYMBOL(d_add_ci);
  
 -/*
 - * Do the slow-case of the dentry name compare.
 - *
 - * Unlike the dentry_cmp() function, we need to atomically
 - * load the name and length information, so that the
 - * filesystem can rely on them, and can use the 'name' and
 - * 'len' information without worrying about walking off the
 - * end of memory etc.
 - *
 - * Thus the read_seqcount_retry() and the "duplicate" info
 - * in arguments (the low-level filesystem should not look
 - * at the dentry inode or name contents directly, since
 - * rename can change them while we're in RCU mode).
 - */
 -enum slow_d_compare {
 -      D_COMP_OK,
 -      D_COMP_NOMATCH,
 -      D_COMP_SEQRETRY,
 -};
  
 -static noinline enum slow_d_compare slow_dentry_cmp(
 -              const struct dentry *parent,
 -              struct dentry *dentry,
 -              unsigned int seq,
 -              const struct qstr *name)
 +static inline bool d_same_name(const struct dentry *dentry,
 +                              const struct dentry *parent,
 +                              const struct qstr *name)
  {
 -      int tlen = dentry->d_name.len;
 -      const char *tname = dentry->d_name.name;
 -
 -      if (read_seqcount_retry(&dentry->d_seq, seq)) {
 -              cpu_relax();
 -              return D_COMP_SEQRETRY;
 +      if (likely(!(parent->d_flags & DCACHE_OP_COMPARE))) {
 +              if (dentry->d_name.len != name->len)
 +                      return false;
 +              return dentry_cmp(dentry, name->name, name->len) == 0;
        }
 -      if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
 -              return D_COMP_NOMATCH;
 -      return D_COMP_OK;
 +      return parent->d_op->d_compare(parent, dentry,
 +                                     dentry->d_name.len, dentry->d_name.name,
 +                                     name) == 0;
  }
  
  /**
@@@ -2100,7 -2140,7 +2100,7 @@@ struct dentry *__d_lookup_rcu(const str
  {
        u64 hashlen = name->hash_len;
        const unsigned char *str = name->name;
 -      struct hlist_bl_head *b = d_hash(parent, hashlen_hash(hashlen));
 +      struct hlist_bl_head *b = d_hash(hashlen_hash(hashlen));
        struct hlist_bl_node *node;
        struct dentry *dentry;
  
@@@ -2141,9 -2181,6 +2141,9 @@@ seqretry
                 * dentry compare, we will do seqretries until it is stable,
                 * and if we end up with a successful lookup, we actually
                 * want to exit RCU lookup anyway.
 +               *
 +               * Note that raw_seqcount_begin still *does* smp_rmb(), so
 +               * we are still guaranteed NUL-termination of ->d_name.name.
                 */
                seq = raw_seqcount_begin(&dentry->d_seq);
                if (dentry->d_parent != parent)
                        continue;
  
                if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
 +                      int tlen;
 +                      const char *tname;
                        if (dentry->d_name.hash != hashlen_hash(hashlen))
                                continue;
 -                      *seqp = seq;
 -                      switch (slow_dentry_cmp(parent, dentry, seq, name)) {
 -                      case D_COMP_OK:
 -                              return dentry;
 -                      case D_COMP_NOMATCH:
 -                              continue;
 -                      default:
 +                      tlen = dentry->d_name.len;
 +                      tname = dentry->d_name.name;
 +                      /* we want a consistent (name,len) pair */
 +                      if (read_seqcount_retry(&dentry->d_seq, seq)) {
 +                              cpu_relax();
                                goto seqretry;
                        }
 +                      if (parent->d_op->d_compare(parent, dentry,
 +                                                  tlen, tname, name) != 0)
 +                              continue;
 +              } else {
 +                      if (dentry->d_name.hash_len != hashlen)
 +                              continue;
 +                      if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0)
 +                              continue;
                }
 -
 -              if (dentry->d_name.hash_len != hashlen)
 -                      continue;
                *seqp = seq;
 -              if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
 -                      return dentry;
 +              return dentry;
        }
        return NULL;
  }
@@@ -2221,8 -2254,10 +2221,8 @@@ EXPORT_SYMBOL(d_lookup)
   */
  struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
  {
 -      unsigned int len = name->len;
        unsigned int hash = name->hash;
 -      const unsigned char *str = name->name;
 -      struct hlist_bl_head *b = d_hash(parent, hash);
 +      struct hlist_bl_head *b = d_hash(hash);
        struct hlist_bl_node *node;
        struct dentry *found = NULL;
        struct dentry *dentry;
                if (d_unhashed(dentry))
                        goto next;
  
 -              /*
 -               * It is safe to compare names since d_move() cannot
 -               * change the qstr (protected by d_lock).
 -               */
 -              if (parent->d_flags & DCACHE_OP_COMPARE) {
 -                      int tlen = dentry->d_name.len;
 -                      const char *tname = dentry->d_name.name;
 -                      if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
 -                              goto next;
 -              } else {
 -                      if (dentry->d_name.len != len)
 -                              goto next;
 -                      if (dentry_cmp(dentry, str, len))
 -                              goto next;
 -              }
 +              if (!d_same_name(dentry, parent, name))
 +                      goto next;
  
                dentry->d_lockref.count++;
                found = dentry;
@@@ -2289,7 -2337,7 +2289,7 @@@ struct dentry *d_hash_and_lookup(struc
         * calculate the standard hash first, as the d_op->d_hash()
         * routine may choose to leave the hash value unchanged.
         */
 -      name->hash = full_name_hash(name->name, name->len);
 +      name->hash = full_name_hash(dir, name->name, name->len);
        if (dir->d_flags & DCACHE_OP_HASH) {
                int err = dir->d_op->d_hash(dir, name);
                if (unlikely(err < 0))
@@@ -2362,7 -2410,7 +2362,7 @@@ static void __d_rehash(struct dentry * 
  
  static void _d_rehash(struct dentry * entry)
  {
 -      __d_rehash(entry, d_hash(entry->d_parent, entry->d_name.hash));
 +      __d_rehash(entry, d_hash(entry->d_name.hash));
  }
  
  /**
@@@ -2414,7 -2462,9 +2414,7 @@@ struct dentry *d_alloc_parallel(struct 
                                const struct qstr *name,
                                wait_queue_head_t *wq)
  {
 -      unsigned int len = name->len;
        unsigned int hash = name->hash;
 -      const unsigned char *str = name->name;
        struct hlist_bl_head *b = in_lookup_hash(parent, hash);
        struct hlist_bl_node *node;
        struct dentry *new = d_alloc(parent, name);
@@@ -2465,8 -2515,17 +2465,8 @@@ retry
                        continue;
                if (dentry->d_parent != parent)
                        continue;
 -              if (parent->d_flags & DCACHE_OP_COMPARE) {
 -                      int tlen = dentry->d_name.len;
 -                      const char *tname = dentry->d_name.name;
 -                      if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
 -                              continue;
 -              } else {
 -                      if (dentry->d_name.len != len)
 -                              continue;
 -                      if (dentry_cmp(dentry, str, len))
 -                              continue;
 -              }
 +              if (!d_same_name(dentry, parent, name))
 +                      continue;
                hlist_bl_unlock(b);
                /* now we can try to grab a reference */
                if (!lockref_get_not_dead(&dentry->d_lockref)) {
                        goto mismatch;
                if (unlikely(d_unhashed(dentry)))
                        goto mismatch;
 -              if (parent->d_flags & DCACHE_OP_COMPARE) {
 -                      int tlen = dentry->d_name.len;
 -                      const char *tname = dentry->d_name.name;
 -                      if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
 -                              goto mismatch;
 -              } else {
 -                      if (unlikely(dentry->d_name.len != len))
 -                              goto mismatch;
 -                      if (unlikely(dentry_cmp(dentry, str, len)))
 -                              goto mismatch;
 -              }
 +              if (unlikely(!d_same_name(dentry, parent, name)))
 +                      goto mismatch;
                /* OK, it *is* a hashed match; return it */
                spin_unlock(&dentry->d_lock);
                dput(new);
@@@ -2547,7 -2615,7 +2547,7 @@@ static inline void __d_add(struct dentr
                raw_write_seqcount_begin(&dentry->d_seq);
                __d_set_inode_and_type(dentry, inode, add_flags);
                raw_write_seqcount_end(&dentry->d_seq);
 -              __fsnotify_d_instantiate(dentry);
 +              fsnotify_update_flags(dentry);
        }
        _d_rehash(dentry);
        if (dir)
@@@ -2590,6 -2658,8 +2590,6 @@@ EXPORT_SYMBOL(d_add)
  struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)
  {
        struct dentry *alias;
 -      int len = entry->d_name.len;
 -      const char *name = entry->d_name.name;
        unsigned int hash = entry->d_name.hash;
  
        spin_lock(&inode->i_lock);
                        continue;
                if (alias->d_parent != entry->d_parent)
                        continue;
 -              if (alias->d_name.len != len)
 -                      continue;
 -              if (dentry_cmp(alias, name, len))
 +              if (!d_same_name(alias, entry->d_parent, &entry->d_name))
                        continue;
                spin_lock(&alias->d_lock);
                if (!d_unhashed(alias)) {
@@@ -2636,7 -2708,7 +2636,7 @@@ EXPORT_SYMBOL(d_exact_alias)
   * Parent inode i_mutex must be held over d_lookup and into this call (to
   * keep renames and concurrent inserts, and readdir(2) away).
   */
- void dentry_update_name_case(struct dentry *dentry, struct qstr *name)
+ void dentry_update_name_case(struct dentry *dentry, const struct qstr *name)
  {
        BUG_ON(!inode_is_locked(dentry->d_parent->d_inode));
        BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */
@@@ -2802,7 -2874,7 +2802,7 @@@ static void __d_move(struct dentry *den
         * for the same hash queue because of how unlikely it is.
         */
        __d_drop(dentry);
 -      __d_rehash(dentry, d_hash(target->d_parent, target->d_name.hash));
 +      __d_rehash(dentry, d_hash(target->d_name.hash));
  
        /*
         * Unhash the target (d_delete() is not usable here).  If exchanging
         */
        __d_drop(target);
        if (exchange) {
 -              __d_rehash(target,
 -                         d_hash(dentry->d_parent, dentry->d_name.hash));
 +              __d_rehash(target, d_hash(dentry->d_name.hash));
        }
  
        /* Switch the names.. */
                list_move(&target->d_child, &target->d_parent->d_subdirs);
                list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
                if (exchange)
 -                      fsnotify_d_move(target);
 -              fsnotify_d_move(dentry);
 +                      fsnotify_update_flags(target);
 +              fsnotify_update_flags(dentry);
        }
  
        write_seqcount_end(&target->d_seq);
@@@ -3038,7 -3111,7 +3038,7 @@@ static int prepend(char **buffer, int *
   * Data dependency barrier is needed to make sure that we see that terminating
   * NUL.  Alpha strikes again, film at 11...
   */
- static int prepend_name(char **buffer, int *buflen, struct qstr *name)
+ static int prepend_name(char **buffer, int *buflen, const struct qstr *name)
  {
        const char *dname = ACCESS_ONCE(name->name);
        u32 dlen = ACCESS_ONCE(name->len);
diff --combined fs/ext2/ext2.h
@@@ -367,7 -367,6 +367,7 @@@ struct ext2_inode 
   */
  #define       EXT2_VALID_FS                   0x0001  /* Unmounted cleanly */
  #define       EXT2_ERROR_FS                   0x0002  /* Errors detected */
 +#define       EFSCORRUPTED                    EUCLEAN /* Filesystem is corrupted */
  
  /*
   * Mount flags
@@@ -740,8 -739,6 +740,8 @@@ extern unsigned long ext2_bg_num_gdb(st
  extern ext2_fsblk_t ext2_new_block(struct inode *, unsigned long, int *);
  extern ext2_fsblk_t ext2_new_blocks(struct inode *, unsigned long,
                                unsigned long *, int *);
 +extern int ext2_data_block_valid(struct ext2_sb_info *sbi, ext2_fsblk_t start_blk,
 +                               unsigned int count);
  extern void ext2_free_blocks (struct inode *, unsigned long,
                              unsigned long);
  extern unsigned long ext2_count_free_blocks (struct super_block *);
@@@ -757,9 -754,9 +757,9 @@@ extern void ext2_rsv_window_add(struct 
  
  /* dir.c */
  extern int ext2_add_link (struct dentry *, struct inode *);
- extern ino_t ext2_inode_by_name(struct inode *, struct qstr *);
+ extern ino_t ext2_inode_by_name(struct inode *, const struct qstr *);
  extern int ext2_make_empty(struct inode *, struct inode *);
- extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct qstr *, struct page **);
+ extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,const struct qstr *, struct page **);
  extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *);
  extern int ext2_empty_dir (struct inode *);
  extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **);
diff --combined fs/f2fs/dir.c
@@@ -185,13 -185,8 +185,13 @@@ static struct f2fs_dir_entry *find_in_l
                /* no need to allocate new dentry pages to all the indices */
                dentry_page = find_data_page(dir, bidx);
                if (IS_ERR(dentry_page)) {
 -                      room = true;
 -                      continue;
 +                      if (PTR_ERR(dentry_page) == -ENOENT) {
 +                              room = true;
 +                              continue;
 +                      } else {
 +                              *res_page = dentry_page;
 +                              break;
 +                      }
                }
  
                de = find_in_block(dentry_page, fname, namehash, &max_slots,
   * Entry is guaranteed to be valid.
   */
  struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
-                       struct qstr *child, struct page **res_page)
+                       const struct qstr *child, struct page **res_page)
  {
        unsigned long npages = dir_blocks(dir);
        struct f2fs_dir_entry *de = NULL;
        struct fscrypt_name fname;
        int err;
  
 -      *res_page = NULL;
 -
        err = fscrypt_setup_filename(dir, child, 1, &fname);
 -      if (err)
 +      if (err) {
 +              *res_page = ERR_PTR(err);
                return NULL;
 +      }
  
        if (f2fs_has_inline_dentry(dir)) {
 +              *res_page = NULL;
                de = find_in_inline_dir(dir, &fname, res_page);
                goto out;
        }
  
 -      if (npages == 0)
 +      if (npages == 0) {
 +              *res_page = NULL;
                goto out;
 +      }
  
        max_depth = F2FS_I(dir)->i_current_depth;
        if (unlikely(max_depth > MAX_DIR_HASH_DEPTH)) {
                                "Corrupted max_depth of %lu: %u",
                                dir->i_ino, max_depth);
                max_depth = MAX_DIR_HASH_DEPTH;
 -              F2FS_I(dir)->i_current_depth = max_depth;
 -              mark_inode_dirty(dir);
 +              f2fs_i_depth_write(dir, max_depth);
        }
  
        for (level = 0; level < max_depth; level++) {
 +              *res_page = NULL;
                de = find_in_level(dir, level, &fname, res_page);
 -              if (de)
 +              if (de || IS_ERR(*res_page))
                        break;
        }
  out:
  
  struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p)
  {
 -      struct page *page;
 -      struct f2fs_dir_entry *de;
 -      struct f2fs_dentry_block *dentry_blk;
 -
 -      if (f2fs_has_inline_dentry(dir))
 -              return f2fs_parent_inline_dir(dir, p);
 -
 -      page = get_lock_data_page(dir, 0, false);
 -      if (IS_ERR(page))
 -              return NULL;
 +      struct qstr dotdot = QSTR_INIT("..", 2);
  
 -      dentry_blk = kmap(page);
 -      de = &dentry_blk->dentry[1];
 -      *p = page;
 -      unlock_page(page);
 -      return de;
 +      return f2fs_find_entry(dir, &dotdot, p);
  }
  
- ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr,
 -ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr)
++ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr,
 +                                                      struct page **page)
  {
        ino_t res = 0;
        struct f2fs_dir_entry *de;
 -      struct page *page;
  
 -      de = f2fs_find_entry(dir, qstr, &page);
 +      de = f2fs_find_entry(dir, qstr, page);
        if (de) {
                res = le32_to_cpu(de->ino);
 -              f2fs_dentry_kunmap(dir, page);
 -              f2fs_put_page(page, 0);
 +              f2fs_dentry_kunmap(dir, *page);
 +              f2fs_put_page(*page, 0);
        }
  
        return res;
@@@ -298,9 -303,9 +298,9 @@@ void f2fs_set_link(struct inode *dir, s
        set_de_type(de, inode->i_mode);
        f2fs_dentry_kunmap(dir, page);
        set_page_dirty(page);
 -      dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 -      mark_inode_dirty(dir);
  
 +      dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 +      f2fs_mark_inode_dirty_sync(dir);
        f2fs_put_page(page, 1);
  }
  
@@@ -380,7 -385,7 +380,7 @@@ struct page *init_inode_metadata(struc
        struct page *page;
        int err;
  
 -      if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
 +      if (is_inode_flag_set(inode, FI_NEW_INODE)) {
                page = new_inode_page(inode);
                if (IS_ERR(page))
                        return page;
         * This file should be checkpointed during fsync.
         * We lost i_pino from now on.
         */
 -      if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
 +      if (is_inode_flag_set(inode, FI_INC_LINK)) {
                file_lost_pino(inode);
                /*
                 * If link the tmpfile to alias through linkat path,
                 */
                if (inode->i_nlink == 0)
                        remove_orphan_inode(F2FS_I_SB(dir), inode->i_ino);
 -              inc_nlink(inode);
 +              f2fs_i_links_write(inode, true);
        }
        return page;
  
  put_error:
 -      /* truncate empty dir pages */
 -      truncate_inode_pages(&inode->i_data, 0);
 -
        clear_nlink(inode);
        update_inode(inode, page);
        f2fs_put_page(page, 1);
  void update_parent_metadata(struct inode *dir, struct inode *inode,
                                                unsigned int current_depth)
  {
 -      if (inode && is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
 -              if (S_ISDIR(inode->i_mode)) {
 -                      inc_nlink(dir);
 -                      set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
 -              }
 -              clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
 +      if (inode && is_inode_flag_set(inode, FI_NEW_INODE)) {
 +              if (S_ISDIR(inode->i_mode))
 +                      f2fs_i_links_write(dir, true);
 +              clear_inode_flag(inode, FI_NEW_INODE);
        }
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 -      mark_inode_dirty(dir);
 +      f2fs_mark_inode_dirty_sync(dir);
  
 -      if (F2FS_I(dir)->i_current_depth != current_depth) {
 -              F2FS_I(dir)->i_current_depth = current_depth;
 -              set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
 -      }
 +      if (F2FS_I(dir)->i_current_depth != current_depth)
 +              f2fs_i_depth_write(dir, current_depth);
  
 -      if (inode && is_inode_flag_set(F2FS_I(inode), FI_INC_LINK))
 -              clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
 +      if (inode && is_inode_flag_set(inode, FI_INC_LINK))
 +              clear_inode_flag(inode, FI_INC_LINK);
  }
  
  int room_for_filename(const void *bitmap, int slots, int max_slots)
@@@ -584,7 -596,9 +584,7 @@@ add_dentry
        set_page_dirty(dentry_page);
  
        if (inode) {
 -              /* we don't need to mark_inode_dirty now */
 -              F2FS_I(inode)->i_pino = dir->i_ino;
 -              update_inode(inode, page);
 +              f2fs_i_pino_write(inode, dir->i_ino);
                f2fs_put_page(page, 1);
        }
  
@@@ -593,6 -607,10 +593,6 @@@ fail
        if (inode)
                up_write(&F2FS_I(inode)->i_sem);
  
 -      if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) {
 -              update_inode_page(dir);
 -              clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
 -      }
        kunmap(dentry_page);
        f2fs_put_page(dentry_page, 1);
  
@@@ -639,34 -657,42 +639,34 @@@ int f2fs_do_tmpfile(struct inode *inode
                err = PTR_ERR(page);
                goto fail;
        }
 -      /* we don't need to mark_inode_dirty now */
 -      update_inode(inode, page);
        f2fs_put_page(page, 1);
  
 -      clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
 +      clear_inode_flag(inode, FI_NEW_INODE);
  fail:
        up_write(&F2FS_I(inode)->i_sem);
        f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
        return err;
  }
  
 -void f2fs_drop_nlink(struct inode *dir, struct inode *inode, struct page *page)
 +void f2fs_drop_nlink(struct inode *dir, struct inode *inode)
  {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
  
        down_write(&F2FS_I(inode)->i_sem);
  
 -      if (S_ISDIR(inode->i_mode)) {
 -              drop_nlink(dir);
 -              if (page)
 -                      update_inode(dir, page);
 -              else
 -                      update_inode_page(dir);
 -      }
 +      if (S_ISDIR(inode->i_mode))
 +              f2fs_i_links_write(dir, false);
        inode->i_ctime = CURRENT_TIME;
  
 -      drop_nlink(inode);
 +      f2fs_i_links_write(inode, false);
        if (S_ISDIR(inode->i_mode)) {
 -              drop_nlink(inode);
 -              i_size_write(inode, 0);
 +              f2fs_i_links_write(inode, false);
 +              f2fs_i_size_write(inode, 0);
        }
        up_write(&F2FS_I(inode)->i_sem);
 -      update_inode_page(inode);
  
        if (inode->i_nlink == 0)
 -              add_orphan_inode(sbi, inode->i_ino);
 +              add_orphan_inode(inode);
        else
                release_orphan_inode(sbi);
  }
@@@ -704,10 -730,9 +704,10 @@@ void f2fs_delete_entry(struct f2fs_dir_
        set_page_dirty(page);
  
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 +      f2fs_mark_inode_dirty_sync(dir);
  
        if (inode)
 -              f2fs_drop_nlink(dir, inode, NULL);
 +              f2fs_drop_nlink(dir, inode);
  
        if (bit_pos == NR_DENTRY_IN_BLOCK &&
                        !truncate_hole(dir, page->index, page->index + 1)) {
diff --combined fs/f2fs/f2fs.h
@@@ -45,7 -45,6 +45,7 @@@ enum 
        FAULT_ORPHAN,
        FAULT_BLOCK,
        FAULT_DIR_DEPTH,
 +      FAULT_EVICT_INODE,
        FAULT_MAX,
  };
  
@@@ -75,8 -74,6 +75,8 @@@ static inline bool time_to_inject(int t
                return false;
        else if (type == FAULT_DIR_DEPTH && !IS_FAULT_SET(type))
                return false;
 +      else if (type == FAULT_EVICT_INODE && !IS_FAULT_SET(type))
 +              return false;
  
        atomic_inc(&f2fs_fault.inject_ops);
        if (atomic_read(&f2fs_fault.inject_ops) >= f2fs_fault.inject_rate) {
  #define F2FS_MOUNT_FORCE_FG_GC                0x00004000
  #define F2FS_MOUNT_DATA_FLUSH         0x00008000
  #define F2FS_MOUNT_FAULT_INJECTION    0x00010000
 +#define F2FS_MOUNT_ADAPTIVE           0x00020000
 +#define F2FS_MOUNT_LFS                        0x00040000
  
  #define clear_opt(sbi, option)        (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
  #define set_opt(sbi, option)  (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
@@@ -133,7 -128,6 +133,7 @@@ struct f2fs_mount_info 
  };
  
  #define F2FS_FEATURE_ENCRYPT  0x0001
 +#define F2FS_FEATURE_HMSMR    0x0002
  
  #define F2FS_HAS_FEATURE(sb, mask)                                    \
        ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
@@@ -164,7 -158,7 +164,7 @@@ enum 
  #define BATCHED_TRIM_BLOCKS(sbi)      \
                (BATCHED_TRIM_SEGMENTS(sbi) << (sbi)->log_blocks_per_seg)
  #define DEF_CP_INTERVAL                       60      /* 60 secs */
 -#define DEF_IDLE_INTERVAL             120     /* 2 mins */
 +#define DEF_IDLE_INTERVAL             5       /* 5 secs */
  
  struct cp_control {
        int reason;
@@@ -268,8 -262,6 +268,8 @@@ static inline bool __has_cursum_space(s
  #define F2FS_IOC_GARBAGE_COLLECT      _IO(F2FS_IOCTL_MAGIC, 6)
  #define F2FS_IOC_WRITE_CHECKPOINT     _IO(F2FS_IOCTL_MAGIC, 7)
  #define F2FS_IOC_DEFRAGMENT           _IO(F2FS_IOCTL_MAGIC, 8)
 +#define F2FS_IOC_MOVE_RANGE           _IOWR(F2FS_IOCTL_MAGIC, 9,      \
 +                                              struct f2fs_move_range)
  
  #define F2FS_IOC_SET_ENCRYPTION_POLICY        FS_IOC_SET_ENCRYPTION_POLICY
  #define F2FS_IOC_GET_ENCRYPTION_POLICY        FS_IOC_GET_ENCRYPTION_POLICY
@@@ -299,13 -291,6 +299,13 @@@ struct f2fs_defragment 
        u64 len;
  };
  
 +struct f2fs_move_range {
 +      u32 dst_fd;             /* destination fd */
 +      u64 pos_in;             /* start position in src_fd */
 +      u64 pos_out;            /* start position in dst_fd */
 +      u64 len;                /* size to move */
 +};
 +
  /*
   * For INODE and NODE manager
   */
@@@ -456,14 -441,11 +456,14 @@@ struct f2fs_inode_info 
        unsigned int clevel;            /* maximum level of given file name */
        nid_t i_xattr_nid;              /* node id that contains xattrs */
        unsigned long long xattr_ver;   /* cp version of xattr modification */
 +      loff_t  last_disk_size;         /* lastly written file size */
  
 -      struct list_head dirty_list;    /* linked in global dirty list */
 +      struct list_head dirty_list;    /* dirty list for dirs and files */
 +      struct list_head gdirty_list;   /* linked in global dirty list */
        struct list_head inmem_pages;   /* inmemory pages managed by f2fs */
        struct mutex inmem_lock;        /* lock for inmemory pages */
        struct extent_tree *extent_tree;        /* cached extent_tree entry */
 +      struct rw_semaphore dio_rwsem[2];/* avoid racing between dio and gc */
  };
  
  static inline void get_extent_info(struct extent_info *ext,
@@@ -516,14 -498,11 +516,14 @@@ static inline bool __is_front_mergeable
        return __is_extent_mergeable(cur, front);
  }
  
 -static inline void __try_update_largest_extent(struct extent_tree *et,
 -                                              struct extent_node *en)
 +extern void f2fs_mark_inode_dirty_sync(struct inode *);
 +static inline void __try_update_largest_extent(struct inode *inode,
 +                      struct extent_tree *et, struct extent_node *en)
  {
 -      if (en->ei.len > et->largest.len)
 +      if (en->ei.len > et->largest.len) {
                et->largest = en->ei;
 +              f2fs_mark_inode_dirty_sync(inode);
 +      }
  }
  
  struct f2fs_nm_info {
        /* NAT cache management */
        struct radix_tree_root nat_root;/* root of the nat entry cache */
        struct radix_tree_root nat_set_root;/* root of the nat set cache */
 -      struct rw_semaphore nat_tree_lock;      /* protect nat_tree_lock */
 +      struct percpu_rw_semaphore nat_tree_lock;       /* protect nat_tree_lock */
        struct list_head nat_entries;   /* cached nat entry list (clean) */
        unsigned int nat_cnt;           /* the # of cached nat entries */
        unsigned int dirty_nat_cnt;     /* total num of nat entries in set */
@@@ -620,7 -599,6 +620,7 @@@ struct flush_cmd 
  struct flush_cmd_control {
        struct task_struct *f2fs_issue_flush;   /* flush thread */
        wait_queue_head_t flush_wait_queue;     /* waiting queue for wake-up */
 +      atomic_t submit_flush;                  /* # of issued flushes */
        struct llist_head issue_list;           /* list for command issue */
        struct llist_node *dispatch_list;       /* list for command dispatch */
  };
@@@ -677,7 -655,6 +677,7 @@@ enum count_type 
        F2FS_DIRTY_NODES,
        F2FS_DIRTY_META,
        F2FS_INMEM_PAGES,
 +      F2FS_DIRTY_IMETA,
        NR_COUNT_TYPE,
  };
  
@@@ -709,15 -686,14 +709,15 @@@ enum page_type 
  struct f2fs_io_info {
        struct f2fs_sb_info *sbi;       /* f2fs_sb_info pointer */
        enum page_type type;    /* contains DATA/NODE/META/META_FLUSH */
 -      int rw;                 /* contains R/RS/W/WS with REQ_META/REQ_PRIO */
 +      int op;                 /* contains REQ_OP_ */
 +      int op_flags;           /* rq_flag_bits */
        block_t new_blkaddr;    /* new block address to be written */
        block_t old_blkaddr;    /* old block address before Cow */
        struct page *page;      /* page to be written */
        struct page *encrypted_page;    /* encrypted page */
  };
  
 -#define is_read_io(rw)        (((rw) & 1) == READ)
 +#define is_read_io(rw) (rw == READ)
  struct f2fs_bio_info {
        struct f2fs_sb_info *sbi;       /* f2fs superblock */
        struct bio *bio;                /* bios to merge */
  enum inode_type {
        DIR_INODE,                      /* for dirty dir inode */
        FILE_INODE,                     /* for dirty regular/symlink inode */
 +      DIRTY_META,                     /* for all dirtied inode metadata */
        NR_INODE_TYPE,
  };
  
@@@ -781,14 -756,14 +781,14 @@@ struct f2fs_sb_info 
        /* for bio operations */
        struct f2fs_bio_info read_io;                   /* for read bios */
        struct f2fs_bio_info write_io[NR_PAGE_TYPE];    /* for write bios */
 +      struct mutex wio_mutex[NODE + 1];       /* bio ordering for NODE/DATA */
  
        /* for checkpoint */
        struct f2fs_checkpoint *ckpt;           /* raw checkpoint pointer */
        struct inode *meta_inode;               /* cache meta blocks */
        struct mutex cp_mutex;                  /* checkpoint procedure lock */
 -      struct rw_semaphore cp_rwsem;           /* blocking FS operations */
 +      struct percpu_rw_semaphore cp_rwsem;            /* blocking FS operations */
        struct rw_semaphore node_write;         /* locking node writes */
 -      struct mutex writepages;                /* mutex for writepages() */
        wait_queue_head_t cp_wait;
        unsigned long last_time[MAX_TIME];      /* to store time in jiffies */
        long interval_time[MAX_TIME];           /* to store thresholds */
@@@ -1074,22 -1049,22 +1074,22 @@@ static inline void clear_ckpt_flags(str
  
  static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
  {
 -      down_read(&sbi->cp_rwsem);
 +      percpu_down_read(&sbi->cp_rwsem);
  }
  
  static inline void f2fs_unlock_op(struct f2fs_sb_info *sbi)
  {
 -      up_read(&sbi->cp_rwsem);
 +      percpu_up_read(&sbi->cp_rwsem);
  }
  
  static inline void f2fs_lock_all(struct f2fs_sb_info *sbi)
  {
 -      down_write(&sbi->cp_rwsem);
 +      percpu_down_write(&sbi->cp_rwsem);
  }
  
  static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
  {
 -      up_write(&sbi->cp_rwsem);
 +      percpu_up_write(&sbi->cp_rwsem);
  }
  
  static inline int __get_cp_reason(struct f2fs_sb_info *sbi)
@@@ -1144,37 -1119,34 +1144,37 @@@ static inline bool f2fs_has_xattr_block
        return ofs == XATTR_NODE_OFFSET;
  }
  
 +static inline void f2fs_i_blocks_write(struct inode *, blkcnt_t, bool);
  static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi,
                                 struct inode *inode, blkcnt_t *count)
  {
 -      block_t valid_block_count;
 +      blkcnt_t diff;
  
 -      spin_lock(&sbi->stat_lock);
  #ifdef CONFIG_F2FS_FAULT_INJECTION
 -      if (time_to_inject(FAULT_BLOCK)) {
 -              spin_unlock(&sbi->stat_lock);
 +      if (time_to_inject(FAULT_BLOCK))
                return false;
 -      }
  #endif
 -      valid_block_count =
 -              sbi->total_valid_block_count + (block_t)(*count);
 -      if (unlikely(valid_block_count > sbi->user_block_count)) {
 -              *count = sbi->user_block_count - sbi->total_valid_block_count;
 +      /*
 +       * let's increase this in prior to actual block count change in order
 +       * for f2fs_sync_file to avoid data races when deciding checkpoint.
 +       */
 +      percpu_counter_add(&sbi->alloc_valid_block_count, (*count));
 +
 +      spin_lock(&sbi->stat_lock);
 +      sbi->total_valid_block_count += (block_t)(*count);
 +      if (unlikely(sbi->total_valid_block_count > sbi->user_block_count)) {
 +              diff = sbi->total_valid_block_count - sbi->user_block_count;
 +              *count -= diff;
 +              sbi->total_valid_block_count = sbi->user_block_count;
                if (!*count) {
                        spin_unlock(&sbi->stat_lock);
 +                      percpu_counter_sub(&sbi->alloc_valid_block_count, diff);
                        return false;
                }
        }
 -      /* *count can be recalculated */
 -      inode->i_blocks += *count;
 -      sbi->total_valid_block_count =
 -              sbi->total_valid_block_count + (block_t)(*count);
        spin_unlock(&sbi->stat_lock);
  
 -      percpu_counter_add(&sbi->alloc_valid_block_count, (*count));
 +      f2fs_i_blocks_write(inode, *count, true);
        return true;
  }
  
@@@ -1185,9 -1157,9 +1185,9 @@@ static inline void dec_valid_block_coun
        spin_lock(&sbi->stat_lock);
        f2fs_bug_on(sbi, sbi->total_valid_block_count < (block_t) count);
        f2fs_bug_on(sbi, inode->i_blocks < count);
 -      inode->i_blocks -= count;
        sbi->total_valid_block_count -= (block_t)count;
        spin_unlock(&sbi->stat_lock);
 +      f2fs_i_blocks_write(inode, count, false);
  }
  
  static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type)
@@@ -1322,7 -1294,7 +1322,7 @@@ static inline bool inc_valid_node_count
        }
  
        if (inode)
 -              inode->i_blocks++;
 +              f2fs_i_blocks_write(inode, 1, true);
  
        sbi->total_valid_node_count++;
        sbi->total_valid_block_count++;
@@@ -1341,7 -1313,7 +1341,7 @@@ static inline void dec_valid_node_count
        f2fs_bug_on(sbi, !sbi->total_valid_node_count);
        f2fs_bug_on(sbi, !inode->i_blocks);
  
 -      inode->i_blocks--;
 +      f2fs_i_blocks_write(inode, 1, false);
        sbi->total_valid_node_count--;
        sbi->total_valid_block_count--;
  
@@@ -1538,12 -1510,12 +1538,12 @@@ static inline void f2fs_change_bit(unsi
  enum {
        FI_NEW_INODE,           /* indicate newly allocated inode */
        FI_DIRTY_INODE,         /* indicate inode is dirty or not */
 +      FI_AUTO_RECOVER,        /* indicate inode is recoverable */
        FI_DIRTY_DIR,           /* indicate directory has dirty pages */
        FI_INC_LINK,            /* need to increment i_nlink */
        FI_ACL_MODE,            /* indicate acl mode */
        FI_NO_ALLOC,            /* should not allocate any blocks */
        FI_FREE_NID,            /* free allocated nide */
 -      FI_UPDATE_DIR,          /* should update inode block for consistency */
        FI_NO_EXTENT,           /* not to use the extent cache */
        FI_INLINE_XATTR,        /* used for inline xattr */
        FI_INLINE_DATA,         /* used for inline data*/
        FI_DIRTY_FILE,          /* indicate regular/symlink has dirty pages */
  };
  
 -static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
 +static inline void __mark_inode_dirty_flag(struct inode *inode,
 +                                              int flag, bool set)
 +{
 +      switch (flag) {
 +      case FI_INLINE_XATTR:
 +      case FI_INLINE_DATA:
 +      case FI_INLINE_DENTRY:
 +              if (set)
 +                      return;
 +      case FI_DATA_EXIST:
 +      case FI_INLINE_DOTS:
 +              f2fs_mark_inode_dirty_sync(inode);
 +      }
 +}
 +
 +static inline void set_inode_flag(struct inode *inode, int flag)
 +{
 +      if (!test_bit(flag, &F2FS_I(inode)->flags))
 +              set_bit(flag, &F2FS_I(inode)->flags);
 +      __mark_inode_dirty_flag(inode, flag, true);
 +}
 +
 +static inline int is_inode_flag_set(struct inode *inode, int flag)
 +{
 +      return test_bit(flag, &F2FS_I(inode)->flags);
 +}
 +
 +static inline void clear_inode_flag(struct inode *inode, int flag)
 +{
 +      if (test_bit(flag, &F2FS_I(inode)->flags))
 +              clear_bit(flag, &F2FS_I(inode)->flags);
 +      __mark_inode_dirty_flag(inode, flag, false);
 +}
 +
 +static inline void set_acl_inode(struct inode *inode, umode_t mode)
  {
 -      if (!test_bit(flag, &fi->flags))
 -              set_bit(flag, &fi->flags);
 +      F2FS_I(inode)->i_acl_mode = mode;
 +      set_inode_flag(inode, FI_ACL_MODE);
 +      f2fs_mark_inode_dirty_sync(inode);
  }
  
 -static inline int is_inode_flag_set(struct f2fs_inode_info *fi, int flag)
 +static inline void f2fs_i_links_write(struct inode *inode, bool inc)
  {
 -      return test_bit(flag, &fi->flags);
 +      if (inc)
 +              inc_nlink(inode);
 +      else
 +              drop_nlink(inode);
 +      f2fs_mark_inode_dirty_sync(inode);
 +}
 +
 +static inline void f2fs_i_blocks_write(struct inode *inode,
 +                                      blkcnt_t diff, bool add)
 +{
 +      bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE);
 +      bool recover = is_inode_flag_set(inode, FI_AUTO_RECOVER);
 +
 +      inode->i_blocks = add ? inode->i_blocks + diff :
 +                              inode->i_blocks - diff;
 +      f2fs_mark_inode_dirty_sync(inode);
 +      if (clean || recover)
 +              set_inode_flag(inode, FI_AUTO_RECOVER);
 +}
 +
 +static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size)
 +{
 +      bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE);
 +      bool recover = is_inode_flag_set(inode, FI_AUTO_RECOVER);
 +
 +      if (i_size_read(inode) == i_size)
 +              return;
 +
 +      i_size_write(inode, i_size);
 +      f2fs_mark_inode_dirty_sync(inode);
 +      if (clean || recover)
 +              set_inode_flag(inode, FI_AUTO_RECOVER);
  }
  
 -static inline void clear_inode_flag(struct f2fs_inode_info *fi, int flag)
 +static inline bool f2fs_skip_inode_update(struct inode *inode)
  {
 -      if (test_bit(flag, &fi->flags))
 -              clear_bit(flag, &fi->flags);
 +      if (!is_inode_flag_set(inode, FI_AUTO_RECOVER))
 +              return false;
 +      return F2FS_I(inode)->last_disk_size == i_size_read(inode);
  }
  
 -static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode)
 +static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)
  {
 -      fi->i_acl_mode = mode;
 -      set_inode_flag(fi, FI_ACL_MODE);
 +      F2FS_I(inode)->i_current_depth = depth;
 +      f2fs_mark_inode_dirty_sync(inode);
  }
  
 -static inline void get_inline_info(struct f2fs_inode_info *fi,
 -                                      struct f2fs_inode *ri)
 +static inline void f2fs_i_xnid_write(struct inode *inode, nid_t xnid)
  {
 +      F2FS_I(inode)->i_xattr_nid = xnid;
 +      f2fs_mark_inode_dirty_sync(inode);
 +}
 +
 +static inline void f2fs_i_pino_write(struct inode *inode, nid_t pino)
 +{
 +      F2FS_I(inode)->i_pino = pino;
 +      f2fs_mark_inode_dirty_sync(inode);
 +}
 +
 +static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)
 +{
 +      struct f2fs_inode_info *fi = F2FS_I(inode);
 +
        if (ri->i_inline & F2FS_INLINE_XATTR)
 -              set_inode_flag(fi, FI_INLINE_XATTR);
 +              set_bit(FI_INLINE_XATTR, &fi->flags);
        if (ri->i_inline & F2FS_INLINE_DATA)
 -              set_inode_flag(fi, FI_INLINE_DATA);
 +              set_bit(FI_INLINE_DATA, &fi->flags);
        if (ri->i_inline & F2FS_INLINE_DENTRY)
 -              set_inode_flag(fi, FI_INLINE_DENTRY);
 +              set_bit(FI_INLINE_DENTRY, &fi->flags);
        if (ri->i_inline & F2FS_DATA_EXIST)
 -              set_inode_flag(fi, FI_DATA_EXIST);
 +              set_bit(FI_DATA_EXIST, &fi->flags);
        if (ri->i_inline & F2FS_INLINE_DOTS)
 -              set_inode_flag(fi, FI_INLINE_DOTS);
 +              set_bit(FI_INLINE_DOTS, &fi->flags);
  }
  
 -static inline void set_raw_inline(struct f2fs_inode_info *fi,
 -                                      struct f2fs_inode *ri)
 +static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
  {
        ri->i_inline = 0;
  
 -      if (is_inode_flag_set(fi, FI_INLINE_XATTR))
 +      if (is_inode_flag_set(inode, FI_INLINE_XATTR))
                ri->i_inline |= F2FS_INLINE_XATTR;
 -      if (is_inode_flag_set(fi, FI_INLINE_DATA))
 +      if (is_inode_flag_set(inode, FI_INLINE_DATA))
                ri->i_inline |= F2FS_INLINE_DATA;
 -      if (is_inode_flag_set(fi, FI_INLINE_DENTRY))
 +      if (is_inode_flag_set(inode, FI_INLINE_DENTRY))
                ri->i_inline |= F2FS_INLINE_DENTRY;
 -      if (is_inode_flag_set(fi, FI_DATA_EXIST))
 +      if (is_inode_flag_set(inode, FI_DATA_EXIST))
                ri->i_inline |= F2FS_DATA_EXIST;
 -      if (is_inode_flag_set(fi, FI_INLINE_DOTS))
 +      if (is_inode_flag_set(inode, FI_INLINE_DOTS))
                ri->i_inline |= F2FS_INLINE_DOTS;
  }
  
  static inline int f2fs_has_inline_xattr(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR);
 +      return is_inode_flag_set(inode, FI_INLINE_XATTR);
  }
  
  static inline unsigned int addrs_per_inode(struct inode *inode)
@@@ -1724,43 -1617,43 +1724,43 @@@ static inline int inline_xattr_size(str
  
  static inline int f2fs_has_inline_data(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DATA);
 +      return is_inode_flag_set(inode, FI_INLINE_DATA);
  }
  
  static inline void f2fs_clear_inline_inode(struct inode *inode)
  {
 -      clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
 -      clear_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
 +      clear_inode_flag(inode, FI_INLINE_DATA);
 +      clear_inode_flag(inode, FI_DATA_EXIST);
  }
  
  static inline int f2fs_exist_data(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_DATA_EXIST);
 +      return is_inode_flag_set(inode, FI_DATA_EXIST);
  }
  
  static inline int f2fs_has_inline_dots(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DOTS);
 +      return is_inode_flag_set(inode, FI_INLINE_DOTS);
  }
  
  static inline bool f2fs_is_atomic_file(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE);
 +      return is_inode_flag_set(inode, FI_ATOMIC_FILE);
  }
  
  static inline bool f2fs_is_volatile_file(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_VOLATILE_FILE);
 +      return is_inode_flag_set(inode, FI_VOLATILE_FILE);
  }
  
  static inline bool f2fs_is_first_block_written(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
 +      return is_inode_flag_set(inode, FI_FIRST_BLOCK_WRITTEN);
  }
  
  static inline bool f2fs_is_drop_cache(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_DROP_CACHE);
 +      return is_inode_flag_set(inode, FI_DROP_CACHE);
  }
  
  static inline void *inline_data_addr(struct page *page)
  
  static inline int f2fs_has_inline_dentry(struct inode *inode)
  {
 -      return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DENTRY);
 +      return is_inode_flag_set(inode, FI_INLINE_DENTRY);
  }
  
  static inline void f2fs_dentry_kunmap(struct inode *dir, struct page *page)
@@@ -1788,13 -1681,11 +1788,13 @@@ static inline int is_file(struct inode 
  static inline void set_file(struct inode *inode, int type)
  {
        F2FS_I(inode)->i_advise |= type;
 +      f2fs_mark_inode_dirty_sync(inode);
  }
  
  static inline void clear_file(struct inode *inode, int type)
  {
        F2FS_I(inode)->i_advise &= ~type;
 +      f2fs_mark_inode_dirty_sync(inode);
  }
  
  static inline int f2fs_readonly(struct super_block *sb)
@@@ -1821,7 -1712,7 +1821,7 @@@ static inline bool is_dot_dotdot(const 
  static inline bool f2fs_may_extent_tree(struct inode *inode)
  {
        if (!test_opt(F2FS_I_SB(inode), EXTENT_CACHE) ||
 -                      is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT))
 +                      is_inode_flag_set(inode, FI_NO_EXTENT))
                return false;
  
        return S_ISREG(inode->i_mode);
@@@ -1857,7 -1748,7 +1857,7 @@@ static inline void *f2fs_kvzalloc(size_
  }
  
  #define get_inode_mode(i) \
 -      ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
 +      ((is_inode_flag_set(i, FI_ACL_MODE)) ? \
         (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
  
  /* get offset of first page in next direct node */
  int f2fs_sync_file(struct file *, loff_t, loff_t, int);
  void truncate_data_blocks(struct dnode_of_data *);
  int truncate_blocks(struct inode *, u64, bool);
 -int f2fs_truncate(struct inode *, bool);
 +int f2fs_truncate(struct inode *);
  int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
  int f2fs_setattr(struct dentry *, struct iattr *);
  int truncate_hole(struct inode *, pgoff_t, pgoff_t);
@@@ -1913,11 -1804,11 +1913,11 @@@ struct page *init_inode_metadata(struc
                        const struct qstr *, struct page *);
  void update_parent_metadata(struct inode *, struct inode *, unsigned int);
  int room_for_filename(const void *, int, int);
 -void f2fs_drop_nlink(struct inode *, struct inode *, struct page *);
 +void f2fs_drop_nlink(struct inode *, struct inode *);
- struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *,
+ struct f2fs_dir_entry *f2fs_find_entry(struct inode *, const struct qstr *,
                                                        struct page **);
  struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
- ino_t f2fs_inode_by_name(struct inode *, struct qstr *, struct page **);
 -ino_t f2fs_inode_by_name(struct inode *, const struct qstr *);
++ino_t f2fs_inode_by_name(struct inode *, const struct qstr *, struct page **);
  void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
                                struct page *, struct inode *);
  int update_dent_inode(struct inode *, struct inode *, const struct qstr *);
@@@ -1941,8 -1832,6 +1941,8 @@@ static inline int f2fs_add_link(struct 
  /*
   * super.c
   */
 +int f2fs_inode_dirtied(struct inode *);
 +void f2fs_inode_synced(struct inode *);
  int f2fs_commit_super(struct f2fs_sb_info *, bool);
  int f2fs_sync_fs(struct super_block *, int);
  extern __printf(3, 4)
@@@ -1976,11 -1865,11 +1976,11 @@@ struct page *new_node_page(struct dnode
  void ra_node_page(struct f2fs_sb_info *, nid_t);
  struct page *get_node_page(struct f2fs_sb_info *, pgoff_t);
  struct page *get_node_page_ra(struct page *, int);
 -void sync_inode_page(struct dnode_of_data *);
  void move_node_page(struct page *, int);
 -int fsync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *,
 -                                                              bool);
 +int fsync_node_pages(struct f2fs_sb_info *, struct inode *,
 +                      struct writeback_control *, bool);
  int sync_node_pages(struct f2fs_sb_info *, struct writeback_control *);
 +void build_free_nids(struct f2fs_sb_info *);
  bool alloc_nid(struct f2fs_sb_info *, nid_t *);
  void alloc_nid_done(struct f2fs_sb_info *, nid_t);
  void alloc_nid_failed(struct f2fs_sb_info *, nid_t);
@@@ -2054,10 -1943,9 +2054,10 @@@ void add_ino_entry(struct f2fs_sb_info 
  void remove_ino_entry(struct f2fs_sb_info *, nid_t, int type);
  void release_ino_entry(struct f2fs_sb_info *, bool);
  bool exist_written_data(struct f2fs_sb_info *, nid_t, int);
 +int f2fs_sync_inode_meta(struct f2fs_sb_info *);
  int acquire_orphan_inode(struct f2fs_sb_info *);
  void release_orphan_inode(struct f2fs_sb_info *);
 -void add_orphan_inode(struct f2fs_sb_info *, nid_t);
 +void add_orphan_inode(struct inode *);
  void remove_orphan_inode(struct f2fs_sb_info *, nid_t);
  int recover_orphan_inodes(struct f2fs_sb_info *);
  int get_valid_checkpoint(struct f2fs_sb_info *);
@@@ -2092,7 -1980,6 +2092,7 @@@ struct page *get_new_data_page(struct i
  int do_write_data_page(struct f2fs_io_info *);
  int f2fs_map_blocks(struct inode *, struct f2fs_map_blocks *, int, int);
  int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *, u64, u64);
 +void f2fs_set_page_dirty_nobuffers(struct page *);
  void f2fs_invalidate_page(struct page *, unsigned int, unsigned int);
  int f2fs_release_page(struct page *, gfp_t);
  
@@@ -2124,7 -2011,7 +2124,7 @@@ struct f2fs_stat_info 
        unsigned long long hit_total, total_ext;
        int ext_tree, zombie_tree, ext_node;
        s64 ndirty_node, ndirty_dent, ndirty_meta, ndirty_data, inmem_pages;
 -      unsigned int ndirty_dirs, ndirty_files;
 +      unsigned int ndirty_dirs, ndirty_files, ndirty_all;
        int nats, dirty_nats, sits, dirty_sits, fnids;
        int total_count, utilization;
        int bg_gc, wb_bios;
@@@ -2293,6 -2180,7 +2293,6 @@@ int f2fs_write_inline_data(struct inod
  bool recover_inline_data(struct inode *, struct page *);
  struct f2fs_dir_entry *find_in_inline_dir(struct inode *,
                                struct fscrypt_name *, struct page **);
 -struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *, struct page **);
  int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *);
  int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *,
                                                nid_t, umode_t);
@@@ -2317,7 -2205,6 +2317,7 @@@ void f2fs_leave_shrinker(struct f2fs_sb
   */
  unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *, int);
  bool f2fs_init_extent_tree(struct inode *, struct f2fs_extent *);
 +void f2fs_drop_extent_tree(struct inode *);
  unsigned int f2fs_destroy_extent_node(struct inode *);
  void f2fs_destroy_extent_tree(struct inode *);
  bool f2fs_lookup_extent_cache(struct inode *, pgoff_t, struct extent_info *);
@@@ -2353,26 -2240,6 +2353,26 @@@ static inline int f2fs_sb_has_crypto(st
        return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT);
  }
  
 +static inline int f2fs_sb_mounted_hmsmr(struct super_block *sb)
 +{
 +      return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_HMSMR);
 +}
 +
 +static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt)
 +{
 +      clear_opt(sbi, ADAPTIVE);
 +      clear_opt(sbi, LFS);
 +
 +      switch (mt) {
 +      case F2FS_MOUNT_ADAPTIVE:
 +              set_opt(sbi, ADAPTIVE);
 +              break;
 +      case F2FS_MOUNT_LFS:
 +              set_opt(sbi, LFS);
 +              break;
 +      }
 +}
 +
  static inline bool f2fs_may_encrypt(struct inode *inode)
  {
  #ifdef CONFIG_F2FS_FS_ENCRYPTION
diff --combined fs/fat/namei_vfat.c
@@@ -107,7 -107,7 +107,7 @@@ static unsigned int vfat_striptail_len(
   */
  static int vfat_hash(const struct dentry *dentry, struct qstr *qstr)
  {
 -      qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
 +      qstr->hash = full_name_hash(dentry, qstr->name, vfat_striptail_len(qstr));
        return 0;
  }
  
@@@ -127,7 -127,7 +127,7 @@@ static int vfat_hashi(const struct dent
        name = qstr->name;
        len = vfat_striptail_len(qstr);
  
 -      hash = init_name_hash();
 +      hash = init_name_hash(dentry);
        while (len--)
                hash = partial_name_hash(nls_tolower(t, *name++), hash);
        qstr->hash = end_name_hash(hash);
@@@ -652,8 -652,8 +652,8 @@@ out_free
        return err;
  }
  
- static int vfat_add_entry(struct inode *dir, struct qstr *qname, int is_dir,
-                         int cluster, struct timespec *ts,
+ static int vfat_add_entry(struct inode *dir, const struct qstr *qname,
+                         int is_dir, int cluster, struct timespec *ts,
                          struct fat_slot_info *sinfo)
  {
        struct msdos_dir_slot *slots;
@@@ -688,7 -688,7 +688,7 @@@ cleanup
        return err;
  }
  
- static int vfat_find(struct inode *dir, struct qstr *qname,
+ static int vfat_find(struct inode *dir, const struct qstr *qname,
                     struct fat_slot_info *sinfo)
  {
        unsigned int len = vfat_striptail_len(qname);
diff --combined fs/fuse/dir.c
@@@ -146,7 -146,7 +146,7 @@@ static void fuse_invalidate_entry(struc
  }
  
  static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
-                            u64 nodeid, struct qstr *name,
+                            u64 nodeid, const struct qstr *name,
                             struct fuse_entry_out *outarg)
  {
        memset(outarg, 0, sizeof(struct fuse_entry_out));
@@@ -282,7 -282,7 +282,7 @@@ int fuse_valid_type(int m
                S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
  }
  
- int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
+ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name,
                     struct fuse_entry_out *outarg, struct inode **inode)
  {
        struct fuse_conn *fc = get_fuse_conn_super(sb);
@@@ -480,7 -480,7 +480,7 @@@ static int fuse_atomic_open(struct inod
        struct fuse_conn *fc = get_fuse_conn(dir);
        struct dentry *res = NULL;
  
 -      if (d_unhashed(entry)) {
 +      if (d_in_lookup(entry)) {
                res = fuse_lookup(dir, entry, 0);
                if (IS_ERR(res))
                        return PTR_ERR(res);
@@@ -955,7 -955,6 +955,7 @@@ int fuse_reverse_inval_entry(struct sup
        if (!dir)
                goto unlock;
  
 +      name->hash = full_name_hash(dir, name->name, name->len);
        entry = d_lookup(dir, name);
        dput(dir);
        if (!entry)
@@@ -1205,7 -1204,7 +1205,7 @@@ static int fuse_direntplus_link(struct 
  
        fc = get_fuse_conn(dir);
  
 -      name.hash = full_name_hash(name.name, name.len);
 +      name.hash = full_name_hash(parent, name.name, name.len);
        dentry = d_lookup(parent, &name);
        if (!dentry) {
  retry:
diff --combined fs/fuse/fuse_i.h
@@@ -259,7 -259,6 +259,7 @@@ struct fuse_io_priv 
        struct kiocb *iocb;
        struct file *file;
        struct completion *done;
 +      bool blocking;
  };
  
  #define FUSE_IO_PRIV_SYNC(f) \
@@@ -704,7 -703,7 +704,7 @@@ struct inode *fuse_iget(struct super_bl
                        int generation, struct fuse_attr *attr,
                        u64 attr_valid, u64 attr_version);
  
- int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
+ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name,
                     struct fuse_entry_out *outarg, struct inode **inode);
  
  /**
diff --combined fs/fuse/inode.c
@@@ -673,13 -673,11 +673,11 @@@ static struct dentry *fuse_get_dentry(s
        inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid);
        if (!inode) {
                struct fuse_entry_out outarg;
-               struct qstr name;
+               const struct qstr name = QSTR_INIT(".", 1);
  
                if (!fc->export_support)
                        goto out_err;
  
-               name.len = 1;
-               name.name = ".";
                err = fuse_lookup_name(sb, handle->nodeid, &name, &outarg,
                                       &inode);
                if (err && err != -ENOENT)
@@@ -775,14 -773,12 +773,12 @@@ static struct dentry *fuse_get_parent(s
        struct inode *inode;
        struct dentry *parent;
        struct fuse_entry_out outarg;
-       struct qstr name;
+       const struct qstr name = QSTR_INIT("..", 2);
        int err;
  
        if (!fc->export_support)
                return ERR_PTR(-ESTALE);
  
-       name.len = 2;
-       name.name = "..";
        err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode),
                               &name, &outarg, &inode);
        if (err) {
@@@ -942,7 -938,7 +938,7 @@@ static void fuse_send_init(struct fuse_
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
                FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
                FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
 -              FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
 +              FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR | FUSE_AUTO_INVAL_DATA |
                FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO |
                FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
                FUSE_PARALLEL_DIROPS;
diff --combined fs/hfs/inode.c
@@@ -128,7 -128,7 +128,7 @@@ static ssize_t hfs_direct_IO(struct kio
  {
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
 -      struct inode *inode = file_inode(file)->i_mapping->host;
 +      struct inode *inode = mapping->host;
        size_t count = iov_iter_count(iter);
        ssize_t ret;
  
@@@ -177,7 -177,7 +177,7 @@@ const struct address_space_operations h
  /*
   * hfs_new_inode
   */
- struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, umode_t mode)
+ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t mode)
  {
        struct super_block *sb = dir->i_sb;
        struct inode *inode = new_inode(sb);
diff --combined fs/hfsplus/hfsplus_fs.h
@@@ -445,17 -445,17 +445,17 @@@ int hfsplus_cat_case_cmp_key(const hfsp
  int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1,
                            const hfsplus_btree_key *k2);
  int hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key,
-                          u32 parent, struct qstr *str);
+                          u32 parent, const struct qstr *str);
  void hfsplus_cat_build_key_with_cnid(struct super_block *sb,
                                     hfsplus_btree_key *key, u32 parent);
  void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms);
  int hfsplus_find_cat(struct super_block *sb, u32 cnid,
                     struct hfs_find_data *fd);
- int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str,
+ int hfsplus_create_cat(u32 cnid, struct inode *dir, const struct qstr *str,
                       struct inode *inode);
- int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str);
- int hfsplus_rename_cat(u32 cnid, struct inode *src_dir, struct qstr *src_name,
-                      struct inode *dst_dir, struct qstr *dst_name);
+ int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str);
+ int hfsplus_rename_cat(u32 cnid, struct inode *src_dir, const struct qstr *src_name,
+                      struct inode *dst_dir, const struct qstr *dst_name);
  
  /* dir.c */
  extern const struct inode_operations hfsplus_dir_inode_operations;
@@@ -526,7 -526,7 +526,7 @@@ int hfsplus_compare_dentry(const struc
  
  /* wrapper.c */
  int hfsplus_submit_bio(struct super_block *sb, sector_t sector, void *buf,
 -                     void **data, int rw);
 +                     void **data, int op, int op_flags);
  int hfsplus_read_wrapper(struct super_block *sb);
  
  /* time macros */
diff --combined fs/logfs/dir.c
@@@ -95,7 -95,7 +95,7 @@@ static int beyond_eof(struct inode *ino
   * of each character and pick a prime nearby, preferably a bit-sparse
   * one.
   */
 -static u32 hash_32(const char *s, int len, u32 seed)
 +static u32 logfs_hash_32(const char *s, int len, u32 seed)
  {
        u32 hash = seed;
        int i;
@@@ -156,10 -156,10 +156,10 @@@ static pgoff_t hash_index(u32 hash, in
  
  static struct page *logfs_get_dd_page(struct inode *dir, struct dentry *dentry)
  {
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
        struct page *page;
        struct logfs_disk_dentry *dd;
 -      u32 hash = hash_32(name->name, name->len, 0);
 +      u32 hash = logfs_hash_32(name->name, name->len, 0);
        pgoff_t index;
        int round;
  
@@@ -323,7 -323,7 +323,7 @@@ static int logfs_readdir(struct file *f
        return 0;
  }
  
- static void logfs_set_name(struct logfs_disk_dentry *dd, struct qstr *name)
+ static void logfs_set_name(struct logfs_disk_dentry *dd, const struct qstr *name)
  {
        dd->namelen = cpu_to_be16(name->len);
        memcpy(dd->name, name->name, name->len);
@@@ -370,7 -370,7 +370,7 @@@ static int logfs_write_dir(struct inod
  {
        struct page *page;
        struct logfs_disk_dentry *dd;
 -      u32 hash = hash_32(dentry->d_name.name, dentry->d_name.len, 0);
 +      u32 hash = logfs_hash_32(dentry->d_name.name, dentry->d_name.len, 0);
        pgoff_t index;
        int round, err;
  
diff --combined fs/nfs/nfs4_fs.h
@@@ -185,7 -185,6 +185,7 @@@ struct nfs4_state 
  struct nfs4_exception {
        struct nfs4_state *state;
        struct inode *inode;
 +      nfs4_stateid *stateid;
        long timeout;
        unsigned char delay : 1,
                      recovering : 1,
@@@ -225,7 -224,8 +225,8 @@@ int nfs_atomic_open(struct inode *, str
  extern struct file_system_type nfs4_fs_type;
  
  /* nfs4namespace.c */
- struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *, struct qstr *);
+ struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *,
+                                        const struct qstr *);
  struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
                               struct nfs_fh *, struct nfs_fattr *);
  int nfs4_replace_transport(struct nfs_server *server,
@@@ -252,7 -252,7 +253,7 @@@ extern int nfs4_proc_fs_locations(struc
  extern int nfs4_proc_get_locations(struct inode *, struct nfs4_fs_locations *,
                struct page *page, struct rpc_cred *);
  extern int nfs4_proc_fsid_present(struct inode *, struct rpc_cred *);
- extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *,
+ extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, const struct qstr *,
                            struct nfs_fh *, struct nfs_fattr *);
  extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
  extern const struct xattr_handler *nfs4_xattr_handlers[];
diff --combined fs/nfs/nfs4proc.c
@@@ -363,7 -363,6 +363,7 @@@ static int nfs4_do_handle_exception(str
  {
        struct nfs_client *clp = server->nfs_client;
        struct nfs4_state *state = exception->state;
 +      const nfs4_stateid *stateid = exception->stateid;
        struct inode *inode = exception->inode;
        int ret = errorcode;
  
                case -NFS4ERR_DELEG_REVOKED:
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_BAD_STATEID:
 -                      if (inode && nfs_async_inode_return_delegation(inode,
 -                                              NULL) == 0)
 -                              goto wait_on_recovery;
 +                      if (inode) {
 +                              int err;
 +
 +                              err = nfs_async_inode_return_delegation(inode,
 +                                              stateid);
 +                              if (err == 0)
 +                                      goto wait_on_recovery;
 +                              if (stateid != NULL && stateid->type == NFS4_DELEGATION_STATEID_TYPE) {
 +                                      exception->retry = 1;
 +                                      break;
 +                              }
 +                      }
                        if (state == NULL)
                                break;
                        ret = nfs4_schedule_stateid_recovery(server, state);
                case -NFS4ERR_DELAY:
                        nfs_inc_server_stats(server, NFSIOS_DELAY);
                case -NFS4ERR_GRACE:
 +              case -NFS4ERR_LAYOUTTRYLATER:
                case -NFS4ERR_RECALLCONFLICT:
                        exception->delay = 1;
                        return 0;
@@@ -2680,17 -2669,28 +2680,17 @@@ static struct nfs4_state *nfs4_do_open(
        return res;
  }
  
 -static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 -                          struct nfs_fattr *fattr, struct iattr *sattr,
 -                          struct nfs4_state *state, struct nfs4_label *ilabel,
 -                          struct nfs4_label *olabel)
 +static int _nfs4_do_setattr(struct inode *inode,
 +                          struct nfs_setattrargs *arg,
 +                          struct nfs_setattrres *res,
 +                          struct rpc_cred *cred,
 +                          struct nfs4_state *state)
  {
        struct nfs_server *server = NFS_SERVER(inode);
 -        struct nfs_setattrargs  arg = {
 -                .fh             = NFS_FH(inode),
 -                .iap            = sattr,
 -              .server         = server,
 -              .bitmask = server->attr_bitmask,
 -              .label          = ilabel,
 -        };
 -        struct nfs_setattrres  res = {
 -              .fattr          = fattr,
 -              .label          = olabel,
 -              .server         = server,
 -        };
          struct rpc_message msg = {
                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
 -              .rpc_argp       = &arg,
 -              .rpc_resp       = &res,
 +              .rpc_argp       = arg,
 +              .rpc_resp       = res,
                .rpc_cred       = cred,
          };
        struct rpc_cred *delegation_cred = NULL;
        bool truncate;
        int status;
  
 -      arg.bitmask = nfs4_bitmask(server, ilabel);
 -      if (ilabel)
 -              arg.bitmask = nfs4_bitmask(server, olabel);
 -
 -      nfs_fattr_init(fattr);
 +      nfs_fattr_init(res->fattr);
  
        /* Servers should only apply open mode checks for file size changes */
 -      truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false;
 +      truncate = (arg->iap->ia_valid & ATTR_SIZE) ? true : false;
        fmode = truncate ? FMODE_WRITE : FMODE_READ;
  
 -      if (nfs4_copy_delegation_stateid(inode, fmode, &arg.stateid, &delegation_cred)) {
 +      if (nfs4_copy_delegation_stateid(inode, fmode, &arg->stateid, &delegation_cred)) {
                /* Use that stateid */
        } else if (truncate && state != NULL) {
                struct nfs_lockowner lockowner = {
                if (!nfs4_valid_open_stateid(state))
                        return -EBADF;
                if (nfs4_select_rw_stateid(state, FMODE_WRITE, &lockowner,
 -                              &arg.stateid, &delegation_cred) == -EIO)
 +                              &arg->stateid, &delegation_cred) == -EIO)
                        return -EBADF;
        } else
 -              nfs4_stateid_copy(&arg.stateid, &zero_stateid);
 +              nfs4_stateid_copy(&arg->stateid, &zero_stateid);
        if (delegation_cred)
                msg.rpc_cred = delegation_cred;
  
 -      status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 +      status = nfs4_call_sync(server->client, server, &msg, &arg->seq_args, &res->seq_res, 1);
  
        put_rpccred(delegation_cred);
        if (status == 0 && state != NULL)
                renew_lease(server, timestamp);
 -      trace_nfs4_setattr(inode, &arg.stateid, status);
 +      trace_nfs4_setattr(inode, &arg->stateid, status);
        return status;
  }
  
@@@ -2737,31 -2741,13 +2737,31 @@@ static int nfs4_do_setattr(struct inod
                           struct nfs4_label *olabel)
  {
        struct nfs_server *server = NFS_SERVER(inode);
 +        struct nfs_setattrargs  arg = {
 +                .fh             = NFS_FH(inode),
 +                .iap            = sattr,
 +              .server         = server,
 +              .bitmask = server->attr_bitmask,
 +              .label          = ilabel,
 +        };
 +        struct nfs_setattrres  res = {
 +              .fattr          = fattr,
 +              .label          = olabel,
 +              .server         = server,
 +        };
        struct nfs4_exception exception = {
                .state = state,
                .inode = inode,
 +              .stateid = &arg.stateid,
        };
        int err;
 +
 +      arg.bitmask = nfs4_bitmask(server, ilabel);
 +      if (ilabel)
 +              arg.bitmask = nfs4_bitmask(server, olabel);
 +
        do {
 -              err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
 +              err = _nfs4_do_setattr(inode, &arg, &res, cred, state);
                switch (err) {
                case -NFS4ERR_OPENMODE:
                        if (!(sattr->ia_valid & ATTR_SIZE)) {
@@@ -3281,6 -3267,13 +3281,6 @@@ static int nfs4_find_root_sec(struct nf
        return status;
  }
  
 -static int nfs4_do_find_root_sec(struct nfs_server *server,
 -              struct nfs_fh *fhandle, struct nfs_fsinfo *info)
 -{
 -      int mv = server->nfs_client->cl_minorversion;
 -      return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
 -}
 -
  /**
   * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
   * @server: initialized nfs_server handle
@@@ -3300,8 -3293,7 +3300,8 @@@ int nfs4_proc_get_rootfh(struct nfs_ser
                status = nfs4_lookup_root(server, fhandle, info);
  
        if (auth_probe || status == NFS4ERR_WRONGSEC)
 -              status = nfs4_do_find_root_sec(server, fhandle, info);
 +              status = server->nfs_client->cl_mvops->find_root_sec(server,
 +                              fhandle, info);
  
        if (status == 0)
                status = nfs4_server_capabilities(server, fhandle);
@@@ -3538,7 -3530,7 +3538,7 @@@ static void nfs_fixup_secinfo_attribute
  }
  
  static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
-                                  struct qstr *name, struct nfs_fh *fhandle,
+                                  const struct qstr *name, struct nfs_fh *fhandle,
                                   struct nfs_fattr *fattr, struct nfs4_label *label)
  {
        struct nfs4_exception exception = { };
@@@ -3580,7 -3572,7 +3580,7 @@@ out
        return err;
  }
  
- static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+ static int nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
                            struct nfs_fh *fhandle, struct nfs_fattr *fattr,
                            struct nfs4_label *label)
  {
  }
  
  struct rpc_clnt *
- nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
+ nfs4_proc_lookup_mountpoint(struct inode *dir, const struct qstr *name,
                            struct nfs_fh *fhandle, struct nfs_fattr *fattr)
  {
        struct rpc_clnt *client = NFS_CLIENT(dir);
@@@ -3755,7 -3747,7 +3755,7 @@@ out
        return status;
  }
  
- static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
+ static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
  {
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_removeargs args = {
        return status;
  }
  
- static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
+ static int nfs4_proc_remove(struct inode *dir, const struct qstr *name)
  {
        struct nfs4_exception exception = { };
        int err;
@@@ -3861,7 -3853,7 +3861,7 @@@ static int nfs4_proc_rename_done(struc
        return 1;
  }
  
- static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
  {
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs4_link_arg arg = {
@@@ -3908,7 -3900,7 +3908,7 @@@ out
        return status;
  }
  
- static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+ static int nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
  {
        struct nfs4_exception exception = { };
        int err;
@@@ -3930,7 -3922,7 +3930,7 @@@ struct nfs4_createdata 
  };
  
  static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
-               struct qstr *name, struct iattr *sattr, u32 ftype)
+               const struct qstr *name, struct iattr *sattr, u32 ftype)
  {
        struct nfs4_createdata *data;
  
@@@ -4400,8 -4392,7 +4400,8 @@@ static void nfs4_proc_read_setup(struc
                                 struct rpc_message *msg)
  {
        hdr->timestamp   = jiffies;
 -      hdr->pgio_done_cb = nfs4_read_done_cb;
 +      if (!hdr->pgio_done_cb)
 +              hdr->pgio_done_cb = nfs4_read_done_cb;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
        nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0);
  }
@@@ -7878,13 -7869,11 +7878,13 @@@ nfs4_layoutget_handle_exception(struct 
        struct inode *inode = lgp->args.inode;
        struct nfs_server *server = NFS_SERVER(inode);
        struct pnfs_layout_hdr *lo;
 -      int status = task->tk_status;
 +      int nfs4err = task->tk_status;
 +      int err, status = 0;
 +      LIST_HEAD(head);
  
        dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);
  
 -      switch (status) {
 +      switch (nfs4err) {
        case 0:
                goto out;
  
                        status = -EOVERFLOW;
                        goto out;
                }
 -              /* Fallthrough */
 +              status = -EBUSY;
 +              break;
        case -NFS4ERR_RECALLCONFLICT:
 -              nfs4_handle_exception(server, -NFS4ERR_RECALLCONFLICT,
 -                                      exception);
                status = -ERECALLCONFLICT;
 -              goto out;
 +              break;
        case -NFS4ERR_EXPIRED:
        case -NFS4ERR_BAD_STATEID:
                exception->timeout = 0;
                spin_lock(&inode->i_lock);
 -              if (nfs4_stateid_match(&lgp->args.stateid,
 +              lo = NFS_I(inode)->layout;
 +              /* If the open stateid was bad, then recover it. */
 +              if (!lo || test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) ||
 +                  nfs4_stateid_match_other(&lgp->args.stateid,
                                        &lgp->args.ctx->state->stateid)) {
                        spin_unlock(&inode->i_lock);
 -                      /* If the open stateid was bad, then recover it. */
                        exception->state = lgp->args.ctx->state;
                        break;
                }
 -              lo = NFS_I(inode)->layout;
 -              if (lo && !test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) &&
 -                  nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) {
 -                      LIST_HEAD(head);
 -
 -                      /*
 -                       * Mark the bad layout state as invalid, then retry
 -                       * with the current stateid.
 -                       */
 -                      set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
 -                      pnfs_mark_matching_lsegs_invalid(lo, &head, NULL, 0);
 -                      spin_unlock(&inode->i_lock);
 -                      pnfs_free_lseg_list(&head);
 -                      status = -EAGAIN;
 -                      goto out;
 -              } else
 -                      spin_unlock(&inode->i_lock);
 -      }
  
 -      status = nfs4_handle_exception(server, status, exception);
 -      if (exception->retry)
 +              /*
 +               * Mark the bad layout state as invalid, then retry
 +               */
 +              pnfs_mark_layout_stateid_invalid(lo, &head);
 +              spin_unlock(&inode->i_lock);
 +              pnfs_free_lseg_list(&head);
                status = -EAGAIN;
 +              goto out;
 +      }
 +
 +      err = nfs4_handle_exception(server, nfs4err, exception);
 +      if (!status) {
 +              if (exception->retry)
 +                      status = -EAGAIN;
 +              else
 +                      status = err;
 +      }
  out:
        dprintk("<-- %s\n", __func__);
        return status;
@@@ -8137,7 -8129,8 +8137,7 @@@ static void nfs4_layoutreturn_release(v
        spin_lock(&lo->plh_inode->i_lock);
        pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range,
                        be32_to_cpu(lrp->args.stateid.seqid));
 -      pnfs_mark_layout_returned_if_empty(lo);
 -      if (lrp->res.lrs_present)
 +      if (lrp->res.lrs_present && pnfs_layout_is_valid(lo))
                pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
        pnfs_clear_layoutreturn_waitbit(lo);
        spin_unlock(&lo->plh_inode->i_lock);
@@@ -8842,7 -8835,7 +8842,7 @@@ const struct nfs4_minor_version_ops *nf
  #endif
  };
  
 -ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
 +static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
  {
        ssize_t error, error2;
  
diff --combined fs/proc/proc_sysctl.c
@@@ -474,7 -474,7 +474,7 @@@ static struct dentry *proc_sys_lookup(s
  {
        struct ctl_table_header *head = grab_header(dir);
        struct ctl_table_header *h = NULL;
-       struct qstr *name = &dentry->d_name;
+       const struct qstr *name = &dentry->d_name;
        struct ctl_table *p;
        struct inode *inode;
        struct dentry *err = ERR_PTR(-ENOENT);
@@@ -623,7 -623,7 +623,7 @@@ static bool proc_sys_fill_cache(struct 
  
        qname.name = table->procname;
        qname.len  = strlen(table->procname);
 -      qname.hash = full_name_hash(qname.name, qname.len);
 +      qname.hash = full_name_hash(dir, qname.name, qname.len);
  
        child = d_lookup(dir, &qname);
        if (!child) {
diff --combined include/linux/dcache.h
@@@ -133,15 -133,14 +133,15 @@@ struct dentry_operations 
        int (*d_compare)(const struct dentry *, const struct dentry *,
                        unsigned int, const char *, const struct qstr *);
        int (*d_delete)(const struct dentry *);
 +      int (*d_init)(struct dentry *);
        void (*d_release)(struct dentry *);
        void (*d_prune)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)(struct dentry *, char *, int);
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(struct dentry *, bool);
 -      struct inode *(*d_select_inode)(struct dentry *, unsigned);
 -      struct dentry *(*d_real)(struct dentry *, struct inode *);
 +      struct dentry *(*d_real)(struct dentry *, const struct inode *,
 +                               unsigned int);
  } ____cacheline_aligned;
  
  /*
  
  #define DCACHE_MAY_FREE                       0x00800000
  #define DCACHE_FALLTHRU                       0x01000000 /* Fall through to lower layer */
 -#define DCACHE_OP_SELECT_INODE                0x02000000 /* Unioned entry: dcache op selects inode */
 -
 -#define DCACHE_ENCRYPTED_WITH_KEY     0x04000000 /* dir is encrypted with a valid key */
 -#define DCACHE_OP_REAL                        0x08000000
 +#define DCACHE_ENCRYPTED_WITH_KEY     0x02000000 /* dir is encrypted with a valid key */
 +#define DCACHE_OP_REAL                        0x04000000
  
  #define DCACHE_PAR_LOOKUP             0x10000000 /* being looked up (with parent locked shared) */
  #define DCACHE_DENTRY_CURSOR          0x20000000
@@@ -263,7 -264,7 +263,7 @@@ extern void d_rehash(struct dentry *)
   
  extern void d_add(struct dentry *, struct inode *);
  
- extern void dentry_update_name_case(struct dentry *, struct qstr *);
+ extern void dentry_update_name_case(struct dentry *, const struct qstr *);
  
  /* used for rename() and baskets */
  extern void d_move(struct dentry *, struct dentry *);
@@@ -556,27 -557,25 +556,27 @@@ static inline struct dentry *d_backing_
        return upper;
  }
  
 -static inline struct dentry *d_real(struct dentry *dentry)
 +/**
 + * d_real - Return the real dentry
 + * @dentry: the dentry to query
 + * @inode: inode to select the dentry from multiple layers (can be NULL)
 + * @flags: open flags to control copy-up behavior
 + *
 + * If dentry is on an union/overlay, then return the underlying, real dentry.
 + * Otherwise return the dentry itself.
 + *
 + * See also: Documentation/filesystems/vfs.txt
 + */
 +static inline struct dentry *d_real(struct dentry *dentry,
 +                                  const struct inode *inode,
 +                                  unsigned int flags)
  {
        if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
 -              return dentry->d_op->d_real(dentry, NULL);
 +              return dentry->d_op->d_real(dentry, inode, flags);
        else
                return dentry;
  }
  
 -static inline struct inode *vfs_select_inode(struct dentry *dentry,
 -                                           unsigned open_flags)
 -{
 -      struct inode *inode = d_inode(dentry);
 -
 -      if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE))
 -              inode = dentry->d_op->d_select_inode(dentry, open_flags);
 -
 -      return inode;
 -}
 -
  /**
   * d_real_inode - Return the real inode
   * @dentry: The dentry to query
   */
  static inline struct inode *d_real_inode(struct dentry *dentry)
  {
 -      return d_backing_inode(d_real(dentry));
 +      return d_backing_inode(d_real(dentry, NULL, 0));
  }
  
  
diff --combined include/linux/nfs_xdr.h
@@@ -1185,6 -1185,17 +1185,6 @@@ struct pnfs_ds_commit_info 
        struct pnfs_commit_bucket *buckets;
  };
  
 -#define NFS4_OP_MAP_NUM_LONGS \
 -      DIV_ROUND_UP(LAST_NFS4_OP, 8 * sizeof(unsigned long))
 -#define NFS4_OP_MAP_NUM_WORDS \
 -      (NFS4_OP_MAP_NUM_LONGS * sizeof(unsigned long) / sizeof(u32))
 -struct nfs4_op_map {
 -      union {
 -              unsigned long longs[NFS4_OP_MAP_NUM_LONGS];
 -              u32 words[NFS4_OP_MAP_NUM_WORDS];
 -      } u;
 -};
 -
  struct nfs41_state_protection {
        u32 how;
        struct nfs4_op_map enforce;
@@@ -1532,7 -1543,7 +1532,7 @@@ struct nfs_rpc_ops 
                            struct nfs_fattr *, struct nfs4_label *);
        int     (*setattr) (struct dentry *, struct nfs_fattr *,
                            struct iattr *);
-       int     (*lookup)  (struct inode *, struct qstr *,
+       int     (*lookup)  (struct inode *, const struct qstr *,
                            struct nfs_fh *, struct nfs_fattr *,
                            struct nfs4_label *);
        int     (*access)  (struct inode *, struct nfs_access_entry *);
                            unsigned int);
        int     (*create)  (struct inode *, struct dentry *,
                            struct iattr *, int);
-       int     (*remove)  (struct inode *, struct qstr *);
+       int     (*remove)  (struct inode *, const struct qstr *);
        void    (*unlink_setup)  (struct rpc_message *, struct inode *dir);
        void    (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
        int     (*unlink_done) (struct rpc_task *, struct inode *);
        void    (*rename_setup)  (struct rpc_message *msg, struct inode *dir);
        void    (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
        int     (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
-       int     (*link)    (struct inode *, struct inode *, struct qstr *);
+       int     (*link)    (struct inode *, struct inode *, const struct qstr *);
        int     (*symlink) (struct inode *, struct dentry *, struct page *,
                            unsigned int, struct iattr *);
        int     (*mkdir)   (struct inode *, struct dentry *, struct iattr *);
-       int     (*rmdir)   (struct inode *, struct qstr *);
+       int     (*rmdir)   (struct inode *, const struct qstr *);
        int     (*readdir) (struct dentry *, struct rpc_cred *,
                            u64, struct page **, unsigned int, int);
        int     (*mknod)   (struct inode *, struct dentry *, struct iattr *,
        int (*have_delegation)(struct inode *, fmode_t);
        int (*return_delegation)(struct inode *);
        struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *);
 -      struct nfs_client *
 -              (*init_client) (struct nfs_client *, const struct rpc_timeout *,
 -                              const char *);
 +      struct nfs_client *(*init_client) (struct nfs_client *,
 +                              const struct nfs_client_initdata *);
        void    (*free_client) (struct nfs_client *);
        struct nfs_server *(*create_server)(struct nfs_mount_info *, struct nfs_subversion *);
        struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
diff --combined security/security.c
@@@ -356,7 -356,7 +356,7 @@@ void security_inode_free(struct inode *
  }
  
  int security_dentry_init_security(struct dentry *dentry, int mode,
-                                       struct qstr *name, void **ctx,
+                                       const struct qstr *name, void **ctx,
                                        u32 *ctxlen)
  {
        return call_int_hook(dentry_init_security, -EOPNOTSUPP, dentry, mode,
@@@ -700,39 -700,18 +700,39 @@@ int security_inode_killpriv(struct dent
  
  int security_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc)
  {
 +      struct security_hook_list *hp;
 +      int rc;
 +
        if (unlikely(IS_PRIVATE(inode)))
                return -EOPNOTSUPP;
 -      return call_int_hook(inode_getsecurity, -EOPNOTSUPP, inode, name,
 -                              buffer, alloc);
 +      /*
 +       * Only one module will provide an attribute with a given name.
 +       */
 +      list_for_each_entry(hp, &security_hook_heads.inode_getsecurity, list) {
 +              rc = hp->hook.inode_getsecurity(inode, name, buffer, alloc);
 +              if (rc != -EOPNOTSUPP)
 +                      return rc;
 +      }
 +      return -EOPNOTSUPP;
  }
  
  int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
  {
 +      struct security_hook_list *hp;
 +      int rc;
 +
        if (unlikely(IS_PRIVATE(inode)))
                return -EOPNOTSUPP;
 -      return call_int_hook(inode_setsecurity, -EOPNOTSUPP, inode, name,
 -                              value, size, flags);
 +      /*
 +       * Only one module will provide an attribute with a given name.
 +       */
 +      list_for_each_entry(hp, &security_hook_heads.inode_setsecurity, list) {
 +              rc = hp->hook.inode_setsecurity(inode, name, value, size,
 +                                                              flags);
 +              if (rc != -EOPNOTSUPP)
 +                      return rc;
 +      }
 +      return -EOPNOTSUPP;
  }
  
  int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
diff --combined security/selinux/hooks.c
@@@ -830,28 -830,6 +830,28 @@@ static int selinux_set_mnt_opts(struct 
                        goto out;
                }
        }
 +
 +      /*
 +       * If this is a user namespace mount, no contexts are allowed
 +       * on the command line and security labels must be ignored.
 +       */
 +      if (sb->s_user_ns != &init_user_ns) {
 +              if (context_sid || fscontext_sid || rootcontext_sid ||
 +                  defcontext_sid) {
 +                      rc = -EACCES;
 +                      goto out;
 +              }
 +              if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
 +                      sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
 +                      rc = security_transition_sid(current_sid(), current_sid(),
 +                                                   SECCLASS_FILE, NULL,
 +                                                   &sbsec->mntpoint_sid);
 +                      if (rc)
 +                              goto out;
 +              }
 +              goto out_set_opts;
 +      }
 +
        /* sets the context of the superblock for the fs being mounted. */
        if (fscontext_sid) {
                rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
                sbsec->def_sid = defcontext_sid;
        }
  
 +out_set_opts:
        rc = sb_finish_set_opts(sb);
  out:
        mutex_unlock(&sbsec->lock);
@@@ -2282,7 -2259,7 +2282,7 @@@ static int check_nnp_nosuid(const struc
                            const struct task_security_struct *new_tsec)
  {
        int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
 -      int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID);
 +      int nosuid = !mnt_may_suid(bprm->file->f_path.mnt);
        int rc;
  
        if (!nnp && !nosuid)
@@@ -2832,7 -2809,7 +2832,7 @@@ static void selinux_inode_free_security
  }
  
  static int selinux_dentry_init_security(struct dentry *dentry, int mode,
-                                       struct qstr *name, void **ctx,
+                                       const struct qstr *name, void **ctx,
                                        u32 *ctxlen)
  {
        u32 newsid;
@@@ -4627,13 -4604,13 +4627,13 @@@ static int selinux_socket_sock_rcv_skb(
                err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
                                               addrp, family, peer_sid, &ad);
                if (err) {
 -                      selinux_netlbl_err(skb, err, 0);
 +                      selinux_netlbl_err(skb, family, err, 0);
                        return err;
                }
                err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
                                   PEER__RECV, &ad);
                if (err) {
 -                      selinux_netlbl_err(skb, err, 0);
 +                      selinux_netlbl_err(skb, family, err, 0);
                        return err;
                }
        }
@@@ -5001,7 -4978,7 +5001,7 @@@ static unsigned int selinux_ip_forward(
                err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
                                               addrp, family, peer_sid, &ad);
                if (err) {
 -                      selinux_netlbl_err(skb, err, 1);
 +                      selinux_netlbl_err(skb, family, err, 1);
                        return NF_DROP;
                }
        }
@@@ -5087,15 -5064,6 +5087,15 @@@ static unsigned int selinux_ipv4_output
        return selinux_ip_output(skb, PF_INET);
  }
  
 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 +static unsigned int selinux_ipv6_output(void *priv,
 +                                      struct sk_buff *skb,
 +                                      const struct nf_hook_state *state)
 +{
 +      return selinux_ip_output(skb, PF_INET6);
 +}
 +#endif        /* IPV6 */
 +
  static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                                                int ifindex,
                                                u16 family)
@@@ -6330,12 -6298,6 +6330,12 @@@ static struct nf_hook_ops selinux_nf_op
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP6_PRI_SELINUX_FIRST,
        },
 +      {
 +              .hook =         selinux_ipv6_output,
 +              .pf =           NFPROTO_IPV6,
 +              .hooknum =      NF_INET_LOCAL_OUT,
 +              .priority =     NF_IP6_PRI_SELINUX_FIRST,
 +      },
  #endif        /* IPV6 */
  };