+++ /dev/null
-RCU-based dcache locking model
-==============================
-
-On many workloads, the most common operation on dcache is to look up a
-dentry, given a parent dentry and the name of the child. Typically,
-for every open(), stat() etc., the dentry corresponding to the
-pathname will be looked up by walking the tree starting with the first
-component of the pathname and using that dentry along with the next
-component to look up the next level and so on. Since it is a frequent
-operation for workloads like multiuser environments and web servers,
-it is important to optimize this path.
-
-Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus in
-every component during path look-up. Since 2.5.10 onwards, fast-walk
-algorithm changed this by holding the dcache_lock at the beginning and
-walking as many cached path component dentries as possible. This
-significantly decreases the number of acquisition of
-dcache_lock. However it also increases the lock hold time
-significantly and affects performance in large SMP machines. Since
-2.5.62 kernel, dcache has been using a new locking model that uses RCU
-to make dcache look-up lock-free.
-
-The current dcache locking model is not very different from the
-existing dcache locking model. Prior to 2.5.62 kernel, dcache_lock
-protected the hash chain, d_child, d_alias, d_lru lists as well as
-d_inode and several other things like mount look-up. RCU-based changes
-affect only the way the hash chain is protected. For everything else
-the dcache_lock must be taken for both traversing as well as
-updating. The hash chain updates too take the dcache_lock.  The
-significant change is the way d_lookup traverses the hash chain, it
-doesn't acquire the dcache_lock for this and rely on RCU to ensure
-that the dentry has not been *freed*.
-
-dcache_lock no longer exists, dentry locking is explained in fs/dcache.c
-
-Dcache locking details
-======================
-
-For many multi-user workloads, open() and stat() on files are very
-frequently occurring operations. Both involve walking of path names to
-find the dentry corresponding to the concerned file. In 2.4 kernel,
-dcache_lock was held during look-up of each path component. Contention
-and cache-line bouncing of this global lock caused significant
-scalability problems. With the introduction of RCU in Linux kernel,
-this was worked around by making the look-up of path components during
-path walking lock-free.
-
-
-Safe lock-free look-up of dcache hash table
-===========================================
-
-Dcache is a complex data structure with the hash table entries also
-linked together in other lists. In 2.4 kernel, dcache_lock protected
-all the lists. RCU dentry hash walking works like this:
-
-1. The deletion from hash chain is done using hlist_del_rcu() macro
-   which doesn't initialize next pointer of the deleted dentry and
-   this allows us to walk safely lock-free while a deletion is
-   happening. This is a standard hlist_rcu iteration.
-
-2. Insertion of a dentry into the hash table is done using
-   hlist_add_head_rcu() which take care of ordering the writes - the
-   writes to the dentry must be visible before the dentry is
-   inserted. This works in conjunction with hlist_for_each_rcu(),
-   which has since been replaced by hlist_for_each_entry_rcu(), while
-   walking the hash chain. The only requirement is that all
-   initialization to the dentry must be done before
-   hlist_add_head_rcu() since we don't have lock protection
-   while traversing the hash chain.
-
-3. The dentry looked up without holding locks cannot be returned for
-   walking if it is unhashed. It then may have a NULL d_inode or other
-   bogosity since RCU doesn't protect the other fields in the dentry. We
-   therefore use a flag DCACHE_UNHASHED to indicate unhashed dentries
-   and use this in conjunction with a per-dentry lock (d_lock). Once
-   looked up without locks, we acquire the per-dentry lock (d_lock) and
-   check if the dentry is unhashed. If so, the look-up is failed. If not,
-   the reference count of the dentry is increased and the dentry is
-   returned.
-
-4. Once a dentry is looked up, it must be ensured during the path walk
-   for that component it doesn't go away. In pre-2.5.10 code, this was
-   done holding a reference to the dentry. dcache_rcu does the same.
-   In some sense, dcache_rcu path walking looks like the pre-2.5.10
-   version.
-
-5. All dentry hash chain updates must take the per-dentry lock (see
-   fs/dcache.c). This excludes dput() to ensure that a dentry that has
-   been looked up concurrently does not get deleted before dget() can
-   take a ref.
-
-6. There are several ways to do reference counting of RCU protected
-   objects. One such example is in ipv4 route cache where deferred
-   freeing (using call_rcu()) is done as soon as the reference count
-   goes to zero. This cannot be done in the case of dentries because
-   tearing down of dentries require blocking (dentry_iput()) which
-   isn't supported from RCU callbacks. Instead, tearing down of
-   dentries happen synchronously in dput(), but actual freeing happens
-   later when RCU grace period is over. This allows safe lock-free
-   walking of the hash chains, but a matched dentry may have been
-   partially torn down. The checking of DCACHE_UNHASHED flag with
-   d_lock held detects such dentries and prevents them from being
-   returned from look-up.
-
-
-Maintaining POSIX rename semantics
-==================================
-
-Since look-up of dentries is lock-free, it can race against a
-concurrent rename operation. For example, during rename of file A to
-B, look-up of either A or B must succeed.  So, if look-up of B happens
-after A has been removed from the hash chain but not added to the new
-hash chain, it may fail.  Also, a comparison while the name is being
-written concurrently by a rename may result in false positive matches
-violating rename semantics.  Issues related to race with rename are
-handled as described below :
-
-1. Look-up can be done in two ways - d_lookup() which is safe from
-   simultaneous renames and __d_lookup() which is not.  If
-   __d_lookup() fails, it must be followed up by a d_lookup() to
-   correctly determine whether a dentry is in the hash table or
-   not. d_lookup() protects look-ups using a sequence lock
-   (rename_lock).
-
-2. The name associated with a dentry (d_name) may be changed if a
-   rename is allowed to happen simultaneously. To avoid memcmp() in
-   __d_lookup() go out of bounds due to a rename and false positive
-   comparison, the name comparison is done while holding the
-   per-dentry lock. This prevents concurrent renames during this
-   operation.
-
-3. Hash table walking during look-up may move to a different bucket as
-   the current dentry is moved to a different bucket due to rename.
-   But we use hlists in dcache hash table and they are
-   null-terminated.  So, even if a dentry moves to a different bucket,
-   hash chain walk will terminate. [with a list_head list, it may not
-   since termination is when the list_head in the original bucket is
-   reached].  Since we redo the d_parent check and compare name while
-   holding d_lock, lock-free look-up will not race against d_move().
-
-4. There can be a theoretical race when a dentry keeps coming back to
-   original bucket due to double moves. Due to this look-up may
-   consider that it has never moved and can end up in a infinite loop.
-   But this is not any worse that theoretical livelocks we already
-   have in the kernel.
-
-
-Important guidelines for filesystem developers related to dcache_rcu
-====================================================================
-
-1. Existing dcache interfaces (pre-2.5.62) exported to filesystem
-   don't change. Only dcache internal implementation changes. However
-   filesystems *must not* delete from the dentry hash chains directly
-   using the list macros like allowed earlier. They must use dcache
-   APIs like d_drop() or __d_drop() depending on the situation.
-
-2. d_flags is now protected by a per-dentry lock (d_lock). All access
-   to d_flags must be protected by it.
-
-3. For a hashed dentry, checking of d_count needs to be protected by
-   d_lock.
-
-
-Papers and other documentation on dcache locking
-================================================
-
-1. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124).
-
-2. http://lse.sourceforge.net/locking/dcache/dcache.html
-
-
-
 
