Commit 3064c356 authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 8fa1f1c2
...@@ -55,7 +55,6 @@ struct mount { ...@@ -55,7 +55,6 @@ struct mount {
int mnt_id; /* mount identifier */ int mnt_id; /* mount identifier */
int mnt_group_id; /* peer group identifier */ int mnt_group_id; /* peer group identifier */
int mnt_expiry_mark; /* true if marked for expiry */ int mnt_expiry_mark; /* true if marked for expiry */
int mnt_pinned;
struct hlist_head mnt_pins; struct hlist_head mnt_pins;
struct path mnt_ex_mountpoint; struct path mnt_ex_mountpoint;
}; };
......
...@@ -937,7 +937,6 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, ...@@ -937,7 +937,6 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
static void mntput_no_expire(struct mount *mnt) static void mntput_no_expire(struct mount *mnt)
{ {
put_again:
rcu_read_lock(); rcu_read_lock();
mnt_add_count(mnt, -1); mnt_add_count(mnt, -1);
if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */ if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */
...@@ -950,14 +949,6 @@ static void mntput_no_expire(struct mount *mnt) ...@@ -950,14 +949,6 @@ static void mntput_no_expire(struct mount *mnt)
unlock_mount_hash(); unlock_mount_hash();
return; return;
} }
if (unlikely(mnt->mnt_pinned)) {
mnt_add_count(mnt, mnt->mnt_pinned + 1);
mnt->mnt_pinned = 0;
rcu_read_unlock();
unlock_mount_hash();
mnt_pin_kill(mnt);
goto put_again;
}
if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) { if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) {
rcu_read_unlock(); rcu_read_unlock();
unlock_mount_hash(); unlock_mount_hash();
...@@ -980,6 +971,8 @@ static void mntput_no_expire(struct mount *mnt) ...@@ -980,6 +971,8 @@ static void mntput_no_expire(struct mount *mnt)
* so mnt_get_writers() below is safe. * so mnt_get_writers() below is safe.
*/ */
WARN_ON(mnt_get_writers(mnt)); WARN_ON(mnt_get_writers(mnt));
if (unlikely(mnt->mnt_pins.first))
mnt_pin_kill(mnt);
fsnotify_vfsmount_delete(&mnt->mnt); fsnotify_vfsmount_delete(&mnt->mnt);
dput(mnt->mnt.mnt_root); dput(mnt->mnt.mnt_root);
deactivate_super(mnt->mnt.mnt_sb); deactivate_super(mnt->mnt.mnt_sb);
...@@ -1007,25 +1000,15 @@ struct vfsmount *mntget(struct vfsmount *mnt) ...@@ -1007,25 +1000,15 @@ struct vfsmount *mntget(struct vfsmount *mnt)
} }
EXPORT_SYMBOL(mntget); EXPORT_SYMBOL(mntget);
void mnt_pin(struct vfsmount *mnt) struct vfsmount *mnt_clone_internal(struct path *path)
{ {
lock_mount_hash(); struct mount *p;
real_mount(mnt)->mnt_pinned++; p = clone_mnt(real_mount(path->mnt), path->dentry, CL_PRIVATE);
unlock_mount_hash(); if (IS_ERR(p))
} return ERR_CAST(p);
EXPORT_SYMBOL(mnt_pin); p->mnt.mnt_flags |= MNT_INTERNAL;
return &p->mnt;
void mnt_unpin(struct vfsmount *m)
{
struct mount *mnt = real_mount(m);
lock_mount_hash();
if (mnt->mnt_pinned) {
mnt_add_count(mnt, 1);
mnt->mnt_pinned--;
}
unlock_mount_hash();
} }
EXPORT_SYMBOL(mnt_unpin);
static inline void mangle(struct seq_file *m, const char *s) static inline void mangle(struct seq_file *m, const char *s)
{ {
......
...@@ -62,6 +62,7 @@ struct vfsmount { ...@@ -62,6 +62,7 @@ struct vfsmount {
}; };
struct file; /* forward dec */ struct file; /* forward dec */
struct path;
extern int mnt_want_write(struct vfsmount *mnt); extern int mnt_want_write(struct vfsmount *mnt);
extern int mnt_want_write_file(struct file *file); extern int mnt_want_write_file(struct file *file);
...@@ -70,8 +71,7 @@ extern void mnt_drop_write(struct vfsmount *mnt); ...@@ -70,8 +71,7 @@ extern void mnt_drop_write(struct vfsmount *mnt);
extern void mnt_drop_write_file(struct file *file); extern void mnt_drop_write_file(struct file *file);
extern void mntput(struct vfsmount *mnt); extern void mntput(struct vfsmount *mnt);
extern struct vfsmount *mntget(struct vfsmount *mnt); extern struct vfsmount *mntget(struct vfsmount *mnt);
extern void mnt_pin(struct vfsmount *mnt); extern struct vfsmount *mnt_clone_internal(struct path *path);
extern void mnt_unpin(struct vfsmount *mnt);
extern int __mnt_is_readonly(struct vfsmount *mnt); extern int __mnt_is_readonly(struct vfsmount *mnt);
struct file_system_type; struct file_system_type;
......
...@@ -154,7 +154,6 @@ static void close_work(struct work_struct *work) ...@@ -154,7 +154,6 @@ static void close_work(struct work_struct *work)
{ {
struct bsd_acct_struct *acct = container_of(work, struct bsd_acct_struct, work); struct bsd_acct_struct *acct = container_of(work, struct bsd_acct_struct, work);
struct file *file = acct->file; struct file *file = acct->file;
mnt_unpin(file->f_path.mnt);
if (file->f_op->flush) if (file->f_op->flush)
file->f_op->flush(file, NULL); file->f_op->flush(file, NULL);
__fput_sync(file); __fput_sync(file);
...@@ -196,9 +195,10 @@ static void acct_pin_kill(struct fs_pin *pin) ...@@ -196,9 +195,10 @@ static void acct_pin_kill(struct fs_pin *pin)
static int acct_on(struct filename *pathname) static int acct_on(struct filename *pathname)
{ {
struct file *file; struct file *file;
struct vfsmount *mnt; struct vfsmount *mnt, *internal;
struct pid_namespace *ns = task_active_pid_ns(current); struct pid_namespace *ns = task_active_pid_ns(current);
struct bsd_acct_struct *acct, *old; struct bsd_acct_struct *acct, *old;
int err;
acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL); acct = kzalloc(sizeof(struct bsd_acct_struct), GFP_KERNEL);
if (!acct) if (!acct)
...@@ -222,6 +222,21 @@ static int acct_on(struct filename *pathname) ...@@ -222,6 +222,21 @@ static int acct_on(struct filename *pathname)
filp_close(file, NULL); filp_close(file, NULL);
return -EIO; return -EIO;
} }
internal = mnt_clone_internal(&file->f_path);
if (IS_ERR(internal)) {
kfree(acct);
filp_close(file, NULL);
return PTR_ERR(internal);
}
err = mnt_want_write(internal);
if (err) {
mntput(internal);
kfree(acct);
filp_close(file, NULL);
return err;
}
mnt = file->f_path.mnt;
file->f_path.mnt = internal;
atomic_long_set(&acct->pin.count, 1); atomic_long_set(&acct->pin.count, 1);
acct->pin.kill = acct_pin_kill; acct->pin.kill = acct_pin_kill;
...@@ -229,8 +244,6 @@ static int acct_on(struct filename *pathname) ...@@ -229,8 +244,6 @@ static int acct_on(struct filename *pathname)
acct->needcheck = jiffies; acct->needcheck = jiffies;
acct->ns = ns; acct->ns = ns;
mutex_init(&acct->lock); mutex_init(&acct->lock);
mnt = file->f_path.mnt;
mnt_pin(mnt);
mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */ mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */
pin_insert(&acct->pin, mnt); pin_insert(&acct->pin, mnt);
...@@ -240,7 +253,8 @@ static int acct_on(struct filename *pathname) ...@@ -240,7 +253,8 @@ static int acct_on(struct filename *pathname)
else else
ns->bacct = acct; ns->bacct = acct;
mutex_unlock(&acct->lock); mutex_unlock(&acct->lock);
mntput(mnt); /* it's pinned, now give up active reference */ mnt_drop_write(mnt);
mntput(mnt);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment