summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/aufs/inode.h1
-rw-r--r--fs/aufs/module.c2
-rw-r--r--fs/aufs/plink.c86
-rw-r--r--fs/aufs/procfs.c2
-rw-r--r--fs/aufs/super.h18
-rw-r--r--fs/aufs/sysrq.c2
-rw-r--r--fs/pnode.c25
-rw-r--r--fs/proc/base.c3
8 files changed, 55 insertions, 84 deletions
diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h
index eeb43d220..e694be498 100644
--- a/fs/aufs/inode.h
+++ b/fs/aufs/inode.h
@@ -65,6 +65,7 @@ struct au_iinfo {
struct au_icntnr {
struct au_iinfo iinfo;
struct inode vfs_inode;
+ struct hlist_node plink;
} ____cacheline_aligned_in_smp;
/* au_pin flags */
diff --git a/fs/aufs/module.c b/fs/aufs/module.c
index 8a28377c5..317fde014 100644
--- a/fs/aufs/module.c
+++ b/fs/aufs/module.c
@@ -74,7 +74,7 @@ int au_dir_roflags;
* iterate_supers_type() doesn't protect us from
* remounting (branch management)
*/
-struct au_splhead au_sbilist;
+struct au_sphlhead au_sbilist;
#endif
struct lock_class_key au_lc_key[AuLcKey_Last];
diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c
index d5b36bd11..b6d63269c 100644
--- a/fs/aufs/plink.c
+++ b/fs/aufs/plink.c
@@ -111,7 +111,7 @@ void au_plink_list(struct super_block *sb)
int i;
struct au_sbinfo *sbinfo;
struct hlist_head *plink_hlist;
- struct pseudo_link *plink;
+ struct au_icntnr *icntnr;
SiMustAnyLock(sb);
@@ -122,8 +122,8 @@ void au_plink_list(struct super_block *sb)
for (i = 0; i < AuPlink_NHASH; i++) {
plink_hlist = &sbinfo->si_plink[i].head;
rcu_read_lock();
- hlist_for_each_entry_rcu(plink, plink_hlist, hlist)
- AuDbg("%lu\n", plink->inode->i_ino);
+ hlist_for_each_entry_rcu(icntnr, plink_hlist, plink)
+ AuDbg("%lu\n", icntnr->vfs_inode.i_ino);
rcu_read_unlock();
}
}
@@ -135,7 +135,7 @@ int au_plink_test(struct inode *inode)
int found, i;
struct au_sbinfo *sbinfo;
struct hlist_head *plink_hlist;
- struct pseudo_link *plink;
+ struct au_icntnr *icntnr;
sbinfo = au_sbi(inode->i_sb);
AuRwMustAnyLock(&sbinfo->si_rwsem);
@@ -146,8 +146,8 @@ int au_plink_test(struct inode *inode)
i = au_plink_hash(inode->i_ino);
plink_hlist = &sbinfo->si_plink[i].head;
rcu_read_lock();
- hlist_for_each_entry_rcu(plink, plink_hlist, hlist)
- if (plink->inode == inode) {
+ hlist_for_each_entry_rcu(icntnr, plink_hlist, plink)
+ if (&icntnr->vfs_inode == inode) {
found = 1;
break;
}
@@ -330,24 +330,6 @@ static int whplink(struct dentry *h_dentry, struct inode *inode,
return err;
}
-/* free a single plink */
-static void do_put_plink(struct pseudo_link *plink, int do_del)
-{
- if (do_del)
- hlist_del(&plink->hlist);
- iput(plink->inode);
- kfree(plink);
-}
-
-static void do_put_plink_rcu(struct rcu_head *rcu)
-{
- struct pseudo_link *plink;
-
- plink = container_of(rcu, struct pseudo_link, rcu);
- iput(plink->inode);
- kfree(plink);
-}
-
/*
* create a new pseudo-link for @h_dentry on @bindex.
* the linked inode is held in aufs @inode.
@@ -358,7 +340,7 @@ void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
struct super_block *sb;
struct au_sbinfo *sbinfo;
struct hlist_head *plink_hlist;
- struct pseudo_link *plink, *tmp;
+ struct au_icntnr *icntnr;
struct au_sphlhead *sphl;
int found, err, cnt, i;
@@ -374,23 +356,19 @@ void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
i = au_plink_hash(inode->i_ino);
sphl = sbinfo->si_plink + i;
plink_hlist = &sphl->head;
- tmp = kmalloc(sizeof(*plink), GFP_NOFS);
- if (tmp)
- tmp->inode = au_igrab(inode);
- else {
- err = -ENOMEM;
- goto out;
- }
+ au_igrab(inode);
spin_lock(&sphl->spin);
- hlist_for_each_entry(plink, plink_hlist, hlist) {
- if (plink->inode == inode) {
+ hlist_for_each_entry(icntnr, plink_hlist, plink) {
+ if (&icntnr->vfs_inode == inode) {
found = 1;
break;
}
}
- if (!found)
- hlist_add_head_rcu(&tmp->hlist, plink_hlist);
+ if (!found) {
+ icntnr = container_of(inode, struct au_icntnr, vfs_inode);
+ hlist_add_head_rcu(&icntnr->plink, plink_hlist);
+ }
spin_unlock(&sphl->spin);
if (!found) {
cnt = au_sphl_count(sphl);
@@ -399,19 +377,13 @@ void au_plink_append(struct inode *inode, aufs_bindex_t bindex,
AuWarn1(msg ", %d\n", cnt);
#undef msg
err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex));
- } else {
- do_put_plink(tmp, 0);
- return;
- }
-
-out:
- if (unlikely(err)) {
- pr_warn("err %d, damaged pseudo link.\n", err);
- if (tmp) {
- au_sphl_del_rcu(&tmp->hlist, sphl);
- call_rcu(&tmp->rcu, do_put_plink_rcu);
+ if (unlikely(err)) {
+ pr_warn("err %d, damaged pseudo link.\n", err);
+ au_sphl_del_rcu(&icntnr->plink, sphl);
+ iput(&icntnr->vfs_inode);
}
- }
+ } else
+ iput(&icntnr->vfs_inode);
}
/* free all plinks */
@@ -421,7 +393,7 @@ void au_plink_put(struct super_block *sb, int verbose)
struct au_sbinfo *sbinfo;
struct hlist_head *plink_hlist;
struct hlist_node *tmp;
- struct pseudo_link *plink;
+ struct au_icntnr *icntnr;
SiMustWriteLock(sb);
@@ -437,8 +409,8 @@ void au_plink_put(struct super_block *sb, int verbose)
pr_warn("pseudo-link is not flushed");
warned = 1;
}
- hlist_for_each_entry_safe(plink, tmp, plink_hlist, hlist)
- do_put_plink(plink, 0);
+ hlist_for_each_entry_safe(icntnr, tmp, plink_hlist, plink)
+ iput(&icntnr->vfs_inode);
INIT_HLIST_HEAD(plink_hlist);
}
}
@@ -489,7 +461,7 @@ void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id)
struct au_sbinfo *sbinfo;
struct hlist_head *plink_hlist;
struct hlist_node *tmp;
- struct pseudo_link *plink;
+ struct au_icntnr *icntnr;
struct inode *inode;
int i, do_put;
@@ -502,12 +474,14 @@ void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id)
/* no spin_lock since sbinfo is write-locked */
for (i = 0; i < AuPlink_NHASH; i++) {
plink_hlist = &sbinfo->si_plink[i].head;
- hlist_for_each_entry_safe(plink, tmp, plink_hlist, hlist) {
- inode = au_igrab(plink->inode);
+ hlist_for_each_entry_safe(icntnr, tmp, plink_hlist, plink) {
+ inode = au_igrab(&icntnr->vfs_inode);
ii_write_lock_child(inode);
do_put = au_plink_do_half_refresh(inode, br_id);
- if (do_put)
- do_put_plink(plink, 1);
+ if (do_put) {
+ hlist_del(&icntnr->plink);
+ iput(inode);
+ }
ii_write_unlock(inode);
iput(inode);
}
diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c
index 2c8893edf..e5a4e3762 100644
--- a/fs/aufs/procfs.c
+++ b/fs/aufs/procfs.c
@@ -44,7 +44,7 @@ static int au_procfs_plm_write_si(struct file *file, unsigned long id)
sb = NULL;
/* don't use au_sbilist_lock() here */
spin_lock(&au_sbilist.spin);
- list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
+ hlist_for_each_entry(sbinfo, &au_sbilist.head, si_list)
if (id == sysaufs_si_id(sbinfo)) {
kobject_get(&sbinfo->si_kobj);
sb = sbinfo->si_sb;
diff --git a/fs/aufs/super.h b/fs/aufs/super.h
index ba2855ad6..23d03a067 100644
--- a/fs/aufs/super.h
+++ b/fs/aufs/super.h
@@ -45,14 +45,6 @@ struct au_wbr_mfs {
unsigned long long mfsrr_watermark;
};
-struct pseudo_link {
- union {
- struct hlist_node hlist;
- struct rcu_head rcu;
- };
- struct inode *inode;
-};
-
#define AuPlink_NHASH 100
static inline int au_plink_hash(ino_t ino)
{
@@ -198,7 +190,7 @@ struct au_sbinfo {
#endif
#ifdef CONFIG_AUFS_SBILIST
- struct list_head si_list;
+ struct hlist_node si_list;
#endif
/* dirty, necessary for unmounting, sysfs and sysrq */
@@ -372,21 +364,21 @@ AuStub(int, au_busy_or_stale, return -EBUSY, void)
#ifdef CONFIG_AUFS_SBILIST
/* module.c */
-extern struct au_splhead au_sbilist;
+extern struct au_sphlhead au_sbilist;
static inline void au_sbilist_init(void)
{
- au_spl_init(&au_sbilist);
+ au_sphl_init(&au_sbilist);
}
static inline void au_sbilist_add(struct super_block *sb)
{
- au_spl_add(&au_sbi(sb)->si_list, &au_sbilist);
+ au_sphl_add(&au_sbi(sb)->si_list, &au_sbilist);
}
static inline void au_sbilist_del(struct super_block *sb)
{
- au_spl_del(&au_sbi(sb)->si_list, &au_sbilist);
+ au_sphl_del(&au_sbi(sb)->si_list, &au_sbilist);
}
#ifdef CONFIG_AUFS_MAGIC_SYSRQ
diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c
index 7921ed716..7d22979b7 100644
--- a/fs/aufs/sysrq.c
+++ b/fs/aufs/sysrq.c
@@ -105,7 +105,7 @@ static void au_sysrq(int key __maybe_unused)
lockdep_off();
au_sbilist_lock();
- list_for_each_entry(sbinfo, &au_sbilist.head, si_list)
+ hlist_for_each_entry(sbinfo, &au_sbilist.head, si_list)
sysrq_sb(sbinfo->si_sb);
au_sbilist_unlock();
lockdep_on();
diff --git a/fs/pnode.c b/fs/pnode.c
index c524fdddc..99899705b 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -198,7 +198,7 @@ static struct mount *next_group(struct mount *m, struct mount *origin)
/* all accesses are serialized by namespace_sem */
static struct user_namespace *user_ns;
-static struct mount *last_dest, *last_source, *dest_master;
+static struct mount *last_dest, *first_source, *last_source, *dest_master;
static struct mountpoint *mp;
static struct hlist_head *list;
@@ -221,20 +221,22 @@ static int propagate_one(struct mount *m)
type = CL_MAKE_SHARED;
} else {
struct mount *n, *p;
+ bool done;
for (n = m; ; n = p) {
p = n->mnt_master;
- if (p == dest_master || IS_MNT_MARKED(p)) {
- while (last_dest->mnt_master != p) {
- last_source = last_source->mnt_master;
- last_dest = last_source->mnt_parent;
- }
- if (!peers(n, last_dest)) {
- last_source = last_source->mnt_master;
- last_dest = last_source->mnt_parent;
- }
+ if (p == dest_master || IS_MNT_MARKED(p))
break;
- }
}
+ do {
+ struct mount *parent = last_source->mnt_parent;
+ if (last_source == first_source)
+ break;
+ done = parent->mnt_master == p;
+ if (done && peers(n, parent))
+ break;
+ last_source = last_source->mnt_master;
+ } while (!done);
+
type = CL_SLAVE;
/* beginning of peer group among the slaves? */
if (IS_MNT_SHARED(m))
@@ -286,6 +288,7 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
*/
user_ns = current->nsproxy->mnt_ns->user_ns;
last_dest = dest_mnt;
+ first_source = source_mnt;
last_source = source_mnt;
mp = dest_mp;
list = tree_list;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 11aba74cb..80e4bc69f 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -955,7 +955,8 @@ static ssize_t environ_read(struct file *file, char __user *buf,
struct mm_struct *mm = file->private_data;
unsigned long env_start, env_end;
- if (!mm)
+ /* Ensure the process spawned far enough to have an environment. */
+ if (!mm || !mm->env_end)
return 0;
page = (char *)__get_free_page(GFP_TEMPORARY);