--- /dev/null
+Path walking and name lookup locking
+====================================
+
+Path resolution is the finding a dentry corresponding to a path name string, by
+performing a path walk. Typically, for every open(), stat() etc., the path name
+will be resolved. Paths are resolved by walking the namespace tree, starting
+with the first component of the pathname (eg. root or cwd) with a known dentry,
+then finding the child of that dentry, which is named the next component in the
+path string. Then repeating the lookup from the child dentry and finding its
+child with the next element, and so on.
+
+Since it is a frequent operation for workloads like multiuser environments and
+web servers, it is important to optimize this code.
+
+Path walking synchronisation history:
+Prior to 2.5.10, dcache_lock was acquired in d_lookup (dcache hash lookup) and
+thus in every component during path look-up. Since 2.5.10 onwards, fast-walk
+algorithm changed this by holding the dcache_lock at the beginning and walking
+as many cached path component dentries as possible. This significantly
+decreases the number of acquisition of dcache_lock. However it also increases
+the lock hold time significantly and affects performance in large SMP machines.
+Since 2.5.62 kernel, dcache has been using a new locking model that uses RCU to
+make dcache look-up lock-free.
+
+All the above algorithms required taking a lock and reference count on the
+dentry that was looked up, so that may be used as the basis for walking the
+next path element. This is inefficient and unscalable. It is inefficient
+because of the locks and atomic operations required for every dentry element
+slows things down. It is not scalable because many parallel applications that
+are path-walk intensive tend to do path lookups starting from a common dentry
+(usually, the root "/" or current working directory). So contention on these
+common path elements causes lock and cacheline queueing.
+
+Since 2.6.38, RCU is used to make a significant part of the entire path walk
+(including dcache look-up) completely "store-free" (so, no locks, atomics, or
+even stores into cachelines of common dentries). This is known as "rcu-walk"
+path walking.
+
+Path walking overview
+=====================
+
+A name string specifies a start (root directory, cwd, fd-relative) and a
+sequence of elements (directory entry names), which together refer to a path in
+the namespace. A path is represented as a (dentry, vfsmount) tuple. The name
+elements are sub-strings, seperated by '/'.
+
+Name lookups will want to find a particular path that a name string refers to
+(usually the final element, or parent of final element). This is done by taking
+the path given by the name's starting point (which we know in advance -- eg.
+current->fs->cwd or current->fs->root) as the first parent of the lookup. Then
+iteratively for each subsequent name element, look up the child of the current
+parent with the given name and if it is not the desired entry, make it the
+parent for the next lookup.
+
+A parent, of course, must be a directory, and we must have appropriate
+permissions on the parent inode to be able to walk into it.
+
+Turning the child into a parent for the next lookup requires more checks and
+procedures. Symlinks essentially substitute the symlink name for the target
+name in the name string, and require some recursive path walking.  Mount points
+must be followed into (thus changing the vfsmount that subsequent path elements
+refer to), switching from the mount point path to the root of the particular
+mounted vfsmount. These behaviours are variously modified depending on the
+exact path walking flags.
+
+Path walking then must, broadly, do several particular things:
+- find the start point of the walk;
+- perform permissions and validity checks on inodes;
+- perform dcache hash name lookups on (parent, name element) tuples;
+- traverse mount points;
+- traverse symlinks;
+- lookup and create missing parts of the path on demand.
+
+Safe store-free look-up of dcache hash table
+============================================
+
+Dcache name lookup
+------------------
+In order to lookup a dcache (parent, name) tuple, we take a hash on the tuple
+and use that to select a bucket in the dcache-hash table. The list of entries
+in that bucket is then walked, and we do a full comparison of each entry
+against our (parent, name) tuple.
+
+The hash lists are RCU protected, so list walking is not serialised with
+concurrent updates (insertion, deletion from the hash). This is a standard RCU
+list application with the exception of renames, which will be covered below.
+
+Parent and name members of a dentry, as well as its membership in the dcache
+hash, and its inode are protected by the per-dentry d_lock spinlock. A
+reference is taken on the dentry (while the fields are verified under d_lock),
+and this stabilises its d_inode pointer and actual inode. This gives a stable
+point to perform the next step of our path walk against.
+
+These members are also protected by d_seq seqlock, although this offers
+read-only protection and no durability of results, so care must be taken when
+using d_seq for synchronisation (see seqcount based lookups, below).
+
+Renames
+-------
+Back to the rename case. In usual RCU protected lists, the only operations that
+will happen to an object is insertion, and then eventually removal from the
+list. The object will not be reused until an RCU grace period is complete.
+This ensures the RCU list traversal primitives can run over the object without
+problems (see RCU documentation for how this works).
+
+However when a dentry is renamed, its hash value can change, requiring it to be
+moved to a new hash list. Allocating and inserting a new alias would be
+expensive and also problematic for directory dentries. Latency would be far to
+high to wait for a grace period after removing the dentry and before inserting
+it in the new hash bucket. So what is done is to insert the dentry into the
+new list immediately.
+
+However, when the dentry's list pointers are updated to point to objects in the
+new list before waiting for a grace period, this can result in a concurrent RCU
+lookup of the old list veering off into the new (incorrect) list and missing
+the remaining dentries on the list.
+
+There is no fundamental problem with walking down the wrong list, because the
+dentry comparisons will never match. However it is fatal to miss a matching
+dentry. So a seqlock is used to detect when a rename has occurred, and so the
+lookup can be retried.
+
+         1      2      3
+        +---+  +---+  +---+
+hlist-->| N-+->| N-+->| N-+->
+head <--+-P |<-+-P |<-+-P |
+        +---+  +---+  +---+
+
+Rename of dentry 2 may require it deleted from the above list, and inserted
+into a new list. Deleting 2 gives the following list.
+
+         1             3
+        +---+         +---+     (don't worry, the longer pointers do not
+hlist-->| N-+-------->| N-+->    impose a measurable performance overhead
+head <--+-P |<--------+-P |      on modern CPUs)
+        +---+         +---+
+          ^      2      ^
+          |    +---+    |
+          |    | N-+----+
+          +----+-P |
+               +---+
+
+This is a standard RCU-list deletion, which leaves the deleted object's
+pointers intact, so a concurrent list walker that is currently looking at
+object 2 will correctly continue to object 3 when it is time to traverse the
+next object.
+
+However, when inserting object 2 onto a new list, we end up with this:
+
+         1             3
+        +---+         +---+
+hlist-->| N-+-------->| N-+->
+head <--+-P |<--------+-P |
+        +---+         +---+
+                 2
+               +---+
+               | N-+---->
+          <----+-P |
+               +---+
+
+Because we didn't wait for a grace period, there may be a concurrent lookup
+still at 2. Now when it follows 2's 'next' pointer, it will walk off into
+another list without ever having checked object 3.
+
+A related, but distinctly different, issue is that of rename atomicity versus
+lookup operations. If a file is renamed from 'A' to 'B', a lookup must only
+find either 'A' or 'B'. So if a lookup of 'A' returns NULL, a subsequent lookup
+of 'B' must succeed (note the reverse is not true).
+
+Between deleting the dentry from the old hash list, and inserting it on the new
+hash list, a lookup may find neither 'A' nor 'B' matching the dentry. The same
+rename seqlock is also used to cover this race in much the same way, by
+retrying a negative lookup result if a rename was in progress.
+
+Seqcount based lookups
+----------------------
+In refcount based dcache lookups, d_lock is used to serialise access to
+the dentry, stabilising it while comparing its name and parent and then
+taking a reference count (the reference count then gives a stable place to
+start the next part of the path walk from).
+
+As explained above, we would like to do path walking without taking locks or
+reference counts on intermediate dentries along the path. To do this, a per
+dentry seqlock (d_seq) is used to take a "coherent snapshot" of what the dentry
+looks like (its name, parent, and inode). That snapshot is then used to start
+the next part of the path walk. When loading the coherent snapshot under d_seq,
+care must be taken to load the members up-front, and use those pointers rather
+than reloading from the dentry later on (otherwise we'd have interesting things
+like d_inode going NULL underneath us, if the name was unlinked).
+
+Also important is to avoid performing any destructive operations (pretty much:
+no non-atomic stores to shared data), and to recheck the seqcount when we are
+"done" with the operation. Retry or abort if the seqcount does not match.
+Avoiding destructive or changing operations means we can easily unwind from
+failure.
+
+What this means is that a caller, provided they are holding RCU lock to
+protect the dentry object from disappearing, can perform a seqcount based
+lookup which does not increment the refcount on the dentry or write to
+it in any way. This returned dentry can be used for subsequent operations,
+provided that d_seq is rechecked after that operation is complete.
+
+Inodes are also rcu freed, so the seqcount lookup dentry's inode may also be
+queried for permissions.
+
+With this two parts of the puzzle, we can do path lookups without taking
+locks or refcounts on dentry elements.
+
+RCU-walk path walking design
+============================
+
+Path walking code now has two distinct modes, ref-walk and rcu-walk. ref-walk
+is the traditional[*] way of performing dcache lookups using d_lock to
+serialise concurrent modifications to the dentry and take a reference count on
+it. ref-walk is simple and obvious, and may sleep, take locks, etc while path
+walking is operating on each dentry. rcu-walk uses seqcount based dentry
+lookups, and can perform lookup of intermediate elements without any stores to
+shared data in the dentry or inode. rcu-walk can not be applied to all cases,
+eg. if the filesystem must sleep or perform non trivial operations, rcu-walk
+must be switched to ref-walk mode.
+
+[*] RCU is still used for the dentry hash lookup in ref-walk, but not the full
+    path walk.
+
+Where ref-walk uses a stable, refcounted ``parent'' to walk the remaining
+path string, rcu-walk uses a d_seq protected snapshot. When looking up a
+child of this parent snapshot, we open d_seq critical section on the child
+before closing d_seq critical section on the parent. This gives an interlocking
+ladder of snapshots to walk down.
+
+
+     proc 101
+      /----------------\
+     / comm:    "vi"    \
+    /  fs.root: dentry0  \
+    \  fs.cwd:  dentry2  /
+     \                  /
+      \----------------/
+
+So when vi wants to open("/home/npiggin/test.c", O_RDWR), then it will
+start from current->fs->root, which is a pinned dentry. Alternatively,
+"./test.c" would start from cwd; both names refer to the same path in
+the context of proc101.
+
+     dentry 0
+    +---------------------+   rcu-walk begins here, we note d_seq, check the
+    | name:    "/"        |   inode's permission, and then look up the next
+    | inode:   10         |   path element which is "home"...
+    | children:"home", ...|
+    +---------------------+
+              |
+     dentry 1 V
+    +---------------------+   ... which brings us here. We find dentry1 via
+    | name:    "home"     |   hash lookup, then note d_seq and compare name
+    | inode:   678        |   string and parent pointer. When we have a match,
+    | children:"npiggin"  |   we now recheck the d_seq of dentry0. Then we
+    +---------------------+   check inode and look up the next element.
+              |
+     dentry2  V
+    +---------------------+   Note: if dentry0 is now modified, lookup is
+    | name:    "npiggin"  |   not necessarily invalid, so we need only keep a
+    | inode:   543        |   parent for d_seq verification, and grandparents
+    | children:"a.c", ... |   can be forgotten.
+    +---------------------+
+              |
+     dentry3  V
+    +---------------------+   At this point we have our destination dentry.
+    | name:    "a.c"      |   We now take its d_lock, verify d_seq of this
+    | inode:   14221      |   dentry. If that checks out, we can increment
+    | children:NULL       |   its refcount because we're holding d_lock.
+    +---------------------+
+
+Taking a refcount on a dentry from rcu-walk mode, by taking its d_lock,
+re-checking its d_seq, and then incrementing its refcount is called
+"dropping rcu" or dropping from rcu-walk into ref-walk mode.
+
+It is, in some sense, a bit of a house of cards. If the seqcount check of the
+parent snapshot fails, the house comes down, because we had closed the d_seq
+section on the grandparent, so we have nothing left to stand on. In that case,
+the path walk must be fully restarted (which we do in ref-walk mode, to avoid
+live locks). It is costly to have a full restart, but fortunately they are
+quite rare.
+
+When we reach a point where sleeping is required, or a filesystem callout
+requires ref-walk, then instead of restarting the walk, we attempt to drop rcu
+at the last known good dentry we have. Avoiding a full restart in ref-walk in
+these cases is fundamental for performance and scalability because blocking
+operations such as creates and unlinks are not uncommon.
+
+The detailed design for rcu-walk is like this:
+* LOOKUP_RCU is set in nd->flags, which distinguishes rcu-walk from ref-walk.
+* Take the RCU lock for the entire path walk, starting with the acquiring
+  of the starting path (eg. root/cwd/fd-path). So now dentry refcounts are
+  not required for dentry persistence.
+* synchronize_rcu is called when unregistering a filesystem, so we can
+  access d_ops and i_ops during rcu-walk.
+* Similarly take the vfsmount lock for the entire path walk. So now mnt
+  refcounts are not required for persistence. Also we are free to perform mount
+  lookups, and to assume dentry mount points and mount roots are stable up and
+  down the path.
+* Have a per-dentry seqlock to protect the dentry name, parent, and inode,
+  so we can load this tuple atomically, and also check whether any of its
+  members have changed.
+* Dentry lookups (based on parent, candidate string tuple) recheck the parent
+  sequence after the child is found in case anything changed in the parent
+  during the path walk.
+* inode is also RCU protected so we can load d_inode and use the inode for
+  limited things.
+* i_mode, i_uid, i_gid can be tested for exec permissions during path walk.
+* i_op can be loaded.
+* When the destination dentry is reached, drop rcu there (ie. take d_lock,
+  verify d_seq, increment refcount).
+* If seqlock verification fails anywhere along the path, do a full restart
+  of the path lookup in ref-walk mode. -ECHILD tends to be used (for want of
+  a better errno) to signal an rcu-walk failure.
+
+The cases where rcu-walk cannot continue are:
+* NULL dentry (ie. any uncached path element)
+* parent with d_inode->i_op->permission or ACLs
+* dentries with d_revalidate
+* Following links
+
+In future patches, permission checks and d_revalidate become rcu-walk aware. It
+may be possible eventually to make following links rcu-walk aware.
+
+Uncached path elements will always require dropping to ref-walk mode, at the
+very least because i_mutex needs to be grabbed, and objects allocated.
+
+Final note:
+"store-free" path walking is not strictly store free. We take vfsmount lock
+and refcounts (both of which can be made per-cpu), and we also store to the
+stack (which is essentially CPU-local), and we also have to take locks and
+refcount on final dentry.
+
+The point is that shared data, where practically possible, is not locked
+or stored into. The result is massive improvements in performance and
+scalability of path resolution.
+
+
+Papers and other documentation on dcache locking
+================================================
+
+1. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124).
+
+2. http://lse.sourceforge.net/locking/dcache/dcache.html
 
                call_rcu(&dentry->d_u.d_rcu, __d_free);
 }
 
