aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/acct.c
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 /kernel/acct.c
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>
Diffstat (limited to 'kernel/acct.c')
-rw-r--r--kernel/acct.c24
1 files changed, 19 insertions, 5 deletions
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