aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-11 14:44:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-11 14:44:11 -0400
commitf6f993328b2abcab86a3c99d7bd9f2066ab03d36 (patch)
treeea6f3902a0fa546493731b3b52a31d98cc747a90 /fs/namespace.c
parentc7a19c795b4b0a3232c157ed29eea85077e95da6 (diff)
parent12a5b5294cb1896e9a3c9fca8ff5a7e3def4e8c6 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs updates from Al Viro: "Stuff in here: - acct.c fixes and general rework of mnt_pin mechanism. That allows to go for delayed-mntput stuff, which will permit mntput() on deep stack without worrying about stack overflows - fs shutdown will happen on shallow stack. IOW, we can do Eric's umount-on-rmdir series without introducing tons of stack overflows on new mntput() call chains it introduces. - Bruce's d_splice_alias() patches - more Miklos' rename() stuff. - a couple of regression fixes (stable fodder, in the end of branch) and a fix for API idiocy in iov_iter.c. There definitely will be another pile, maybe even two. I'd like to get Eric's series in this time, but even if we miss it, it'll go right in the beginning of for-next in the next cycle - the tricky part of prereqs is in this pile" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (40 commits) fix copy_tree() regression __generic_file_write_iter(): fix handling of sync error after DIO switch iov_iter_get_pages() to passing maximal number of pages fs: mark __d_obtain_alias static dcache: d_splice_alias should detect loops exportfs: update Exporting documentation dcache: d_find_alias needn't recheck IS_ROOT && DCACHE_DISCONNECTED dcache: remove unused d_find_alias parameter dcache: d_obtain_alias callers don't all want DISCONNECTED dcache: d_splice_alias should ignore DCACHE_DISCONNECTED dcache: d_splice_alias mustn't create directory aliases dcache: close d_move race in d_splice_alias dcache: move d_splice_alias namei: trivial fix to vfs_rename_dir comment VFS: allow ->d_manage() to declare -EISDIR in rcu_walk mode. cifs: support RENAME_NOREPLACE hostfs: support rename flags shmem: support RENAME_EXCHANGE shmem: support RENAME_NOREPLACE btrfs: add RENAME_NOREPLACE ...
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c67
1 files changed, 33 insertions, 34 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 0acabea58319..a01c7730e9af 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -16,7 +16,6 @@
16#include <linux/namei.h> 16#include <linux/namei.h>
17#include <linux/security.h> 17#include <linux/security.h>
18#include <linux/idr.h> 18#include <linux/idr.h>
19#include <linux/acct.h> /* acct_auto_close_mnt */
20#include <linux/init.h> /* init_rootfs */ 19#include <linux/init.h> /* init_rootfs */
21#include <linux/fs_struct.h> /* get_fs_root et.al. */ 20#include <linux/fs_struct.h> /* get_fs_root et.al. */
22#include <linux/fsnotify.h> /* fsnotify_vfsmount_delete */ 21#include <linux/fsnotify.h> /* fsnotify_vfsmount_delete */
@@ -779,6 +778,20 @@ static void attach_mnt(struct mount *mnt,
779 list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); 778 list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
780} 779}
781 780
781static void attach_shadowed(struct mount *mnt,
782 struct mount *parent,
783 struct mount *shadows)
784{
785 if (shadows) {
786 hlist_add_behind_rcu(&mnt->mnt_hash, &shadows->mnt_hash);
787 list_add(&mnt->mnt_child, &shadows->mnt_child);
788 } else {
789 hlist_add_head_rcu(&mnt->mnt_hash,
790 m_hash(&parent->mnt, mnt->mnt_mountpoint));
791 list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
792 }
793}
794
782/* 795/*
783 * vfsmount lock must be held for write 796 * vfsmount lock must be held for write
784 */ 797 */
@@ -797,12 +810,7 @@ static void commit_tree(struct mount *mnt, struct mount *shadows)
797 810
798 list_splice(&head, n->list.prev); 811 list_splice(&head, n->list.prev);
799 812
800 if (shadows) 813 attach_shadowed(mnt, parent, shadows);
801 hlist_add_behind_rcu(&mnt->mnt_hash, &shadows->mnt_hash);
802 else
803 hlist_add_head_rcu(&mnt->mnt_hash,
804 m_hash(&parent->mnt, mnt->mnt_mountpoint));
805 list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
806 touch_mnt_namespace(n); 814 touch_mnt_namespace(n);
807} 815}
808 816
@@ -951,7 +959,6 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
951 959
952static void mntput_no_expire(struct mount *mnt) 960static void mntput_no_expire(struct mount *mnt)
953{ 961{
954put_again:
955 rcu_read_lock(); 962 rcu_read_lock();
956 mnt_add_count(mnt, -1); 963 mnt_add_count(mnt, -1);
957 if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */ 964 if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */
@@ -964,14 +971,6 @@ put_again:
964 unlock_mount_hash(); 971 unlock_mount_hash();
965 return; 972 return;
966 } 973 }
967 if (unlikely(mnt->mnt_pinned)) {
968 mnt_add_count(mnt, mnt->mnt_pinned + 1);
969 mnt->mnt_pinned = 0;
970 rcu_read_unlock();
971 unlock_mount_hash();
972 acct_auto_close_mnt(&mnt->mnt);
973 goto put_again;
974 }
975 if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) { 974 if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) {
976 rcu_read_unlock(); 975 rcu_read_unlock();
977 unlock_mount_hash(); 976 unlock_mount_hash();
@@ -994,6 +993,8 @@ put_again:
994 * so mnt_get_writers() below is safe. 993 * so mnt_get_writers() below is safe.
995 */ 994 */
996 WARN_ON(mnt_get_writers(mnt)); 995 WARN_ON(mnt_get_writers(mnt));
996 if (unlikely(mnt->mnt_pins.first))
997 mnt_pin_kill(mnt);
997 fsnotify_vfsmount_delete(&mnt->mnt); 998 fsnotify_vfsmount_delete(&mnt->mnt);
998 dput(mnt->mnt.mnt_root); 999 dput(mnt->mnt.mnt_root);
999 deactivate_super(mnt->mnt.mnt_sb); 1000 deactivate_super(mnt->mnt.mnt_sb);
@@ -1021,25 +1022,15 @@ struct vfsmount *mntget(struct vfsmount *mnt)
1021} 1022}
1022EXPORT_SYMBOL(mntget); 1023EXPORT_SYMBOL(mntget);
1023 1024
1024void mnt_pin(struct vfsmount *mnt) 1025struct vfsmount *mnt_clone_internal(struct path *path)
1025{
1026 lock_mount_hash();
1027 real_mount(mnt)->mnt_pinned++;
1028 unlock_mount_hash();
1029}
1030EXPORT_SYMBOL(mnt_pin);
1031
1032void mnt_unpin(struct vfsmount *m)
1033{ 1026{
1034 struct mount *mnt = real_mount(m); 1027 struct mount *p;
1035 lock_mount_hash(); 1028 p = clone_mnt(real_mount(path->mnt), path->dentry, CL_PRIVATE);
1036 if (mnt->mnt_pinned) { 1029 if (IS_ERR(p))
1037 mnt_add_count(mnt, 1); 1030 return ERR_CAST(p);
1038 mnt->mnt_pinned--; 1031 p->mnt.mnt_flags |= MNT_INTERNAL;
1039 } 1032 return &p->mnt;
1040 unlock_mount_hash();
1041} 1033}
1042EXPORT_SYMBOL(mnt_unpin);
1043 1034
1044static inline void mangle(struct seq_file *m, const char *s) 1035static inline void mangle(struct seq_file *m, const char *s)
1045{ 1036{
@@ -1505,6 +1496,7 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
1505 continue; 1496 continue;
1506 1497
1507 for (s = r; s; s = next_mnt(s, r)) { 1498 for (s = r; s; s = next_mnt(s, r)) {
1499 struct mount *t = NULL;
1508 if (!(flag & CL_COPY_UNBINDABLE) && 1500 if (!(flag & CL_COPY_UNBINDABLE) &&
1509 IS_MNT_UNBINDABLE(s)) { 1501 IS_MNT_UNBINDABLE(s)) {
1510 s = skip_mnt_tree(s); 1502 s = skip_mnt_tree(s);
@@ -1526,7 +1518,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
1526 goto out; 1518 goto out;
1527 lock_mount_hash(); 1519 lock_mount_hash();
1528 list_add_tail(&q->mnt_list, &res->mnt_list); 1520 list_add_tail(&q->mnt_list, &res->mnt_list);
1529 attach_mnt(q, parent, p->mnt_mp); 1521 mnt_set_mountpoint(parent, p->mnt_mp, q);
1522 if (!list_empty(&parent->mnt_mounts)) {
1523 t = list_last_entry(&parent->mnt_mounts,
1524 struct mount, mnt_child);
1525 if (t->mnt_mp != p->mnt_mp)
1526 t = NULL;
1527 }
1528 attach_shadowed(q, parent, t);
1530 unlock_mount_hash(); 1529 unlock_mount_hash();
1531 } 1530 }
1532 } 1531 }