+/**
+ * dentry_rcuwalk_barrier - invalidate in-progress rcu-walk lookups
+ * After this call, in-progress rcu-walk path lookup will fail. This
+ * should be called after unhashing, and after changing d_inode (if
+ * the dentry has not already been unhashed).
+ */
+static inline void dentry_rcuwalk_barrier(struct dentry *dentry)
+{
+       assert_spin_locked(&dentry->d_lock);
+       /* Go through a barrier */
+       write_seqcount_barrier(&dentry->d_seq);
+}
+
 /*
  * Release the dentry's inode, using the filesystem
- * d_iput() operation if defined.
+ * d_iput() operation if defined. Dentry has no refcount
+ * and is unhashed.
  */
 static void dentry_iput(struct dentry * dentry)
        __releases(dentry->d_lock)
        }
 }
 
+/*
+ * Release the dentry's inode, using the filesystem
+ * d_iput() operation if defined. dentry remains in-use.
+ */
+static void dentry_unlink_inode(struct dentry * dentry)
+       __releases(dentry->d_lock)
+       __releases(dcache_inode_lock)
+{
+       struct inode *inode = dentry->d_inode;
+       dentry->d_inode = NULL;
+       list_del_init(&dentry->d_alias);
+       dentry_rcuwalk_barrier(dentry);
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&dcache_inode_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);
+}
+
 /*
  * dentry_lru_(add|del|move_tail) must be called with d_lock held.
  */
                spin_lock(&dcache_hash_lock);
                hlist_del_rcu(&dentry->d_hash);
                spin_unlock(&dcache_hash_lock);
+               dentry_rcuwalk_barrier(dentry);
        }
 }
 EXPORT_SYMBOL(__d_drop);
                spin_unlock(&dcache_inode_lock);
                goto relock;
        }
+
        if (ref)
                dentry->d_count--;
        /* if dentry was on the d_lru list delete it from there */
        dentry->d_count = 1;
        dentry->d_flags = DCACHE_UNHASHED;
        spin_lock_init(&dentry->d_lock);
+       seqcount_init(&dentry->d_seq);
        dentry->d_inode = NULL;
        dentry->d_parent = NULL;
        dentry->d_sb = NULL;
        if (inode)
                list_add(&dentry->d_alias, &inode->i_dentry);
        dentry->d_inode = inode;
+       dentry_rcuwalk_barrier(dentry);
        spin_unlock(&dentry->d_lock);
        fsnotify_d_instantiate(dentry, inode);
 }
 }
 EXPORT_SYMBOL(d_add_ci);
 
