diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-06-25 23:33:49 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-06-30 23:30:44 -0400 |
commit | d4c91a8f7e5514a1e9cd37b453fda0dedfa8045d (patch) | |
tree | b482299b94b6ad6561bb27215f71b798a7073188 | |
parent | ae0a843c740b4e63684eefae96097cf62d9b7a14 (diff) |
new helper: d_same_name()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/dcache.c | 127 |
1 files changed, 36 insertions, 91 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index dc37c0238b46..040c2586d483 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -2066,42 +2066,19 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | |||
2066 | } | 2066 | } |
2067 | EXPORT_SYMBOL(d_add_ci); | 2067 | EXPORT_SYMBOL(d_add_ci); |
2068 | 2068 | ||
2069 | /* | ||
2070 | * Do the slow-case of the dentry name compare. | ||
2071 | * | ||
2072 | * Unlike the dentry_cmp() function, we need to atomically | ||
2073 | * load the name and length information, so that the | ||
2074 | * filesystem can rely on them, and can use the 'name' and | ||
2075 | * 'len' information without worrying about walking off the | ||
2076 | * end of memory etc. | ||
2077 | * | ||
2078 | * Thus the read_seqcount_retry() and the "duplicate" info | ||
2079 | * in arguments (the low-level filesystem should not look | ||
2080 | * at the dentry inode or name contents directly, since | ||
2081 | * rename can change them while we're in RCU mode). | ||
2082 | */ | ||
2083 | enum slow_d_compare { | ||
2084 | D_COMP_OK, | ||
2085 | D_COMP_NOMATCH, | ||
2086 | D_COMP_SEQRETRY, | ||
2087 | }; | ||
2088 | 2069 | ||
2089 | static noinline enum slow_d_compare slow_dentry_cmp( | 2070 | static inline bool d_same_name(const struct dentry *dentry, |
2090 | const struct dentry *parent, | 2071 | const struct dentry *parent, |
2091 | struct dentry *dentry, | 2072 | const struct qstr *name) |
2092 | unsigned int seq, | ||
2093 | const struct qstr *name) | ||
2094 | { | 2073 | { |
2095 | int tlen = dentry->d_name.len; | 2074 | if (likely(!(parent->d_flags & DCACHE_OP_COMPARE))) { |
2096 | const char *tname = dentry->d_name.name; | 2075 | if (dentry->d_name.len != name->len) |
2097 | 2076 | return false; | |
2098 | if (read_seqcount_retry(&dentry->d_seq, seq)) { | 2077 | return dentry_cmp(dentry, name->name, name->len) == 0; |
2099 | cpu_relax(); | ||
2100 | return D_COMP_SEQRETRY; | ||
2101 | } | 2078 | } |
2102 | if (parent->d_op->d_compare(parent, dentry, tlen, tname, name)) | 2079 | return parent->d_op->d_compare(parent, dentry, |
2103 | return D_COMP_NOMATCH; | 2080 | dentry->d_name.len, dentry->d_name.name, |
2104 | return D_COMP_OK; | 2081 | name) == 0; |
2105 | } | 2082 | } |
2106 | 2083 | ||
2107 | /** | 2084 | /** |
@@ -2180,6 +2157,9 @@ seqretry: | |||
2180 | * dentry compare, we will do seqretries until it is stable, | 2157 | * dentry compare, we will do seqretries until it is stable, |
2181 | * and if we end up with a successful lookup, we actually | 2158 | * and if we end up with a successful lookup, we actually |
2182 | * want to exit RCU lookup anyway. | 2159 | * want to exit RCU lookup anyway. |
2160 | * | ||
2161 | * Note that raw_seqcount_begin still *does* smp_rmb(), so | ||
2162 | * we are still guaranteed NUL-termination of ->d_name.name. | ||
2183 | */ | 2163 | */ |
2184 | seq = raw_seqcount_begin(&dentry->d_seq); | 2164 | seq = raw_seqcount_begin(&dentry->d_seq); |
2185 | if (dentry->d_parent != parent) | 2165 | if (dentry->d_parent != parent) |
@@ -2188,24 +2168,28 @@ seqretry: | |||
2188 | continue; | 2168 | continue; |
2189 | 2169 | ||
2190 | if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) { | 2170 | if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) { |
2171 | int tlen; | ||
2172 | const char *tname; | ||
2191 | if (dentry->d_name.hash != hashlen_hash(hashlen)) | 2173 | if (dentry->d_name.hash != hashlen_hash(hashlen)) |
2192 | continue; | 2174 | continue; |
2193 | *seqp = seq; | 2175 | tlen = dentry->d_name.len; |
2194 | switch (slow_dentry_cmp(parent, dentry, seq, name)) { | 2176 | tname = dentry->d_name.name; |
2195 | case D_COMP_OK: | 2177 | /* we want a consistent (name,len) pair */ |
2196 | return dentry; | 2178 | if (read_seqcount_retry(&dentry->d_seq, seq)) { |
2197 | case D_COMP_NOMATCH: | 2179 | cpu_relax(); |
2198 | continue; | ||
2199 | default: | ||
2200 | goto seqretry; | 2180 | goto seqretry; |
2201 | } | 2181 | } |
2182 | if (parent->d_op->d_compare(parent, dentry, | ||
2183 | tlen, tname, name) != 0) | ||
2184 | continue; | ||
2185 | } else { | ||
2186 | if (dentry->d_name.hash_len != hashlen) | ||
2187 | continue; | ||
2188 | if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0) | ||
2189 | continue; | ||
2202 | } | 2190 | } |
2203 | |||
2204 | if (dentry->d_name.hash_len != hashlen) | ||
2205 | continue; | ||
2206 | *seqp = seq; | 2191 | *seqp = seq; |
2207 | if (!dentry_cmp(dentry, str, hashlen_len(hashlen))) | 2192 | return dentry; |
2208 | return dentry; | ||
2209 | } | 2193 | } |
2210 | return NULL; | 2194 | return NULL; |
2211 | } | 2195 | } |
@@ -2253,9 +2237,7 @@ EXPORT_SYMBOL(d_lookup); | |||
2253 | */ | 2237 | */ |
2254 | struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) | 2238 | struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) |
2255 | { | 2239 | { |
2256 | unsigned int len = name->len; | ||
2257 | unsigned int hash = name->hash; | 2240 | unsigned int hash = name->hash; |
2258 | const unsigned char *str = name->name; | ||
2259 | struct hlist_bl_head *b = d_hash(parent, hash); | 2241 | struct hlist_bl_head *b = d_hash(parent, hash); |
2260 | struct hlist_bl_node *node; | 2242 | struct hlist_bl_node *node; |
2261 | struct dentry *found = NULL; | 2243 | struct dentry *found = NULL; |
@@ -2294,21 +2276,8 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) | |||
2294 | if (d_unhashed(dentry)) | 2276 | if (d_unhashed(dentry)) |
2295 | goto next; | 2277 | goto next; |
2296 | 2278 | ||
2297 | /* | 2279 | if (!d_same_name(dentry, parent, name)) |
2298 | * It is safe to compare names since d_move() cannot | 2280 | goto next; |
2299 | * change the qstr (protected by d_lock). | ||
2300 | */ | ||
2301 | if (parent->d_flags & DCACHE_OP_COMPARE) { | ||
2302 | int tlen = dentry->d_name.len; | ||
2303 | const char *tname = dentry->d_name.name; | ||
2304 | if (parent->d_op->d_compare(parent, dentry, tlen, tname, name)) | ||
2305 | goto next; | ||
2306 | } else { | ||
2307 | if (dentry->d_name.len != len) | ||
2308 | goto next; | ||
2309 | if (dentry_cmp(dentry, str, len)) | ||
2310 | goto next; | ||
2311 | } | ||
2312 | 2281 | ||
2313 | dentry->d_lockref.count++; | 2282 | dentry->d_lockref.count++; |
2314 | found = dentry; | 2283 | found = dentry; |
@@ -2461,9 +2430,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent, | |||
2461 | const struct qstr *name, | 2430 | const struct qstr *name, |
2462 | wait_queue_head_t *wq) | 2431 | wait_queue_head_t *wq) |
2463 | { | 2432 | { |
2464 | unsigned int len = name->len; | ||
2465 | unsigned int hash = name->hash; | 2433 | unsigned int hash = name->hash; |
2466 | const unsigned char *str = name->name; | ||
2467 | struct hlist_bl_head *b = in_lookup_hash(parent, hash); | 2434 | struct hlist_bl_head *b = in_lookup_hash(parent, hash); |
2468 | struct hlist_bl_node *node; | 2435 | struct hlist_bl_node *node; |
2469 | struct dentry *new = d_alloc(parent, name); | 2436 | struct dentry *new = d_alloc(parent, name); |
@@ -2514,17 +2481,8 @@ retry: | |||
2514 | continue; | 2481 | continue; |
2515 | if (dentry->d_parent != parent) | 2482 | if (dentry->d_parent != parent) |
2516 | continue; | 2483 | continue; |
2517 | if (parent->d_flags & DCACHE_OP_COMPARE) { | 2484 | if (!d_same_name(dentry, parent, name)) |
2518 | int tlen = dentry->d_name.len; | 2485 | continue; |
2519 | const char *tname = dentry->d_name.name; | ||
2520 | if (parent->d_op->d_compare(parent, dentry, tlen, tname, name)) | ||
2521 | continue; | ||
2522 | } else { | ||
2523 | if (dentry->d_name.len != len) | ||
2524 | continue; | ||
2525 | if (dentry_cmp(dentry, str, len)) | ||
2526 | continue; | ||
2527 | } | ||
2528 | hlist_bl_unlock(b); | 2486 | hlist_bl_unlock(b); |
2529 | /* now we can try to grab a reference */ | 2487 | /* now we can try to grab a reference */ |
2530 | if (!lockref_get_not_dead(&dentry->d_lockref)) { | 2488 | if (!lockref_get_not_dead(&dentry->d_lockref)) { |
@@ -2551,17 +2509,8 @@ retry: | |||
2551 | goto mismatch; | 2509 | goto mismatch; |
2552 | if (unlikely(d_unhashed(dentry))) | 2510 | if (unlikely(d_unhashed(dentry))) |
2553 | goto mismatch; | 2511 | goto mismatch; |
2554 | if (parent->d_flags & DCACHE_OP_COMPARE) { | 2512 | if (unlikely(!d_same_name(dentry, parent, name))) |
2555 | int tlen = dentry->d_name.len; | 2513 | goto mismatch; |
2556 | const char *tname = dentry->d_name.name; | ||
2557 | if (parent->d_op->d_compare(parent, dentry, tlen, tname, name)) | ||
2558 | goto mismatch; | ||
2559 | } else { | ||
2560 | if (unlikely(dentry->d_name.len != len)) | ||
2561 | goto mismatch; | ||
2562 | if (unlikely(dentry_cmp(dentry, str, len))) | ||
2563 | goto mismatch; | ||
2564 | } | ||
2565 | /* OK, it *is* a hashed match; return it */ | 2514 | /* OK, it *is* a hashed match; return it */ |
2566 | spin_unlock(&dentry->d_lock); | 2515 | spin_unlock(&dentry->d_lock); |
2567 | dput(new); | 2516 | dput(new); |
@@ -2657,8 +2606,6 @@ EXPORT_SYMBOL(d_add); | |||
2657 | struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode) | 2606 | struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode) |
2658 | { | 2607 | { |
2659 | struct dentry *alias; | 2608 | struct dentry *alias; |
2660 | int len = entry->d_name.len; | ||
2661 | const char *name = entry->d_name.name; | ||
2662 | unsigned int hash = entry->d_name.hash; | 2609 | unsigned int hash = entry->d_name.hash; |
2663 | 2610 | ||
2664 | spin_lock(&inode->i_lock); | 2611 | spin_lock(&inode->i_lock); |
@@ -2672,9 +2619,7 @@ struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode) | |||
2672 | continue; | 2619 | continue; |
2673 | if (alias->d_parent != entry->d_parent) | 2620 | if (alias->d_parent != entry->d_parent) |
2674 | continue; | 2621 | continue; |
2675 | if (alias->d_name.len != len) | 2622 | if (!d_same_name(alias, entry->d_parent, &entry->d_name)) |
2676 | continue; | ||
2677 | if (dentry_cmp(alias, name, len)) | ||
2678 | continue; | 2623 | continue; |
2679 | spin_lock(&alias->d_lock); | 2624 | spin_lock(&alias->d_lock); |
2680 | if (!d_unhashed(alias)) { | 2625 | if (!d_unhashed(alias)) { |