Why we Use both mm_users and mm_count in struct mm_struct{ }

anish singh anish198519851985 at gmail.com
Mon Mar 25 03:13:30 EDT 2013


On Mon, Mar 25, 2013 at 12:16 PM, Rami Rosen <roszenrami at gmail.com> wrote:
> Hi,
>
> Regarding your question about the previous thread:
> Think of a context switch, let's say between a userspace process and a
> kernel thread. A context switch is done between two processes
> (processes are represented by struct task_struct). So when you look at
> context_switch() prototype, you see:
>
> context_switch(struct rq *rq, struct task_struct *prev,
> ...)
>
> and prev is the process which ran in the run_queue of the scheduler
> previously, before switching
> to the new kernel thread. And we borrow memory descriptor from this process.
and I think the memory descriptor would be changed so that it can point
to the kernel thread.
>
> Rgs,
> Rami Rosen
> http://ramirose.wix.com/ramirosen
>
>
>
>
>
>
> On Mon, Mar 25, 2013 at 8:02 AM, anish singh
> <anish198519851985 at gmail.com> wrote:
>> On Mon, Mar 25, 2013 at 1:35 AM, Rami Rosen <roszenrami at gmail.com> wrote:
>>> Hi, Niroj,
>>>
>>> Please look at the following scenario:
>>> Suppose we create a kernel thread.
>>> With kernel threads, the mm member of the task_struct is NULL.
>>> (We are not permitted to access user space addresses from kernel thread,
>>> so we don't need mm).
>>> Kernel threads use ("borrow") the active_mm of the previous thread.
>> as we know that kernel threads are not associated with any user space
>> process then why this overheads of active_mm or why we borrow the
>> active_mm of the previous thread.
>> Can you explain: what is previous thread here?
>>> But in order to avoid freeing the active_mm if the previous threads terminates
>>> before the kernel thread terminates, we increment mm_count of the
>>> active_mm of the previous thread
>>> when we create a kernel thread (which "borrows" the active_mm of the
>>> previous thread).
>>> In such a case, even if the mm_users is 0, mm_count is not 0, and
>>> we do not free that mm_active.
>>> (remember that mm_users is initialized to 1).
>>>
>>> To be more specific:
>>> when that previous thread terminates, we call
>>> the mmput() (see exit_mm(), in kernel/exit.c)
>>> mmput() decrements mm_users and calls mmdrop().
>>> Since in mmdrop(), after decrements mm_count it is not 0,
>>> we do not free the mm_struct.
>>>
>>> Here are the code snippets:
>>>
>>> /*
>>>  * Decrement the use count and release all resources for an mm.
>>>  */
>>> void mmput(struct mm_struct *mm)
>>> {
>>>         might_sleep();
>>>
>>>         if (atomic_dec_and_test(&mm->mm_users)) {
>>>                 uprobe_clear_state(mm);
>>>                 exit_aio(mm);
>>>                 ksm_exit(mm);
>>>                 khugepaged_exit(mm); /* must run before exit_mmap */
>>>                 exit_mmap(mm);
>>>                 set_mm_exe_file(mm, NULL);
>>>                 if (!list_empty(&mm->mmlist)) {
>>>                         spin_lock(&mmlist_lock);
>>>                         list_del(&mm->mmlist);
>>>                         spin_unlock(&mmlist_lock);
>>>                 }
>>>                 if (mm->binfmt)
>>>                         module_put(mm->binfmt->module);
>>>                 mmdrop(mm);
>>>         }
>>> }
>>>
>>>
>>>
>>> mmdrop() is for freeing a memory descriptor:
>>>
>>> static inline void mmdrop(struct mm_struct * mm)
>>> {
>>>         if (unlikely(atomic_dec_and_test(&mm->mm_count)))
>>>                 __mmdrop(mm);
>>> }
>>>
>>>
>>> When the condition if (!mm) is true, this means this is a kernel thread:
>>>
>>> static inline void
>>> context_switch(struct rq *rq, struct task_struct *prev,
>>>                struct task_struct *next)
>>> {
>>>         struct mm_struct *mm, *oldmm;
>>>
>>>         prepare_task_switch(rq, prev, next);
>>>
>>>         mm = next->mm;
>>>         oldmm = prev->active_mm;
>>>         /*
>>>          * For paravirt, this is coupled with an exit in switch_to to
>>>          * combine the page table reload and the switch backend into
>>>          * one hypercall.
>>>          */
>>>         arch_start_context_switch(prev);
>>>
>>>         if (!mm) {
>>>                 next->active_mm = oldmm;
>>>                 atomic_inc(&oldmm->mm_count);
>>>                 enter_lazy_tlb(oldmm, next);
>>>         } else
>>> ...
>>>
>>> Regards,
>>> Rami Rosen
>>> http://ramirose.wix.com/ramirosen
>>>
>>>
>>>
>>>
>>> On Sat, Mar 23, 2013 at 7:02 AM, Niroj Pokhrel <nirojpokhrel at gmail.com> wrote:
>>>> Hi all,
>>>> I have been going through the Address Space in the linux and came across two
>>>> variables in the struct mm_struct and I'm a bit confused about the two:
>>>> struct mm_struct
>>>> {
>>>>               ..........
>>>>               atomic_t   mm_users;
>>>>               atomic_t   mm_count;
>>>>               ............
>>>> }
>>>> Basically, after reading through I came to understand that mm_users are used
>>>> to store the number of processes or threads using the memory so depending
>>>> upon the number of users it is going to be set.
>>>> But, I am confused with mm_count, it is said the mm_count is increment by
>>>> one for all the mm_users and when all the mm_users value is reduced to zero
>>>> then mm_count is reduced. So, my question is can the value of mm_count be
>>>> ever greater than one because all the mm_users are equivalent to mm_count .
>>>> So, if not then why are we using the mm_count as we can simply remove the
>>>> memory areas whenever the mm_users count reduce to zero.
>>>> May be the explanation is simple but I'm lost. Thanking all of you in
>>>> advance.
>>>>
>>>>
>>>> Regards,
>>>> Niroj Pokhrel
>>>>
>>>> _______________________________________________
>>>> Kernelnewbies mailing list
>>>> Kernelnewbies at kernelnewbies.org
>>>> http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
>>>>
>>>
>>> _______________________________________________
>>> Kernelnewbies mailing list
>>> Kernelnewbies at kernelnewbies.org
>>> http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies



More information about the Kernelnewbies mailing list