diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-08 13:50:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-08 13:50:54 -0400 |
commit | b8d4c1f9f48e344fe1d6e6ffae01d4b31bf0aac0 (patch) | |
tree | 24685a7b0ebf8af0ff55f1384e0be125aa29da47 | |
parent | 090a81d8766e21d33ab3e4d24e6c8e5eedf086dd (diff) | |
parent | 49d31c2f389acfe83417083e1208422b4091cd9e (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.c | 32 | ||||
-rw-r--r-- | fs/debugfs/inode.c | 10 | ||||
-rw-r--r-- | fs/filesystems.c | 4 | ||||
-rw-r--r-- | fs/inode.c | 2 | ||||
-rw-r--r-- | fs/minix/itree_common.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 10 | ||||
-rw-r--r-- | fs/notify/fsnotify.c | 8 | ||||
-rw-r--r-- | fs/statfs.c | 2 | ||||
-rw-r--r-- | include/linux/dcache.h | 6 | ||||
-rw-r--r-- | include/linux/fsnotify.h | 31 |
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 | ||
280 | void 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 | } | ||
294 | EXPORT_SYMBOL(take_dentry_name_snapshot); | ||
295 | |||
296 | void 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 | } | ||
305 | EXPORT_SYMBOL(release_dentry_name_snapshot); | ||
306 | |||
280 | static inline void __d_set_inode_and_type(struct dentry *dentry, | 307 | static 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 | ||
3599 | void __init vfs_caches_init_early(void) | 3626 | void __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 | ||
145 | static inline int get_block(struct inode * inode, sector_t block, | 145 | static 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 | ||
594 | struct name_snapshot { | ||
595 | const char *name; | ||
596 | char inline_name[DNAME_INLINE_LEN]; | ||
597 | }; | ||
598 | void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *); | ||
599 | void 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 | */ | ||
301 | static 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 | */ | ||
309 | static inline void fsnotify_oldname_free(const unsigned char *old_name) | ||
310 | { | ||
311 | kfree(old_name); | ||
312 | } | ||
313 | |||
314 | #else /* CONFIG_FSNOTIFY */ | ||
315 | |||
316 | static inline const char *fsnotify_oldname_init(const unsigned char *name) | ||
317 | { | ||
318 | return NULL; | ||
319 | } | ||
320 | |||
321 | static 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 */ |