nfsd: fix fi_delegees leak when fi_had_conflict returns true
[cascardo/linux.git] / fs / dcache.c
index 5bc72b0..e368d4f 100644 (file)
@@ -44,7 +44,7 @@
 /*
  * Usage:
  * dcache->d_inode->i_lock protects:
- *   - i_dentry, d_alias, d_inode of aliases
+ *   - i_dentry, d_u.d_alias, d_inode of aliases
  * dcache_hash_bucket lock protects:
  *   - the dcache hash table
  * s_anon bl list spinlock protects:
@@ -59,7 +59,7 @@
  *   - d_unhashed()
  *   - d_parent and d_subdirs
  *   - childrens' d_child and d_parent
- *   - d_alias, d_inode
+ *   - d_u.d_alias, d_inode
  *
  * Ordering:
  * dentry->d_inode->i_lock
@@ -252,14 +252,12 @@ static void __d_free(struct rcu_head *head)
 {
        struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
 
-       WARN_ON(!hlist_unhashed(&dentry->d_alias));
        kmem_cache_free(dentry_cache, dentry); 
 }
 
 static void __d_free_external(struct rcu_head *head)
 {
        struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
-       WARN_ON(!hlist_unhashed(&dentry->d_alias));
        kfree(external_name(dentry));
        kmem_cache_free(dentry_cache, dentry); 
 }
@@ -271,6 +269,7 @@ static inline int dname_external(const struct dentry *dentry)
 
 static void dentry_free(struct dentry *dentry)
 {
+       WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
        if (unlikely(dname_external(dentry))) {
                struct external_name *p = external_name(dentry);
                if (likely(atomic_dec_and_test(&p->u.count))) {
@@ -311,7 +310,7 @@ static void dentry_iput(struct dentry * dentry)
        struct inode *inode = dentry->d_inode;
        if (inode) {
                dentry->d_inode = NULL;
-               hlist_del_init(&dentry->d_alias);
+               hlist_del_init(&dentry->d_u.d_alias);
                spin_unlock(&dentry->d_lock);
                spin_unlock(&inode->i_lock);
                if (!inode->i_nlink)
@@ -336,7 +335,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
        struct inode *inode = dentry->d_inode;
        __d_clear_type(dentry);
        dentry->d_inode = NULL;
-       hlist_del_init(&dentry->d_alias);
+       hlist_del_init(&dentry->d_u.d_alias);
        dentry_rcuwalk_barrier(dentry);
        spin_unlock(&dentry->d_lock);
        spin_unlock(&inode->i_lock);
@@ -496,7 +495,7 @@ static void __dentry_kill(struct dentry *dentry)
        }
        /* if it was on the hash then remove it */
        __d_drop(dentry);
-       list_del(&dentry->d_u.d_child);
+       __list_del_entry(&dentry->d_child);
        /*
         * Inform d_walk() that we are no longer attached to the
         * dentry tree
@@ -722,7 +721,7 @@ static struct dentry *__d_find_alias(struct inode *inode)
 
 again:
        discon_alias = NULL;
-       hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
                spin_lock(&alias->d_lock);
                if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
                        if (IS_ROOT(alias) &&
@@ -772,7 +771,7 @@ void d_prune_aliases(struct inode *inode)
        struct dentry *dentry;
 restart:
        spin_lock(&inode->i_lock);
-       hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
                spin_lock(&dentry->d_lock);
                if (!dentry->d_lockref.count) {
                        struct dentry *parent = lock_parent(dentry);
@@ -1051,7 +1050,7 @@ repeat:
 resume:
        while (next != &this_parent->d_subdirs) {
                struct list_head *tmp = next;
-               struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
+               struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
                next = tmp->next;
 
                spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
@@ -1083,33 +1082,31 @@ resume:
        /*
         * All done at this level ... ascend and resume the search.
         */