+/**
+ * __d_lookup_rcu - search for a dentry (racy, store-free)
+ * @parent: parent dentry
+ * @name: qstr of name we wish to find
+ * @seq: returns d_seq value at the point where the dentry was found
+ * @inode: returns dentry->d_inode when the inode was found valid.
+ * Returns: dentry, or NULL
+ *
+ * __d_lookup_rcu is the dcache lookup function for rcu-walk name
+ * resolution (store-free path walking) design described in
+ * Documentation/filesystems/path-lookup.txt.
+ *
+ * This is not to be used outside core vfs.
+ *
+ * __d_lookup_rcu must only be used in rcu-walk mode, ie. with vfsmount lock
+ * held, and rcu_read_lock held. The returned dentry must not be stored into
+ * without taking d_lock and checking d_seq sequence count against @seq
+ * returned here.
+ *
+ * A refcount may be taken on the found dentry with the __d_rcu_to_refcount
+ * function.
+ *
+ * Alternatively, __d_lookup_rcu may be called again to look up the child of
+ * the returned dentry, so long as its parent's seqlock is checked after the
+ * child is looked up. Thus, an interlocking stepping of sequence lock checks
+ * is formed, giving integrity down the path walk.
+ */
+struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
+                               unsigned *seq, struct inode **inode)
+{
+       unsigned int len = name->len;
+       unsigned int hash = name->hash;
+       const unsigned char *str = name->name;
+       struct hlist_head *head = d_hash(parent, hash);
+       struct hlist_node *node;
+       struct dentry *dentry;
+
+       /*
+        * Note: There is significant duplication with __d_lookup_rcu which is
+        * required to prevent single threaded performance regressions
+        * especially on architectures where smp_rmb (in seqcounts) are costly.
+        * Keep the two functions in sync.
+        */
+
+       /*
+        * The hash list is protected using RCU.
+        *
+        * Carefully use d_seq when comparing a candidate dentry, to avoid
+        * races with d_move().
+        *
+        * It is possible that concurrent renames can mess up our list
+        * walk here and result in missing our dentry, resulting in the
+        * false-negative result. d_lookup() protects against concurrent
+        * renames using rename_lock seqlock.
+        *
+        * See Documentation/vfs/dcache-locking.txt for more details.
+        */
+       hlist_for_each_entry_rcu(dentry, node, head, d_hash) {
+               struct inode *i;
+               const char *tname;
+               int tlen;
+
+               if (dentry->d_name.hash != hash)
+                       continue;
+
+seqretry:
+               *seq = read_seqcount_begin(&dentry->d_seq);
+               if (dentry->d_parent != parent)
+                       continue;
+               if (d_unhashed(dentry))
+                       continue;
+               tlen = dentry->d_name.len;
+               tname = dentry->d_name.name;
+               i = dentry->d_inode;
+               /*
+                * This seqcount check is required to ensure name and
+                * len are loaded atomically, so as not to walk off the
+                * edge of memory when walking. If we could load this
+                * atomically some other way, we could drop this check.
+                */
+               if (read_seqcount_retry(&dentry->d_seq, *seq))
+                       goto seqretry;
+               if (parent->d_op && parent->d_op->d_compare) {
+                       if (parent->d_op->d_compare(parent, *inode,
+                                               dentry, i,
+                                               tlen, tname, name))
+                               continue;
+               } else {
+                       if (tlen != len)
+                               continue;
+                       if (memcmp(tname, str, tlen))
+                               continue;
+               }
+               /*
+                * No extra seqcount check is required after the name
+                * compare. The caller must perform a seqcount check in
+                * order to do anything useful with the returned dentry
+                * anyway.
+                */
+               *inode = i;
+               return dentry;
+       }
+       return NULL;
+}
+
 /**
  * d_lookup - search for a dentry
  * @parent: parent dentry
  * dentry is returned. The caller must use dput to free the entry when it has
  * finished using it. %NULL is returned if the dentry does not exist.
  */
-struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
+struct dentry *d_lookup(struct dentry *parent, struct qstr *name)
 {
-       struct dentry * dentry = NULL;
+       struct dentry *dentry;
        unsigned seq;
 
         do {
 }
 EXPORT_SYMBOL(d_lookup);
 
-/*
+/**
  * __d_lookup - search for a dentry (racy)
  * @parent: parent dentry
  * @name: qstr of name we wish to find
  *
  * __d_lookup callers must be commented.
  */
-struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
+struct dentry *__d_lookup(struct dentry *parent, struct qstr *name)
 {
        unsigned int len = name->len;
        unsigned int hash = name->hash;
        const unsigned char *str = name->name;
        struct hlist_head *head = d_hash(parent,hash);
-       struct dentry *found = NULL;
        struct hlist_node *node;
+       struct dentry *found = NULL;
        struct dentry *dentry;
 
+       /*
+        * Note: There is significant duplication with __d_lookup_rcu which is
+        * required to prevent single threaded performance regressions
+        * especially on architectures where smp_rmb (in seqcounts) are costly.
+        * Keep the two functions in sync.
+        */
+
        /*
         * The hash list is protected using RCU.
         *
        rcu_read_lock();
        
        hlist_for_each_entry_rcu(dentry, node, head, d_hash) {
-               struct qstr *qstr;
+               const char *tname;
+               int tlen;
 
                if (dentry->d_name.hash != hash)
                        continue;
-               if (dentry->d_parent != parent)
-                       continue;
 
                spin_lock(&dentry->d_lock);
-
-               /*
-                * Recheck the dentry after taking the lock - d_move may have
-                * changed things. Don't bother checking the hash because
-                * we're about to compare the whole name anyway.
-                */
                if (dentry->d_parent != parent)
                        goto next;
-
-               /* non-existing due to RCU? */
                if (d_unhashed(dentry))
                        goto next;
 
                 * It is safe to compare names since d_move() cannot
                 * change the qstr (protected by d_lock).
                 */
-               qstr = &dentry->d_name;
+               tlen = dentry->d_name.len;
+               tname = dentry->d_name.name;
                if (parent->d_op && parent->d_op->d_compare) {
                        if (parent->d_op->d_compare(parent, parent->d_inode,
                                                dentry, dentry->d_inode,
-                                               qstr->len, qstr->name, name))
+                                               tlen, tname, name))
                                goto next;
                } else {
-                       if (qstr->len != len)
+                       if (tlen != len)
                                goto next;
-                       if (memcmp(qstr->name, str, len))
+                       if (memcmp(tname, str, tlen))
                                goto next;
                }
 
                        goto again;
                }
                dentry->d_flags &= ~DCACHE_CANT_MOUNT;
-               dentry_iput(dentry);
+               dentry_unlink_inode(dentry);
                fsnotify_nameremove(dentry, isdir);
                return;
        }
        BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */
 
        spin_lock(&dentry->d_lock);
+       write_seqcount_begin(&dentry->d_seq);
        memcpy((unsigned char *)dentry->d_name.name, name->name, name->len);
+       write_seqcount_end(&dentry->d_seq);
        spin_unlock(&dentry->d_lock);
 }
 EXPORT_SYMBOL(dentry_update_name_case);
 
        dentry_lock_for_move(dentry, target);
 
+       write_seqcount_begin(&dentry->d_seq);
+       write_seqcount_begin(&target->d_seq);
+
        /* Move the dentry to the target hash queue, if on different bucket */
        spin_lock(&dcache_hash_lock);
        if (!d_unhashed(dentry))
        spin_unlock(&dcache_hash_lock);
 
        /* Unhash the target: dput() will then get rid of it */
+       /* __d_drop does write_seqcount_barrier, but they're OK to nest. */
        __d_drop(target);
 
        list_del(&dentry->d_u.d_child);
 
        list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
 
+       write_seqcount_end(&target->d_seq);
+       write_seqcount_end(&dentry->d_seq);
+
        dentry_unlock_parents_for_move(dentry, target);
        spin_unlock(&target->d_lock);
        fsnotify_d_move(dentry);
 
        dentry_lock_for_move(anon, dentry);
 
+       write_seqcount_begin(&dentry->d_seq);
+       write_seqcount_begin(&anon->d_seq);
+
        dparent = dentry->d_parent;
        aparent = anon->d_parent;
 
        else
                INIT_LIST_HEAD(&anon->d_u.d_child);
 
+       write_seqcount_end(&dentry->d_seq);
+       write_seqcount_end(&anon->d_seq);
+
        dentry_unlock_parents_for_move(anon, dentry);
        spin_unlock(&dentry->d_lock);
 
 
                tmp = &(*tmp)->next;
        }
        write_unlock(&file_systems_lock);
+
+       synchronize_rcu();
+
        return -EINVAL;
 }
 
 
 /*
  * This does basic POSIX ACL permission checking
  */
-static int acl_permission_check(struct inode *inode, int mask,
-               int (*check_acl)(struct inode *inode, int mask))
+static inline int __acl_permission_check(struct inode *inode, int mask,
+               int (*check_acl)(struct inode *inode, int mask), int rcu)
 {
        umode_t                 mode = inode->i_mode;
 
                mode >>= 6;
        else {
                if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
-                       int error = check_acl(inode, mask);
-                       if (error != -EAGAIN)
-                               return error;
+                       if (rcu) {
+                               return -ECHILD;
+                       } else {
+                               int error = check_acl(inode, mask);
+                               if (error != -EAGAIN)
+                                       return error;
+                       }
                }
 
                if (in_group_p(inode->i_gid))
        return -EACCES;
 }
 
