aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c225
1 files changed, 129 insertions, 96 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 1b3f2ac59c5e..a66feed7311d 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -183,7 +183,7 @@ static inline void mnt_dec_count(struct vfsmount *mnt)
183unsigned int mnt_get_count(struct vfsmount *mnt) 183unsigned int mnt_get_count(struct vfsmount *mnt)
184{ 184{
185#ifdef CONFIG_SMP 185#ifdef CONFIG_SMP
186 unsigned int count = atomic_read(&mnt->mnt_longrefs); 186 unsigned int count = 0;
187 int cpu; 187 int cpu;
188 188
189 for_each_possible_cpu(cpu) { 189 for_each_possible_cpu(cpu) {
@@ -217,7 +217,7 @@ struct vfsmount *alloc_vfsmnt(const char *name)
217 if (!mnt->mnt_pcp) 217 if (!mnt->mnt_pcp)
218 goto out_free_devname; 218 goto out_free_devname;
219 219
220 atomic_set(&mnt->mnt_longrefs, 1); 220 this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
221#else 221#else
222 mnt->mnt_count = 1; 222 mnt->mnt_count = 1;
223 mnt->mnt_writers = 0; 223 mnt->mnt_writers = 0;
@@ -611,6 +611,21 @@ static void attach_mnt(struct vfsmount *mnt, struct path *path)
611 list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts); 611 list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts);
612} 612}
613 613
614static inline void __mnt_make_longterm(struct vfsmount *mnt)
615{
616#ifdef CONFIG_SMP
617 atomic_inc(&mnt->mnt_longterm);
618#endif
619}
620
621/* needs vfsmount lock for write */
622static inline void __mnt_make_shortterm(struct vfsmount *mnt)
623{
624#ifdef CONFIG_SMP
625 atomic_dec(&mnt->mnt_longterm);
626#endif
627}
628
614/* 629/*
615 * vfsmount lock must be held for write 630 * vfsmount lock must be held for write
616 */ 631 */
@@ -624,8 +639,11 @@ static void commit_tree(struct vfsmount *mnt)
624 BUG_ON(parent == mnt); 639 BUG_ON(parent == mnt);
625 640
626 list_add_tail(&head, &mnt->mnt_list); 641 list_add_tail(&head, &mnt->mnt_list);
627 list_for_each_entry(m, &head, mnt_list) 642 list_for_each_entry(m, &head, mnt_list) {
628 m->mnt_ns = n; 643 m->mnt_ns = n;
644 __mnt_make_longterm(m);
645 }
646
629 list_splice(&head, n->list.prev); 647 list_splice(&head, n->list.prev);
630 648
631 list_add_tail(&mnt->mnt_hash, mount_hashtable + 649 list_add_tail(&mnt->mnt_hash, mount_hashtable +
@@ -734,51 +752,30 @@ static inline void mntfree(struct vfsmount *mnt)
734 deactivate_super(sb); 752 deactivate_super(sb);
735} 753}
736 754
737#ifdef CONFIG_SMP 755static void mntput_no_expire(struct vfsmount *mnt)
738static inline void __mntput(struct vfsmount *mnt, int longrefs)
739{ 756{
740 if (!longrefs) {
741put_again: 757put_again:
742 br_read_lock(vfsmount_lock); 758#ifdef CONFIG_SMP
743 if (likely(atomic_read(&mnt->mnt_longrefs))) { 759 br_read_lock(vfsmount_lock);
744 mnt_dec_count(mnt); 760 if (likely(atomic_read(&mnt->mnt_longterm))) {
745 br_read_unlock(vfsmount_lock); 761 mnt_dec_count(mnt);
746 return;
747 }
748 br_read_unlock(vfsmount_lock); 762 br_read_unlock(vfsmount_lock);
749 } else { 763 return;
750 BUG_ON(!atomic_read(&mnt->mnt_longrefs));
751 if (atomic_add_unless(&mnt->mnt_longrefs, -1, 1))
752 return;
753 } 764 }
765 br_read_unlock(vfsmount_lock);
754 766
755 br_write_lock(vfsmount_lock); 767 br_write_lock(vfsmount_lock);
756 if (!longrefs) 768 mnt_dec_count(mnt);
757 mnt_dec_count(mnt);
758 else
759 atomic_dec(&mnt->mnt_longrefs);
760 if (mnt_get_count(mnt)) { 769 if (mnt_get_count(mnt)) {
761 br_write_unlock(vfsmount_lock); 770 br_write_unlock(vfsmount_lock);
762 return; 771 return;
763 } 772 }
764 if (unlikely(mnt->mnt_pinned)) {
765 mnt_add_count(mnt, mnt->mnt_pinned + 1);
766 mnt->mnt_pinned = 0;
767 br_write_unlock(vfsmount_lock);
768 acct_auto_close_mnt(mnt);
769 goto put_again;
770 }
771 br_write_unlock(vfsmount_lock);
772 mntfree(mnt);
773}
774#else 773#else
775static inline void __mntput(struct vfsmount *mnt, int longrefs)
776{
777put_again:
778 mnt_dec_count(mnt); 774 mnt_dec_count(mnt);
779 if (likely(mnt_get_count(mnt))) 775 if (likely(mnt_get_count(mnt)))
780 return; 776 return;
781 br_write_lock(vfsmount_lock); 777 br_write_lock(vfsmount_lock);
778#endif
782 if (unlikely(mnt->mnt_pinned)) { 779 if (unlikely(mnt->mnt_pinned)) {
783 mnt_add_count(mnt, mnt->mnt_pinned + 1); 780 mnt_add_count(mnt, mnt->mnt_pinned + 1);
784 mnt->mnt_pinned = 0; 781 mnt->mnt_pinned = 0;
@@ -789,12 +786,6 @@ put_again:
789 br_write_unlock(vfsmount_lock); 786 br_write_unlock(vfsmount_lock);
790 mntfree(mnt); 787 mntfree(mnt);
791} 788}
792#endif
793
794static void mntput_no_expire(struct vfsmount *mnt)
795{
796 __mntput(mnt, 0);
797}
798 789
799void mntput(struct vfsmount *mnt) 790void mntput(struct vfsmount *mnt)
800{ 791{
@@ -802,7 +793,7 @@ void mntput(struct vfsmount *mnt)
802 /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ 793 /* avoid cacheline pingpong, hope gcc doesn't get "smart" */
803 if (unlikely(mnt->mnt_expiry_mark)) 794 if (unlikely(mnt->mnt_expiry_mark))
804 mnt->mnt_expiry_mark = 0; 795 mnt->mnt_expiry_mark = 0;
805 __mntput(mnt, 0); 796 mntput_no_expire(mnt);
806 } 797 }
807} 798}
808EXPORT_SYMBOL(mntput); 799EXPORT_SYMBOL(mntput);
@@ -815,33 +806,6 @@ struct vfsmount *mntget(struct vfsmount *mnt)
815} 806}
816EXPORT_SYMBOL(mntget); 807EXPORT_SYMBOL(mntget);
817 808
818void mntput_long(struct vfsmount *mnt)
819{
820#ifdef CONFIG_SMP
821 if (mnt) {
822 /* avoid cacheline pingpong, hope gcc doesn't get "smart" */
823 if (unlikely(mnt->mnt_expiry_mark))
824 mnt->mnt_expiry_mark = 0;
825 __mntput(mnt, 1);
826 }
827#else
828 mntput(mnt);
829#endif
830}
831EXPORT_SYMBOL(mntput_long);
832
833struct vfsmount *mntget_long(struct vfsmount *mnt)
834{
835#ifdef CONFIG_SMP
836 if (mnt)
837 atomic_inc(&mnt->mnt_longrefs);
838 return mnt;
839#else
840 return mntget(mnt);
841#endif
842}
843EXPORT_SYMBOL(mntget_long);
844
845void mnt_pin(struct vfsmount *mnt) 809void mnt_pin(struct vfsmount *mnt)
846{ 810{
847 br_write_lock(vfsmount_lock); 811 br_write_lock(vfsmount_lock);
@@ -1216,7 +1180,7 @@ void release_mounts(struct list_head *head)
1216 dput(dentry); 1180 dput(dentry);
1217 mntput(m); 1181 mntput(m);
1218 } 1182 }
1219 mntput_long(mnt); 1183 mntput(mnt);
1220 } 1184 }
1221} 1185}
1222 1186
@@ -1226,19 +1190,21 @@ void release_mounts(struct list_head *head)
1226 */ 1190 */
1227void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) 1191void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
1228{ 1192{
1193 LIST_HEAD(tmp_list);
1229 struct vfsmount *p; 1194 struct vfsmount *p;
1230 1195
1231 for (p = mnt; p; p = next_mnt(p, mnt)) 1196 for (p = mnt; p; p = next_mnt(p, mnt))
1232 list_move(&p->mnt_hash, kill); 1197 list_move(&p->mnt_hash, &tmp_list);
1233 1198
1234 if (propagate) 1199 if (propagate)
1235 propagate_umount(kill); 1200 propagate_umount(&tmp_list);
1236 1201
1237 list_for_each_entry(p, kill, mnt_hash) { 1202 list_for_each_entry(p, &tmp_list, mnt_hash) {
1238 list_del_init(&p->mnt_expire); 1203 list_del_init(&p->mnt_expire);
1239 list_del_init(&p->mnt_list); 1204 list_del_init(&p->mnt_list);
1240 __touch_mnt_namespace(p->mnt_ns); 1205 __touch_mnt_namespace(p->mnt_ns);
1241 p->mnt_ns = NULL; 1206 p->mnt_ns = NULL;
1207 __mnt_make_shortterm(p);
1242 list_del_init(&p->mnt_child); 1208 list_del_init(&p->mnt_child);
1243 if (p->mnt_parent != p) { 1209 if (p->mnt_parent != p) {
1244 p->mnt_parent->mnt_ghosts++; 1210 p->mnt_parent->mnt_ghosts++;
@@ -1246,6 +1212,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
1246 } 1212 }
1247 change_mnt_propagation(p, MS_PRIVATE); 1213 change_mnt_propagation(p, MS_PRIVATE);
1248 } 1214 }
1215 list_splice(&tmp_list, kill);
1249} 1216}
1250 1217
1251static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); 1218static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts);
@@ -1277,7 +1244,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
1277 */ 1244 */
1278 br_write_lock(vfsmount_lock); 1245 br_write_lock(vfsmount_lock);
1279 if (mnt_get_count(mnt) != 2) { 1246 if (mnt_get_count(mnt) != 2) {
1280 br_write_lock(vfsmount_lock); 1247 br_write_unlock(vfsmount_lock);
1281 return -EBUSY; 1248 return -EBUSY;
1282 } 1249 }
1283 br_write_unlock(vfsmount_lock); 1250 br_write_unlock(vfsmount_lock);
@@ -1848,9 +1815,10 @@ static int do_move_mount(struct path *path, char *old_name)
1848 return err; 1815 return err;
1849 1816
1850 down_write(&namespace_sem); 1817 down_write(&namespace_sem);
1851 while (d_mountpoint(path->dentry) && 1818 err = follow_down(path, true);
1852 follow_down(path)) 1819 if (err < 0)
1853 ; 1820 goto out;
1821
1854 err = -EINVAL; 1822 err = -EINVAL;
1855 if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) 1823 if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
1856 goto out; 1824 goto out;
@@ -1908,6 +1876,8 @@ out:
1908 return err; 1876 return err;
1909} 1877}
1910 1878
1879static int do_add_mount(struct vfsmount *, struct path *, int);
1880
1911/* 1881/*
1912 * create a new mount for userspace and request it to be added into the 1882 * create a new mount for userspace and request it to be added into the
1913 * namespace's tree 1883 * namespace's tree
@@ -1916,6 +1886,7 @@ static int do_new_mount(struct path *path, char *type, int flags,
1916 int mnt_flags, char *name, void *data) 1886 int mnt_flags, char *name, void *data)
1917{ 1887{
1918 struct vfsmount *mnt; 1888 struct vfsmount *mnt;
1889 int err;
1919 1890
1920 if (!type) 1891 if (!type)
1921 return -EINVAL; 1892 return -EINVAL;
@@ -1928,15 +1899,47 @@ static int do_new_mount(struct path *path, char *type, int flags,
1928 if (IS_ERR(mnt)) 1899 if (IS_ERR(mnt))
1929 return PTR_ERR(mnt); 1900 return PTR_ERR(mnt);
1930 1901
1931 return do_add_mount(mnt, path, mnt_flags, NULL); 1902 err = do_add_mount(mnt, path, mnt_flags);
1903 if (err)
1904 mntput(mnt);
1905 return err;
1906}
1907
1908int finish_automount(struct vfsmount *m, struct path *path)
1909{
1910 int err;
1911 /* The new mount record should have at least 2 refs to prevent it being
1912 * expired before we get a chance to add it
1913 */
1914 BUG_ON(mnt_get_count(m) < 2);
1915
1916 if (m->mnt_sb == path->mnt->mnt_sb &&
1917 m->mnt_root == path->dentry) {
1918 err = -ELOOP;
1919 goto fail;
1920 }
1921
1922 err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
1923 if (!err)
1924 return 0;
1925fail:
1926 /* remove m from any expiration list it may be on */
1927 if (!list_empty(&m->mnt_expire)) {
1928 down_write(&namespace_sem);
1929 br_write_lock(vfsmount_lock);
1930 list_del_init(&m->mnt_expire);
1931 br_write_unlock(vfsmount_lock);
1932 up_write(&namespace_sem);
1933 }
1934 mntput(m);
1935 mntput(m);
1936 return err;
1932} 1937}
1933 1938
1934/* 1939/*
1935 * add a mount into a namespace's mount tree 1940 * add a mount into a namespace's mount tree
1936 * - provide the option of adding the new mount to an expiration list
1937 */ 1941 */
1938int do_add_mount(struct vfsmount *newmnt, struct path *path, 1942static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
1939 int mnt_flags, struct list_head *fslist)
1940{ 1943{
1941 int err; 1944 int err;
1942 1945
@@ -1944,9 +1947,10 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
1944 1947
1945 down_write(&namespace_sem); 1948 down_write(&namespace_sem);
1946 /* Something was mounted here while we slept */ 1949 /* Something was mounted here while we slept */
1947 while (d_mountpoint(path->dentry) && 1950 err = follow_down(path, true);
1948 follow_down(path)) 1951 if (err < 0)
1949 ; 1952 goto unlock;
1953
1950 err = -EINVAL; 1954 err = -EINVAL;
1951 if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) 1955 if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
1952 goto unlock; 1956 goto unlock;
@@ -1962,22 +1966,29 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
1962 goto unlock; 1966 goto unlock;
1963 1967
1964 newmnt->mnt_flags = mnt_flags; 1968 newmnt->mnt_flags = mnt_flags;
1965 if ((err = graft_tree(newmnt, path))) 1969 err = graft_tree(newmnt, path);
1966 goto unlock;
1967
1968 if (fslist) /* add to the specified expiration list */
1969 list_add_tail(&newmnt->mnt_expire, fslist);
1970
1971 up_write(&namespace_sem);
1972 return 0;
1973 1970
1974unlock: 1971unlock:
1975 up_write(&namespace_sem); 1972 up_write(&namespace_sem);
1976 mntput_long(newmnt);
1977 return err; 1973 return err;
1978} 1974}
1979 1975
1980EXPORT_SYMBOL_GPL(do_add_mount); 1976/**
1977 * mnt_set_expiry - Put a mount on an expiration list
1978 * @mnt: The mount to list.
1979 * @expiry_list: The list to add the mount to.
1980 */
1981void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
1982{
1983 down_write(&namespace_sem);
1984 br_write_lock(vfsmount_lock);
1985
1986 list_add_tail(&mnt->mnt_expire, expiry_list);
1987
1988 br_write_unlock(vfsmount_lock);
1989 up_write(&namespace_sem);
1990}
1991EXPORT_SYMBOL(mnt_set_expiry);
1981 1992
1982/* 1993/*
1983 * process a list of expirable mountpoints with the intent of discarding any 1994 * process a list of expirable mountpoints with the intent of discarding any
@@ -2266,6 +2277,22 @@ static struct mnt_namespace *alloc_mnt_ns(void)
2266 return new_ns; 2277 return new_ns;
2267} 2278}
2268 2279
2280void mnt_make_longterm(struct vfsmount *mnt)
2281{
2282 __mnt_make_longterm(mnt);
2283}
2284
2285void mnt_make_shortterm(struct vfsmount *mnt)
2286{
2287#ifdef CONFIG_SMP
2288 if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
2289 return;
2290 br_write_lock(vfsmount_lock);
2291 atomic_dec(&mnt->mnt_longterm);
2292 br_write_unlock(vfsmount_lock);
2293#endif
2294}
2295
2269/* 2296/*
2270 * Allocate a new namespace structure and populate it with contents 2297 * Allocate a new namespace structure and populate it with contents
2271 * copied from the namespace of the passed in task structure. 2298 * copied from the namespace of the passed in task structure.
@@ -2303,14 +2330,19 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
2303 q = new_ns->root; 2330 q = new_ns->root;
2304 while (p) { 2331 while (p) {
2305 q->mnt_ns = new_ns; 2332 q->mnt_ns = new_ns;
2333 __mnt_make_longterm(q);
2306 if (fs) { 2334 if (fs) {
2307 if (p == fs->root.mnt) { 2335 if (p == fs->root.mnt) {
2336 fs->root.mnt = mntget(q);
2337 __mnt_make_longterm(q);
2338 mnt_make_shortterm(p);
2308 rootmnt = p; 2339 rootmnt = p;
2309 fs->root.mnt = mntget_long(q);
2310 } 2340 }
2311 if (p == fs->pwd.mnt) { 2341 if (p == fs->pwd.mnt) {
2342 fs->pwd.mnt = mntget(q);
2343 __mnt_make_longterm(q);
2344 mnt_make_shortterm(p);
2312 pwdmnt = p; 2345 pwdmnt = p;
2313 fs->pwd.mnt = mntget_long(q);
2314 } 2346 }
2315 } 2347 }
2316 p = next_mnt(p, mnt_ns->root); 2348 p = next_mnt(p, mnt_ns->root);
@@ -2319,9 +2351,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
2319 up_write(&namespace_sem); 2351 up_write(&namespace_sem);
2320 2352
2321 if (rootmnt) 2353 if (rootmnt)
2322 mntput_long(rootmnt); 2354 mntput(rootmnt);
2323 if (pwdmnt) 2355 if (pwdmnt)
2324 mntput_long(pwdmnt); 2356 mntput(pwdmnt);
2325 2357
2326 return new_ns; 2358 return new_ns;
2327} 2359}
@@ -2354,6 +2386,7 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
2354 new_ns = alloc_mnt_ns(); 2386 new_ns = alloc_mnt_ns();
2355 if (!IS_ERR(new_ns)) { 2387 if (!IS_ERR(new_ns)) {
2356 mnt->mnt_ns = new_ns; 2388 mnt->mnt_ns = new_ns;
2389 __mnt_make_longterm(mnt);
2357 new_ns->root = mnt; 2390 new_ns->root = mnt;
2358 list_add(&new_ns->list, &new_ns->root->mnt_list); 2391 list_add(&new_ns->list, &new_ns->root->mnt_list);
2359 } 2392 }