+       rcu_read_lock();
+ascend:
        if (this_parent != parent) {
                struct dentry *child = this_parent;
                this_parent = child->d_parent;
 
-               rcu_read_lock();
                spin_unlock(&child->d_lock);
                spin_lock(&this_parent->d_lock);
 
-               /*
-                * might go back up the wrong parent if we have had a rename
-                * or deletion
-                */
-               if (this_parent != child->d_parent ||
-                        (child->d_flags & DCACHE_DENTRY_KILLED) ||
-                        need_seqretry(&rename_lock, seq)) {
-                       spin_unlock(&this_parent->d_lock);
-                       rcu_read_unlock();
+               /* might go back up the wrong parent if we have had a rename. */
+               if (need_seqretry(&rename_lock, seq))
                        goto rename_retry;
+               next = child->d_child.next;
+               while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+                       if (next == &this_parent->d_subdirs)
+                               goto ascend;
+                       child = list_entry(next, struct dentry, d_child);
+                       next = next->next;
                }
                rcu_read_unlock();
-               next = child->d_u.d_child.next;
                goto resume;
        }
-       if (need_seqretry(&rename_lock, seq)) {
-               spin_unlock(&this_parent->d_lock);
+       if (need_seqretry(&rename_lock, seq))
                goto rename_retry;
-       }
+       rcu_read_unlock();
        if (finish)
                finish(data);
 
@@ -1119,6 +1116,9 @@ out_unlock:
        return;
 
 rename_retry:
+       spin_unlock(&this_parent->d_lock);
+       rcu_read_unlock();
+       BUG_ON(seq & 1);
        if (!retry)
                return;
        seq = 1;
@@ -1455,8 +1455,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
        INIT_HLIST_BL_NODE(&dentry->d_hash);
        INIT_LIST_HEAD(&dentry->d_lru);
        INIT_LIST_HEAD(&dentry->d_subdirs);
-       INIT_HLIST_NODE(&dentry->d_alias);
-       INIT_LIST_HEAD(&dentry->d_u.d_child);
+       INIT_HLIST_NODE(&dentry->d_u.d_alias);
+       INIT_LIST_HEAD(&dentry->d_child);
        d_set_d_op(dentry, dentry->d_sb->s_d_op);
 
        this_cpu_inc(nr_dentry);
@@ -1486,7 +1486,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
         */
        __dget_dlock(parent);
        dentry->d_parent = parent;
-       list_add(&dentry->d_u.d_child, &parent->d_subdirs);
+       list_add(&dentry->d_child, &parent->d_subdirs);
        spin_unlock(&parent->d_lock);
 
        return dentry;
@@ -1579,7 +1579,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
        spin_lock(&dentry->d_lock);
        __d_set_type(dentry, add_flags);
        if (inode)
-               hlist_add_head(&dentry->d_alias, &inode->i_dentry);
+               hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
        dentry->d_inode = inode;
        dentry_rcuwalk_barrier(dentry);
        spin_unlock(&dentry->d_lock);
@@ -1603,7 +1603,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
  
 void d_instantiate(struct dentry *entry, struct inode * inode)
 {
-       BUG_ON(!hlist_unhashed(&entry->d_alias));
+       BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
        if (inode)
                spin_lock(&inode->i_lock);
        __d_instantiate(entry, inode);
@@ -1642,7 +1642,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
                return NULL;
        }
 
-       hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
                /*
                 * Don't need alias->d_lock here, because aliases with
                 * d_parent == entry->d_parent are not subject to name or
@@ -1668,7 +1668,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
 {
        struct dentry *result;
 
-       BUG_ON(!hlist_unhashed(&entry->d_alias));
+       BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
 
        if (inode)
                spin_lock(&inode->i_lock);
@@ -1699,7 +1699,7 @@ EXPORT_SYMBOL(d_instantiate_unique);
  */
 int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
 {
-       BUG_ON(!hlist_unhashed(&entry->d_alias));
+       BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
 
        spin_lock(&inode->i_lock);
        if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
@@ -1738,7 +1738,7 @@ static struct dentry * __d_find_any_alias(struct inode *inode)
 
        if (hlist_empty(&inode->i_dentry))
                return NULL;
-       alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+       alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
        __dget(alias);
        return alias;
 }
