diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-07 14:17:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-07 14:17:26 -0400 |
commit | 78438ce18f26dbcaa8993bb45d20ffb0cec3bc3e (patch) | |
tree | 2f6fe2eb05296a410a44ee7d602cafe2d202467b /fs/dcache.c | |
parent | 168e153d5ebbdd6a3fa85db1cc4879ed4b7030e0 (diff) | |
parent | ce285c267a003acbf607f3540ff71287f82e5282 (diff) |
Merge branch 'stable-fodder' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs stable fodder fixes from Al Viro:
- acct_on() fix for deadlock caught by overlayfs folks
- autofs RCU use-after-free SNAFU (->d_manage() can be called
locklessly, so we need to RCU-delay freeing the objects it looks at)
- (hopefully) the end of "do we need freeing this dentry RCU-delayed"
whack-a-mole.
* 'stable-fodder' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
autofs: fix use-after-free in lockless ->d_manage()
dcache: sort the freeing-without-RCU-delay mess for good.
acct_on(): don't mess with freeze protection
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index aac41adf4743..c663c602f9ef 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -344,7 +344,7 @@ static void dentry_free(struct dentry *dentry) | |||
344 | } | 344 | } |
345 | } | 345 | } |
346 | /* if dentry was never visible to RCU, immediate free is OK */ | 346 | /* if dentry was never visible to RCU, immediate free is OK */ |
347 | if (!(dentry->d_flags & DCACHE_RCUACCESS)) | 347 | if (dentry->d_flags & DCACHE_NORCU) |
348 | __d_free(&dentry->d_u.d_rcu); | 348 | __d_free(&dentry->d_u.d_rcu); |
349 | else | 349 | else |
350 | call_rcu(&dentry->d_u.d_rcu, __d_free); | 350 | call_rcu(&dentry->d_u.d_rcu, __d_free); |
@@ -1701,7 +1701,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
1701 | struct dentry *dentry = __d_alloc(parent->d_sb, name); | 1701 | struct dentry *dentry = __d_alloc(parent->d_sb, name); |
1702 | if (!dentry) | 1702 | if (!dentry) |
1703 | return NULL; | 1703 | return NULL; |
1704 | dentry->d_flags |= DCACHE_RCUACCESS; | ||
1705 | spin_lock(&parent->d_lock); | 1704 | spin_lock(&parent->d_lock); |
1706 | /* | 1705 | /* |
1707 | * don't need child lock because it is not subject | 1706 | * don't need child lock because it is not subject |
@@ -1726,7 +1725,7 @@ struct dentry *d_alloc_cursor(struct dentry * parent) | |||
1726 | { | 1725 | { |
1727 | struct dentry *dentry = d_alloc_anon(parent->d_sb); | 1726 | struct dentry *dentry = d_alloc_anon(parent->d_sb); |
1728 | if (dentry) { | 1727 | if (dentry) { |
1729 | dentry->d_flags |= DCACHE_RCUACCESS | DCACHE_DENTRY_CURSOR; | 1728 | dentry->d_flags |= DCACHE_DENTRY_CURSOR; |
1730 | dentry->d_parent = dget(parent); | 1729 | dentry->d_parent = dget(parent); |
1731 | } | 1730 | } |
1732 | return dentry; | 1731 | return dentry; |
@@ -1739,10 +1738,17 @@ struct dentry *d_alloc_cursor(struct dentry * parent) | |||
1739 | * | 1738 | * |
1740 | * For a filesystem that just pins its dentries in memory and never | 1739 | * For a filesystem that just pins its dentries in memory and never |
1741 | * performs lookups at all, return an unhashed IS_ROOT dentry. | 1740 | * performs lookups at all, return an unhashed IS_ROOT dentry. |
1741 | * This is used for pipes, sockets et.al. - the stuff that should | ||
1742 | * never be anyone's children or parents. Unlike all other | ||
1743 | * dentries, these will not have RCU delay between dropping the | ||
1744 | * last reference and freeing them. | ||
1742 | */ | 1745 | */ |
1743 | struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) | 1746 | struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) |
1744 | { | 1747 | { |
1745 | return __d_alloc(sb, name); | 1748 | struct dentry *dentry = __d_alloc(sb, name); |
1749 | if (likely(dentry)) | ||
1750 | dentry->d_flags |= DCACHE_NORCU; | ||
1751 | return dentry; | ||
1746 | } | 1752 | } |
1747 | EXPORT_SYMBOL(d_alloc_pseudo); | 1753 | EXPORT_SYMBOL(d_alloc_pseudo); |
1748 | 1754 | ||
@@ -1911,12 +1917,10 @@ struct dentry *d_make_root(struct inode *root_inode) | |||
1911 | 1917 | ||
1912 | if (root_inode) { | 1918 | if (root_inode) { |
1913 | res = d_alloc_anon(root_inode->i_sb); | 1919 | res = d_alloc_anon(root_inode->i_sb); |
1914 | if (res) { | 1920 | if (res) |
1915 | res->d_flags |= DCACHE_RCUACCESS; | ||
1916 | d_instantiate(res, root_inode); | 1921 | d_instantiate(res, root_inode); |
1917 | } else { | 1922 | else |
1918 | iput(root_inode); | 1923 | iput(root_inode); |
1919 | } | ||
1920 | } | 1924 | } |
1921 | return res; | 1925 | return res; |
1922 | } | 1926 | } |
@@ -2781,9 +2785,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target, | |||
2781 | copy_name(dentry, target); | 2785 | copy_name(dentry, target); |
2782 | target->d_hash.pprev = NULL; | 2786 | target->d_hash.pprev = NULL; |
2783 | dentry->d_parent->d_lockref.count++; | 2787 | dentry->d_parent->d_lockref.count++; |
2784 | if (dentry == old_parent) | 2788 | if (dentry != old_parent) /* wasn't IS_ROOT */ |
2785 | dentry->d_flags |= DCACHE_RCUACCESS; | ||
2786 | else | ||
2787 | WARN_ON(!--old_parent->d_lockref.count); | 2789 | WARN_ON(!--old_parent->d_lockref.count); |
2788 | } else { | 2790 | } else { |
2789 | target->d_parent = old_parent; | 2791 | target->d_parent = old_parent; |