+static inline int acl_permission_check(struct inode *inode, int mask,
+               int (*check_acl)(struct inode *inode, int mask))
+{
+       return __acl_permission_check(inode, mask, check_acl, 0);
+}
+
 /**
  * generic_permission  -  check for access rights on a Posix-like filesystem
  * @inode:     inode to check access rights for
 }
 EXPORT_SYMBOL(path_put);
 
+/**
+ * nameidata_drop_rcu - drop this nameidata out of rcu-walk
+ * @nd: nameidata pathwalk data to drop
+ * @Returns: 0 on success, -ECHLID on failure
+ *
+ * Path walking has 2 modes, rcu-walk and ref-walk (see
+ * Documentation/filesystems/path-lookup.txt). __drop_rcu* functions attempt
+ * to drop out of rcu-walk mode and take normal reference counts on dentries
+ * and vfsmounts to transition to rcu-walk mode. __drop_rcu* functions take
+ * refcounts at the last known good point before rcu-walk got stuck, so
+ * ref-walk may continue from there. If this is not successful (eg. a seqcount
+ * has changed), then failure is returned and path walk restarts from the
+ * beginning in ref-walk mode.
+ *
+ * nameidata_drop_rcu attempts to drop the current nd->path and nd->root into
+ * ref-walk. Must be called from rcu-walk context.
+ */
+static int nameidata_drop_rcu(struct nameidata *nd)
+{
+       struct fs_struct *fs = current->fs;
+       struct dentry *dentry = nd->path.dentry;
+
+       BUG_ON(!(nd->flags & LOOKUP_RCU));
+       if (nd->root.mnt) {
+               spin_lock(&fs->lock);
+               if (nd->root.mnt != fs->root.mnt ||
+                               nd->root.dentry != fs->root.dentry)
+                       goto err_root;
+       }
+       spin_lock(&dentry->d_lock);
+       if (!__d_rcu_to_refcount(dentry, nd->seq))
+               goto err;
+       BUG_ON(nd->inode != dentry->d_inode);
+       spin_unlock(&dentry->d_lock);
+       if (nd->root.mnt) {
+               path_get(&nd->root);
+               spin_unlock(&fs->lock);
+       }
+       mntget(nd->path.mnt);
+
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+       nd->flags &= ~LOOKUP_RCU;
+       return 0;
+err:
+       spin_unlock(&dentry->d_lock);
+err_root:
+       if (nd->root.mnt)
+               spin_unlock(&fs->lock);
+       return -ECHILD;
+}
+
+/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
+static inline int nameidata_drop_rcu_maybe(struct nameidata *nd)
+{
+       if (nd->flags & LOOKUP_RCU)
+               return nameidata_drop_rcu(nd);
+       return 0;
+}
+
+/**
+ * nameidata_dentry_drop_rcu - drop nameidata and dentry out of rcu-walk
+ * @nd: nameidata pathwalk data to drop
+ * @dentry: dentry to drop
+ * @Returns: 0 on success, -ECHLID on failure
+ *
+ * nameidata_dentry_drop_rcu attempts to drop the current nd->path and nd->root,
+ * and dentry into ref-walk. @dentry must be a path found by a do_lookup call on
+ * @nd. Must be called from rcu-walk context.
+ */
+static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry)
+{
+       struct fs_struct *fs = current->fs;
+       struct dentry *parent = nd->path.dentry;
+
+       BUG_ON(!(nd->flags & LOOKUP_RCU));
+       if (nd->root.mnt) {
+               spin_lock(&fs->lock);
+               if (nd->root.mnt != fs->root.mnt ||
+                               nd->root.dentry != fs->root.dentry)
+                       goto err_root;
+       }
+       spin_lock(&parent->d_lock);
+       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+       if (!__d_rcu_to_refcount(dentry, nd->seq))
+               goto err;
+       /*
+        * If the sequence check on the child dentry passed, then the child has
+        * not been removed from its parent. This means the parent dentry must
+        * be valid and able to take a reference at this point.
+        */
+       BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
+       BUG_ON(!parent->d_count);
+       parent->d_count++;
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&parent->d_lock);
+       if (nd->root.mnt) {
+               path_get(&nd->root);
+               spin_unlock(&fs->lock);
+       }
+       mntget(nd->path.mnt);
+
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+       nd->flags &= ~LOOKUP_RCU;
+       return 0;
+err:
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&parent->d_lock);
+err_root:
+       if (nd->root.mnt)
+               spin_unlock(&fs->lock);
+       return -ECHILD;
+}
+
+/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
+static inline int nameidata_dentry_drop_rcu_maybe(struct nameidata *nd, struct dentry *dentry)
+{
+       if (nd->flags & LOOKUP_RCU)
+               return nameidata_dentry_drop_rcu(nd, dentry);
+       return 0;
+}
+
+/**
+ * nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk
+ * @nd: nameidata pathwalk data to drop
+ * @Returns: 0 on success, -ECHLID on failure
+ *
+ * nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk.
+ * nd->path should be the final element of the lookup, so nd->root is discarded.
+ * Must be called from rcu-walk context.
+ */
+static int nameidata_drop_rcu_last(struct nameidata *nd)
+{
+       struct dentry *dentry = nd->path.dentry;
+
+       BUG_ON(!(nd->flags & LOOKUP_RCU));
+       nd->flags &= ~LOOKUP_RCU;
+       nd->root.mnt = NULL;
+       spin_lock(&dentry->d_lock);
+       if (!__d_rcu_to_refcount(dentry, nd->seq))
+               goto err_unlock;
+       BUG_ON(nd->inode != dentry->d_inode);
+       spin_unlock(&dentry->d_lock);
+
+       mntget(nd->path.mnt);
+
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+
+       return 0;
+
+err_unlock:
+       spin_unlock(&dentry->d_lock);
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+       return -ECHILD;
+}
+
+/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
+static inline int nameidata_drop_rcu_last_maybe(struct nameidata *nd)
+{
+       if (likely(nd->flags & LOOKUP_RCU))
+               return nameidata_drop_rcu_last(nd);
+       return 0;
+}
+
 /**
  * release_open_intent - free up open intent resources
  * @nd: pointer to nameidata
  * short-cut DAC fails, then call ->permission() to do more
  * complete permission check.
  */
-static int exec_permission(struct inode *inode)
+static inline int __exec_permission(struct inode *inode, int rcu)
 {
        int ret;
 
        if (inode->i_op->permission) {
+               if (rcu)
+                       return -ECHILD;
                ret = inode->i_op->permission(inode, MAY_EXEC);
                if (!ret)
                        goto ok;
                return ret;
        }
-       ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl);
+       ret = __acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl, rcu);
        if (!ret)
                goto ok;
+       if (rcu && ret == -ECHILD)
+               return ret;
 
        if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))
                goto ok;
 
        return ret;
 ok:
-       return security_inode_permission(inode, MAY_EXEC);
+       return security_inode_exec_permission(inode, rcu);
+}
+
+static int exec_permission(struct inode *inode)
+{
+       return __exec_permission(inode, 0);
+}
+
+static int exec_permission_rcu(struct inode *inode)
+{
+       return __exec_permission(inode, 1);
 }
 
 static __always_inline void set_root(struct nameidata *nd)
 
 static int link_path_walk(const char *, struct nameidata *);
 
+static __always_inline void set_root_rcu(struct nameidata *nd)
+{
+       if (!nd->root.mnt) {
+               struct fs_struct *fs = current->fs;
+               spin_lock(&fs->lock);
+               nd->root = fs->root;
+               spin_unlock(&fs->lock);
+       }
+}
+
 static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
 {
+       int ret;
+
        if (IS_ERR(link))
                goto fail;
 
                nd->path = nd->root;
                path_get(&nd->root);
        }
+       nd->inode = nd->path.dentry->d_inode;
 
-       return link_path_walk(link, nd);
+       ret = link_path_walk(link, nd);
+       return ret;
 fail:
        path_put(&nd->path);
        return PTR_ERR(link);
 
 static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
 {
-       dput(nd->path.dentry);
-       if (nd->path.mnt != path->mnt) {
-               mntput(nd->path.mnt);
-               nd->path.mnt = path->mnt;
+       if (!(nd->flags & LOOKUP_RCU)) {
+               dput(nd->path.dentry);
+               if (nd->path.mnt != path->mnt)
+                       mntput(nd->path.mnt);
        }
+       nd->path.mnt = path->mnt;
        nd->path.dentry = path->dentry;
 }
 
 
        if (path->mnt != nd->path.mnt) {
                path_to_nameidata(path, nd);
+               nd->inode = nd->path.dentry->d_inode;
                dget(dentry);
        }
        mntget(path->mnt);
+
        nd->last_type = LAST_BIND;
        *p = dentry->d_inode->i_op->follow_link(dentry, nd);
        error = PTR_ERR(*p);
        return err;
 }
 
