Chinaunix

标题: __exit_mm 为何增加 mm_count 引用 [打印本页]

作者: zylthinking    时间: 2011-11-18 11:13
标题: __exit_mm 为何增加 mm_count 引用
static inline void __exit_mm(struct task_struct * tsk)
{
        struct mm_struct * mm = tsk->mm;

        mm_release();
        if (mm) {
                atomic_inc(&mm->mm_count);
                if (mm != tsk->active_mm) BUG();
                /* more a memory barrier than a real lock */
                task_lock(tsk);
                tsk->mm = NULL;
                task_unlock(tsk);
                enter_lazy_tlb(mm, current, smp_processor_id());
                mmput(mm);
        }
}

谁还要防止 mm struct 被释放????
作者: zylthinking    时间: 2011-11-18 12:35
感觉这个问题转化成了 lazy tlb 机制实现原理。。。。。。继续跟踪。
作者: flikelinux    时间: 2011-11-18 15:36
因为下面要对该结构体操作,防止操作的过程中其他内核路径将该结构体释放了。mmput又会对mm_count减1
作者: zylthinking    时间: 2011-11-18 16:14
因为下面要对该结构体操作,防止操作的过程中其他内核路径将该结构体释放了。mmput又会对mm_count减1
flikelinux 发表于 2011-11-18 15:36


单说一个普通情况, mm->count 和 mm->user_count 都是1, 这个是 allocate_mm 中设置的。
mm->count 和 mm->user_count 区别在于无论 mm->user_count 是多大, 都只是对应一个 mm->count.
因此, fork 的时候, 增加了 mm->user_count 却仍然保持 mm->count 为原值。
换句话说, mm->user_count记录的是有几个 task->mm 引用了这个  mm, 只要被任意一个引用, 则 mm->count 值至少为1

mm->count 变化发生与除此之外的其他引用中, 比如 switch 中被暂借到 active_mm 时;
因此,

230static int exec_mmap(void)
231{
232        struct mm_struct * mm, * old_mm;
233
234        old_mm = current->mm;
235        if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
236                flush_cache_mm(old_mm);
237                mm_release();
238                exit_mmap(old_mm);
239                flush_tlb_mm(old_mm);
240                return 0;
241        }
242
243        mm = mm_alloc();
244        if (mm) {
245                struct mm_struct *active_mm = current->active_mm;
246
247                current->mm = mm;
248                current->active_mm = mm;
249                activate_mm(active_mm, mm);
250                mm_release();
251                if (old_mm) {
252                        if (active_mm != old_mm) BUG();
253                        mmput(old_mm);   // 这里只需要 mmput 即可, 因为 active_mm 是本身, 在 switch 时直接赋值而没有增加 mm->count, mm->count, mm->user_count 都是1
254                        return 0;
255                }
256                mmdrop(active_mm);  // 而这里, 确实暂借的, mm_count 被增加了; 需要额外释放
257                return 0;
258        }
259        return -ENOMEM;
260}
261

因此, 你那种解释是肤浅的
作者: zylthinking    时间: 2011-11-18 16:26
本帖最后由 zylthinking 于 2011-11-18 16:29 编辑

找到点证据, 但还是没明白这个 lazy tlb 的全貌, 但已经明白这个 atomic_inc(&mm->mm_count);  是因为 task->mm = NULL 了, 然而还存在着 task->active_mm != NULL, 原来两个一致, active_mm 躲在 mm 之后过日子, 没什么自己出头露面的必要, 但这次没有挡风墙了, 只好增加 mm_count

271/*
272 * We can use these to temporarily drop into
273 * "lazy TLB" mode and back.
274 */
275struct mm_struct * start_lazy_tlb(void)
276{
277        struct mm_struct *mm = current->mm;
278        current->mm = NULL;
279        /* active_mm is still 'mm' */
280        atomic_inc(&mm->mm_count);    // 如出一辄
281        enter_lazy_tlb(mm, current, smp_processor_id());

282        return mm;
283}
284
285void end_lazy_tlb(struct mm_struct *mm)
286{
287        struct mm_struct *active_mm = current->active_mm;
288
289        current->mm = mm;
290        if (mm != active_mm) {
291                current->active_mm = mm;
292                activate_mm(active_mm, mm);
293        }
294        mmdrop(active_mm);  //对应的释放
295}
296
作者: zylthinking    时间: 2011-11-18 16:53
明白了, 和 lazy tlb 没太大关系, 我还不明白这玩艺呢
保留active_mm 的原因在于调度时需要, 因此这玩艺至少要保留到调度后。

615        /*
616         * there are 3 processes which are affected by a context switch:
617         *
618         * prev == .... ==> (last => next)
619         *
620         * It's the 'much more previous' 'prev' that is on next's stack,
621         * but prev is set to (the just run) 'last' process by switch_to().
622         * This might sound slightly confusing but makes tons of sense.
623         */
624        prepare_to_switch();
625        {
626                struct mm_struct *mm = next->mm;
627                struct mm_struct *oldmm = prev->active_mm;
628                if (!mm) {
629                        if (next->active_mm) BUG();
630                        next->active_mm = oldmm;
631                        atomic_inc(&oldmm->mm_count);
632                        enter_lazy_tlb(oldmm, next, this_cpu);
633                } else {
634                        if (next->active_mm != mm) BUG();
635                        switch_mm(oldmm, mm, next, this_cpu);
636                }
637
638                if (!prev->mm) {    // 释放地
639                        prev->active_mm = NULL;
640                        mmdrop(oldmm);
641                }

642        }
643
644        /*




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2