diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/dcache.c | 143 |
1 files changed, 35 insertions, 108 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index e605e90d0f0a..435991eada1e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -2575,11 +2575,11 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) | |||
| 2575 | * Note: If ever the locking in lock_rename() changes, then please | 2575 | * Note: If ever the locking in lock_rename() changes, then please |
| 2576 | * remember to update this too... | 2576 | * remember to update this too... |
| 2577 | */ | 2577 | */ |
| 2578 | static struct dentry *__d_unalias(struct inode *inode, | 2578 | static int __d_unalias(struct inode *inode, |
| 2579 | struct dentry *dentry, struct dentry *alias) | 2579 | struct dentry *dentry, struct dentry *alias) |
| 2580 | { | 2580 | { |
| 2581 | struct mutex *m1 = NULL, *m2 = NULL; | 2581 | struct mutex *m1 = NULL, *m2 = NULL; |
| 2582 | struct dentry *ret = ERR_PTR(-EBUSY); | 2582 | int ret = -EBUSY; |
| 2583 | 2583 | ||
| 2584 | /* If alias and dentry share a parent, then no extra locks required */ | 2584 | /* If alias and dentry share a parent, then no extra locks required */ |
| 2585 | if (alias->d_parent == dentry->d_parent) | 2585 | if (alias->d_parent == dentry->d_parent) |
| @@ -2594,7 +2594,7 @@ static struct dentry *__d_unalias(struct inode *inode, | |||
| 2594 | m2 = &alias->d_parent->d_inode->i_mutex; | 2594 | m2 = &alias->d_parent->d_inode->i_mutex; |
| 2595 | out_unalias: | 2595 | out_unalias: |
| 2596 | __d_move(alias, dentry, false); | 2596 | __d_move(alias, dentry, false); |
| 2597 | ret = alias; | 2597 | ret = 0; |
| 2598 | out_err: | 2598 | out_err: |
| 2599 | spin_unlock(&inode->i_lock); | 2599 | spin_unlock(&inode->i_lock); |
| 2600 | if (m2) | 2600 | if (m2) |
| @@ -2629,130 +2629,57 @@ out_err: | |||
| 2629 | */ | 2629 | */ |
| 2630 | struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | 2630 | struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) |
| 2631 | { | 2631 | { |
| 2632 | struct dentry *new = NULL; | ||
| 2633 | |||
| 2634 | if (IS_ERR(inode)) | 2632 | if (IS_ERR(inode)) |
| 2635 | return ERR_CAST(inode); | 2633 | return ERR_CAST(inode); |
| 2636 | 2634 | ||
| 2637 | if (inode && S_ISDIR(inode->i_mode)) { | ||
| 2638 | spin_lock(&inode->i_lock); | ||
| 2639 | new = __d_find_any_alias(inode); | ||
| 2640 | if (new) { | ||
| 2641 | if (!IS_ROOT(new)) { | ||
| 2642 | spin_unlock(&inode->i_lock); | ||
| 2643 | dput(new); | ||
| 2644 | iput(inode); | ||
| 2645 | return ERR_PTR(-EIO); | ||
| 2646 | } | ||
| 2647 | if (d_ancestor(new, dentry)) { | ||
| 2648 | spin_unlock(&inode->i_lock); | ||
| 2649 | dput(new); | ||
| 2650 | iput(inode); | ||
| 2651 | return ERR_PTR(-EIO); | ||
| 2652 | } | ||
| 2653 | write_seqlock(&rename_lock); | ||
| 2654 | __d_move(new, dentry, false); | ||
| 2655 | write_sequnlock(&rename_lock); | ||
| 2656 | spin_unlock(&inode->i_lock); | ||
| 2657 | security_d_instantiate(new, inode); | ||
| 2658 | iput(inode); | ||
| 2659 | } else { | ||
| 2660 | /* already taking inode->i_lock, so d_add() by hand */ | ||
| 2661 | __d_instantiate(dentry, inode); | ||
| 2662 | spin_unlock(&inode->i_lock); | ||
| 2663 | security_d_instantiate(dentry, inode); | ||
| 2664 | d_rehash(dentry); | ||
| 2665 | } | ||
| 2666 | } else { | ||
| 2667 | d_instantiate(dentry, inode); | ||
| 2668 | if (d_unhashed(dentry)) | ||
| 2669 | d_rehash(dentry); | ||
| 2670 | } | ||
| 2671 | return new; | ||
| 2672 | } | ||
| 2673 | EXPORT_SYMBOL(d_splice_alias); | ||
| 2674 | |||
| 2675 | /** | ||
| 2676 | * d_materialise_unique - introduce an inode into the tree | ||
| 2677 | * @dentry: candidate dentry | ||
| 2678 | * @inode: inode to bind to the dentry, to which aliases may be attached | ||
| 2679 | * | ||
| 2680 | * Introduces an dentry into the tree, substituting an extant disconnected | ||
| 2681 | * root directory alias in its place if there is one. Caller must hold the | ||
| 2682 | * i_mutex of the parent directory. | ||
| 2683 | */ | ||
| 2684 | struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | ||
| 2685 | { | ||
| 2686 | struct dentry *actual; | ||
| 2687 | |||
| 2688 | BUG_ON(!d_unhashed(dentry)); | 2635 | BUG_ON(!d_unhashed(dentry)); |
| 2689 | 2636 | ||
| 2690 | if (!inode) { | 2637 | if (!inode) { |
| 2691 | actual = dentry; | ||
| 2692 | __d_instantiate(dentry, NULL); | 2638 | __d_instantiate(dentry, NULL); |
| 2693 | d_rehash(actual); | 2639 | goto out; |
| 2694 | goto out_nolock; | ||
| 2695 | } | 2640 | } |
| 2696 | |||
| 2697 | spin_lock(&inode->i_lock); | 2641 | spin_lock(&inode->i_lock); |
| 2698 | |||
| 2699 | if (S_ISDIR(inode->i_mode)) { | 2642 | if (S_ISDIR(inode->i_mode)) { |
| 2700 | struct dentry *alias; | 2643 | struct dentry *new = __d_find_any_alias(inode); |
| 2701 | 2644 | if (unlikely(new)) { | |
| 2702 | /* Does an aliased dentry already exist? */ | ||
| 2703 | alias = __d_find_alias(inode); | ||
| 2704 | if (alias) { | ||
| 2705 | actual = alias; | ||
| 2706 | write_seqlock(&rename_lock); | 2645 | write_seqlock(&rename_lock); |
| 2707 | 2646 | if (unlikely(d_ancestor(new, dentry))) { | |
| 2708 | if (d_ancestor(alias, dentry)) { | 2647 | write_sequnlock(&rename_lock); |
| 2709 | /* Check for loops */ | ||
| 2710 | actual = ERR_PTR(-ELOOP); | ||
| 2711 | spin_unlock(&inode->i_lock); | 2648 | spin_unlock(&inode->i_lock); |
| 2712 | } else if (IS_ROOT(alias)) { | 2649 | dput(new); |
| 2713 | /* Is this an anonymous mountpoint that we | 2650 | new = ERR_PTR(-ELOOP); |
| 2714 | * could splice into our tree? */ | 2651 | pr_warn_ratelimited( |
| 2715 | __d_move(alias, dentry, false); | 2652 | "VFS: Lookup of '%s' in %s %s" |
| 2653 | " would have caused loop\n", | ||
| 2654 | dentry->d_name.name, | ||
| 2655 | inode->i_sb->s_type->name, | ||
| 2656 | inode->i_sb->s_id); | ||
| 2657 | } else if (!IS_ROOT(new)) { | ||
| 2658 | int err = __d_unalias(inode, dentry, new); | ||
| 2716 | write_sequnlock(&rename_lock); | 2659 | write_sequnlock(&rename_lock); |
| 2717 | goto found; | 2660 | if (err) { |
| 2661 | dput(new); | ||
| 2662 | new = ERR_PTR(err); | ||
| 2663 | } | ||
| 2718 | } else { | 2664 | } else { |
| 2719 | /* Nope, but we must(!) avoid directory | 2665 | __d_move(new, dentry, false); |
| 2720 | * aliasing. This drops inode->i_lock */ | 2666 | write_sequnlock(&rename_lock); |
| 2721 | actual = __d_unalias(inode, dentry, alias); | 2667 | spin_unlock(&inode->i_lock); |
| 2722 | } | 2668 | security_d_instantiate(new, inode); |
| 2723 | write_sequnlock(&rename_lock); | ||
| 2724 | if (IS_ERR(actual)) { | ||
| 2725 | if (PTR_ERR(actual) == -ELOOP) | ||
| 2726 | pr_warn_ratelimited( | ||
| 2727 | "VFS: Lookup of '%s' in %s %s" | ||
| 2728 | " would have caused loop\n", | ||
| 2729 | dentry->d_name.name, | ||
| 2730 | inode->i_sb->s_type->name, | ||
| 2731 | inode->i_sb->s_id); | ||
| 2732 | dput(alias); | ||
| 2733 | } | 2669 | } |
| 2734 | goto out_nolock; | 2670 | iput(inode); |
| 2671 | return new; | ||
| 2735 | } | 2672 | } |
| 2736 | } | 2673 | } |
| 2737 | 2674 | /* already taking inode->i_lock, so d_add() by hand */ | |
| 2738 | /* Add a unique reference */ | 2675 | __d_instantiate(dentry, inode); |
| 2739 | actual = __d_instantiate_unique(dentry, inode); | ||
| 2740 | if (!actual) | ||
| 2741 | actual = dentry; | ||
| 2742 | |||
| 2743 | d_rehash(actual); | ||
| 2744 | found: | ||
| 2745 | spin_unlock(&inode->i_lock); | 2676 | spin_unlock(&inode->i_lock); |
| 2746 | out_nolock: | 2677 | out: |
| 2747 | if (actual == dentry) { | 2678 | security_d_instantiate(dentry, inode); |
| 2748 | security_d_instantiate(dentry, inode); | 2679 | d_rehash(dentry); |
| 2749 | return NULL; | 2680 | return NULL; |
| 2750 | } | ||
| 2751 | |||
| 2752 | iput(inode); | ||
| 2753 | return actual; | ||
| 2754 | } | 2681 | } |
| 2755 | EXPORT_SYMBOL_GPL(d_materialise_unique); | 2682 | EXPORT_SYMBOL(d_splice_alias); |
| 2756 | 2683 | ||
| 2757 | static int prepend(char **buffer, int *buflen, const char *str, int namelen) | 2684 | static int prepend(char **buffer, int *buflen, const char *str, int namelen) |
| 2758 | { | 2685 | { |
