@@ -2163,9 +2163,11 @@ EXPORT_SYMBOL(hashlen_string);
21632163
21642164/*
21652165 * Calculate the length and hash of the path component, and
2166- * return the "hash_len" as the result.
2166+ * return the length as the result.
21672167 */
2168- static inline unsigned long hash_name (struct nameidata * nd , const char * name )
2168+ static inline unsigned long hash_name (struct nameidata * nd ,
2169+ const char * name ,
2170+ unsigned long * lastword )
21692171{
21702172 unsigned long a = 0 , b , x = 0 , y = (unsigned long )nd -> path .dentry ;
21712173 unsigned long adata , bdata , mask , len ;
@@ -2185,14 +2187,25 @@ static inline unsigned long hash_name(struct nameidata *nd, const char *name)
21852187 adata = prep_zero_mask (a , adata , & constants );
21862188 bdata = prep_zero_mask (b , bdata , & constants );
21872189 mask = create_zero_mask (adata | bdata );
2188- x ^= a & zero_bytemask (mask );
2190+ a &= zero_bytemask (mask );
2191+ * lastword = a ;
2192+ x ^= a ;
21892193 len += find_zero (mask );
21902194
21912195 nd -> last .hash = fold_hash (x , y );
21922196 nd -> last .len = len ;
21932197 return len ;
21942198}
21952199
2200+ /*
2201+ * Note that the 'last' word is always zero-masked, but
2202+ * was loaded as a possibly big-endian word.
2203+ */
2204+ #ifdef __BIG_ENDIAN
2205+ #define LAST_WORD_IS_DOT (0x2eul << (BITS_PER_LONG-8))
2206+ #define LAST_WORD_IS_DOTDOT (0x2e2eul << (BITS_PER_LONG-16))
2207+ #endif
2208+
21962209#else /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */
21972210
21982211/* Return the hash of a string of known length */
@@ -2225,24 +2238,31 @@ EXPORT_SYMBOL(hashlen_string);
22252238 * We know there's a real path component here of at least
22262239 * one character.
22272240 */
2228- static inline unsigned long hash_name (struct nameidata * nd , const char * name )
2241+ static inline unsigned long hash_name (struct nameidata * nd , const char * name , unsigned long * lastword )
22292242{
22302243 unsigned long hash = init_name_hash (nd -> path .dentry );
2231- unsigned long len = 0 , c ;
2244+ unsigned long len = 0 , c , last = 0 ;
22322245
22332246 c = (unsigned char )* name ;
22342247 do {
2248+ last = (last << 8 ) + c ;
22352249 len ++ ;
22362250 hash = partial_name_hash (c , hash );
22372251 c = (unsigned char )name [len ];
22382252 } while (c && c != '/' );
2253+ * lastword = last ;
22392254 nd -> last .hash = end_name_hash (hash );
22402255 nd -> last .len = len ;
22412256 return len ;
22422257}
22432258
22442259#endif
22452260
2261+ #ifndef LAST_WORD_IS_DOT
2262+ #define LAST_WORD_IS_DOT 0x2e
2263+ #define LAST_WORD_IS_DOTDOT 0x2e2e
2264+ #endif
2265+
22462266/*
22472267 * Name resolution.
22482268 * This is the basic name resolution function, turning a pathname into
@@ -2271,34 +2291,38 @@ static int link_path_walk(const char *name, struct nameidata *nd)
22712291 for (;;) {
22722292 struct mnt_idmap * idmap ;
22732293 const char * link ;
2294+ unsigned long lastword ;
22742295 unsigned int len ;
2275- int type ;
22762296
22772297 idmap = mnt_idmap (nd -> path .mnt );
22782298 err = may_lookup (idmap , nd );
22792299 if (err )
22802300 return err ;
22812301
22822302 nd -> last .name = name ;
2283- len = hash_name (nd , name );
2303+ len = hash_name (nd , name , & lastword );
22842304 name += len ;
22852305
2286- type = LAST_NORM ;
2287- /* We know len is at least 1, so compare against 2 */
2288- if (len <= 2 && name [-1 ] == '.' ) {
2289- if (len == 2 ) {
2290- if (name [-2 ] == '.' ) {
2291- type = LAST_DOTDOT ;
2292- nd -> state |= ND_JUMPED ;
2293- }
2294- } else {
2295- type = LAST_DOT ;
2296- }
2297- }
2298- nd -> last_type = type ;
2299- if (likely (type == LAST_NORM )) {
2300- struct dentry * parent = nd -> path .dentry ;
2306+ switch (lastword ) {
2307+ case LAST_WORD_IS_DOTDOT :
2308+ if (len != 2 )
2309+ goto normal ;
2310+ nd -> last_type = LAST_DOTDOT ;
2311+ nd -> state |= ND_JUMPED ;
2312+ break ;
2313+
2314+ case LAST_WORD_IS_DOT :
2315+ if (len != 1 )
2316+ goto normal ;
2317+ nd -> last_type = LAST_DOT ;
2318+ break ;
2319+
2320+ default :
2321+ normal :
2322+ nd -> last_type = LAST_NORM ;
23012323 nd -> state &= ~ND_JUMPED ;
2324+
2325+ struct dentry * parent = nd -> path .dentry ;
23022326 if (unlikely (parent -> d_flags & DCACHE_OP_HASH )) {
23032327 err = parent -> d_op -> d_hash (parent , & nd -> last );
23042328 if (err < 0 )
0 commit comments