aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-08 13:50:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-08 13:50:54 -0400
commitb8d4c1f9f48e344fe1d6e6ffae01d4b31bf0aac0 (patch)
tree24685a7b0ebf8af0ff55f1384e0be125aa29da47
parent090a81d8766e21d33ab3e4d24e6c8e5eedf086dd (diff)
parent49d31c2f389acfe83417083e1208422b4091cd9e (diff)
Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc filesystem updates from Al Viro: "Assorted normal VFS / filesystems stuff..." * 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: dentry name snapshots Make statfs properly return read-only state after emergency remount fs/dcache: init in_lookup_hashtable minix: Deinline get_block, save 2691 bytes fs: Reorder inode_owner_or_capable() to avoid needless fs: warn in case userspace lied about modprobe return
-rw-r--r--fs/dcache.c32
-rw-r--r--fs/debugfs/inode.c10
-rw-r--r--fs/filesystems.c4
-rw-r--r--fs/inode.c2
-rw-r--r--fs/minix/itree_common.c2
-rw-r--r--fs/namei.c10
-rw-r--r--fs/notify/fsnotify.c8
-rw-r--r--fs/statfs.c2
-rw-r--r--include/linux/dcache.h6
-rw-r--r--include/linux/fsnotify.h31
10 files changed, 61 insertions, 46 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index a140fe1dbb1a..7ece68d0d4db 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -277,6 +277,33 @@ static inline int dname_external(const struct dentry *dentry)
277 return dentry->d_name.name != dentry->d_iname; 277 return dentry->d_name.name != dentry->d_iname;
278} 278}
279 279
280void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry)
281{
282 spin_lock(&dentry->d_lock);
283 if (unlikely(dname_external(dentry))) {
284 struct external_name *p = external_name(dentry);
285 atomic_inc(&p->u.count);
286 spin_unlock(&dentry->d_lock);
287 name->name = p->name;
288 } else {
289 memcpy(name->inline_name, dentry->d_iname, DNAME_INLINE_LEN);
290 spin_unlock(&dentry->d_lock);
291 name->name = name->inline_name;
292 }
293}
294EXPORT_SYMBOL(take_dentry_name_snapshot);
295
296void release_dentry_name_snapshot(struct name_snapshot *name)
297{
298 if (unlikely(name->name != name->inline_name)) {
299 struct external_name *p;
300 p = container_of(name->name, struct external_name, name[0]);
301 if (unlikely(atomic_dec_and_test(&p->u.count)))
302 kfree_rcu(p, u.head);
303 }
304}
305EXPORT_SYMBOL(release_dentry_name_snapshot);
306
280static inline void __d_set_inode_and_type(struct dentry *dentry, 307static inline void __d_set_inode_and_type(struct dentry *dentry,
281 struct inode *inode, 308 struct inode *inode,
282 unsigned type_flags) 309 unsigned type_flags)
@@ -3598,6 +3625,11 @@ EXPORT_SYMBOL(d_genocide);
3598 3625
3599void __init vfs_caches_init_early(void) 3626void __init vfs_caches_init_early(void)
3600{ 3627{
3628 int i;
3629
3630 for (i = 0; i < ARRAY_SIZE(in_lookup_hashtable); i++)
3631 INIT_HLIST_BL_HEAD(&in_lookup_hashtable[i]);
3632
3601 dcache_init_early(); 3633 dcache_init_early();
3602 inode_init_early(); 3634 inode_init_early();
3603} 3635}
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 77440e4aa9d4..a0e4e2f7e0be 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -766,7 +766,7 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
766{ 766{
767 int error; 767 int error;
768 struct dentry *dentry = NULL, *trap; 768 struct dentry *dentry = NULL, *trap;
769 const char *old_name; 769 struct name_snapshot old_name;
770 770
771 trap = lock_rename(new_dir, old_dir); 771 trap = lock_rename(new_dir, old_dir);
772 /* Source or destination directories don't exist? */ 772 /* Source or destination directories don't exist? */
@@ -781,19 +781,19 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
781 if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry)) 781 if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry))
782 goto exit; 782 goto exit;
783 783
784 old_name = fsnotify_oldname_init(old_dentry->d_name.name); 784 take_dentry_name_snapshot(&old_name, old_dentry);
785 785
786 error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir), 786 error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir),
787 dentry, 0); 787 dentry, 0);
788 if (error) { 788 if (error) {
789 fsnotify_oldname_free(old_name); 789 release_dentry_name_snapshot(&old_name);
790 goto exit; 790 goto exit;
791 } 791 }
792 d_move(old_dentry, dentry); 792 d_move(old_dentry, dentry);
793 fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name, 793 fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name.name,
794 d_is_dir(old_dentry), 794 d_is_dir(old_dentry),
795 NULL, old_dentry); 795 NULL, old_dentry);
796 fsnotify_oldname_free(old_name); 796 release_dentry_name_snapshot(&old_name);
797 unlock_rename(new_dir, old_dir); 797 unlock_rename(new_dir, old_dir);
798 dput(dentry); 798 dput(dentry);
799 return old_dentry; 799 return old_dentry;
diff --git a/fs/filesystems.c b/fs/filesystems.c
index cac75547d35c..8b99955e3504 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -275,8 +275,10 @@ struct file_system_type *get_fs_type(const char *name)
275 int len = dot ? dot - name : strlen(name); 275 int len = dot ? dot - name : strlen(name);
276 276
277 fs = __get_fs_type(name, len); 277 fs = __get_fs_type(name, len);
278 if (!fs && (request_module("fs-%.*s", len, name) == 0)) 278 if (!fs && (request_module("fs-%.*s", len, name) == 0)) {
279 fs = __get_fs_type(name, len); 279 fs = __get_fs_type(name, len);
280 WARN_ONCE(!fs, "request_module fs-%.*s succeeded, but still no fs?\n", len, name);
281 }
280 282
281 if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) { 283 if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) {
282 put_filesystem(fs); 284 put_filesystem(fs);
diff --git a/fs/inode.c b/fs/inode.c
index 5cbc8e6e9390..50370599e371 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -2014,7 +2014,7 @@ bool inode_owner_or_capable(const struct inode *inode)
2014 return true; 2014 return true;
2015 2015
2016 ns = current_user_ns(); 2016 ns = current_user_ns();
2017 if (ns_capable(ns, CAP_FOWNER) && kuid_has_mapping(ns, inode->i_uid)) 2017 if (kuid_has_mapping(ns, inode->i_uid) && ns_capable(ns, CAP_FOWNER))
2018 return true; 2018 return true;
2019 return false; 2019 return false;
2020} 2020}
diff --git a/fs/minix/itree_common.c b/fs/minix/itree_common.c
index 4c57c9af6946..2d1ca08870f7 100644
--- a/fs/minix/itree_common.c
+++ b/fs/minix/itree_common.c
@@ -142,7 +142,7 @@ changed:
142 return -EAGAIN; 142 return -EAGAIN;
143} 143}
144 144
145static inline int get_block(struct inode * inode, sector_t block, 145static int get_block(struct inode * inode, sector_t block,
146 struct buffer_head *bh, int create) 146 struct buffer_head *bh, int create)
147{ 147{
148 int err = -EIO; 148 int err = -EIO;
diff --git a/fs/namei.c b/fs/namei.c
index 8bacc390c51e..e0b46eb0e212 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1008,7 +1008,7 @@ static int may_linkat(struct path *link)
1008 /* Source inode owner (or CAP_FOWNER) can hardlink all they like, 1008 /* Source inode owner (or CAP_FOWNER) can hardlink all they like,
1009 * otherwise, it must be a safe source. 1009 * otherwise, it must be a safe source.
1010 */ 1010 */
1011 if (inode_owner_or_capable(inode) || safe_hardlink_source(inode)) 1011 if (safe_hardlink_source(inode) || inode_owner_or_capable(inode))
1012 return 0; 1012 return 0;
1013 1013
1014 audit_log_link_denied("linkat", link); 1014 audit_log_link_denied("linkat", link);
@@ -4363,11 +4363,11 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
4363{ 4363{
4364 int error; 4364 int error;
4365 bool is_dir = d_is_dir(old_dentry); 4365 bool is_dir = d_is_dir(old_dentry);
4366 const unsigned char *old_name;
4367 struct inode *source = old_dentry->d_inode; 4366 struct inode *source = old_dentry->d_inode;
4368 struct inode *target = new_dentry->d_inode; 4367 struct inode *target = new_dentry->d_inode;
4369 bool new_is_dir = false; 4368 bool new_is_dir = false;
4370 unsigned max_links = new_dir->i_sb->s_max_links; 4369 unsigned max_links = new_dir->i_sb->s_max_links;
4370 struct name_snapshot old_name;
4371 4371
4372 if (source == target) 4372 if (source == target)
4373 return 0; 4373 return 0;
@@ -4414,7 +4414,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
4414 if (error) 4414 if (error)
4415 return error; 4415 return error;
4416 4416
4417 old_name = fsnotify_oldname_init(old_dentry->d_name.name); 4417 take_dentry_name_snapshot(&old_name, old_dentry);
4418 dget(new_dentry); 4418 dget(new_dentry);
4419 if (!is_dir || (flags & RENAME_EXCHANGE)) 4419 if (!is_dir || (flags & RENAME_EXCHANGE))
4420 lock_two_nondirectories(source, target); 4420 lock_two_nondirectories(source, target);
@@ -4469,14 +4469,14 @@ out:
4469 inode_unlock(target); 4469 inode_unlock(target);
4470 dput(new_dentry); 4470 dput(new_dentry);
4471 if (!error) { 4471 if (!error) {
4472 fsnotify_move(old_dir, new_dir, old_name, is_dir, 4472 fsnotify_move(old_dir, new_dir, old_name.name, is_dir,
4473 !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry); 4473 !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry);
4474 if (flags & RENAME_EXCHANGE) { 4474 if (flags & RENAME_EXCHANGE) {
4475 fsnotify_move(new_dir, old_dir, old_dentry->d_name.name, 4475 fsnotify_move(new_dir, old_dir, old_dentry->d_name.name,
4476 new_is_dir, NULL, new_dentry); 4476 new_is_dir, NULL, new_dentry);
4477 } 4477 }
4478 } 4478 }
4479 fsnotify_oldname_free(old_name); 4479 release_dentry_name_snapshot(&old_name);
4480 4480
4481 return error; 4481 return error;
4482} 4482}
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 01a9f0f007d4..0c4583b61717 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -161,16 +161,20 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask
161 if (unlikely(!fsnotify_inode_watches_children(p_inode))) 161 if (unlikely(!fsnotify_inode_watches_children(p_inode)))
162 __fsnotify_update_child_dentry_flags(p_inode); 162 __fsnotify_update_child_dentry_flags(p_inode);
163 else if (p_inode->i_fsnotify_mask & mask) { 163 else if (p_inode->i_fsnotify_mask & mask) {
164 struct name_snapshot name;
165
164 /* we are notifying a parent so come up with the new mask which 166 /* we are notifying a parent so come up with the new mask which
165 * specifies these are events which came from a child. */ 167 * specifies these are events which came from a child. */
166 mask |= FS_EVENT_ON_CHILD; 168 mask |= FS_EVENT_ON_CHILD;
167 169
170 take_dentry_name_snapshot(&name, dentry);
168 if (path) 171 if (path)
169 ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH, 172 ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
170 dentry->d_name.name, 0); 173 name.name, 0);
171 else 174 else
172 ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, 175 ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
173 dentry->d_name.name, 0); 176 name.name, 0);
177 release_dentry_name_snapshot(&name);
174 } 178 }
175 179
176 dput(parent); 180 dput(parent);
diff --git a/fs/statfs.c b/fs/statfs.c
index 41a6a82da5e2..fab9b6a3c116 100644
--- a/fs/statfs.c
+++ b/fs/statfs.c
@@ -38,6 +38,8 @@ static int flags_by_sb(int s_flags)
38 flags |= ST_SYNCHRONOUS; 38 flags |= ST_SYNCHRONOUS;
39 if (s_flags & MS_MANDLOCK) 39 if (s_flags & MS_MANDLOCK)
40 flags |= ST_MANDLOCK; 40 flags |= ST_MANDLOCK;
41 if (s_flags & MS_RDONLY)
42 flags |= ST_RDONLY;
41 return flags; 43 return flags;
42} 44}
43 45
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index d2e38dc6172c..025727bf6797 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -591,5 +591,11 @@ static inline struct inode *d_real_inode(const struct dentry *dentry)
591 return d_backing_inode(d_real((struct dentry *) dentry, NULL, 0)); 591 return d_backing_inode(d_real((struct dentry *) dentry, NULL, 0));
592} 592}
593 593
594struct name_snapshot {
595 const char *name;
596 char inline_name[DNAME_INLINE_LEN];
597};
598void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
599void release_dentry_name_snapshot(struct name_snapshot *);
594 600
595#endif /* __LINUX_DCACHE_H */ 601#endif /* __LINUX_DCACHE_H */
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index b43d3f5bd9ea..b78aa7ac77ce 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -293,35 +293,4 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
293 } 293 }
294} 294}
295 295
296#if defined(CONFIG_FSNOTIFY) /* notify helpers */
297
298/*
299 * fsnotify_oldname_init - save off the old filename before we change it
300 */
301static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name)
302{
303 return kstrdup(name, GFP_KERNEL);
304}
305
306/*
307 * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
308 */
309static inline void fsnotify_oldname_free(const unsigned char *old_name)
310{
311 kfree(old_name);
312}
313
314#else /* CONFIG_FSNOTIFY */
315
316static inline const char *fsnotify_oldname_init(const unsigned char *name)
317{
318 return NULL;
319}
320
321static inline void fsnotify_oldname_free(const unsigned char *old_name)
322{
323}
324
325#endif /* CONFIG_FSNOTIFY */
326
327#endif /* _LINUX_FS_NOTIFY_H */ 296#endif /* _LINUX_FS_NOTIFY_H */