diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/dcache.c | 48 |
1 files changed, 22 insertions, 26 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 89b9d1f14871..23a3401af2fb 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -352,48 +352,44 @@ repeat: | |||
| 352 | } | 352 | } |
| 353 | } | 353 | } |
| 354 | /* Unreachable? Get rid of it */ | 354 | /* Unreachable? Get rid of it */ |
| 355 | if (d_unhashed(dentry)) | 355 | if (d_unhashed(dentry)) |
| 356 | goto kill_it; | 356 | goto kill_it; |
| 357 | if (list_empty(&dentry->d_lru)) { | 357 | if (list_empty(&dentry->d_lru)) { |
| 358 | dentry->d_flags |= DCACHE_REFERENCED; | 358 | dentry->d_flags |= DCACHE_REFERENCED; |
| 359 | dentry_lru_add(dentry); | 359 | dentry_lru_add(dentry); |
| 360 | } | 360 | } |
| 361 | spin_unlock(&dentry->d_lock); | 361 | spin_unlock(&dentry->d_lock); |
| 362 | return; | 362 | return; |
| 363 | 363 | ||
| 364 | relock1: | ||
| 365 | spin_lock(&dentry->d_lock); | ||
| 366 | kill_it: | 364 | kill_it: |
| 367 | inode = dentry->d_inode; | 365 | inode = dentry->d_inode; |
| 368 | if (inode) { | 366 | if (inode && !spin_trylock(&inode->i_lock)) |
| 369 | if (!spin_trylock(&inode->i_lock)) { | 367 | goto retry; |
| 370 | relock2: | 368 | |
| 371 | spin_unlock(&dentry->d_lock); | ||
| 372 | goto relock1; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | parent = dentry->d_parent; | 369 | parent = dentry->d_parent; |
| 376 | if (parent && parent != dentry) { | 370 | if (parent && parent != dentry && !spin_trylock(&parent->d_lock)) { |
| 377 | if (!spin_trylock(&parent->d_lock)) { | ||
| 378 | if (inode) | ||
| 379 | spin_unlock(&inode->i_lock); | ||
| 380 | goto relock2; | ||
| 381 | } | ||
| 382 | } | ||
| 383 | if (atomic_read(&dentry->d_count)) { | ||
| 384 | /* This case should be fine */ | ||
| 385 | spin_unlock(&dentry->d_lock); | ||
| 386 | if (parent && parent != dentry) | ||
| 387 | spin_unlock(&parent->d_lock); | ||
| 388 | if (inode) | 371 | if (inode) |
| 389 | spin_unlock(&inode->i_lock); | 372 | spin_unlock(&inode->i_lock); |
| 390 | return; | 373 | goto retry; |
| 391 | } | 374 | } |
| 375 | |||
| 392 | /* if dentry was on the d_lru list delete it from there */ | 376 | /* if dentry was on the d_lru list delete it from there */ |
| 393 | dentry_lru_del(dentry); | 377 | dentry_lru_del(dentry); |
| 394 | dentry = d_kill(dentry); | 378 | dentry = d_kill(dentry); |
| 395 | if (dentry) | 379 | if (dentry) |
| 396 | goto repeat; | 380 | goto repeat; |
| 381 | return; | ||
| 382 | |||
| 383 | retry: | ||
| 384 | /* | ||
| 385 | * We are about to drop dentry->d_lock. dentry->d_count is 0 | ||
| 386 | * so it could be freed by someone else and leave us with a | ||
| 387 | * stale pointer. Prevent this by increasing d_count before | ||
| 388 | * dropping d_lock. | ||
| 389 | */ | ||
| 390 | atomic_inc(&dentry->d_count); | ||
| 391 | spin_unlock(&dentry->d_lock); | ||
| 392 | goto repeat; | ||
| 397 | } | 393 | } |
| 398 | 394 | ||
| 399 | /** | 395 | /** |
