Why we Use both mm_users and mm_count in struct mm_struct{ }
Rami Rosen
roszenrami at gmail.com
Mon Mar 25 02:46:36 EDT 2013
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.
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