+static int follow_up_rcu(struct path *path)
+{
+       struct vfsmount *parent;
+       struct dentry *mountpoint;
+
+       parent = path->mnt->mnt_parent;
+       if (parent == path->mnt)
+               return 0;
+       mountpoint = path->mnt->mnt_mountpoint;
+       path->dentry = mountpoint;
+       path->mnt = parent;
+       return 1;
+}
+
 int follow_up(struct path *path)
 {
        struct vfsmount *parent;
 /*
  * serialization is taken care of in namespace.c
  */
+static void __follow_mount_rcu(struct nameidata *nd, struct path *path,
+                               struct inode **inode)
+{
+       while (d_mountpoint(path->dentry)) {
+               struct vfsmount *mounted;
+               mounted = __lookup_mnt(path->mnt, path->dentry, 1);
+               if (!mounted)
+                       return;
+               path->mnt = mounted;
+               path->dentry = mounted->mnt_root;
+               nd->seq = read_seqcount_begin(&path->dentry->d_seq);
+               *inode = path->dentry->d_inode;
+       }
+}
+
 static int __follow_mount(struct path *path)
 {
        int res = 0;
        return 0;
 }
 
-static __always_inline void follow_dotdot(struct nameidata *nd)
+static int follow_dotdot_rcu(struct nameidata *nd)
+{
+       struct inode *inode = nd->inode;
+
+       set_root_rcu(nd);
+
+       while(1) {
+               if (nd->path.dentry == nd->root.dentry &&
+                   nd->path.mnt == nd->root.mnt) {
+                       break;
+               }
+               if (nd->path.dentry != nd->path.mnt->mnt_root) {
+                       struct dentry *old = nd->path.dentry;
+                       struct dentry *parent = old->d_parent;
+                       unsigned seq;
+
+                       seq = read_seqcount_begin(&parent->d_seq);
+                       if (read_seqcount_retry(&old->d_seq, nd->seq))
+                               return -ECHILD;
+                       inode = parent->d_inode;
+                       nd->path.dentry = parent;
+                       nd->seq = seq;
+                       break;
+               }
+               if (!follow_up_rcu(&nd->path))
+                       break;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               inode = nd->path.dentry->d_inode;
+       }
+       __follow_mount_rcu(nd, &nd->path, &inode);
+       nd->inode = inode;
+
+       return 0;
+}
+
+static void follow_dotdot(struct nameidata *nd)
 {
        set_root(nd);
 
                        break;
        }
        follow_mount(&nd->path);
+       nd->inode = nd->path.dentry->d_inode;
 }
 
 /*
  *  It _is_ time-critical.
  */
 static int do_lookup(struct nameidata *nd, struct qstr *name,
-                    struct path *path)
+                       struct path *path, struct inode **inode)
 {
        struct vfsmount *mnt = nd->path.mnt;
-       struct dentry *dentry, *parent;
+       struct dentry *dentry, *parent = nd->path.dentry;
        struct inode *dir;
        /*
         * See if the low-level filesystem might want
         * to use its own hash..
         */
-       if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
-               int err = nd->path.dentry->d_op->d_hash(nd->path.dentry,
-                               nd->path.dentry->d_inode, name);
+       if (parent->d_op && parent->d_op->d_hash) {
+               int err = parent->d_op->d_hash(parent, nd->inode, name);
                if (err < 0)
                        return err;
        }
         * of a false negative due to a concurrent rename, we're going to
         * do the non-racy lookup, below.
         */
-       dentry = __d_lookup(nd->path.dentry, name);
-       if (!dentry)
-               goto need_lookup;
+       if (nd->flags & LOOKUP_RCU) {
+               unsigned seq;
+
+               *inode = nd->inode;
+               dentry = __d_lookup_rcu(parent, name, &seq, inode);
+               if (!dentry) {
+                       if (nameidata_drop_rcu(nd))
+                               return -ECHILD;
+                       goto need_lookup;
+               }
+               /* Memory barrier in read_seqcount_begin of child is enough */
+               if (__read_seqcount_retry(&parent->d_seq, nd->seq))
+                       return -ECHILD;
+
+               nd->seq = seq;
+               if (dentry->d_op && dentry->d_op->d_revalidate) {
+                       /* We commonly drop rcu-walk here */
+                       if (nameidata_dentry_drop_rcu(nd, dentry))
+                               return -ECHILD;
+                       goto need_revalidate;
+               }
+               path->mnt = mnt;
+               path->dentry = dentry;
+               __follow_mount_rcu(nd, path, inode);
+       } else {
+               dentry = __d_lookup(parent, name);
+               if (!dentry)
+                       goto need_lookup;
 found:
-       if (dentry->d_op && dentry->d_op->d_revalidate)
-               goto need_revalidate;
+               if (dentry->d_op && dentry->d_op->d_revalidate)
+                       goto need_revalidate;
 done:
-       path->mnt = mnt;
-       path->dentry = dentry;
-       __follow_mount(path);
+               path->mnt = mnt;
+               path->dentry = dentry;
+               __follow_mount(path);
+               *inode = path->dentry->d_inode;
+       }
        return 0;
 
 need_lookup:
-       parent = nd->path.dentry;
        dir = parent->d_inode;
+       BUG_ON(nd->inode != dir);
 
        mutex_lock(&dir->i_mutex);
        /*
 static int link_path_walk(const char *name, struct nameidata *nd)
 {
        struct path next;
-       struct inode *inode;
        int err;
        unsigned int lookup_flags = nd->flags;
        
        if (!*name)
                goto return_reval;
 
-       inode = nd->path.dentry->d_inode;
        if (nd->depth)
                lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
 
        /* At this point we know we have a real path component. */
        for(;;) {
+               struct inode *inode;
                unsigned long hash;
                struct qstr this;
                unsigned int c;
 
                nd->flags |= LOOKUP_CONTINUE;
-               err = exec_permission(inode);
+               if (nd->flags & LOOKUP_RCU) {
+                       err = exec_permission_rcu(nd->inode);
+                       if (err == -ECHILD) {
+                               if (nameidata_drop_rcu(nd))
+                                       return -ECHILD;
+                               goto exec_again;
+                       }
+               } else {
+exec_again:
+                       err = exec_permission(nd->inode);
+               }
                if (err)
                        break;
 
                if (this.name[0] == '.') switch (this.len) {
                        default:
                                break;
-                       case 2: 
+                       case 2:
                                if (this.name[1] != '.')
                                        break;
-                               follow_dotdot(nd);
-                               inode = nd->path.dentry->d_inode;
+                               if (nd->flags & LOOKUP_RCU) {
+                                       if (follow_dotdot_rcu(nd))
+                                               return -ECHILD;
+                               } else
+                                       follow_dotdot(nd);
                                /* fallthrough */
                        case 1:
                                continue;
                }
                /* This does the actual lookups.. */
-               err = do_lookup(nd, &this, &next);
+               err = do_lookup(nd, &this, &next, &inode);
                if (err)
                        break;
-
                err = -ENOENT;
-               inode = next.dentry->d_inode;
                if (!inode)
                        goto out_dput;
 
                if (inode->i_op->follow_link) {
+                       /* We commonly drop rcu-walk here */
+                       if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
+                               return -ECHILD;
+                       BUG_ON(inode != next.dentry->d_inode);
                        err = do_follow_link(&next, nd);
                        if (err)
                                goto return_err;
+                       nd->inode = nd->path.dentry->d_inode;
                        err = -ENOENT;
-                       inode = nd->path.dentry->d_inode;
-                       if (!inode)
+                       if (!nd->inode)
                                break;
-               } else
+               } else {
                        path_to_nameidata(&next, nd);
+                       nd->inode = inode;
+               }
                err = -ENOTDIR; 
-               if (!inode->i_op->lookup)
+               if (!nd->inode->i_op->lookup)
                        break;
                continue;
                /* here ends the main loop */
                if (this.name[0] == '.') switch (this.len) {
                        default:
                                break;
-                       case 2: 
+                       case 2:
                                if (this.name[1] != '.')
                                        break;
-                               follow_dotdot(nd);
-                               inode = nd->path.dentry->d_inode;
+                               if (nd->flags & LOOKUP_RCU) {
+                                       if (follow_dotdot_rcu(nd))
+                                               return -ECHILD;
+                               } else
+                                       follow_dotdot(nd);
                                /* fallthrough */
                        case 1:
                                goto return_reval;
                }
-               err = do_lookup(nd, &this, &next);
+               err = do_lookup(nd, &this, &next, &inode);
                if (err)
                        break;
-               inode = next.dentry->d_inode;
                if (follow_on_final(inode, lookup_flags)) {
+                       if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
+                               return -ECHILD;
+                       BUG_ON(inode != next.dentry->d_inode);
                        err = do_follow_link(&next, nd);
                        if (err)
                                goto return_err;
-                       inode = nd->path.dentry->d_inode;
-               } else
+                       nd->inode = nd->path.dentry->d_inode;
+               } else {
                        path_to_nameidata(&next, nd);
+                       nd->inode = inode;
+               }
                err = -ENOENT;
