diff options
-rw-r--r-- | Documentation/filesystems/porting | 5 | ||||
-rw-r--r-- | fs/autofs/autofs_i.h | 1 | ||||
-rw-r--r-- | fs/autofs/inode.c | 2 | ||||
-rw-r--r-- | fs/dcache.c | 24 | ||||
-rw-r--r-- | fs/internal.h | 2 | ||||
-rw-r--r-- | fs/nsfs.c | 3 | ||||
-rw-r--r-- | include/linux/dcache.h | 2 | ||||
-rw-r--r-- | include/linux/mount.h | 2 | ||||
-rw-r--r-- | kernel/acct.c | 4 |
9 files changed, 26 insertions, 19 deletions
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index b8d3ddd8b8db..d392d4b0c393 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting | |||
@@ -663,3 +663,8 @@ in your dentry operations instead. | |||
663 | there, but that's it. Freeing memory in the callback is fine; doing | 663 | there, but that's it. Freeing memory in the callback is fine; doing |
664 | more than that is possible, but requires a lot of care and is best | 664 | more than that is possible, but requires a lot of care and is best |
665 | avoided. | 665 | avoided. |
666 | -- | ||
667 | [mandatory] | ||
668 | DCACHE_RCUACCESS is gone; having an RCU delay on dentry freeing is the | ||
669 | default. DCACHE_NORCU opts out, and only d_alloc_pseudo() has any | ||
670 | business doing so. | ||
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h index 70c132acdab1..e1091312abe1 100644 --- a/fs/autofs/autofs_i.h +++ b/fs/autofs/autofs_i.h | |||
@@ -71,6 +71,7 @@ struct autofs_info { | |||
71 | 71 | ||
72 | kuid_t uid; | 72 | kuid_t uid; |
73 | kgid_t gid; | 73 | kgid_t gid; |
74 | struct rcu_head rcu; | ||
74 | }; | 75 | }; |
75 | 76 | ||
76 | #define AUTOFS_INF_EXPIRING (1<<0) /* dentry in the process of expiring */ | 77 | #define AUTOFS_INF_EXPIRING (1<<0) /* dentry in the process of expiring */ |
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index 80597b88718b..fb0225f21c12 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c | |||
@@ -36,7 +36,7 @@ void autofs_clean_ino(struct autofs_info *ino) | |||
36 | 36 | ||
37 | void autofs_free_ino(struct autofs_info *ino) | 37 | void autofs_free_ino(struct autofs_info *ino) |
38 | { | 38 | { |
39 | kfree(ino); | 39 | kfree_rcu(ino, rcu); |
40 | } | 40 | } |
41 | 41 | ||
42 | void autofs_kill_sb(struct super_block *sb) | 42 | void autofs_kill_sb(struct super_block *sb) |
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; |
diff --git a/fs/internal.h b/fs/internal.h index 6a8b71643af4..2e7362837a6e 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -89,9 +89,7 @@ extern int sb_prepare_remount_readonly(struct super_block *); | |||
89 | 89 | ||
90 | extern void __init mnt_init(void); | 90 | extern void __init mnt_init(void); |
91 | 91 | ||
92 | extern int __mnt_want_write(struct vfsmount *); | ||
93 | extern int __mnt_want_write_file(struct file *); | 92 | extern int __mnt_want_write_file(struct file *); |
94 | extern void __mnt_drop_write(struct vfsmount *); | ||
95 | extern void __mnt_drop_write_file(struct file *); | 93 | extern void __mnt_drop_write_file(struct file *); |
96 | 94 | ||
97 | /* | 95 | /* |
@@ -85,13 +85,12 @@ slow: | |||
85 | inode->i_fop = &ns_file_operations; | 85 | inode->i_fop = &ns_file_operations; |
86 | inode->i_private = ns; | 86 | inode->i_private = ns; |
87 | 87 | ||
88 | dentry = d_alloc_pseudo(mnt->mnt_sb, &empty_name); | 88 | dentry = d_alloc_anon(mnt->mnt_sb); |
89 | if (!dentry) { | 89 | if (!dentry) { |
90 | iput(inode); | 90 | iput(inode); |
91 | return ERR_PTR(-ENOMEM); | 91 | return ERR_PTR(-ENOMEM); |
92 | } | 92 | } |
93 | d_instantiate(dentry, inode); | 93 | d_instantiate(dentry, inode); |
94 | dentry->d_flags |= DCACHE_RCUACCESS; | ||
95 | dentry->d_fsdata = (void *)ns->ops; | 94 | dentry->d_fsdata = (void *)ns->ops; |
96 | d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); | 95 | d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); |
97 | if (d) { | 96 | if (d) { |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 60996e64c579..6e1e8e6602c6 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -176,7 +176,6 @@ struct dentry_operations { | |||
176 | * typically using d_splice_alias. */ | 176 | * typically using d_splice_alias. */ |
177 | 177 | ||
178 | #define DCACHE_REFERENCED 0x00000040 /* Recently used, don't discard. */ | 178 | #define DCACHE_REFERENCED 0x00000040 /* Recently used, don't discard. */ |
179 | #define DCACHE_RCUACCESS 0x00000080 /* Entry has ever been RCU-visible */ | ||
180 | 179 | ||
181 | #define DCACHE_CANT_MOUNT 0x00000100 | 180 | #define DCACHE_CANT_MOUNT 0x00000100 |
182 | #define DCACHE_GENOCIDE 0x00000200 | 181 | #define DCACHE_GENOCIDE 0x00000200 |
@@ -217,6 +216,7 @@ struct dentry_operations { | |||
217 | 216 | ||
218 | #define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */ | 217 | #define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */ |
219 | #define DCACHE_DENTRY_CURSOR 0x20000000 | 218 | #define DCACHE_DENTRY_CURSOR 0x20000000 |
219 | #define DCACHE_NORCU 0x40000000 /* No RCU delay for freeing */ | ||
220 | 220 | ||
221 | extern seqlock_t rename_lock; | 221 | extern seqlock_t rename_lock; |
222 | 222 | ||
diff --git a/include/linux/mount.h b/include/linux/mount.h index 9197ddbf35fb..bf8cc4108b8f 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
@@ -87,6 +87,8 @@ extern bool mnt_may_suid(struct vfsmount *mnt); | |||
87 | 87 | ||
88 | struct path; | 88 | struct path; |
89 | extern struct vfsmount *clone_private_mount(const struct path *path); | 89 | extern struct vfsmount *clone_private_mount(const struct path *path); |
90 | extern int __mnt_want_write(struct vfsmount *); | ||
91 | extern void __mnt_drop_write(struct vfsmount *); | ||
90 | 92 | ||
91 | struct file_system_type; | 93 | struct file_system_type; |
92 | extern struct vfsmount *fc_mount(struct fs_context *fc); | 94 | extern struct vfsmount *fc_mount(struct fs_context *fc); |
diff --git a/kernel/acct.c b/kernel/acct.c index addf7732fb56..81f9831a7859 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
@@ -227,7 +227,7 @@ static int acct_on(struct filename *pathname) | |||
227 | filp_close(file, NULL); | 227 | filp_close(file, NULL); |
228 | return PTR_ERR(internal); | 228 | return PTR_ERR(internal); |
229 | } | 229 | } |
230 | err = mnt_want_write(internal); | 230 | err = __mnt_want_write(internal); |
231 | if (err) { | 231 | if (err) { |
232 | mntput(internal); | 232 | mntput(internal); |
233 | kfree(acct); | 233 | kfree(acct); |
@@ -252,7 +252,7 @@ static int acct_on(struct filename *pathname) | |||
252 | old = xchg(&ns->bacct, &acct->pin); | 252 | old = xchg(&ns->bacct, &acct->pin); |
253 | mutex_unlock(&acct->lock); | 253 | mutex_unlock(&acct->lock); |
254 | pin_kill(old); | 254 | pin_kill(old); |
255 | mnt_drop_write(mnt); | 255 | __mnt_drop_write(mnt); |
256 | mntput(mnt); | 256 | mntput(mnt); |
257 | return 0; | 257 | return 0; |
258 | } | 258 | } |