@@ -1800,7 +1800,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
        spin_lock(&tmp->d_lock);
        tmp->d_inode = inode;
        tmp->d_flags |= add_flags;
-       hlist_add_head(&tmp->d_alias, &inode->i_dentry);
+       hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry);
        hlist_bl_lock(&tmp->d_sb->s_anon);
        hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
        hlist_bl_unlock(&tmp->d_sb->s_anon);
@@ -1889,51 +1889,19 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
         * if not go ahead and create it now.
         */
        found = d_hash_and_lookup(dentry->d_parent, name);
-       if (unlikely(IS_ERR(found)))
-               goto err_out;
        if (!found) {
                new = d_alloc(dentry->d_parent, name);
                if (!new) {
                        found = ERR_PTR(-ENOMEM);
-                       goto err_out;
-               }
-
-               found = d_splice_alias(inode, new);
-               if (found) {
-                       dput(new);
-                       return found;
-               }
-               return new;
-       }
-
-       /*
-        * If a matching dentry exists, and it's not negative use it.
-        *
-        * Decrement the reference count to balance the iget() done
-        * earlier on.
-        */
-       if (found->d_inode) {
-               if (unlikely(found->d_inode != inode)) {
-                       /* This can't happen because bad inodes are unhashed. */
-                       BUG_ON(!is_bad_inode(inode));
-                       BUG_ON(!is_bad_inode(found->d_inode));
+               } else {
+                       found = d_splice_alias(inode, new);
+                       if (found) {
+                               dput(new);
+                               return found;
+                       }
+                       return new;
                }
-               iput(inode);
-               return found;
        }
-
-       /*
-        * Negative dentry: instantiate it unless the inode is a directory and
-        * already has a dentry.
-        */
-       new = d_splice_alias(inode, found);
-       if (new) {
-               dput(found);
-               found = new;
-       }
-       return found;
-
-err_out:
        iput(inode);
        return found;
 }
@@ -2235,7 +2203,7 @@ int d_validate(struct dentry *dentry, struct dentry *dparent)
        struct dentry *child;
 
        spin_lock(&dparent->d_lock);
-       list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) {
+       list_for_each_entry(child, &dparent->d_subdirs, d_child) {
                if (dentry == child) {
                        spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
                        __dget_dlock(dentry);
@@ -2393,6 +2361,8 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
                         */
                        unsigned int i;
                        BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long)));
+                       kmemcheck_mark_initialized(dentry->d_iname, DNAME_INLINE_LEN);
+                       kmemcheck_mark_initialized(target->d_iname, DNAME_INLINE_LEN);
                        for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) {
                                swap(((long *) &dentry->d_iname)[i],
                                     ((long *) &target->d_iname)[i]);
@@ -2526,13 +2496,13 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
                /* splicing a tree */
                dentry->d_parent = target->d_parent;
                target->d_parent = target;
-               list_del_init(&target->d_u.d_child);
-               list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+               list_del_init(&target->d_child);
+               list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
        } else {
                /* swapping two dentries */
                swap(dentry->d_parent, target->d_parent);
-               list_move(&target->d_u.d_child, &target->d_parent->d_subdirs);
-               list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+               list_move(&target->d_child, &target->d_parent->d_subdirs);
+               list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
                if (exchange)
                        fsnotify_d_move(target);
                fsnotify_d_move(dentry);
@@ -2608,11 +2578,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)
@@ -2627,7 +2597,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)
@@ -2662,130 +2632,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)
 {
@@ -3321,7 +3218,7 @@ void d_tmpfile(struct dentry *dentry, struct inode *inode)
 {
        inode_dec_link_count(inode);
        BUG_ON(dentry->d_name.name != dentry->d_iname ||
-               !hlist_unhashed(&dentry->d_alias) ||
+               !hlist_unhashed(&dentry->d_u.d_alias) ||
                !d_unlinked(dentry));
        spin_lock(&dentry->d_parent->d_lock);
        spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);