Merge branch 'work.autofs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 Sep 2019 17:14:22 +0000 (10:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 19 Sep 2019 17:14:22 +0000 (10:14 -0700)
Pull autofs updates from Al Viro:
 "The most interesting part here is getting rid of the last trylock loop
  on dentry->d_lock.

  The ones in fs/dcache.c had been dealt with several years ago, but
  there'd been leftovers in fs/autofs/expire.c"

* 'work.autofs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  autofs_lookup(): hold ->d_lock over playing with ->d_flags
  get rid of autofs_info->active_count
  autofs: simplify get_next_positive_...(), get rid of trylocks

fs/autofs/autofs_i.h
fs/autofs/expire.c
fs/autofs/root.c

index 8c0c11181fad765159309246ca075e19701d1c88..8bcec8dcabb67787930e5932ce7d6c8a6c18b353 100644 (file)
@@ -58,7 +58,6 @@ struct autofs_info {
        struct completion expire_complete;
 
        struct list_head active;
-       int active_count;
 
        struct list_head expiring;
 
index cdff0567aacb34eec648ccf648b531bfde26c455..2866fabf497f2e770116b46a2f87ed5eecbe3f04 100644 (file)
@@ -70,6 +70,27 @@ done:
        return status;
 }
 
+/* p->d_lock held */
+static struct dentry *positive_after(struct dentry *p, struct dentry *child)
+{
+       if (child)
+               child = list_next_entry(child, d_child);
+       else
+               child = list_first_entry(&p->d_subdirs, struct dentry, d_child);
+
+       list_for_each_entry_from(child, &p->d_subdirs, d_child) {
+               spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
+               if (simple_positive(child)) {
+                       dget_dlock(child);
+                       spin_unlock(&child->d_lock);
+                       return child;
+               }
+               spin_unlock(&child->d_lock);
+       }
+
+       return NULL;
+}
+
 /*
  * Calculate and dget next entry in the subdirs list under root.
  */
@@ -77,43 +98,14 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
                                               struct dentry *root)
 {
        struct autofs_sb_info *sbi = autofs_sbi(root->d_sb);
-       struct list_head *next;
        struct dentry *q;
 
        spin_lock(&sbi->lookup_lock);
        spin_lock(&root->d_lock);
-
-       if (prev)
-               next = prev->d_child.next;
-       else {
-               prev = dget_dlock(root);
-               next = prev->d_subdirs.next;
-       }
-
-cont:
-       if (next == &root->d_subdirs) {
-               spin_unlock(&root->d_lock);
-               spin_unlock(&sbi->lookup_lock);
-               dput(prev);
-               return NULL;
-       }
-
-       q = list_entry(next, struct dentry, d_child);
-
-       spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
-       /* Already gone or negative dentry (under construction) - try next */
-       if (!d_count(q) || !simple_positive(q)) {
-               spin_unlock(&q->d_lock);
-               next = q->d_child.next;
-               goto cont;
-       }
-       dget_dlock(q);
-       spin_unlock(&q->d_lock);
+       q = positive_after(root, prev);
        spin_unlock(&root->d_lock);
        spin_unlock(&sbi->lookup_lock);
-
        dput(prev);
-
        return q;
 }
 
