From: Ram <linuxram@us.ibm.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: dhowells@redhat.com, jamie@shareable.org,
viro@parcelfarce.linux.theplanet.co.uk,
Andrew Morton <akpm@osdl.org>,
linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH] fix race in mark_mounts_for_expiry()
Date: Wed, 18 May 2005 11:47:54 -0700 [thread overview]
Message-ID: <1116442073.24560.142.camel@localhost> (raw)
In-Reply-To: <E1DYRnw-0001J6-00@dorka.pomaz.szeredi.hu>
On Wed, 2005-05-18 at 09:53, Miklos Szeredi wrote:
> > E.g. having a separate task count, which is incremented/decremented
> > only by clone/exit. If the task count goes to zero, umount_tree is
> > called on root, but namespace is not freed.
> >
> > And each mnt_namespace holds a proper reference to the namespace, so
> > it's safe to dereference it anytime. When truly no more references
> > remain, the namespace can go away.
> >
> > Hmm?
First of all the reason this race exists implies Al Viro may have had
assertion in his mind that "All tasks that have access to a namespace
has a refcount on that namespace". If that was what he was thinking,
than the I would stick with that assertion being true. The overall idea
I am thinking off is:
1) have the automounter hold a refcount on any new namespace created
the mounts in which the automounter has interest in.
2) have a refcount on the namespace when a new task gains access to
a namespace through the file descriptor or any other
similar mechanisms and remove the reference
once the fd gets closed. (bit tricky to implement)
Do you agree with the overall idea?
If so I will try to come up with a patch.
RP
>
> Here's a patch (compile and boot tested).
>
> Now there are two solutions to one problem, the previous one is ugly,
> this one is buggy. Which should it be?
>
> Thanks,
> Miklos
>
> Index: linux/include/linux/namespace.h
> ===================================================================
> --- linux.orig/include/linux/namespace.h 2005-05-18 18:02:24.000000000 +0200
> +++ linux/include/linux/namespace.h 2005-05-18 18:28:48.000000000 +0200
> @@ -7,18 +7,26 @@
>
> struct namespace {
> atomic_t count;
> + atomic_t task_count; /* how many tasks use this */
> struct vfsmount * root;
> struct list_head list;
> struct rw_semaphore sem;
> };
>
> extern int copy_namespace(int, struct task_struct *);
> -extern void __put_namespace(struct namespace *namespace);
> +extern void __exit_namespace(struct namespace *namespace);
>
> static inline void put_namespace(struct namespace *namespace)
> {
> - if (atomic_dec_and_test(&namespace->count))
> - __put_namespace(namespace);
> + if (namespace && atomic_dec_and_test(&namespace->count))
> + kfree(namespace);
> +}
> +
> +static inline struct namespace *get_namespace(struct namespace *namespace)
> +{
> + if (namespace)
> + atomic_inc(&namespace->count);
> + return namespace;
> }
>
> static inline void exit_namespace(struct task_struct *p)
> @@ -28,14 +36,10 @@ static inline void exit_namespace(struct
> task_lock(p);
> p->namespace = NULL;
> task_unlock(p);
> - put_namespace(namespace);
> + if (atomic_dec_and_test(&p->namespace->task_count))
> + __exit_namespace(p->namespace);
> }
> }
>
> -static inline void get_namespace(struct namespace *namespace)
> -{
> - atomic_inc(&namespace->count);
> -}
> -
> #endif
> #endif
> Index: linux/fs/namespace.c
> ===================================================================
> --- linux.orig/fs/namespace.c 2005-05-18 17:42:46.000000000 +0200
> +++ linux/fs/namespace.c 2005-05-18 18:32:29.000000000 +0200
> @@ -160,7 +160,7 @@ clone_mnt(struct vfsmount *old, struct d
> mnt->mnt_root = dget(root);
> mnt->mnt_mountpoint = mnt->mnt_root;
> mnt->mnt_parent = mnt;
> - mnt->mnt_namespace = current->namespace;
> + mnt->mnt_namespace = get_namespace(current->namespace);
>
> /* stick the duplicate mount on the same expiry list
> * as the original if that was on one */
> @@ -345,13 +345,15 @@ static void umount_tree(struct vfsmount
> for (p = mnt; p; p = next_mnt(p, mnt)) {
> list_del(&p->mnt_list);
> list_add(&p->mnt_list, &kill);
> - p->mnt_namespace = NULL;
> }
>
> while (!list_empty(&kill)) {
> + struct namespace *n;
> mnt = list_entry(kill.next, struct vfsmount, mnt_list);
> list_del_init(&mnt->mnt_list);
> list_del_init(&mnt->mnt_fslink);
> + n = mnt->mnt_namespace;
> + mnt->mnt_namespace = NULL;
> if (mnt->mnt_parent == mnt) {
> spin_unlock(&vfsmount_lock);
> } else {
> @@ -361,6 +363,7 @@ static void umount_tree(struct vfsmount
> path_release(&old_nd);
> }
> mntput(mnt);
> + put_namespace(n);
> spin_lock(&vfsmount_lock);
> }
> }
> @@ -866,12 +869,9 @@ void mark_mounts_for_expiry(struct list_
> mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink);
> list_del_init(&mnt->mnt_fslink);
>
> - /* don't do anything if the namespace is dead - all the
> - * vfsmounts from it are going away anyway */
> - namespace = mnt->mnt_namespace;
> - if (!namespace || atomic_read(&namespace->count) <= 0)
> + namespace = get_namespace(mnt->mnt_namespace);
> + if (!namespace)
> continue;
> - get_namespace(namespace);
>
> spin_unlock(&vfsmount_lock);
> down_write(&namespace->sem);
> @@ -1073,8 +1073,10 @@ int copy_namespace(int flags, struct tas
>
> get_namespace(namespace);
>
> - if (!(flags & CLONE_NEWNS))
> + if (!(flags & CLONE_NEWNS)) {
> + atomic_inc(&namespace->task_count);
> return 0;
> + }
>
> if (!capable(CAP_SYS_ADMIN)) {
> put_namespace(namespace);
> @@ -1086,6 +1088,7 @@ int copy_namespace(int flags, struct tas
> goto out;
>
> atomic_set(&new_ns->count, 1);
> + atomic_set(&new_ns->task_count, 1);
> init_rwsem(&new_ns->sem);
> INIT_LIST_HEAD(&new_ns->list);
>
> @@ -1109,7 +1112,9 @@ int copy_namespace(int flags, struct tas
> p = namespace->root;
> q = new_ns->root;
> while (p) {
> - q->mnt_namespace = new_ns;
> + struct namespace *oldns = q->mnt_namespace;
> + q->mnt_namespace = get_namespace(new_ns);
> + put_namespace(oldns);
> if (fs) {
> if (p == fs->rootmnt) {
> rootmnt = p;
> @@ -1381,16 +1386,17 @@ static void __init init_mount_tree(void)
> if (!namespace)
> panic("Can't allocate initial namespace");
> atomic_set(&namespace->count, 1);
> + atomic_set(&namespace->task_count, 0);
> INIT_LIST_HEAD(&namespace->list);
> init_rwsem(&namespace->sem);
> list_add(&mnt->mnt_list, &namespace->list);
> namespace->root = mnt;
> - mnt->mnt_namespace = namespace;
> + mnt->mnt_namespace = get_namespace(namespace);
>
> init_task.namespace = namespace;
> read_lock(&tasklist_lock);
> do_each_thread(g, p) {
> - get_namespace(namespace);
> + atomic_inc(&namespace->task_count);
> p->namespace = namespace;
> } while_each_thread(g, p);
> read_unlock(&tasklist_lock);
> @@ -1448,12 +1454,13 @@ void __init mnt_init(unsigned long mempa
> init_mount_tree();
> }
>
> -void __put_namespace(struct namespace *namespace)
> +void __exit_namespace(struct namespace *namespace)
> {
> down_write(&namespace->sem);
> spin_lock(&vfsmount_lock);
> umount_tree(namespace->root);
> + namespace->root = NULL;
> spin_unlock(&vfsmount_lock);
> up_write(&namespace->sem);
> - kfree(namespace);
> + put_namespace(namespace);
> }
> Index: linux/fs/super.c
> ===================================================================
> --- linux.orig/fs/super.c 2005-05-17 13:46:56.000000000 +0200
> +++ linux/fs/super.c 2005-05-18 18:44:18.000000000 +0200
> @@ -37,6 +37,7 @@
> #include <linux/writeback.h> /* for the emergency remount stuff */
> #include <linux/idr.h>
> #include <linux/kobject.h>
> +#include <linux/namespace.h>
> #include <asm/uaccess.h>
>
>
> @@ -842,7 +843,7 @@ do_kern_mount(const char *fstype, int fl
> mnt->mnt_root = dget(sb->s_root);
> mnt->mnt_mountpoint = sb->s_root;
> mnt->mnt_parent = mnt;
> - mnt->mnt_namespace = current->namespace;
> + mnt->mnt_namespace = get_namespace(current->namespace);
> up_write(&sb->s_umount);
> put_filesystem(type);
> return mnt;
next prev parent reply other threads:[~2005-05-18 18:48 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-05-13 10:44 [PATCH] namespace.c: fix bind mount from foreign namespace Miklos Szeredi
2005-05-13 16:49 ` Ram
2005-05-13 17:06 ` Al Viro
2005-05-13 17:17 ` Miklos Szeredi
2005-05-13 17:25 ` Al Viro
2005-05-13 17:34 ` Miklos Szeredi
2005-05-13 17:29 ` Ram
2005-05-13 18:40 ` Miklos Szeredi
[not found] ` <1116012287.6248.410.camel@localhost>
[not found] ` <E1DWfqJ-0004eP-00@dorka.pomaz.szeredi.hu>
[not found] ` <1116013840.6248.429.camel@localhost>
2005-05-14 6:11 ` Miklos Szeredi
2005-05-16 15:11 ` Ram
2005-05-16 8:44 ` Miklos Szeredi
2005-05-16 8:59 ` Miklos Szeredi
2005-05-16 11:26 ` Jamie Lokier
2005-05-16 13:23 ` Miklos Szeredi
2005-05-16 11:14 ` Jamie Lokier
2005-05-17 3:50 ` Ram
2005-05-16 20:15 ` Miklos Szeredi
2005-05-17 1:28 ` Jamie Lokier
2005-05-17 5:34 ` Miklos Szeredi
[not found] ` <1116360352.24560.85.camel@localhost>
[not found] ` <E1DYI0m-0000K5-00@dorka.pomaz.szeredi.hu>
[not found] ` <1116399887.24560.116.camel@localhost>
[not found] ` <1116400118.24560.119.camel@localhost>
2005-05-18 9:51 ` [PATCH] fix race in mark_mounts_for_expiry() Miklos Szeredi
2005-05-18 10:32 ` David Howells
2005-05-18 10:37 ` Miklos Szeredi
2005-05-18 10:46 ` David Howells
2005-05-18 10:53 ` Miklos Szeredi
2005-05-18 11:07 ` Trond Myklebust
2005-05-18 11:32 ` Miklos Szeredi
2005-05-18 12:50 ` Jamie Lokier
2005-05-18 13:21 ` Miklos Szeredi
2005-05-18 17:34 ` Jamie Lokier
2005-05-18 19:05 ` Miklos Szeredi
2005-05-18 19:52 ` Jamie Lokier
2005-05-19 12:41 ` Miklos Szeredi
2005-05-18 10:59 ` David Howells
2005-05-18 11:14 ` Miklos Szeredi
2005-05-18 11:51 ` David Howells
2005-05-18 12:08 ` Miklos Szeredi
2005-05-18 12:33 ` Miklos Szeredi
2005-05-18 16:53 ` Miklos Szeredi
2005-05-18 18:47 ` Ram [this message]
2005-05-18 19:19 ` Miklos Szeredi
2005-05-18 20:35 ` Ram
2005-05-19 12:52 ` Miklos Szeredi
2005-05-17 18:48 ` [PATCH] namespace.c: fix bind mount from foreign namespace Ram
2005-05-17 0:00 ` Jamie Lokier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1116442073.24560.142.camel@localhost \
--to=linuxram@us.ibm.com \
--cc=akpm@osdl.org \
--cc=dhowells@redhat.com \
--cc=jamie@shareable.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=viro@parcelfarce.linux.theplanet.co.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).