diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/aufs/inode.h | 1 | ||||
-rw-r--r-- | fs/aufs/module.c | 2 | ||||
-rw-r--r-- | fs/aufs/plink.c | 86 | ||||
-rw-r--r-- | fs/aufs/procfs.c | 2 | ||||
-rw-r--r-- | fs/aufs/super.h | 18 | ||||
-rw-r--r-- | fs/aufs/sysrq.c | 2 | ||||
-rw-r--r-- | fs/pnode.c | 25 | ||||
-rw-r--r-- | fs/proc/base.c | 3 |
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); |