@@ -1712,17 +1712,26 @@ static struct dentry *lookup_slow(const struct qstr *name,
17121712}
17131713
17141714static inline int may_lookup (struct mnt_idmap * idmap ,
1715- struct nameidata * nd )
1715+ struct nameidata * restrict nd )
17161716{
1717- if (nd -> flags & LOOKUP_RCU ) {
1718- int err = inode_permission (idmap , nd -> inode , MAY_EXEC |MAY_NOT_BLOCK );
1719- if (!err ) // success, keep going
1720- return 0 ;
1721- if (!try_to_unlazy (nd ))
1722- return - ECHILD ; // redo it all non-lazy
1723- if (err != - ECHILD ) // hard error
1724- return err ;
1725- }
1717+ int err , mask ;
1718+
1719+ mask = nd -> flags & LOOKUP_RCU ? MAY_NOT_BLOCK : 0 ;
1720+ err = inode_permission (idmap , nd -> inode , mask | MAY_EXEC );
1721+ if (likely (!err ))
1722+ return 0 ;
1723+
1724+ // If we failed, and we weren't in LOOKUP_RCU, it's final
1725+ if (!(nd -> flags & LOOKUP_RCU ))
1726+ return err ;
1727+
1728+ // Drop out of RCU mode to make sure it wasn't transient
1729+ if (!try_to_unlazy (nd ))
1730+ return - ECHILD ; // redo it all non-lazy
1731+
1732+ if (err != - ECHILD ) // hard error
1733+ return err ;
1734+
17261735 return inode_permission (idmap , nd -> inode , MAY_EXEC );
17271736}
17281737
@@ -2163,33 +2172,65 @@ EXPORT_SYMBOL(hashlen_string);
21632172
21642173/*
21652174 * Calculate the length and hash of the path component, and
2166- * return the "hash_len" as the result.
2175+ * return the length as the result.
21672176 */
2168- static inline u64 hash_name (const void * salt , const char * name )
2177+ static inline const char * hash_name (struct nameidata * nd ,
2178+ const char * name ,
2179+ unsigned long * lastword )
21692180{
2170- unsigned long a = 0 , b , x = 0 , y = (unsigned long )salt ;
2181+ unsigned long a , b , x , y = (unsigned long )nd -> path . dentry ;
21712182 unsigned long adata , bdata , mask , len ;
21722183 const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS ;
21732184
2174- len = 0 ;
2175- goto inside ;
2185+ /*
2186+ * The first iteration is special, because it can result in
2187+ * '.' and '..' and has no mixing other than the final fold.
2188+ */
2189+ a = load_unaligned_zeropad (name );
2190+ b = a ^ REPEAT_BYTE ('/' );
2191+ if (has_zero (a , & adata , & constants ) | has_zero (b , & bdata , & constants )) {
2192+ adata = prep_zero_mask (a , adata , & constants );
2193+ bdata = prep_zero_mask (b , bdata , & constants );
2194+ mask = create_zero_mask (adata | bdata );
2195+ a &= zero_bytemask (mask );
2196+ * lastword = a ;
2197+ len = find_zero (mask );
2198+ nd -> last .hash = fold_hash (a , y );
2199+ nd -> last .len = len ;
2200+ return name + len ;
2201+ }
21762202
2203+ len = 0 ;
2204+ x = 0 ;
21772205 do {
21782206 HASH_MIX (x , y , a );
21792207 len += sizeof (unsigned long );
2180- inside :
21812208 a = load_unaligned_zeropad (name + len );
21822209 b = a ^ REPEAT_BYTE ('/' );
21832210 } while (!(has_zero (a , & adata , & constants ) | has_zero (b , & bdata , & constants )));
21842211
21852212 adata = prep_zero_mask (a , adata , & constants );
21862213 bdata = prep_zero_mask (b , bdata , & constants );
21872214 mask = create_zero_mask (adata | bdata );
2188- x ^= a & zero_bytemask (mask );
2215+ a &= zero_bytemask (mask );
2216+ x ^= a ;
2217+ len += find_zero (mask );
2218+ * lastword = 0 ; // Multi-word components cannot be DOT or DOTDOT
21892219
2190- return hashlen_create (fold_hash (x , y ), len + find_zero (mask ));
2220+ nd -> last .hash = fold_hash (x , y );
2221+ nd -> last .len = len ;
2222+ return name + len ;
21912223}
21922224
2225+ /*
2226+ * Note that the 'last' word is always zero-masked, but
2227+ * was loaded as a possibly big-endian word.
2228+ */
2229+ #ifdef __BIG_ENDIAN
2230+ #define LAST_WORD_IS_DOT (0x2eul << (BITS_PER_LONG-8))
2231+ #define LAST_WORD_IS_DOTDOT (0x2e2eul << (BITS_PER_LONG-16))
2232+ #endif
2233+
21932234#else /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */
21942235
21952236/* Return the hash of a string of known length */
@@ -2222,22 +2263,35 @@ EXPORT_SYMBOL(hashlen_string);
22222263 * We know there's a real path component here of at least
22232264 * one character.
22242265 */
2225- static inline u64 hash_name (const void * salt , const char * name )
2266+ static inline const char * hash_name (struct nameidata * nd , const char * name , unsigned long * lastword )
22262267{
2227- unsigned long hash = init_name_hash (salt );
2228- unsigned long len = 0 , c ;
2268+ unsigned long hash = init_name_hash (nd -> path . dentry );
2269+ unsigned long len = 0 , c , last = 0 ;
22292270
22302271 c = (unsigned char )* name ;
22312272 do {
2273+ last = (last << 8 ) + c ;
22322274 len ++ ;
22332275 hash = partial_name_hash (c , hash );
22342276 c = (unsigned char )name [len ];
22352277 } while (c && c != '/' );
2236- return hashlen_create (end_name_hash (hash ), len );
2278+
2279+ // This is reliable for DOT or DOTDOT, since the component
2280+ // cannot contain NUL characters - top bits being zero means
2281+ // we cannot have had any other pathnames.
2282+ * lastword = last ;
2283+ nd -> last .hash = end_name_hash (hash );
2284+ nd -> last .len = len ;
2285+ return name + len ;
22372286}
22382287
22392288#endif
22402289
2290+ #ifndef LAST_WORD_IS_DOT
2291+ #define LAST_WORD_IS_DOT 0x2e
2292+ #define LAST_WORD_IS_DOTDOT 0x2e2e
2293+ #endif
2294+
22412295/*
22422296 * Name resolution.
22432297 * This is the basic name resolution function, turning a pathname into
@@ -2266,45 +2320,38 @@ static int link_path_walk(const char *name, struct nameidata *nd)
22662320 for (;;) {
22672321 struct mnt_idmap * idmap ;
22682322 const char * link ;
2269- u64 hash_len ;
2270- int type ;
2323+ unsigned long lastword ;
22712324
22722325 idmap = mnt_idmap (nd -> path .mnt );
22732326 err = may_lookup (idmap , nd );
22742327 if (err )
22752328 return err ;
22762329
2277- hash_len = hash_name (nd -> path .dentry , name );
2330+ nd -> last .name = name ;
2331+ name = hash_name (nd , name , & lastword );
22782332
2279- type = LAST_NORM ;
2280- if (name [0 ] == '.' ) switch (hashlen_len (hash_len )) {
2281- case 2 :
2282- if (name [1 ] == '.' ) {
2283- type = LAST_DOTDOT ;
2284- nd -> state |= ND_JUMPED ;
2285- }
2286- break ;
2287- case 1 :
2288- type = LAST_DOT ;
2289- }
2290- if (likely (type == LAST_NORM )) {
2291- struct dentry * parent = nd -> path .dentry ;
2333+ switch (lastword ) {
2334+ case LAST_WORD_IS_DOTDOT :
2335+ nd -> last_type = LAST_DOTDOT ;
2336+ nd -> state |= ND_JUMPED ;
2337+ break ;
2338+
2339+ case LAST_WORD_IS_DOT :
2340+ nd -> last_type = LAST_DOT ;
2341+ break ;
2342+
2343+ default :
2344+ nd -> last_type = LAST_NORM ;
22922345 nd -> state &= ~ND_JUMPED ;
2346+
2347+ struct dentry * parent = nd -> path .dentry ;
22932348 if (unlikely (parent -> d_flags & DCACHE_OP_HASH )) {
2294- struct qstr this = { { .hash_len = hash_len }, .name = name };
2295- err = parent -> d_op -> d_hash (parent , & this );
2349+ err = parent -> d_op -> d_hash (parent , & nd -> last );
22962350 if (err < 0 )
22972351 return err ;
2298- hash_len = this .hash_len ;
2299- name = this .name ;
23002352 }
23012353 }
23022354
2303- nd -> last .hash_len = hash_len ;
2304- nd -> last .name = name ;
2305- nd -> last_type = type ;
2306-
2307- name += hashlen_len (hash_len );
23082355 if (!* name )
23092356 goto OK ;
23102357 /*
0 commit comments