aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c223
1 files changed, 128 insertions, 95 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 3ddfd9046c44..7b0b95371696 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);
@@ -1844,9 +1811,10 @@ static int do_move_mount(struct path *path, char *old_name)
1844 return err; 1811 return err;
1845 1812
1846 down_write(&namespace_sem); 1813 down_write(&namespace_sem);
1847 while (d_mountpoint(path->dentry) && 1814 err = follow_down(path, true);
1848 follow_down(path)) 1815 if (err < 0)
1849 ; 1816 goto out;
1817
1850 err = -EINVAL; 1818 err = -EINVAL;
1851 if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) 1819 if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
1852 goto out; 1820 goto out;
@@ -1904,6 +1872,8 @@ out:
1904 return err; 1872 return err;
1905} 1873}
1906 1874
1875static int do_add_mount(struct vfsmount *, struct path *, int);
1876
1907/* 1877/*
1908 * create a new mount for userspace and request it to be added into the 1878 * create a new mount for userspace and request it to be added into the
1909 * namespace's tree 1879 * namespace's tree
@@ -1912,6 +1882,7 @@ static int do_new_mount(struct path *path, char *type, int flags,
1912 int mnt_flags, char *name, void *data) 1882 int mnt_flags, char *name, void *data)
1913{ 1883{
1914 struct vfsmount *mnt; 1884 struct vfsmount *mnt;
1885 int err;
1915 1886
1916 if (!type) 1887 if (!type)
1917 return -EINVAL; 1888 return -EINVAL;
@@ -1924,15 +1895,47 @@ static int do_new_mount(struct path *path, char *type, int flags,
1924 if (IS_ERR(mnt)) 1895 if (IS_ERR(mnt))
1925 return PTR_ERR(mnt); 1896 return PTR_ERR(mnt);
1926 1897
1927 return do_add_mount(mnt, path, mnt_flags, NULL); 1898 err = do_add_mount(mnt, path, mnt_flags);
1899 if (err)
1900 mntput(mnt);
1901 return err;
1902}
1903
1904int finish_automount(struct vfsmount *m, struct path *path)
1905{
1906 int err;
1907 /* The new mount record should have at least 2 refs to prevent it being
1908 * expired before we get a chance to add it
1909 */
1910 BUG_ON(mnt_get_count(m) < 2);
1911
1912 if (m->mnt_sb == path->mnt->mnt_sb &&
1913 m->mnt_root == path->dentry) {
1914 err = -ELOOP;
1915 goto fail;
1916 }
1917
1918 err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
1919 if (!err)
1920 return 0;
1921fail:
1922 /* remove m from any expiration list it may be on */
1923 if (!list_empty(&m->mnt_expire)) {
1924 down_write(&namespace_sem);
1925 br_write_lock(vfsmount_lock);
1926 list_del_init(&m->mnt_expire);
1927 br_write_unlock(vfsmount_lock);
1928 up_write(&namespace_sem);
1929 }
1930 mntput(m);
1931 mntput(m);
1932 return err;
1928} 1933}
1929 1934
1930/* 1935/*
1931 * add a mount into a namespace's mount tree 1936 * add a mount into a namespace's mount tree
1932 * - provide the option of adding the new mount to an expiration list
1933 */ 1937 */
1934int do_add_mount(struct vfsmount *newmnt, struct path *path, 1938static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
1935 int mnt_flags, struct list_head *fslist)
1936{ 1939{
1937 int err; 1940 int err;
1938 1941
@@ -1940,9 +1943,10 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
1940 1943
1941 down_write(&namespace_sem); 1944 down_write(&namespace_sem);
1942 /* Something was mounted here while we slept */ 1945 /* Something was mounted here while we slept */
1943 while (d_mountpoint(path->dentry) && 1946 err = follow_down(path, true);
1944 follow_down(path)) 1947 if (err < 0)
1945 ; 1948 goto unlock;
1949
1946 err = -EINVAL; 1950 err = -EINVAL;
1947 if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) 1951 if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
1948 goto unlock; 1952 goto unlock;
@@ -1958,22 +1962,29 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
1958 goto unlock; 1962 goto unlock;
1959 1963
1960 newmnt->mnt_flags = mnt_flags; 1964 newmnt->mnt_flags = mnt_flags;
1961 if ((err = graft_tree(newmnt, path))) 1965 err = graft_tree(newmnt, path);
1962 goto unlock;
1963
1964 if (fslist) /* add to the specified expiration list */
1965 list_add_tail(&newmnt->mnt_expire, fslist);
1966
1967 up_write(&namespace_sem);
1968 return 0;
1969 1966
1970unlock: 1967unlock:
1971 up_write(&namespace_sem); 1968 up_write(&namespace_sem);
1972 mntput_long(newmnt);
1973 return err; 1969 return err;
1974} 1970}
1975 1971
1976EXPORT_SYMBOL_GPL(do_add_mount); 1972/**
1973 * mnt_set_expiry - Put a mount on an expiration list
1974 * @mnt: The mount to list.
1975 * @expiry_list: The list to add the mount to.
1976 */
1977void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
1978{
1979 down_write(&namespace_sem);
1980 br_write_lock(vfsmount_lock);
1981
1982 list_add_tail(&mnt->mnt_expire, expiry_list);
1983
1984 br_write_unlock(vfsmount_lock);
1985 up_write(&namespace_sem);
1986}
1987EXPORT_SYMBOL(mnt_set_expiry);
1977 1988
1978/* 1989/*
1979 * process a list of expirable mountpoints with the intent of discarding any 1990 * process a list of expirable mountpoints with the intent of discarding any
@@ -2262,6 +2273,22 @@ static struct mnt_namespace *alloc_mnt_ns(void)
2262 return new_ns; 2273 return new_ns;
2263} 2274}
2264 2275
2276void mnt_make_longterm(struct vfsmount *mnt)
2277{
2278 __mnt_make_longterm(mnt);
2279}
2280
2281void mnt_make_shortterm(struct vfsmount *mnt)
2282{
2283#ifdef CONFIG_SMP
2284 if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
2285 return;
2286 br_write_lock(vfsmount_lock);
2287 atomic_dec(&mnt->mnt_longterm);
2288 br_write_unlock(vfsmount_lock);
2289#endif
2290}
2291
2265/* 2292/*
2266 * Allocate a new namespace structure and populate it with contents 2293 * Allocate a new namespace structure and populate it with contents
2267 * copied from the namespace of the passed in task structure. 2294 * copied from the namespace of the passed in task structure.
@@ -2299,14 +2326,19 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
2299 q = new_ns->root; 2326 q = new_ns->root;
2300 while (p) { 2327 while (p) {
2301 q->mnt_ns = new_ns; 2328 q->mnt_ns = new_ns;
2329 __mnt_make_longterm(q);
2302 if (fs) { 2330 if (fs) {
2303 if (p == fs->root.mnt) { 2331 if (p == fs->root.mnt) {
2332 fs->root.mnt = mntget(q);
2333 __mnt_make_longterm(q);
2334 mnt_make_shortterm(p);
2304 rootmnt = p; 2335 rootmnt = p;
2305 fs->root.mnt = mntget_long(q);
2306 } 2336 }
2307 if (p == fs->pwd.mnt) { 2337 if (p == fs->pwd.mnt) {
2338 fs->pwd.mnt = mntget(q);
2339 __mnt_make_longterm(q);
2340 mnt_make_shortterm(p);
2308 pwdmnt = p; 2341 pwdmnt = p;
2309 fs->pwd.mnt = mntget_long(q);
2310 } 2342 }
2311 } 2343 }
2312 p = next_mnt(p, mnt_ns->root); 2344 p = next_mnt(p, mnt_ns->root);
@@ -2315,9 +2347,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
2315 up_write(&namespace_sem); 2347 up_write(&namespace_sem);
2316 2348
2317 if (rootmnt) 2349 if (rootmnt)
2318 mntput_long(rootmnt); 2350 mntput(rootmnt);
2319 if (pwdmnt) 2351 if (pwdmnt)
2320 mntput_long(pwdmnt); 2352 mntput(pwdmnt);
2321 2353
2322 return new_ns; 2354 return new_ns;
2323} 2355}
@@ -2350,6 +2382,7 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
2350 new_ns = alloc_mnt_ns(); 2382 new_ns = alloc_mnt_ns();
2351 if (!IS_ERR(new_ns)) { 2383 if (!IS_ERR(new_ns)) {
2352 mnt->mnt_ns = new_ns; 2384 mnt->mnt_ns = new_ns;
2385 __mnt_make_longterm(mnt);
2353 new_ns->root = mnt; 2386 new_ns->root = mnt;
2354 list_add(&new_ns->list, &new_ns->root->mnt_list); 2387 list_add(&new_ns->list, &new_ns->root->mnt_list);
2355 } 2388 }