aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-08-07 09:12:31 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-08-07 14:40:09 -0400
commit3064c3563ba4c23e2c7a47254ec056ed9ba0098a (patch)
tree806bc1df85e925686cc1075b659a6d6fe3e14aec
parent8fa1f1c2bd86007beb4a4845e6087ac4a704dc80 (diff)
death to mnt_pinned
Rather than playing silly buggers with vfsmount refcounts, just have acct_on() ask fs/namespace.c for internal clone of file->f_path.mnt and replace it with said clone. Then attach the pin to original vfsmount. Voila - the clone will be alive until the file gets closed, making sure that underlying superblock remains active, etc., and we can drop the original vfsmount, so that it's not kept busy. If the file lives until the final mntput of the original vfsmount, we'll notice that there's an fs_pin (one in bsd_acct_struct that holds that file) and mnt_pin_kill() will take it out. Since ->kill() is synchronous, we won't proceed past that point until these files are closed (and private clones of our vfsmount are gone), so we get the same ordering warranties we used to get. mnt_pin()/mnt_unpin()/->mnt_pinned is gone now, and good riddance - it never became usable outside of kernel/acct.c (and racy wrt umount even there). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/mount.h1
-rw-r--r--fs/namespace.c35
-rw-r--r--include/linux/mount.h4
-rw-r--r--kernel/acct.c24
4 files changed, 30 insertions, 34 deletions
diff --git a/fs/mount.h b/fs/mount.h
index 0a2d1458681f..6740a6215529 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -55,7 +55,6 @@ struct mount {
55 int mnt_id; /* mount identifier */ 55 int mnt_id; /* mount identifier */
56 int mnt_group_id; /* peer group identifier */ 56 int mnt_group_id; /* peer group identifier */
57 int mnt_expiry_mark; /* true if marked for expiry */ 57 int mnt_expiry_mark; /* true if marked for expiry */
58 int mnt_pinned;
59 struct hlist_head mnt_pins; 58 struct hlist_head mnt_pins;
60 struct path mnt_ex_mountpoint; 59 struct path mnt_ex_mountpoint;
61}; 60};
diff --git a/fs/namespace.c b/fs/namespace.c
index 0e4ce51c5277..65af9d0e0d67 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -937,7 +937,6 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
937 937
938static void mntput_no_expire(struct mount *mnt) 938static void mntput_no_expire(struct mount *mnt)
939{ 939{
940put_again:
941 rcu_read_lock(); 940 rcu_read_lock();
942 mnt_add_count(mnt, -1); 941 mnt_add_count(mnt, -1);
943 if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */ 942 if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */
@@ -950,14 +949,6 @@ put_again:
950 unlock_mount_hash(); 949 unlock_mount_hash();
951 return; 950 return;
952 } 951 }
953 if (unlikely(mnt->mnt_pinned)) {
954 mnt_add_count(mnt, mnt->mnt_pinned + 1);
955 mnt->mnt_pinned = 0;
956 rcu_read_unlock();
957 unlock_mount_hash();
958 mnt_pin_kill(mnt);
959 goto put_again;
960 }
961 if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) { 952 if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) {
962 rcu_read_unlock(); 953 rcu_read_unlock();
963 unlock_mount_hash(); 954 unlock_mount_hash();
@@ -980,6 +971,8 @@ put_again:
980 * so mnt_get_writers() below is safe. 971 * so mnt_get_writers() below is safe.
981 */ 972 */
982 WARN_ON(mnt_get_writers(mnt)); 973 WARN_ON(mnt_get_writers(mnt));
974 if (unlikely(mnt->mnt_pins.first))
975 mnt_pin_kill(mnt);
983 fsnotify_vfsmount_delete(&mnt->mnt); 976 fsnotify_vfsmount_delete(&mnt->mnt);
984 dput(mnt->mnt.mnt_root); 977 dput(mnt->mnt.mnt_root);
985 deactivate_super(mnt->mnt.mnt_sb); 978 deactivate_super(mnt->mnt.mnt_sb);
@@ -1007,25 +1000,15 @@ struct vfsmount *mntget(struct vfsmount *mnt)
1007} 1000}
1008EXPORT_SYMBOL(mntget); 1001EXPORT_SYMBOL(mntget);
1009 1002
1010void mnt_pin(struct vfsmount *mnt) 1003struct vfsmount *mnt_clone_internal(struct path *path)
1011{ 1004{
1012 lock_mount_hash(); 1005 struct mount *p;
1013 real_mount(mnt)->mnt_pinned++; 1006 p = clone_mnt(real_mount(path->mnt), path->dentry, CL_PRIVATE);
1014 unlock_mount_hash(); 1007 if (IS_ERR(p))
1015} 1008 return ERR_CAST(p);
1016EXPORT_SYMBOL(mnt_pin); 1009 p->mnt.mnt_flags |= MNT_INTERNAL;
1017 1010 return &p->mnt;
1018void mnt_unpin(struct vfsmount *m)
1019{
1020 struct mount *mnt = real_mount(m);
1021 lock_mount_hash();
1022 if (mnt->mnt_pinned) {
1023 mnt_add_count(mnt, 1);
1024 mnt->mnt_pinned--;
1025 }
1026 unlock_mount_hash();
1027} 1011}
1028EXPORT_SYMBOL(mnt_unpin);
1029 1012
1030static inline void mangle(struct seq_file *m, const char *s) 1013static inline void mangle(struct seq_file *m, const char *s)
1031{ 1014{
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 839bac270904..864b120c1345 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -62,6 +62,7 @@ struct vfsmount {
62}; 62};
63 63
64struct file; /* forward dec */ 64struct file; /* forward dec */
65struct path;
65 66
66extern int mnt_want_write(struct vfsmount *mnt); 67extern int mnt_want_write(struct vfsmount *mnt);
67extern int mnt_want_write_file(struct file *file); 68extern int mnt_want_write_file(struct file *file);
@@ -70,8 +71,7 @@ extern void mnt_drop_write(struct vfsmount *mnt);
70extern void mnt_drop_write_file(struct file *file); 71extern void mnt_drop_write_file(struct file *file);
71extern void mntput(struct vfsmount *mnt); 72extern void mntput(struct vfsmount *mnt);
72extern struct vfsmount *mntget(struct vfsmount *mnt); 73extern struct vfsmount *mntget(struct vfsmount *mnt);
73extern void mnt_pin(struct vfsmount *mnt); 74extern struct vfsmount *mnt_clone_internal(struct path *path);
74extern void mnt_unpin(struct vfsmount *mnt);
75extern int __mnt_is_readonly(struct vfsmount *mnt); 75extern int __mnt_is_readonly(struct vfsmount *mnt);
76 76
77struct file_system_type; 77struct file_system_type;
diff --git a/kernel/acct.c b/kernel/acct.c
index a7993a6cb604..2e6cf818021d 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -154,7 +154,6 @@ static void close_work(struct work_struct *work)
154{ 154{
155 struct bsd_acct_struct *acct = container_of(work, struct bsd_acct_struct, work); 155 struct bsd_acct_struct *acct = container_of(work, struct bsd_acct_struct, work);
156 struct file *file = acct->file; 156 struct file *file = acct->file;
157 mnt_unpin(file->f_path.mnt);
158 if (file->f_op->flush) 157 if (file->f_op->flush)
159 file->f_op->flush(file, NULL); 158 file->f_op->flush(file, NULL);
160 __fput_sync(file); 159 __fput_sync(file);
@@ -196,9 +195,10 @@ static void acct_pin_kill(struct fs_pin *pin)
196static int acct_on(struct filename *pathname) 195static int acct_on(struct filename *pathname)
197{ 196{
198 struct file *file; 197 struct file *file;
199 struct vfsmount *mnt; 198 struct vfsmount *mnt, *internal;
200 struct pid_namespace *ns = task_active_pid_ns(current); 199 struct pid_namespace *ns = task_active_pid_ns(current);
201 struct bsd_acct_struct *acct, *old; 200 struct bsd_acct_struct *acct, *old;
201 int err;
202 202
203 acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL); 203 acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL);
204 if (!acct) 204 if (!acct)
@@ -222,6 +222,21 @@ static int acct_on(struct filename *pathname)
222 filp_close(file, NULL); 222 filp_close(file, NULL);
223 return -EIO; 223 return -EIO;
224 } 224 }
225 internal = mnt_clone_internal(&file->f_path);
226 if (IS_ERR(internal)) {
227 kfree(acct);
228 filp_close(file, NULL);
229 return PTR_ERR(internal);
230 }
231 err = mnt_want_write(internal);
232 if (err) {
233 mntput(internal);
234 kfree(acct);
235 filp_close(file, NULL);
236 return err;
237 }
238 mnt = file->f_path.mnt;
239 file->f_path.mnt = internal;
225 240
226 atomic_long_set(&acct->pin.count, 1); 241 atomic_long_set(&acct->pin.count, 1);
227 acct->pin.kill = acct_pin_kill; 242 acct->pin.kill = acct_pin_kill;
@@ -229,8 +244,6 @@ static int acct_on(struct filename *pathname)
229 acct->needcheck = jiffies; 244 acct->needcheck = jiffies;
230 acct->ns = ns; 245 acct->ns = ns;
231 mutex_init(&acct->lock); 246 mutex_init(&acct->lock);
232 mnt = file->f_path.mnt;
233 mnt_pin(mnt);
234 mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */ 247 mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */
235 pin_insert(&acct->pin, mnt); 248 pin_insert(&acct->pin, mnt);
236 249
@@ -240,7 +253,8 @@ static int acct_on(struct filename *pathname)
240 else 253 else
241 ns->bacct = acct; 254 ns->bacct = acct;
242 mutex_unlock(&acct->lock); 255 mutex_unlock(&acct->lock);
243 mntput(mnt); /* it's pinned, now give up active reference */ 256 mnt_drop_write(mnt);
257 mntput(mnt);
244 return 0; 258 return 0;
245} 259}
246 260