From 83adc7532229f1909cf37c429780f02f06fe05ee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 24 Nov 2011 22:37:54 -0500 Subject: [PATCH] vfs: spread struct mount - work with counters Signed-off-by: Al Viro --- fs/namespace.c | 124 +++++++++++++++++++++++++------------------------ fs/pnode.c | 2 +- fs/pnode.h | 2 +- 3 files changed, 66 insertions(+), 62 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) /* * vfsmount lock must be held for read */ -static inline void mnt_add_count(struct vfsmount *mnt, int n) +static inline void mnt_add_count(struct mount *mnt, int n) { #ifdef CONFIG_SMP - this_cpu_add(mnt->mnt_pcp->mnt_count, n); + this_cpu_add(mnt->mnt.mnt_pcp->mnt_count, n); #else preempt_disable(); - mnt->mnt_count += n; + mnt->mnt.mnt_count += n; preempt_enable(); #endif } @@ -155,19 +155,19 @@ static inline void mnt_add_count(struct vfsmount *mnt, int n) /* * vfsmount lock must be held for write */ -unsigned int mnt_get_count(struct vfsmount *mnt) +unsigned int mnt_get_count(struct mount *mnt) { #ifdef CONFIG_SMP unsigned int count = 0; int cpu; for_each_possible_cpu(cpu) { - count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count; + count += per_cpu_ptr(mnt->mnt.mnt_pcp, cpu)->mnt_count; } return count; #else - return mnt->mnt_count; + return mnt->mnt.mnt_count; #endif } @@ -253,32 +253,32 @@ int __mnt_is_readonly(struct vfsmount *mnt) } EXPORT_SYMBOL_GPL(__mnt_is_readonly); -static inline void mnt_inc_writers(struct vfsmount *mnt) +static inline void mnt_inc_writers(struct mount *mnt) { #ifdef CONFIG_SMP - this_cpu_inc(mnt->mnt_pcp->mnt_writers); + this_cpu_inc(mnt->mnt.mnt_pcp->mnt_writers); #else - mnt->mnt_writers++; + mnt->mnt.mnt_writers++; #endif } -static inline void mnt_dec_writers(struct vfsmount *mnt) +static inline void mnt_dec_writers(struct mount *mnt) { #ifdef CONFIG_SMP - this_cpu_dec(mnt->mnt_pcp->mnt_writers); + this_cpu_dec(mnt->mnt.mnt_pcp->mnt_writers); #else - mnt->mnt_writers--; + mnt->mnt.mnt_writers--; #endif } -static unsigned int mnt_get_writers(struct vfsmount *mnt) +static unsigned int mnt_get_writers(struct mount *mnt) { #ifdef CONFIG_SMP unsigned int count = 0; int cpu; for_each_possible_cpu(cpu) { - count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers; + count += per_cpu_ptr(mnt->mnt.mnt_pcp, cpu)->mnt_writers; } return count; @@ -297,7 +297,7 @@ static unsigned int mnt_get_writers(struct vfsmount *mnt) */ /** * mnt_want_write - get write access to a mount - * @mnt: the mount on which to take a write + * @m: the mount on which to take a write * * This tells the low-level filesystem that a write is * about to be performed to it, and makes sure that @@ -305,8 +305,9 @@ static unsigned int mnt_get_writers(struct vfsmount *mnt) * the write operation is finished, mnt_drop_write() * must be called. This is effectively a refcount. */ -int mnt_want_write(struct vfsmount *mnt) +int mnt_want_write(struct vfsmount *m) { + struct mount *mnt = real_mount(m); int ret = 0; preempt_disable(); @@ -317,7 +318,7 @@ int mnt_want_write(struct vfsmount *mnt) * incremented count after it has set MNT_WRITE_HOLD. */ smp_mb(); - while (mnt->mnt_flags & MNT_WRITE_HOLD) + while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) cpu_relax(); /* * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will @@ -325,7 +326,7 @@ int mnt_want_write(struct vfsmount *mnt) * MNT_WRITE_HOLD is cleared. */ smp_rmb(); - if (__mnt_is_readonly(mnt)) { + if (__mnt_is_readonly(m)) { mnt_dec_writers(mnt); ret = -EROFS; goto out; @@ -354,7 +355,7 @@ int mnt_clone_write(struct vfsmount *mnt) if (__mnt_is_readonly(mnt)) return -EROFS; preempt_disable(); - mnt_inc_writers(mnt); + mnt_inc_writers(real_mount(mnt)); preempt_enable(); return 0; } @@ -388,7 +389,7 @@ EXPORT_SYMBOL_GPL(mnt_want_write_file); void mnt_drop_write(struct vfsmount *mnt) { preempt_disable(); - mnt_dec_writers(mnt); + mnt_dec_writers(real_mount(mnt)); preempt_enable(); } EXPORT_SYMBOL_GPL(mnt_drop_write); @@ -399,12 +400,12 @@ void mnt_drop_write_file(struct file *file) } EXPORT_SYMBOL(mnt_drop_write_file); -static int mnt_make_readonly(struct vfsmount *mnt) +static int mnt_make_readonly(struct mount *mnt) { int ret = 0; br_write_lock(vfsmount_lock); - mnt->mnt_flags |= MNT_WRITE_HOLD; + mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; /* * After storing MNT_WRITE_HOLD, we'll read the counters. This store * should be visible before we do. @@ -430,21 +431,21 @@ static int mnt_make_readonly(struct vfsmount *mnt) if (mnt_get_writers(mnt) > 0) ret = -EBUSY; else - mnt->mnt_flags |= MNT_READONLY; + mnt->mnt.mnt_flags |= MNT_READONLY; /* * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers * that become unheld will see MNT_READONLY. */ smp_wmb(); - mnt->mnt_flags &= ~MNT_WRITE_HOLD; + mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; br_write_unlock(vfsmount_lock); return ret; } -static void __mnt_unmake_readonly(struct vfsmount *mnt) +static void __mnt_unmake_readonly(struct mount *mnt) { br_write_lock(vfsmount_lock); - mnt->mnt_flags &= ~MNT_READONLY; + mnt->mnt.mnt_flags &= ~MNT_READONLY; br_write_unlock(vfsmount_lock); } @@ -590,18 +591,18 @@ static void attach_mnt(struct mount *mnt, struct path *path) list_add_tail(&mnt->mnt.mnt_child, &path->mnt->mnt_mounts); } -static inline void __mnt_make_longterm(struct vfsmount *mnt) +static inline void __mnt_make_longterm(struct mount *mnt) { #ifdef CONFIG_SMP - atomic_inc(&mnt->mnt_longterm); + atomic_inc(&mnt->mnt.mnt_longterm); #endif } /* needs vfsmount lock for write */ -static inline void __mnt_make_shortterm(struct vfsmount *mnt) +static inline void __mnt_make_shortterm(struct mount *mnt) { #ifdef CONFIG_SMP - atomic_dec(&mnt->mnt_longterm); + atomic_dec(&mnt->mnt.mnt_longterm); #endif } @@ -611,15 +612,15 @@ static inline void __mnt_make_shortterm(struct vfsmount *mnt) static void commit_tree(struct mount *mnt) { struct mount *parent = mnt->mnt_parent; - struct vfsmount *m; + struct mount *m; LIST_HEAD(head); struct mnt_namespace *n = parent->mnt.mnt_ns; BUG_ON(parent == mnt); list_add_tail(&head, &mnt->mnt.mnt_list); - list_for_each_entry(m, &head, mnt_list) { - m->mnt_ns = n; + list_for_each_entry(m, &head, mnt.mnt_list) { + m->mnt.mnt_ns = n; __mnt_make_longterm(m); } @@ -740,9 +741,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, return NULL; } -static inline void mntfree(struct vfsmount *mnt) +static inline void mntfree(struct mount *mnt) { - struct super_block *sb = mnt->mnt_sb; + struct vfsmount *m = &mnt->mnt; + struct super_block *sb = m->mnt_sb; /* * This probably indicates that somebody messed @@ -755,18 +757,19 @@ static inline void mntfree(struct vfsmount *mnt) * so mnt_get_writers() below is safe. */ WARN_ON(mnt_get_writers(mnt)); - fsnotify_vfsmount_delete(mnt); - dput(mnt->mnt_root); - free_vfsmnt(real_mount(mnt)); + fsnotify_vfsmount_delete(m); + dput(m->mnt_root); + free_vfsmnt(mnt); deactivate_super(sb); } -static void mntput_no_expire(struct vfsmount *mnt) +static void mntput_no_expire(struct vfsmount *m) { + struct mount *mnt = real_mount(m); put_again: #ifdef CONFIG_SMP br_read_lock(vfsmount_lock); - if (likely(atomic_read(&mnt->mnt_longterm))) { + if (likely(atomic_read(&mnt->mnt.mnt_longterm))) { mnt_add_count(mnt, -1); br_read_unlock(vfsmount_lock); return; @@ -785,11 +788,11 @@ static void mntput_no_expire(struct vfsmount *mnt) return; br_write_lock(vfsmount_lock); #endif - if (unlikely(mnt->mnt_pinned)) { - mnt_add_count(mnt, mnt->mnt_pinned + 1); - mnt->mnt_pinned = 0; + if (unlikely(mnt->mnt.mnt_pinned)) { + mnt_add_count(mnt, mnt->mnt.mnt_pinned + 1); + mnt->mnt.mnt_pinned = 0; br_write_unlock(vfsmount_lock); - acct_auto_close_mnt(mnt); + acct_auto_close_mnt(m); goto put_again; } br_write_unlock(vfsmount_lock); @@ -810,7 +813,7 @@ EXPORT_SYMBOL(mntput); struct vfsmount *mntget(struct vfsmount *mnt) { if (mnt) - mnt_add_count(mnt, 1); + mnt_add_count(real_mount(mnt), 1); return mnt; } EXPORT_SYMBOL(mntget); @@ -827,7 +830,7 @@ void mnt_unpin(struct vfsmount *mnt) { br_write_lock(vfsmount_lock); if (mnt->mnt_pinned) { - mnt_add_count(mnt, 1); + mnt_add_count(real_mount(mnt), 1); mnt->mnt_pinned--; } br_write_unlock(vfsmount_lock); @@ -1150,7 +1153,7 @@ int may_umount_tree(struct vfsmount *mnt) /* write lock needed for mnt_get_count */ br_write_lock(vfsmount_lock); for (p = real_mount(mnt); p; p = next_mnt(p, mnt)) { - actual_refs += mnt_get_count(&p->mnt); + actual_refs += mnt_get_count(p); minimum_refs += 2; } br_write_unlock(vfsmount_lock); @@ -1234,7 +1237,7 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill) list_del_init(&p->mnt.mnt_list); __touch_mnt_namespace(p->mnt.mnt_ns); p->mnt.mnt_ns = NULL; - __mnt_make_shortterm(&p->mnt); + __mnt_make_shortterm(p); list_del_init(&p->mnt.mnt_child); if (mnt_has_parent(p)) { p->mnt_parent->mnt.mnt_ghosts++; @@ -1273,7 +1276,7 @@ static int do_umount(struct mount *mnt, int flags) * all race cases, but it's a slowpath. */ br_write_lock(vfsmount_lock); - if (mnt_get_count(&mnt->mnt) != 2) { + if (mnt_get_count(mnt) != 2) { br_write_unlock(vfsmount_lock); return -EBUSY; } @@ -1798,9 +1801,9 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags) return 0; if (readonly_request) - error = mnt_make_readonly(mnt); + error = mnt_make_readonly(real_mount(mnt)); else - __mnt_unmake_readonly(mnt); + __mnt_unmake_readonly(real_mount(mnt)); return error; } @@ -2034,7 +2037,7 @@ int finish_automount(struct vfsmount *m, struct path *path) /* The new mount record should have at least 2 refs to prevent it being * expired before we get a chance to add it */ - BUG_ON(mnt_get_count(m) < 2); + BUG_ON(mnt_get_count(real_mount(m)) < 2); if (m->mnt_sb == path->mnt->mnt_sb && m->mnt_root == path->dentry) { @@ -2365,16 +2368,17 @@ static struct mnt_namespace *alloc_mnt_ns(void) void mnt_make_longterm(struct vfsmount *mnt) { - __mnt_make_longterm(mnt); + __mnt_make_longterm(real_mount(mnt)); } -void mnt_make_shortterm(struct vfsmount *mnt) +void mnt_make_shortterm(struct vfsmount *m) { #ifdef CONFIG_SMP - if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) + struct mount *mnt = real_mount(m); + if (atomic_add_unless(&mnt->mnt.mnt_longterm, -1, 1)) return; br_write_lock(vfsmount_lock); - atomic_dec(&mnt->mnt_longterm); + atomic_dec(&mnt->mnt.mnt_longterm); br_write_unlock(vfsmount_lock); #endif } @@ -2418,17 +2422,17 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, q = new; while (p) { q->mnt.mnt_ns = new_ns; - __mnt_make_longterm(&q->mnt); + __mnt_make_longterm(q); if (fs) { if (&p->mnt == fs->root.mnt) { fs->root.mnt = mntget(&q->mnt); - __mnt_make_longterm(&q->mnt); + __mnt_make_longterm(q); mnt_make_shortterm(&p->mnt); rootmnt = &p->mnt; } if (&p->mnt == fs->pwd.mnt) { fs->pwd.mnt = mntget(&q->mnt); - __mnt_make_longterm(&q->mnt); + __mnt_make_longterm(q); mnt_make_shortterm(&p->mnt); pwdmnt = &p->mnt; } @@ -2474,7 +2478,7 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) new_ns = alloc_mnt_ns(); if (!IS_ERR(new_ns)) { mnt->mnt_ns = new_ns; - __mnt_make_longterm(mnt); + __mnt_make_longterm(real_mount(mnt)); new_ns->root = mnt; list_add(&new_ns->list, &new_ns->root->mnt_list); } else { diff --git a/fs/pnode.c b/fs/pnode.c index bd280200bd37..50fdb29eebfe 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -274,7 +274,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, */ static inline int do_refcount_check(struct mount *mnt, int count) { - int mycount = mnt_get_count(&mnt->mnt) - mnt->mnt.mnt_ghosts; + int mycount = mnt_get_count(mnt) - mnt->mnt.mnt_ghosts; return (mycount > count); } diff --git a/fs/pnode.h b/fs/pnode.h index 866b3e292887..0a7a919d5efd 100644 --- a/fs/pnode.h +++ b/fs/pnode.h @@ -36,7 +36,7 @@ int propagate_umount(struct list_head *); int propagate_mount_busy(struct mount *, int); void mnt_release_group_id(struct mount *); int get_dominating_id(struct vfsmount *mnt, const struct path *root); -unsigned int mnt_get_count(struct vfsmount *mnt); +unsigned int mnt_get_count(struct mount *mnt); void mnt_set_mountpoint(struct vfsmount *, struct dentry *, struct mount *); void release_mounts(struct list_head *);