-               if (!inode)
+               if (!nd->inode)
                        break;
                if (lookup_flags & LOOKUP_DIRECTORY) {
                        err = -ENOTDIR; 
-                       if (!inode->i_op->lookup)
+                       if (!nd->inode->i_op->lookup)
                                break;
                }
                goto return_base;
                 */
                if (nd->path.dentry && nd->path.dentry->d_sb &&
                    (nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {
+                       if (nameidata_drop_rcu_maybe(nd))
+                               return -ECHILD;
                        err = -ESTALE;
                        /* Note: we do not d_invalidate() */
                        if (!nd->path.dentry->d_op->d_revalidate(
                                break;
                }
 return_base:
+               if (nameidata_drop_rcu_last_maybe(nd))
+                       return -ECHILD;
                return 0;
 out_dput:
-               path_put_conditional(&next, nd);
+               if (!(nd->flags & LOOKUP_RCU))
+                       path_put_conditional(&next, nd);
                break;
        }
-       path_put(&nd->path);
+       if (!(nd->flags & LOOKUP_RCU))
+               path_put(&nd->path);
 return_err:
        return err;
 }
 
+static inline int path_walk_rcu(const char *name, struct nameidata *nd)
+{
+       current->total_link_count = 0;
+
+       return link_path_walk(name, nd);
+}
+
+static inline int path_walk_simple(const char *name, struct nameidata *nd)
+{
+       current->total_link_count = 0;
+
+       return link_path_walk(name, nd);
+}
+
 static int path_walk(const char *name, struct nameidata *nd)
 {
        struct path save = nd->path;
        return result;
 }
 
+static void path_finish_rcu(struct nameidata *nd)
+{
+       if (nd->flags & LOOKUP_RCU) {
+               /* RCU dangling. Cancel it. */
+               nd->flags &= ~LOOKUP_RCU;
+               nd->root.mnt = NULL;
+               rcu_read_unlock();
+               br_read_unlock(vfsmount_lock);
+       }
+       if (nd->file)
+               fput(nd->file);
+}
+
+static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
+{
+       int retval = 0;
+       int fput_needed;
+       struct file *file;
+
+       nd->last_type = LAST_ROOT; /* if there are only slashes... */
+       nd->flags = flags | LOOKUP_RCU;
+       nd->depth = 0;
+       nd->root.mnt = NULL;
+       nd->file = NULL;
+
+       if (*name=='/') {
+               struct fs_struct *fs = current->fs;
+
+               br_read_lock(vfsmount_lock);
+               rcu_read_lock();
+
+               spin_lock(&fs->lock);
+               nd->root = fs->root;
+               nd->path = nd->root;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               spin_unlock(&fs->lock);
+
+       } else if (dfd == AT_FDCWD) {
+               struct fs_struct *fs = current->fs;
+
+               br_read_lock(vfsmount_lock);
+               rcu_read_lock();
+
+               spin_lock(&fs->lock);
+               nd->path = fs->pwd;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               spin_unlock(&fs->lock);
+       } else {
+               struct dentry *dentry;
+
+               file = fget_light(dfd, &fput_needed);
+               retval = -EBADF;
+               if (!file)
+                       goto out_fail;
+
+               dentry = file->f_path.dentry;
+
+               retval = -ENOTDIR;
+               if (!S_ISDIR(dentry->d_inode->i_mode))
+                       goto fput_fail;
+
+               retval = file_permission(file, MAY_EXEC);
+               if (retval)
+                       goto fput_fail;
+
+               nd->path = file->f_path;
+               if (fput_needed)
+                       nd->file = file;
+
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               br_read_lock(vfsmount_lock);
+               rcu_read_lock();
+       }
+       nd->inode = nd->path.dentry->d_inode;
+       return 0;
+
+fput_fail:
+       fput_light(file, fput_needed);
+out_fail:
+       return retval;
+}
+
 static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
 {
        int retval = 0;
 
                fput_light(file, fput_needed);
        }
+       nd->inode = nd->path.dentry->d_inode;
        return 0;
 
 fput_fail:
 static int do_path_lookup(int dfd, const char *name,
                                unsigned int flags, struct nameidata *nd)
 {
-       int retval = path_init(dfd, name, flags, nd);
-       if (!retval)
-               retval = path_walk(name, nd);
-       if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
-                               nd->path.dentry->d_inode))
-               audit_inode(name, nd->path.dentry);
+       int retval;
+
+       /*
+        * Path walking is largely split up into 2 different synchronisation
+        * schemes, rcu-walk and ref-walk (explained in
+        * Documentation/filesystems/path-lookup.txt). These share much of the
+        * path walk code, but some things particularly setup, cleanup, and
+        * following mounts are sufficiently divergent that functions are
+        * duplicated. Typically there is a function foo(), and its RCU
+        * analogue, foo_rcu().
+        *
+        * -ECHILD is the error number of choice (just to avoid clashes) that
+        * is returned if some aspect of an rcu-walk fails. Such an error must
+        * be handled by restarting a traditional ref-walk (which will always
+        * be able to complete).
+        */
+       retval = path_init_rcu(dfd, name, flags, nd);
+       if (unlikely(retval))
+               return retval;
+       retval = path_walk_rcu(name, nd);
+       path_finish_rcu(nd);
        if (nd->root.mnt) {
                path_put(&nd->root);
                nd->root.mnt = NULL;
        }
+
+       if (unlikely(retval == -ECHILD || retval == -ESTALE)) {
+               /* slower, locked walk */
+               if (retval == -ESTALE)
+                       flags |= LOOKUP_REVAL;
+               retval = path_init(dfd, name, flags, nd);
+               if (unlikely(retval))
+                       return retval;
+               retval = path_walk(name, nd);
+               if (nd->root.mnt) {
+                       path_put(&nd->root);
+                       nd->root.mnt = NULL;
+               }
+       }
+
+       if (likely(!retval)) {
+               if (unlikely(!audit_dummy_context())) {
+                       if (nd->path.dentry && nd->inode)
+                               audit_inode(name, nd->path.dentry);
+               }
+       }
+
        return retval;
 }
 
        path_get(&nd->path);
        nd->root = nd->path;
        path_get(&nd->root);
+       nd->inode = nd->path.dentry->d_inode;
 
        retval = path_walk(name, nd);
        if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
-                               nd->path.dentry->d_inode))
+                               nd->inode))
                audit_inode(name, nd->path.dentry);
 
        path_put(&nd->root);
        mutex_unlock(&dir->d_inode->i_mutex);
        dput(nd->path.dentry);
        nd->path.dentry = path->dentry;
+
        if (error)
                return error;
        /* Don't check for write permission, don't truncate */
        return ERR_PTR(error);
 }
 
+/*
+ * Handle O_CREAT case for do_filp_open
+ */
 static struct file *do_last(struct nameidata *nd, struct path *path,
                            int open_flag, int acc_mode,
                            int mode, const char *pathname)
                }
                /* fallthrough */
        case LAST_ROOT:
-               if (open_flag & O_CREAT)
-                       goto exit;
-               /* fallthrough */
+               goto exit;
        case LAST_BIND:
                audit_inode(pathname, dir);
                goto ok;
        }
 
        /* trailing slashes? */
-       if (nd->last.name[nd->last.len]) {
-               if (open_flag & O_CREAT)
-                       goto exit;
-               nd->flags |= LOOKUP_DIRECTORY | LOOKUP_FOLLOW;
-       }
-
-       /* just plain open? */
-       if (!(open_flag & O_CREAT)) {
-               error = do_lookup(nd, &nd->last, path);
-               if (error)
-                       goto exit;
-               error = -ENOENT;
-               if (!path->dentry->d_inode)
-                       goto exit_dput;
-               if (path->dentry->d_inode->i_op->follow_link)
-                       return NULL;
-               error = -ENOTDIR;
-               if (nd->flags & LOOKUP_DIRECTORY) {
-                       if (!path->dentry->d_inode->i_op->lookup)
-                               goto exit_dput;
-               }
-               path_to_nameidata(path, nd);
-               audit_inode(pathname, nd->path.dentry);
-               goto ok;
-       }
+       if (nd->last.name[nd->last.len])
+               goto exit;
 
-       /* OK, it's O_CREAT */
        mutex_lock(&dir->d_inode->i_mutex);
 
        path->dentry = lookup_hash(nd);
                return NULL;
 
        path_to_nameidata(path, nd);
+       nd->inode = path->dentry->d_inode;
        error = -EISDIR;
-       if (S_ISDIR(path->dentry->d_inode->i_mode))
+       if (S_ISDIR(nd->inode->i_mode))
                goto exit;
 ok:
        filp = finish_open(nd, open_flag, acc_mode);
        struct path path;
        int count = 0;
        int flag = open_to_namei_flags(open_flag);
-       int force_reval = 0;
+       int flags;
 
        if (!(open_flag & O_CREAT))
                mode = 0;
        if (open_flag & O_APPEND)
                acc_mode |= MAY_APPEND;
 
