aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-11-24 22:37:54 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2012-01-03 22:57:05 -0500
commit83adc7532229f1909cf37c429780f02f06fe05ee (patch)
tree7f7a36fea3f903c7f9c3f3860bc395a2ba7ad806 /fs/namespace.c
parenta73324da7af4052e1d1ddec6a5980f552420e58b (diff)
vfs: spread struct mount - work with counters
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c124
1 files changed, 64 insertions, 60 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index ec798e77b726..a13165c871c2 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -141,13 +141,13 @@ void mnt_release_group_id(struct mount *mnt)
141/* 141/*
142 * vfsmount lock must be held for read 142 * vfsmount lock must be held for read
143 */ 143 */
144static inline void mnt_add_count(struct vfsmount *mnt, int n) 144static inline void mnt_add_count(struct mount *mnt, int n)
145{ 145{
146#ifdef CONFIG_SMP 146#ifdef CONFIG_SMP
147 this_cpu_add(mnt->mnt_pcp->mnt_count, n); 147 this_cpu_add(mnt->mnt.mnt_pcp->mnt_count, n);
148#else 148#else
149 preempt_disable(); 149 preempt_disable();
150 mnt->mnt_count += n; 150 mnt->mnt.mnt_count += n;
151 preempt_enable(); 151 preempt_enable();
152#endif 152#endif
153} 153}
@@ -155,19 +155,19 @@ static inline void mnt_add_count(struct vfsmount *mnt, int n)
155/* 155/*
156 * vfsmount lock must be held for write 156 * vfsmount lock must be held for write
157 */ 157 */
158unsigned int mnt_get_count(struct vfsmount *mnt) 158unsigned int mnt_get_count(struct mount *mnt)
159{ 159{
160#ifdef CONFIG_SMP 160#ifdef CONFIG_SMP
161 unsigned int count = 0; 161 unsigned int count = 0;
162 int cpu; 162 int cpu;
163 163
164 for_each_possible_cpu(cpu) { 164 for_each_possible_cpu(cpu) {
165 count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count; 165 count += per_cpu_ptr(mnt->mnt.mnt_pcp, cpu)->mnt_count;
166 } 166 }
167 167
168 return count; 168 return count;
169#else 169#else
170 return mnt->mnt_count; 170 return mnt->mnt.mnt_count;
171#endif 171#endif
172} 172}
173 173
@@ -253,32 +253,32 @@ int __mnt_is_readonly(struct vfsmount *mnt)
253} 253}
254EXPORT_SYMBOL_GPL(__mnt_is_readonly); 254EXPORT_SYMBOL_GPL(__mnt_is_readonly);
255 255
256static inline void mnt_inc_writers(struct vfsmount *mnt) 256static inline void mnt_inc_writers(struct mount *mnt)
257{ 257{
258#ifdef CONFIG_SMP 258#ifdef CONFIG_SMP
259 this_cpu_inc(mnt->mnt_pcp->mnt_writers); 259 this_cpu_inc(mnt->mnt.mnt_pcp->mnt_writers);
260#else 260#else
261 mnt->mnt_writers++; 261 mnt->mnt.mnt_writers++;
262#endif 262#endif
263} 263}
264 264
265static inline void mnt_dec_writers(struct vfsmount *mnt) 265static inline void mnt_dec_writers(struct mount *mnt)
266{ 266{
267#ifdef CONFIG_SMP 267#ifdef CONFIG_SMP
268 this_cpu_dec(mnt->mnt_pcp->mnt_writers); 268 this_cpu_dec(mnt->mnt.mnt_pcp->mnt_writers);
269#else 269#else
270 mnt->mnt_writers--; 270 mnt->mnt.mnt_writers--;
271#endif 271#endif
272} 272}
273 273
274static unsigned int mnt_get_writers(struct vfsmount *mnt) 274static unsigned int mnt_get_writers(struct mount *mnt)
275{ 275{
276#ifdef CONFIG_SMP 276#ifdef CONFIG_SMP
277 unsigned int count = 0; 277 unsigned int count = 0;
278 int cpu; 278 int cpu;
279 279
280 for_each_possible_cpu(cpu) { 280 for_each_possible_cpu(cpu) {
281 count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers; 281 count += per_cpu_ptr(mnt->mnt.mnt_pcp, cpu)->mnt_writers;
282 } 282 }
283 283
284 return count; 284 return count;
@@ -297,7 +297,7 @@ static unsigned int mnt_get_writers(struct vfsmount *mnt)
297 */ 297 */
298/** 298/**
299 * mnt_want_write - get write access to a mount 299 * mnt_want_write - get write access to a mount
300 * @mnt: the mount on which to take a write 300 * @m: the mount on which to take a write
301 * 301 *
302 * This tells the low-level filesystem that a write is 302 * This tells the low-level filesystem that a write is
303 * about to be performed to it, and makes sure that 303 * about to be performed to it, and makes sure that
@@ -305,8 +305,9 @@ static unsigned int mnt_get_writers(struct vfsmount *mnt)
305 * the write operation is finished, mnt_drop_write() 305 * the write operation is finished, mnt_drop_write()
306 * must be called. This is effectively a refcount. 306 * must be called. This is effectively a refcount.
307 */ 307 */
308int mnt_want_write(struct vfsmount *mnt) 308int mnt_want_write(struct vfsmount *m)
309{ 309{
310 struct mount *mnt = real_mount(m);
310 int ret = 0; 311 int ret = 0;
311 312
312 preempt_disable(); 313 preempt_disable();
@@ -317,7 +318,7 @@ int mnt_want_write(struct vfsmount *mnt)
317 * incremented count after it has set MNT_WRITE_HOLD. 318 * incremented count after it has set MNT_WRITE_HOLD.
318 */ 319 */
319 smp_mb(); 320 smp_mb();
320 while (mnt->mnt_flags & MNT_WRITE_HOLD) 321 while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD)
321 cpu_relax(); 322 cpu_relax();
322 /* 323 /*
323 * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will 324 * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will
@@ -325,7 +326,7 @@ int mnt_want_write(struct vfsmount *mnt)
325 * MNT_WRITE_HOLD is cleared. 326 * MNT_WRITE_HOLD is cleared.
326 */ 327 */
327 smp_rmb(); 328 smp_rmb();
328 if (__mnt_is_readonly(mnt)) { 329 if (__mnt_is_readonly(m)) {
329 mnt_dec_writers(mnt); 330 mnt_dec_writers(mnt);
330 ret = -EROFS; 331 ret = -EROFS;
331 goto out; 332 goto out;
@@ -354,7 +355,7 @@ int mnt_clone_write(struct vfsmount *mnt)
354 if (__mnt_is_readonly(mnt)) 355 if (__mnt_is_readonly(mnt))
355 return -EROFS; 356 return -EROFS;
356 preempt_disable(); 357 preempt_disable();
357 mnt_inc_writers(mnt); 358 mnt_inc_writers(real_mount(mnt));
358 preempt_enable(); 359 preempt_enable();
359 return 0; 360 return 0;
360} 361}
@@ -388,7 +389,7 @@ EXPORT_SYMBOL_GPL(mnt_want_write_file);
388void mnt_drop_write(struct vfsmount *mnt) 389void mnt_drop_write(struct vfsmount *mnt)
389{ 390{
390 preempt_disable(); 391 preempt_disable();
391 mnt_dec_writers(mnt); 392 mnt_dec_writers(real_mount(mnt));
392 preempt_enable(); 393 preempt_enable();
393} 394}
394EXPORT_SYMBOL_GPL(mnt_drop_write); 395EXPORT_SYMBOL_GPL(mnt_drop_write);
@@ -399,12 +400,12 @@ void mnt_drop_write_file(struct file *file)
399} 400}
400EXPORT_SYMBOL(mnt_drop_write_file); 401EXPORT_SYMBOL(mnt_drop_write_file);
401 402
402static int mnt_make_readonly(struct vfsmount *mnt) 403static int mnt_make_readonly(struct mount *mnt)
403{ 404{
404 int ret = 0; 405 int ret = 0;
405 406
406 br_write_lock(vfsmount_lock); 407 br_write_lock(vfsmount_lock);
407 mnt->mnt_flags |= MNT_WRITE_HOLD; 408 mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;
408 /* 409 /*
409 * After storing MNT_WRITE_HOLD, we'll read the counters. This store 410 * After storing MNT_WRITE_HOLD, we'll read the counters. This store
410 * should be visible before we do. 411 * should be visible before we do.
@@ -430,21 +431,21 @@ static int mnt_make_readonly(struct vfsmount *mnt)
430 if (mnt_get_writers(mnt) > 0) 431 if (mnt_get_writers(mnt) > 0)
431 ret = -EBUSY; 432 ret = -EBUSY;
432 else 433 else
433 mnt->mnt_flags |= MNT_READONLY; 434 mnt->mnt.mnt_flags |= MNT_READONLY;
434 /* 435 /*
435 * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers 436 * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers
436 * that become unheld will see MNT_READONLY. 437 * that become unheld will see MNT_READONLY.
437 */ 438 */
438 smp_wmb(); 439 smp_wmb();
439 mnt->mnt_flags &= ~MNT_WRITE_HOLD; 440 mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;
440 br_write_unlock(vfsmount_lock); 441 br_write_unlock(vfsmount_lock);
441 return ret; 442 return ret;
442} 443}
443 444
444static void __mnt_unmake_readonly(struct vfsmount *mnt) 445static void __mnt_unmake_readonly(struct mount *mnt)
445{ 446{
446 br_write_lock(vfsmount_lock); 447 br_write_lock(vfsmount_lock);
447 mnt->mnt_flags &= ~MNT_READONLY; 448 mnt->mnt.mnt_flags &= ~MNT_READONLY;
448 br_write_unlock(vfsmount_lock); 449 br_write_unlock(vfsmount_lock);
449} 450}
450 451
@@ -590,18 +591,18 @@ static void attach_mnt(struct mount *mnt, struct path *path)
590 list_add_tail(&mnt->mnt.mnt_child, &path->mnt->mnt_mounts); 591 list_add_tail(&mnt->mnt.mnt_child, &path->mnt->mnt_mounts);
591} 592}
592 593
593static inline void __mnt_make_longterm(struct vfsmount *mnt) 594static inline void __mnt_make_longterm(struct mount *mnt)
594{ 595{
595#ifdef CONFIG_SMP 596#ifdef CONFIG_SMP
596 atomic_inc(&mnt->mnt_longterm); 597 atomic_inc(&mnt->mnt.mnt_longterm);
597#endif 598#endif
598} 599}
599 600
600/* needs vfsmount lock for write */ 601/* needs vfsmount lock for write */
601static inline void __mnt_make_shortterm(struct vfsmount *mnt) 602static inline void __mnt_make_shortterm(struct mount *mnt)
602{ 603{
603#ifdef CONFIG_SMP 604#ifdef CONFIG_SMP
604 atomic_dec(&mnt->mnt_longterm); 605 atomic_dec(&mnt->mnt.mnt_longterm);
605#endif 606#endif
606} 607}
607 608
@@ -611,15 +612,15 @@ static inline void __mnt_make_shortterm(struct vfsmount *mnt)
611static void commit_tree(struct mount *mnt) 612static void commit_tree(struct mount *mnt)
612{ 613{
613 struct mount *parent = mnt->mnt_parent; 614 struct mount *parent = mnt->mnt_parent;
614 struct vfsmount *m; 615 struct mount *m;
615 LIST_HEAD(head); 616 LIST_HEAD(head);
616 struct mnt_namespace *n = parent->mnt.mnt_ns; 617 struct mnt_namespace *n = parent->mnt.mnt_ns;
617 618
618 BUG_ON(parent == mnt); 619 BUG_ON(parent == mnt);
619 620
620 list_add_tail(&head, &mnt->mnt.mnt_list); 621 list_add_tail(&head, &mnt->mnt.mnt_list);
621 list_for_each_entry(m, &head, mnt_list) { 622 list_for_each_entry(m, &head, mnt.mnt_list) {
622 m->mnt_ns = n; 623 m->mnt.mnt_ns = n;
623 __mnt_make_longterm(m); 624 __mnt_make_longterm(m);
624 } 625 }
625 626
@@ -740,9 +741,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
740 return NULL; 741 return NULL;
741} 742}
742 743
743static inline void mntfree(struct vfsmount *mnt) 744static inline void mntfree(struct mount *mnt)
744{ 745{
745 struct super_block *sb = mnt->mnt_sb; 746 struct vfsmount *m = &mnt->mnt;
747 struct super_block *sb = m->mnt_sb;
746 748
747 /* 749 /*
748 * This probably indicates that somebody messed 750 * This probably indicates that somebody messed
@@ -755,18 +757,19 @@ static inline void mntfree(struct vfsmount *mnt)
755 * so mnt_get_writers() below is safe. 757 * so mnt_get_writers() below is safe.
756 */ 758 */
757 WARN_ON(mnt_get_writers(mnt)); 759 WARN_ON(mnt_get_writers(mnt));
758 fsnotify_vfsmount_delete(mnt); 760 fsnotify_vfsmount_delete(m);
759 dput(mnt->mnt_root); 761 dput(m->mnt_root);
760 free_vfsmnt(real_mount(mnt)); 762 free_vfsmnt(mnt);
761 deactivate_super(sb); 763 deactivate_super(sb);
762} 764}
763 765
764static void mntput_no_expire(struct vfsmount *mnt) 766static void mntput_no_expire(struct vfsmount *m)
765{ 767{
768 struct mount *mnt = real_mount(m);
766put_again: 769put_again:
767#ifdef CONFIG_SMP 770#ifdef CONFIG_SMP
768 br_read_lock(vfsmount_lock); 771 br_read_lock(vfsmount_lock);
769 if (likely(atomic_read(&mnt->mnt_longterm))) { 772 if (likely(atomic_read(&mnt->mnt.mnt_longterm))) {
770 mnt_add_count(mnt, -1); 773 mnt_add_count(mnt, -1);
771 br_read_unlock(vfsmount_lock); 774 br_read_unlock(vfsmount_lock);
772 return; 775 return;
@@ -785,11 +788,11 @@ put_again:
785 return; 788 return;
786 br_write_lock(vfsmount_lock); 789 br_write_lock(vfsmount_lock);
787#endif 790#endif
788 if (unlikely(mnt->mnt_pinned)) { 791 if (unlikely(mnt->mnt.mnt_pinned)) {
789 mnt_add_count(mnt, mnt->mnt_pinned + 1); 792 mnt_add_count(mnt, mnt->mnt.mnt_pinned + 1);
790 mnt->mnt_pinned = 0; 793 mnt->mnt.mnt_pinned = 0;
791 br_write_unlock(vfsmount_lock); 794 br_write_unlock(vfsmount_lock);
792 acct_auto_close_mnt(mnt); 795 acct_auto_close_mnt(m);
793 goto put_again; 796 goto put_again;
794 } 797 }
795 br_write_unlock(vfsmount_lock); 798 br_write_unlock(vfsmount_lock);
@@ -810,7 +813,7 @@ EXPORT_SYMBOL(mntput);
810struct vfsmount *mntget(struct vfsmount *mnt) 813struct vfsmount *mntget(struct vfsmount *mnt)
811{ 814{
812 if (mnt) 815 if (mnt)
813 mnt_add_count(mnt, 1); 816 mnt_add_count(real_mount(mnt), 1);
814 return mnt; 817 return mnt;
815} 818}
816EXPORT_SYMBOL(mntget); 819EXPORT_SYMBOL(mntget);
@@ -827,7 +830,7 @@ void mnt_unpin(struct vfsmount *mnt)
827{ 830{
828 br_write_lock(vfsmount_lock); 831 br_write_lock(vfsmount_lock);
829 if (mnt->mnt_pinned) { 832 if (mnt->mnt_pinned) {
830 mnt_add_count(mnt, 1); 833 mnt_add_count(real_mount(mnt), 1);
831 mnt->mnt_pinned--; 834 mnt->mnt_pinned--;
832 } 835 }
833 br_write_unlock(vfsmount_lock); 836 br_write_unlock(vfsmount_lock);
@@ -1150,7 +1153,7 @@ int may_umount_tree(struct vfsmount *mnt)
1150 /* write lock needed for mnt_get_count */ 1153 /* write lock needed for mnt_get_count */
1151 br_write_lock(vfsmount_lock); 1154 br_write_lock(vfsmount_lock);
1152 for (p = real_mount(mnt); p; p = next_mnt(p, mnt)) { 1155 for (p = real_mount(mnt); p; p = next_mnt(p, mnt)) {
1153 actual_refs += mnt_get_count(&p->mnt); 1156 actual_refs += mnt_get_count(p);
1154 minimum_refs += 2; 1157 minimum_refs += 2;
1155 } 1158 }
1156 br_write_unlock(vfsmount_lock); 1159 br_write_unlock(vfsmount_lock);
@@ -1234,7 +1237,7 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill)
1234 list_del_init(&p->mnt.mnt_list); 1237 list_del_init(&p->mnt.mnt_list);
1235 __touch_mnt_namespace(p->mnt.mnt_ns); 1238 __touch_mnt_namespace(p->mnt.mnt_ns);
1236 p->mnt.mnt_ns = NULL; 1239 p->mnt.mnt_ns = NULL;
1237 __mnt_make_shortterm(&p->mnt); 1240 __mnt_make_shortterm(p);
1238 list_del_init(&p->mnt.mnt_child); 1241 list_del_init(&p->mnt.mnt_child);
1239 if (mnt_has_parent(p)) { 1242 if (mnt_has_parent(p)) {
1240 p->mnt_parent->mnt.mnt_ghosts++; 1243 p->mnt_parent->mnt.mnt_ghosts++;
@@ -1273,7 +1276,7 @@ static int do_umount(struct mount *mnt, int flags)
1273 * all race cases, but it's a slowpath. 1276 * all race cases, but it's a slowpath.
1274 */ 1277 */
1275 br_write_lock(vfsmount_lock); 1278 br_write_lock(vfsmount_lock);
1276 if (mnt_get_count(&mnt->mnt) != 2) { 1279 if (mnt_get_count(mnt) != 2) {
1277 br_write_unlock(vfsmount_lock); 1280 br_write_unlock(vfsmount_lock);
1278 return -EBUSY; 1281 return -EBUSY;
1279 } 1282 }
@@ -1798,9 +1801,9 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
1798 return 0; 1801 return 0;
1799 1802
1800 if (readonly_request) 1803 if (readonly_request)
1801 error = mnt_make_readonly(mnt); 1804 error = mnt_make_readonly(real_mount(mnt));
1802 else 1805 else
1803 __mnt_unmake_readonly(mnt); 1806 __mnt_unmake_readonly(real_mount(mnt));
1804 return error; 1807 return error;
1805} 1808}
1806 1809
@@ -2034,7 +2037,7 @@ int finish_automount(struct vfsmount *m, struct path *path)
2034 /* The new mount record should have at least 2 refs to prevent it being 2037 /* The new mount record should have at least 2 refs to prevent it being
2035 * expired before we get a chance to add it 2038 * expired before we get a chance to add it
2036 */ 2039 */
2037 BUG_ON(mnt_get_count(m) < 2); 2040 BUG_ON(mnt_get_count(real_mount(m)) < 2);
2038 2041
2039 if (m->mnt_sb == path->mnt->mnt_sb && 2042 if (m->mnt_sb == path->mnt->mnt_sb &&
2040 m->mnt_root == path->dentry) { 2043 m->mnt_root == path->dentry) {
@@ -2365,16 +2368,17 @@ static struct mnt_namespace *alloc_mnt_ns(void)
2365 2368
2366void mnt_make_longterm(struct vfsmount *mnt) 2369void mnt_make_longterm(struct vfsmount *mnt)
2367{ 2370{
2368 __mnt_make_longterm(mnt); 2371 __mnt_make_longterm(real_mount(mnt));
2369} 2372}
2370 2373
2371void mnt_make_shortterm(struct vfsmount *mnt) 2374void mnt_make_shortterm(struct vfsmount *m)
2372{ 2375{
2373#ifdef CONFIG_SMP 2376#ifdef CONFIG_SMP
2374 if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) 2377 struct mount *mnt = real_mount(m);
2378 if (atomic_add_unless(&mnt->mnt.mnt_longterm, -1, 1))
2375 return; 2379 return;
2376 br_write_lock(vfsmount_lock); 2380 br_write_lock(vfsmount_lock);
2377 atomic_dec(&mnt->mnt_longterm); 2381 atomic_dec(&mnt->mnt.mnt_longterm);
2378 br_write_unlock(vfsmount_lock); 2382 br_write_unlock(vfsmount_lock);
2379#endif 2383#endif
2380} 2384}
@@ -2418,17 +2422,17 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
2418 q = new; 2422 q = new;
2419 while (p) { 2423 while (p) {
2420 q->mnt.mnt_ns = new_ns; 2424 q->mnt.mnt_ns = new_ns;
2421 __mnt_make_longterm(&q->mnt); 2425 __mnt_make_longterm(q);
2422 if (fs) { 2426 if (fs) {
2423 if (&p->mnt == fs->root.mnt) { 2427 if (&p->mnt == fs->root.mnt) {
2424 fs->root.mnt = mntget(&q->mnt); 2428 fs->root.mnt = mntget(&q->mnt);
2425 __mnt_make_longterm(&q->mnt); 2429 __mnt_make_longterm(q);
2426 mnt_make_shortterm(&p->mnt); 2430 mnt_make_shortterm(&p->mnt);
2427 rootmnt = &p->mnt; 2431 rootmnt = &p->mnt;
2428 } 2432 }
2429 if (&p->mnt == fs->pwd.mnt) { 2433 if (&p->mnt == fs->pwd.mnt) {
2430 fs->pwd.mnt = mntget(&q->mnt); 2434 fs->pwd.mnt = mntget(&q->mnt);
2431 __mnt_make_longterm(&q->mnt); 2435 __mnt_make_longterm(q);
2432 mnt_make_shortterm(&p->mnt); 2436 mnt_make_shortterm(&p->mnt);
2433 pwdmnt = &p->mnt; 2437 pwdmnt = &p->mnt;
2434 } 2438 }
@@ -2474,7 +2478,7 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
2474 new_ns = alloc_mnt_ns(); 2478 new_ns = alloc_mnt_ns();
2475 if (!IS_ERR(new_ns)) { 2479 if (!IS_ERR(new_ns)) {
2476 mnt->mnt_ns = new_ns; 2480 mnt->mnt_ns = new_ns;
2477 __mnt_make_longterm(mnt); 2481 __mnt_make_longterm(real_mount(mnt));
2478 new_ns->root = mnt; 2482 new_ns->root = mnt;
2479 list_add(&new_ns->list, &new_ns->root->mnt_list); 2483 list_add(&new_ns->list, &new_ns->root->mnt_list);
2480 } else { 2484 } else {