@@ -124,59 +116,28 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev,
                                               struct dentry *root)
 {
        struct autofs_sb_info *sbi = autofs_sbi(root->d_sb);
-       struct list_head *next;
-       struct dentry *p, *ret;
+       struct dentry *p = prev, *ret = NULL, *d = NULL;
 
        if (prev == NULL)
                return dget(root);
 
        spin_lock(&sbi->lookup_lock);
-relock:
-       p = prev;
        spin_lock(&p->d_lock);
-again:
-       next = p->d_subdirs.next;
-       if (next == &p->d_subdirs) {
-               while (1) {
-                       struct dentry *parent;
-
-                       if (p == root) {
-                               spin_unlock(&p->d_lock);
-                               spin_unlock(&sbi->lookup_lock);
-                               dput(prev);
-                               return NULL;
-                       }
+       while (1) {
+               struct dentry *parent;
 
-                       parent = p->d_parent;
-                       if (!spin_trylock(&parent->d_lock)) {
-                               spin_unlock(&p->d_lock);
-                               cpu_relax();
-                               goto relock;
-                       }
-                       spin_unlock(&p->d_lock);
-                       next = p->d_child.next;
-                       p = parent;
-                       if (next != &parent->d_subdirs)
-                               break;
-               }
-       }
-       ret = list_entry(next, struct dentry, d_child);
-
-       spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
-       /* Negative dentry - try next */
-       if (!simple_positive(ret)) {
+               ret = positive_after(p, d);
+               if (ret || p == root)
+                       break;
+               parent = p->d_parent;
                spin_unlock(&p->d_lock);
-               lock_set_subclass(&ret->d_lock.dep_map, 0, _RET_IP_);
-               p = ret;
-               goto again;
+               spin_lock(&parent->d_lock);
+               d = p;
+               p = parent;
        }
-       dget_dlock(ret);
-       spin_unlock(&ret->d_lock);
        spin_unlock(&p->d_lock);
        spin_unlock(&sbi->lookup_lock);
-
        dput(prev);
-
        return ret;
 }
 
index e646569c75eda3a9d47674dca2c2b3b1a778dfc7..29abafc0ce31271c9684e83b383fca007198c669 100644 (file)
@@ -60,38 +60,15 @@ const struct dentry_operations autofs_dentry_operations = {
        .d_release      = autofs_dentry_release,
 };
 
-static void autofs_add_active(struct dentry *dentry)
-{
-       struct autofs_sb_info *sbi = autofs_sbi(dentry->d_sb);
-       struct autofs_info *ino;
-
-       ino = autofs_dentry_ino(dentry);
-       if (ino) {
-               spin_lock(&sbi->lookup_lock);
-               if (!ino->active_count) {
-                       if (list_empty(&ino->active))
-                               list_add(&ino->active, &sbi->active_list);
-               }
-               ino->active_count++;
-               spin_unlock(&sbi->lookup_lock);
-       }
-}
-
 static void autofs_del_active(struct dentry *dentry)
 {
        struct autofs_sb_info *sbi = autofs_sbi(dentry->d_sb);
        struct autofs_info *ino;
 
        ino = autofs_dentry_ino(dentry);
-       if (ino) {
-               spin_lock(&sbi->lookup_lock);
-               ino->active_count--;
-               if (!ino->active_count) {
-                       if (!list_empty(&ino->active))
-                               list_del_init(&ino->active);
-               }
-               spin_unlock(&sbi->lookup_lock);
-       }
+       spin_lock(&sbi->lookup_lock);
+       list_del_init(&ino->active);
+       spin_unlock(&sbi->lookup_lock);
 }
 
 static int autofs_dir_open(struct inode *inode, struct file *file)
@@ -527,19 +504,22 @@ static struct dentry *autofs_lookup(struct inode *dir,
                if (!autofs_oz_mode(sbi) && !IS_ROOT(dentry->d_parent))
                        return ERR_PTR(-ENOENT);
 
-               /* Mark entries in the root as mount triggers */
-               if (IS_ROOT(dentry->d_parent) &&
-                   autofs_type_indirect(sbi->type))
-                       __managed_dentry_set_managed(dentry);
-
                ino = autofs_new_ino(sbi);
                if (!ino)
                        return ERR_PTR(-ENOMEM);
 
+               spin_lock(&sbi->lookup_lock);
+               spin_lock(&dentry->d_lock);
+               /* Mark entries in the root as mount triggers */
+               if (IS_ROOT(dentry->d_parent) &&
+                   autofs_type_indirect(sbi->type))
+                       __managed_dentry_set_managed(dentry);
                dentry->d_fsdata = ino;
                ino->dentry = dentry;
 
-               autofs_add_active(dentry);
+               list_add(&ino->active, &sbi->active_list);
+               spin_unlock(&sbi->lookup_lock);
+               spin_unlock(&dentry->d_lock);
        }
        return NULL;
 }