@@ -1672,13 +1672,15 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
16721672 path -> dentry = dentry ;
16731673 if (nd -> flags & LOOKUP_RCU ) {
16741674 unsigned int seq = nd -> next_seq ;
1675+ if (likely (!d_managed (dentry )))
1676+ return 0 ;
16751677 if (likely (__follow_mount_rcu (nd , path )))
16761678 return 0 ;
16771679 // *path and nd->next_seq might've been clobbered
16781680 path -> mnt = nd -> path .mnt ;
16791681 path -> dentry = dentry ;
16801682 nd -> next_seq = seq ;
1681- if (!try_to_unlazy_next (nd , dentry ))
1683+ if (unlikely ( !try_to_unlazy_next (nd , dentry ) ))
16821684 return - ECHILD ;
16831685 }
16841686 ret = traverse_mounts (path , & jumped , & nd -> total_link_count , nd -> flags );
@@ -1941,13 +1943,23 @@ static int reserve_stack(struct nameidata *nd, struct path *link)
19411943
19421944enum {WALK_TRAILING = 1 , WALK_MORE = 2 , WALK_NOFOLLOW = 4 };
19431945
1944- static const char * pick_link (struct nameidata * nd , struct path * link ,
1946+ static noinline const char * pick_link (struct nameidata * nd , struct path * link ,
19451947 struct inode * inode , int flags )
19461948{
19471949 struct saved * last ;
19481950 const char * res ;
1949- int error = reserve_stack ( nd , link ) ;
1951+ int error ;
19501952
1953+ if (nd -> flags & LOOKUP_RCU ) {
1954+ /* make sure that d_is_symlink from step_into_slowpath() matches the inode */
1955+ if (read_seqcount_retry (& link -> dentry -> d_seq , nd -> next_seq ))
1956+ return ERR_PTR (- ECHILD );
1957+ } else {
1958+ if (link -> mnt == nd -> path .mnt )
1959+ mntget (link -> mnt );
1960+ }
1961+
1962+ error = reserve_stack (nd , link );
19511963 if (unlikely (error )) {
19521964 if (!(nd -> flags & LOOKUP_RCU ))
19531965 path_put (link );
@@ -2021,14 +2033,15 @@ static const char *pick_link(struct nameidata *nd, struct path *link,
20212033 *
20222034 * NOTE: dentry must be what nd->next_seq had been sampled from.
20232035 */
2024- static const char * step_into (struct nameidata * nd , int flags ,
2036+ static noinline const char * step_into_slowpath (struct nameidata * nd , int flags ,
20252037 struct dentry * dentry )
20262038{
20272039 struct path path ;
20282040 struct inode * inode ;
2029- int err = handle_mounts ( nd , dentry , & path ) ;
2041+ int err ;
20302042
2031- if (err < 0 )
2043+ err = handle_mounts (nd , dentry , & path );
2044+ if (unlikely (err < 0 ))
20322045 return ERR_PTR (err );
20332046 inode = path .dentry -> d_inode ;
20342047 if (likely (!d_is_symlink (path .dentry )) ||
@@ -2050,15 +2063,32 @@ static const char *step_into(struct nameidata *nd, int flags,
20502063 nd -> seq = nd -> next_seq ;
20512064 return NULL ;
20522065 }
2053- if (nd -> flags & LOOKUP_RCU ) {
2054- /* make sure that d_is_symlink above matches inode */
2055- if (read_seqcount_retry (& path .dentry -> d_seq , nd -> next_seq ))
2066+ return pick_link (nd , & path , inode , flags );
2067+ }
2068+
2069+ static __always_inline const char * step_into (struct nameidata * nd , int flags ,
2070+ struct dentry * dentry )
2071+ {
2072+ /*
2073+ * In the common case we are in rcu-walk and traversing over a non-mounted on
2074+ * directory (as opposed to e.g., a symlink).
2075+ *
2076+ * We can handle that and negative entries with the checks below.
2077+ */
2078+ if (likely ((nd -> flags & LOOKUP_RCU ) &&
2079+ !d_managed (dentry ) && !d_is_symlink (dentry ))) {
2080+ struct inode * inode = dentry -> d_inode ;
2081+ if (read_seqcount_retry (& dentry -> d_seq , nd -> next_seq ))
20562082 return ERR_PTR (- ECHILD );
2057- } else {
2058- if (path .mnt == nd -> path .mnt )
2059- mntget (path .mnt );
2083+ if (unlikely (!inode ))
2084+ return ERR_PTR (- ENOENT );
2085+ nd -> path .dentry = dentry ;
2086+ /* nd->path.mnt is retained on purpose */
2087+ nd -> inode = inode ;
2088+ nd -> seq = nd -> next_seq ;
2089+ return NULL ;
20602090 }
2061- return pick_link (nd , & path , inode , flags );
2091+ return step_into_slowpath (nd , flags , dentry );
20622092}
20632093
20642094static struct dentry * follow_dotdot_rcu (struct nameidata * nd )
@@ -2171,7 +2201,7 @@ static const char *handle_dots(struct nameidata *nd, int type)
21712201 return NULL ;
21722202}
21732203
2174- static const char * walk_component (struct nameidata * nd , int flags )
2204+ static __always_inline const char * walk_component (struct nameidata * nd , int flags )
21752205{
21762206 struct dentry * dentry ;
21772207 /*
0 commit comments