diff options
| -rw-r--r-- | fs/dcache.c | 62 |
1 files changed, 36 insertions, 26 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 6888dde4d568..1577c14dfb4e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -441,36 +441,12 @@ void d_drop(struct dentry *dentry) | |||
| 441 | } | 441 | } |
| 442 | EXPORT_SYMBOL(d_drop); | 442 | EXPORT_SYMBOL(d_drop); |
| 443 | 443 | ||
| 444 | /* | 444 | static void __dentry_kill(struct dentry *dentry) |
| 445 | * Finish off a dentry we've decided to kill. | ||
| 446 | * dentry->d_lock must be held, returns with it unlocked. | ||
| 447 | * If ref is non-zero, then decrement the refcount too. | ||
| 448 | * Returns dentry requiring refcount drop, or NULL if we're done. | ||
| 449 | */ | ||
| 450 | static struct dentry * | ||
| 451 | dentry_kill(struct dentry *dentry, int unlock_on_failure) | ||
| 452 | __releases(dentry->d_lock) | ||
| 453 | { | 445 | { |
| 454 | struct inode *inode; | ||
| 455 | struct dentry *parent = NULL; | 446 | struct dentry *parent = NULL; |
| 456 | bool can_free = true; | 447 | bool can_free = true; |
| 457 | |||
| 458 | inode = dentry->d_inode; | ||
| 459 | if (inode && !spin_trylock(&inode->i_lock)) { | ||
| 460 | relock: | ||
| 461 | if (unlock_on_failure) { | ||
| 462 | spin_unlock(&dentry->d_lock); | ||
| 463 | cpu_relax(); | ||
| 464 | } | ||
| 465 | return dentry; /* try again with same dentry */ | ||
| 466 | } | ||
| 467 | if (!IS_ROOT(dentry)) | 448 | if (!IS_ROOT(dentry)) |
| 468 | parent = dentry->d_parent; | 449 | parent = dentry->d_parent; |
| 469 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
| 470 | if (inode) | ||
| 471 | spin_unlock(&inode->i_lock); | ||
| 472 | goto relock; | ||
| 473 | } | ||
| 474 | 450 | ||
| 475 | /* | 451 | /* |
| 476 | * The dentry is now unrecoverably dead to the world. | 452 | * The dentry is now unrecoverably dead to the world. |
| @@ -514,10 +490,44 @@ relock: | |||
| 514 | can_free = false; | 490 | can_free = false; |
| 515 | } | 491 | } |
| 516 | spin_unlock(&dentry->d_lock); | 492 | spin_unlock(&dentry->d_lock); |
| 517 | out: | ||
| 518 | if (likely(can_free)) | 493 | if (likely(can_free)) |
| 519 | dentry_free(dentry); | 494 | dentry_free(dentry); |
| 495 | } | ||
| 496 | |||
| 497 | /* | ||
| 498 | * Finish off a dentry we've decided to kill. | ||
| 499 | * dentry->d_lock must be held, returns with it unlocked. | ||
| 500 | * If ref is non-zero, then decrement the refcount too. | ||
| 501 | * Returns dentry requiring refcount drop, or NULL if we're done. | ||
| 502 | */ | ||
| 503 | static struct dentry * | ||
| 504 | dentry_kill(struct dentry *dentry, int unlock_on_failure) | ||
| 505 | __releases(dentry->d_lock) | ||
| 506 | { | ||
| 507 | struct inode *inode = dentry->d_inode; | ||
| 508 | struct dentry *parent = NULL; | ||
| 509 | |||
| 510 | if (inode && unlikely(!spin_trylock(&inode->i_lock))) | ||
| 511 | goto failed; | ||
| 512 | |||
| 513 | if (!IS_ROOT(dentry)) { | ||
| 514 | parent = dentry->d_parent; | ||
| 515 | if (unlikely(!spin_trylock(&parent->d_lock))) { | ||
| 516 | if (inode) | ||
| 517 | spin_unlock(&inode->i_lock); | ||
| 518 | goto failed; | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | __dentry_kill(dentry); | ||
| 520 | return parent; | 523 | return parent; |
| 524 | |||
| 525 | failed: | ||
| 526 | if (unlock_on_failure) { | ||
| 527 | spin_unlock(&dentry->d_lock); | ||
| 528 | cpu_relax(); | ||
| 529 | } | ||
| 530 | return dentry; /* try again with same dentry */ | ||
| 521 | } | 531 | } |
| 522 | 532 | ||
| 523 | /* | 533 | /* |
