Hi Eric, Today's linux-next merge of the userns tree got a conflict in fs/namespace.c between various commits from Linus' tree and various commits from the userns tree. I fixed it up (hopefully - see below) and can carry the fix as necessary (no action is required). -- Cheers, Stephen Rothwell sfr@canb.auug.org.au diff --cc fs/namespace.c index 182bc41cd887,128c051041be..000000000000 --- a/fs/namespace.c +++ b/fs/namespace.c @@@ -667,13 -632,47 +668,47 @@@ struct vfsmount *lookup_mnt(struct pat return m; } - static struct mountpoint *new_mountpoint(struct dentry *dentry) + /* + * __is_local_mountpoint - Test to see if dentry is a mountpoint in the + * current mount namespace. + * + * The common case is dentries are not mountpoints at all and that + * test is handled inline. For the slow case when we are actually + * dealing with a mountpoint of some kind, walk through all of the + * mounts in the current mount namespace and test to see if the dentry + * is a mountpoint. + * + * The mount_hashtable is not usable in the context because we + * need to identify all mounts that may be in the current mount + * namespace not just a mount that happens to have some specified + * parent mount. + */ + bool __is_local_mountpoint(struct dentry *dentry) + { + struct mnt_namespace *ns = current->nsproxy->mnt_ns; + struct mount *mnt; + bool is_covered = false; + + if (!d_mountpoint(dentry)) + goto out; + + down_read(&namespace_sem); + list_for_each_entry(mnt, &ns->list, mnt_list) { + is_covered = (mnt->mnt_mountpoint == dentry); + if (is_covered) + break; + } + up_read(&namespace_sem); + out: + return is_covered; + } + + static struct mountpoint *lookup_mountpoint(struct dentry *dentry) { - struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry); + struct hlist_head *chain = mp_hash(dentry); struct mountpoint *mp; - int ret; - list_for_each_entry(mp, chain, m_hash) { + hlist_for_each_entry(mp, chain, m_hash) { if (mp->m_dentry == dentry) { /* might be worth a WARN_ON() */ if (d_unlinked(dentry)) @@@ -695,7 -702,8 +738,8 @@@ static struct mountpoint *new_mountpoin mp->m_dentry = dentry; mp->m_count = 1; - list_add(&mp->m_hash, chain); + hlist_add_head(&mp->m_hash, chain); + INIT_LIST_HEAD(&mp->m_list); return mp; } @@@ -748,7 -757,8 +793,8 @@@ static void detach_mnt(struct mount *mn mnt->mnt_parent = mnt; mnt->mnt_mountpoint = mnt->mnt.mnt_root; list_del_init(&mnt->mnt_child); - list_del_init(&mnt->mnt_hash); + hlist_del_init_rcu(&mnt->mnt_hash); + list_del_init(&mnt->mnt_mp_list); put_mountpoint(mnt->mnt_mp); mnt->mnt_mp = NULL; } @@@ -936,9 -943,35 +983,25 @@@ static struct mount *clone_mnt(struct m return ERR_PTR(err); } -static void delayed_free(struct rcu_head *head) -{ - struct mount *mnt = container_of(head, struct mount, mnt_rcu); - kfree(mnt->mnt_devname); -#ifdef CONFIG_SMP - free_percpu(mnt->mnt_pcp); -#endif - kmem_cache_free(mnt_cache, mnt); -} - + static void cleanup_mnt(struct mount *mnt) + { + fsnotify_vfsmount_delete(&mnt->mnt); + dput(mnt->mnt.mnt_root); + deactivate_super(mnt->mnt.mnt_sb); + mnt_free_id(mnt); + complete(mnt->mnt_undone); - call_rcu(&mnt->mnt_rcu, delayed_free); ++ call_rcu(&mnt->mnt_rcu, delayed_free_vfsmnt); + } + + static void cleanup_mnt_work(struct work_struct *work) + { + cleanup_mnt(container_of(work, struct mount, mnt_cleanup_work)); + } + static void mntput_no_expire(struct mount *mnt) { - put_again: + struct completion undone; + rcu_read_lock(); mnt_add_count(mnt, -1); if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */