diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 53 |
1 files changed, 34 insertions, 19 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 37f72ee5bf7..fbdcbca4072 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1813,8 +1813,6 @@ seqretry: | |||
1813 | tname = dentry->d_name.name; | 1813 | tname = dentry->d_name.name; |
1814 | i = dentry->d_inode; | 1814 | i = dentry->d_inode; |
1815 | prefetch(tname); | 1815 | prefetch(tname); |
1816 | if (i) | ||
1817 | prefetch(i); | ||
1818 | /* | 1816 | /* |
1819 | * This seqcount check is required to ensure name and | 1817 | * This seqcount check is required to ensure name and |
1820 | * len are loaded atomically, so as not to walk off the | 1818 | * len are loaded atomically, so as not to walk off the |
@@ -2213,14 +2211,15 @@ static void dentry_unlock_parents_for_move(struct dentry *dentry, | |||
2213 | * The hash value has to match the hash queue that the dentry is on.. | 2211 | * The hash value has to match the hash queue that the dentry is on.. |
2214 | */ | 2212 | */ |
2215 | /* | 2213 | /* |
2216 | * d_move - move a dentry | 2214 | * __d_move - move a dentry |
2217 | * @dentry: entry to move | 2215 | * @dentry: entry to move |
2218 | * @target: new dentry | 2216 | * @target: new dentry |
2219 | * | 2217 | * |
2220 | * Update the dcache to reflect the move of a file name. Negative | 2218 | * Update the dcache to reflect the move of a file name. Negative |
2221 | * dcache entries should not be moved in this way. | 2219 | * dcache entries should not be moved in this way. Caller hold |
2220 | * rename_lock. | ||
2222 | */ | 2221 | */ |
2223 | void d_move(struct dentry * dentry, struct dentry * target) | 2222 | static void __d_move(struct dentry * dentry, struct dentry * target) |
2224 | { | 2223 | { |
2225 | if (!dentry->d_inode) | 2224 | if (!dentry->d_inode) |
2226 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); | 2225 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); |
@@ -2228,8 +2227,6 @@ void d_move(struct dentry * dentry, struct dentry * target) | |||
2228 | BUG_ON(d_ancestor(dentry, target)); | 2227 | BUG_ON(d_ancestor(dentry, target)); |
2229 | BUG_ON(d_ancestor(target, dentry)); | 2228 | BUG_ON(d_ancestor(target, dentry)); |
2230 | 2229 | ||
2231 | write_seqlock(&rename_lock); | ||
2232 | |||
2233 | dentry_lock_for_move(dentry, target); | 2230 | dentry_lock_for_move(dentry, target); |
2234 | 2231 | ||
2235 | write_seqcount_begin(&dentry->d_seq); | 2232 | write_seqcount_begin(&dentry->d_seq); |
@@ -2275,6 +2272,20 @@ void d_move(struct dentry * dentry, struct dentry * target) | |||
2275 | spin_unlock(&target->d_lock); | 2272 | spin_unlock(&target->d_lock); |
2276 | fsnotify_d_move(dentry); | 2273 | fsnotify_d_move(dentry); |
2277 | spin_unlock(&dentry->d_lock); | 2274 | spin_unlock(&dentry->d_lock); |
2275 | } | ||
2276 | |||
2277 | /* | ||
2278 | * d_move - move a dentry | ||
2279 | * @dentry: entry to move | ||
2280 | * @target: new dentry | ||
2281 | * | ||
2282 | * Update the dcache to reflect the move of a file name. Negative | ||
2283 | * dcache entries should not be moved in this way. | ||
2284 | */ | ||
2285 | void d_move(struct dentry *dentry, struct dentry *target) | ||
2286 | { | ||
2287 | write_seqlock(&rename_lock); | ||
2288 | __d_move(dentry, target); | ||
2278 | write_sequnlock(&rename_lock); | 2289 | write_sequnlock(&rename_lock); |
2279 | } | 2290 | } |
2280 | EXPORT_SYMBOL(d_move); | 2291 | EXPORT_SYMBOL(d_move); |
@@ -2302,7 +2313,7 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) | |||
2302 | * This helper attempts to cope with remotely renamed directories | 2313 | * This helper attempts to cope with remotely renamed directories |
2303 | * | 2314 | * |
2304 | * It assumes that the caller is already holding | 2315 | * It assumes that the caller is already holding |
2305 | * dentry->d_parent->d_inode->i_mutex and the inode->i_lock | 2316 | * dentry->d_parent->d_inode->i_mutex, inode->i_lock and rename_lock |
2306 | * | 2317 | * |
2307 | * Note: If ever the locking in lock_rename() changes, then please | 2318 | * Note: If ever the locking in lock_rename() changes, then please |
2308 | * remember to update this too... | 2319 | * remember to update this too... |
@@ -2317,11 +2328,6 @@ static struct dentry *__d_unalias(struct inode *inode, | |||
2317 | if (alias->d_parent == dentry->d_parent) | 2328 | if (alias->d_parent == dentry->d_parent) |
2318 | goto out_unalias; | 2329 | goto out_unalias; |
2319 | 2330 | ||
2320 | /* Check for loops */ | ||
2321 | ret = ERR_PTR(-ELOOP); | ||
2322 | if (d_ancestor(alias, dentry)) | ||
2323 | goto out_err; | ||
2324 | |||
2325 | /* See lock_rename() */ | 2331 | /* See lock_rename() */ |
2326 | ret = ERR_PTR(-EBUSY); | 2332 | ret = ERR_PTR(-EBUSY); |
2327 | if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex)) | 2333 | if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex)) |
@@ -2331,7 +2337,7 @@ static struct dentry *__d_unalias(struct inode *inode, | |||
2331 | goto out_err; | 2337 | goto out_err; |
2332 | m2 = &alias->d_parent->d_inode->i_mutex; | 2338 | m2 = &alias->d_parent->d_inode->i_mutex; |
2333 | out_unalias: | 2339 | out_unalias: |
2334 | d_move(alias, dentry); | 2340 | __d_move(alias, dentry); |
2335 | ret = alias; | 2341 | ret = alias; |
2336 | out_err: | 2342 | out_err: |
2337 | spin_unlock(&inode->i_lock); | 2343 | spin_unlock(&inode->i_lock); |
@@ -2416,15 +2422,24 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
2416 | alias = __d_find_alias(inode, 0); | 2422 | alias = __d_find_alias(inode, 0); |
2417 | if (alias) { | 2423 | if (alias) { |
2418 | actual = alias; | 2424 | actual = alias; |
2419 | /* Is this an anonymous mountpoint that we could splice | 2425 | write_seqlock(&rename_lock); |
2420 | * into our tree? */ | 2426 | |
2421 | if (IS_ROOT(alias)) { | 2427 | if (d_ancestor(alias, dentry)) { |
2428 | /* Check for loops */ | ||
2429 | actual = ERR_PTR(-ELOOP); | ||
2430 | } else if (IS_ROOT(alias)) { | ||
2431 | /* Is this an anonymous mountpoint that we | ||
2432 | * could splice into our tree? */ | ||
2422 | __d_materialise_dentry(dentry, alias); | 2433 | __d_materialise_dentry(dentry, alias); |
2434 | write_sequnlock(&rename_lock); | ||
2423 | __d_drop(alias); | 2435 | __d_drop(alias); |
2424 | goto found; | 2436 | goto found; |
2437 | } else { | ||
2438 | /* Nope, but we must(!) avoid directory | ||
2439 | * aliasing */ | ||
2440 | actual = __d_unalias(inode, dentry, alias); | ||
2425 | } | 2441 | } |
2426 | /* Nope, but we must(!) avoid directory aliasing */ | 2442 | write_sequnlock(&rename_lock); |
2427 | actual = __d_unalias(inode, dentry, alias); | ||
2428 | if (IS_ERR(actual)) | 2443 | if (IS_ERR(actual)) |
2429 | dput(alias); | 2444 | dput(alias); |
2430 | goto out_nolock; | 2445 | goto out_nolock; |