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