-       /* find the parent */
-reval:
-       error = path_init(dfd, pathname, LOOKUP_PARENT, &nd);
+       flags = LOOKUP_OPEN;
+       if (open_flag & O_CREAT) {
+               flags |= LOOKUP_CREATE;
+               if (open_flag & O_EXCL)
+                       flags |= LOOKUP_EXCL;
+       }
+       if (open_flag & O_DIRECTORY)
+               flags |= LOOKUP_DIRECTORY;
+       if (!(open_flag & O_NOFOLLOW))
+               flags |= LOOKUP_FOLLOW;
+
+       filp = get_empty_filp();
+       if (!filp)
+               return ERR_PTR(-ENFILE);
+
+       filp->f_flags = open_flag;
+       nd.intent.open.file = filp;
+       nd.intent.open.flags = flag;
+       nd.intent.open.create_mode = mode;
+
+       if (open_flag & O_CREAT)
+               goto creat;
+
+       /* !O_CREAT, simple open */
+       error = do_path_lookup(dfd, pathname, flags, &nd);
+       if (unlikely(error))
+               goto out_filp;
+       error = -ELOOP;
+       if (!(nd.flags & LOOKUP_FOLLOW)) {
+               if (nd.inode->i_op->follow_link)
+                       goto out_path;
+       }
+       error = -ENOTDIR;
+       if (nd.flags & LOOKUP_DIRECTORY) {
+               if (!nd.inode->i_op->lookup)
+                       goto out_path;
+       }
+       audit_inode(pathname, nd.path.dentry);
+       filp = finish_open(&nd, open_flag, acc_mode);
+       return filp;
+
+creat:
+       /* OK, have to create the file. Find the parent. */
+       error = path_init_rcu(dfd, pathname,
+                       LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
        if (error)
-               return ERR_PTR(error);
-       if (force_reval)
-               nd.flags |= LOOKUP_REVAL;
+               goto out_filp;
+       error = path_walk_rcu(pathname, &nd);
+       path_finish_rcu(&nd);
+       if (unlikely(error == -ECHILD || error == -ESTALE)) {
+               /* slower, locked walk */
+               if (error == -ESTALE) {
+reval:
+                       flags |= LOOKUP_REVAL;
+               }
+               error = path_init(dfd, pathname,
+                               LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
+               if (error)
+                       goto out_filp;
 
-       current->total_link_count = 0;
-       error = link_path_walk(pathname, &nd);
-       if (error) {
-               filp = ERR_PTR(error);
-               goto out;
+               error = path_walk_simple(pathname, &nd);
        }
-       if (unlikely(!audit_dummy_context()) && (open_flag & O_CREAT))
+       if (unlikely(error))
+               goto out_filp;
+       if (unlikely(!audit_dummy_context()))
                audit_inode(pathname, nd.path.dentry);
 
        /*
         * We have the parent and last component.
         */
-
-       error = -ENFILE;
-       filp = get_empty_filp();
-       if (filp == NULL)
-               goto exit_parent;
-       nd.intent.open.file = filp;
-       filp->f_flags = open_flag;
-       nd.intent.open.flags = flag;
-       nd.intent.open.create_mode = mode;
-       nd.flags &= ~LOOKUP_PARENT;
-       nd.flags |= LOOKUP_OPEN;
-       if (open_flag & O_CREAT) {
-               nd.flags |= LOOKUP_CREATE;
-               if (open_flag & O_EXCL)
-                       nd.flags |= LOOKUP_EXCL;
-       }
-       if (open_flag & O_DIRECTORY)
-               nd.flags |= LOOKUP_DIRECTORY;
-       if (!(open_flag & O_NOFOLLOW))
-               nd.flags |= LOOKUP_FOLLOW;
+       nd.flags = flags;
        filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
        while (unlikely(!filp)) { /* trailing symlink */
                struct path holder;
-               struct inode *inode = path.dentry->d_inode;
                void *cookie;
                error = -ELOOP;
                /* S_ISDIR part is a temporary automount kludge */
-               if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(inode->i_mode))
+               if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(nd.inode->i_mode))
                        goto exit_dput;
                if (count++ == 32)
                        goto exit_dput;
                        goto exit_dput;
                error = __do_follow_link(&path, &nd, &cookie);
                if (unlikely(error)) {
+                       if (!IS_ERR(cookie) && nd.inode->i_op->put_link)
+                               nd.inode->i_op->put_link(path.dentry, &nd, cookie);
                        /* nd.path had been dropped */
-                       if (!IS_ERR(cookie) && inode->i_op->put_link)
-                               inode->i_op->put_link(path.dentry, &nd, cookie);
-                       path_put(&path);
-                       release_open_intent(&nd);
-                       filp = ERR_PTR(error);
-                       goto out;
+                       nd.path = path;
+                       goto out_path;
                }
                holder = path;
                nd.flags &= ~LOOKUP_PARENT;
                filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
-               if (inode->i_op->put_link)
-                       inode->i_op->put_link(holder.dentry, &nd, cookie);
+               if (nd.inode->i_op->put_link)
+                       nd.inode->i_op->put_link(holder.dentry, &nd, cookie);
                path_put(&holder);
        }
 out:
        if (nd.root.mnt)
                path_put(&nd.root);
-       if (filp == ERR_PTR(-ESTALE) && !force_reval) {
-               force_reval = 1;
+       if (filp == ERR_PTR(-ESTALE) && !(flags & LOOKUP_REVAL))
                goto reval;
-       }
        return filp;
 
 exit_dput:
        path_put_conditional(&path, &nd);
+out_path:
+       path_put(&nd.path);
+out_filp:
        if (!IS_ERR(nd.intent.open.file))
                release_open_intent(&nd);
-exit_parent:
-       path_put(&nd.path);
        filp = ERR_PTR(error);
        goto out;
 }
 
                const struct dentry *dentry, const struct inode *inode,
                unsigned int len, const char *str, const struct qstr *name)
 {
+       /* Although proc doesn't have negative dentries, rcu-walk means
+        * that inode here can be NULL */
+       if (!inode)
+               return 0;
        if (name->len != len)
                return 1;
        if (memcmp(name->name, str, len))
 
 #include <linux/list.h>
 #include <linux/rculist.h>
 #include <linux/spinlock.h>
+#include <linux/seqlock.h>
 #include <linux/cache.h>
 #include <linux/rcupdate.h>
 
        unsigned int d_count;           /* protected by d_lock */
        unsigned int d_flags;           /* protected by d_lock */
        spinlock_t d_lock;              /* per dentry lock */
+       seqcount_t d_seq;               /* per dentry seqlock */
        int d_mounted;
        struct inode *d_inode;          /* Where the name belongs to - NULL is
                                         * negative */
 extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
 
 /* appendix may either be NULL or be used for transname suffixes */
-extern struct dentry * d_lookup(struct dentry *, struct qstr *);
-extern struct dentry * __d_lookup(struct dentry *, struct qstr *);
-extern struct dentry * d_hash_and_lookup(struct dentry *, struct qstr *);
+extern struct dentry *d_lookup(struct dentry *, struct qstr *);
+extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
+extern struct dentry *__d_lookup(struct dentry *, struct qstr *);
+extern struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
+                               unsigned *seq, struct inode **inode);
+
+/**
+ * __d_rcu_to_refcount - take a refcount on dentry if sequence check is ok
+ * @dentry: dentry to take a ref on
+ * @seq: seqcount to verify against
+ * @Returns: 0 on failure, else 1.
+ *
+ * __d_rcu_to_refcount operates on a dentry,seq pair that was returned
+ * by __d_lookup_rcu, to get a reference on an rcu-walk dentry.
+ */
+static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq)
+{
+       int ret = 0;
+
+       assert_spin_locked(&dentry->d_lock);
+       if (!read_seqcount_retry(&dentry->d_seq, seq)) {
+               ret = 1;
+               dentry->d_count++;
+       }
+
+       return ret;
+}
 
 /* validate "insecure" dentry pointer */
 extern int d_validate(struct dentry *, struct dentry *);
 
        struct path     path;
        struct qstr     last;
        struct path     root;
+       struct file     *file;
+       struct inode    *inode; /* path.dentry.d_inode */
        unsigned int    flags;
+       unsigned        seq;
        int             last_type;
        unsigned        depth;
        char *saved_names[MAX_NESTED_LINKS + 1];
  *  - internal "there are more path components" flag
  *  - dentry cache is untrusted; force a real lookup
  */
-#define LOOKUP_FOLLOW           1
-#define LOOKUP_DIRECTORY        2
-#define LOOKUP_CONTINUE                 4
-#define LOOKUP_PARENT          16
-#define LOOKUP_REVAL           64
+#define LOOKUP_FOLLOW          0x0001
+#define LOOKUP_DIRECTORY       0x0002
+#define LOOKUP_CONTINUE                0x0004
+
+#define LOOKUP_PARENT          0x0010
+#define LOOKUP_REVAL           0x0020
+#define LOOKUP_RCU             0x0040
 /*
  * Intent data
  */
 
  *     called when the actual read/write operations are performed.
  *     @inode contains the inode structure to check.
  *     @mask contains the permission mask.
- *     @nd contains the nameidata (may be NULL).
  *     Return 0 if permission is granted.
  * @inode_setattr:
  *     Check permission before setting file attributes.  Note that the kernel
 int security_inode_readlink(struct dentry *dentry);
 int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
 int security_inode_permission(struct inode *inode, int mask);
+int security_inode_exec_permission(struct inode *inode, unsigned int flags);
 int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
 int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
 int security_inode_setxattr(struct dentry *dentry, const char *name,
        return 0;
 }
 
+static inline int security_inode_exec_permission(struct inode *inode,
+                                                 unsigned int flags)
+{
+       return 0;
+}
+
 static inline int security_inode_setattr(struct dentry *dentry,
                                          struct iattr *attr)
 {
 
        return security_ops->inode_permission(inode, mask);
 }
 
+int security_inode_exec_permission(struct inode *inode, unsigned int flags)
+{
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+       if (flags)
+               return -ECHILD;
+       return security_ops->inode_permission(inode, MAY_EXEC);
+}
+
 int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
 {
        if (unlikely(IS_PRIVATE(dentry->d_inode)))