merge d_materialise_unique() into d_splice_alias()
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 13 Oct 2014 02:16:02 +0000 (22:16 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Wed, 19 Nov 2014 18:01:19 +0000 (13:01 -0500)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/dcache.c
include/linux/dcache.h

index e605e90d0f0a07f237c16fbe1532d82998526d15..435991eada1ef554a8f724a602dc951f14050c3e 100644 (file)
@@ -2575,11 +2575,11 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)
  * Note: If ever the locking in lock_rename() changes, then please
  * remember to update this too...
  */
-static struct dentry *__d_unalias(struct inode *inode,
+static int __d_unalias(struct inode *inode,
                struct dentry *dentry, struct dentry *alias)
 {
        struct mutex *m1 = NULL, *m2 = NULL;
-       struct dentry *ret = ERR_PTR(-EBUSY);
+       int ret = -EBUSY;
 
        /* If alias and dentry share a parent, then no extra locks required */
        if (alias->d_parent == dentry->d_parent)
@@ -2594,7 +2594,7 @@ static struct dentry *__d_unalias(struct inode *inode,
        m2 = &alias->d_parent->d_inode->i_mutex;
 out_unalias:
        __d_move(alias, dentry, false);
-       ret = alias;
+       ret = 0;
 out_err:
        spin_unlock(&inode->i_lock);
        if (m2)
@@ -2629,130 +2629,57 @@ out_err:
  */
 struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
 {
-       struct dentry *new = NULL;
-
        if (IS_ERR(inode))
                return ERR_CAST(inode);
 
-       if (inode && S_ISDIR(inode->i_mode)) {
-               spin_lock(&inode->i_lock);
-               new = __d_find_any_alias(inode);
-               if (new) {
-                       if (!IS_ROOT(new)) {
-                               spin_unlock(&inode->i_lock);
-                               dput(new);
-                               iput(inode);
-                               return ERR_PTR(-EIO);
-                       }
-                       if (d_ancestor(new, dentry)) {
-                               spin_unlock(&inode->i_lock);
-                               dput(new);
-                               iput(inode);
-                               return ERR_PTR(-EIO);
-                       }
-                       write_seqlock(&rename_lock);
-                       __d_move(new, dentry, false);
-                       write_sequnlock(&rename_lock);
-                       spin_unlock(&inode->i_lock);
-                       security_d_instantiate(new, inode);
-                       iput(inode);
-               } else {
-                       /* already taking inode->i_lock, so d_add() by hand */
-                       __d_instantiate(dentry, inode);
-                       spin_unlock(&inode->i_lock);
-                       security_d_instantiate(dentry, inode);
-                       d_rehash(dentry);
-               }
-       } else {
-               d_instantiate(dentry, inode);
-               if (d_unhashed(dentry))
-                       d_rehash(dentry);
-       }
-       return new;
-}
-EXPORT_SYMBOL(d_splice_alias);
-
-/**
- * d_materialise_unique - introduce an inode into the tree
- * @dentry: candidate dentry
- * @inode: inode to bind to the dentry, to which aliases may be attached
- *
- * Introduces an dentry into the tree, substituting an extant disconnected
- * root directory alias in its place if there is one. Caller must hold the
- * i_mutex of the parent directory.
- */
-struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
-{
-       struct dentry *actual;
-
        BUG_ON(!d_unhashed(dentry));
 
        if (!inode) {
-               actual = dentry;
                __d_instantiate(dentry, NULL);
-               d_rehash(actual);
-               goto out_nolock;
+               goto out;
        }
-
        spin_lock(&inode->i_lock);
-
        if (S_ISDIR(inode->i_mode)) {
-               struct dentry *alias;
-
-               /* Does an aliased dentry already exist? */
-               alias = __d_find_alias(inode);
-               if (alias) {
-                       actual = alias;
+               struct dentry *new = __d_find_any_alias(inode);
+               if (unlikely(new)) {
                        write_seqlock(&rename_lock);
-
-                       if (d_ancestor(alias, dentry)) {
-                               /* Check for loops */
-                               actual = ERR_PTR(-ELOOP);
+                       if (unlikely(d_ancestor(new, dentry))) {
+                               write_sequnlock(&rename_lock);
                                spin_unlock(&inode->i_lock);
-                       } else if (IS_ROOT(alias)) {
-                               /* Is this an anonymous mountpoint that we
-                                * could splice into our tree? */
-                               __d_move(alias, dentry, false);
+                               dput(new);
+                               new = ERR_PTR(-ELOOP);
+                               pr_warn_ratelimited(
+                                       "VFS: Lookup of '%s' in %s %s"
+                                       " would have caused loop\n",
+                                       dentry->d_name.name,
+                                       inode->i_sb->s_type->name,
+                                       inode->i_sb->s_id);
+                       } else if (!IS_ROOT(new)) {
+                               int err = __d_unalias(inode, dentry, new);
                                write_sequnlock(&rename_lock);
-                               goto found;
+                               if (err) {
+                                       dput(new);
+                                       new = ERR_PTR(err);
+                               }
                        } else {
-                               /* Nope, but we must(!) avoid directory
-                                * aliasing. This drops inode->i_lock */
-                               actual = __d_unalias(inode, dentry, alias);
-                       }
-                       write_sequnlock(&rename_lock);
-                       if (IS_ERR(actual)) {
-                               if (PTR_ERR(actual) == -ELOOP)
-                                       pr_warn_ratelimited(
-                                               "VFS: Lookup of '%s' in %s %s"
-                                               " would have caused loop\n",
-                                               dentry->d_name.name,
-                                               inode->i_sb->s_type->name,
-                                               inode->i_sb->s_id);
-                               dput(alias);
+                               __d_move(new, dentry, false);
+                               write_sequnlock(&rename_lock);
+                               spin_unlock(&inode->i_lock);
+                               security_d_instantiate(new, inode);
                        }
-                       goto out_nolock;
+                       iput(inode);
+                       return new;
                }
        }
-
-       /* Add a unique reference */
-       actual = __d_instantiate_unique(dentry, inode);
-       if (!actual)
-               actual = dentry;
-
-       d_rehash(actual);
-found:
+       /* already taking inode->i_lock, so d_add() by hand */
+       __d_instantiate(dentry, inode);
        spin_unlock(&inode->i_lock);
-out_nolock:
-       if (actual == dentry) {
-               security_d_instantiate(dentry, inode);
-               return NULL;
-       }
-
-       iput(inode);
-       return actual;
+out:
+       security_d_instantiate(dentry, inode);
+       d_rehash(dentry);
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(d_materialise_unique);
+EXPORT_SYMBOL(d_splice_alias);
 
 static int prepend(char **buffer, int *buflen, const char *str, int namelen)
 {
index 1c2f1b84468bd26099747ccc15d634dcdd33c334..ee569da27b72aa4de8450f17696c774f283c3563 100644 (file)
@@ -230,7 +230,7 @@ extern seqlock_t rename_lock;
  */
 extern void d_instantiate(struct dentry *, struct inode *);
 extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
-extern struct dentry * d_materialise_unique(struct dentry *, struct inode *);
+#define d_materialise_unique(d, i) d_splice_alias(i, d)
 extern int d_instantiate_no_diralias(struct dentry *, struct inode *);
 extern void __d_drop(struct dentry *dentry);
 extern void d_drop(struct dentry *dentry);