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 */ |
