Why we Use both mm_users and mm_count in struct mm_struct{ }
From: anish singh <hidden>
Date: 2013-03-25 06:02:18
On Mon, Mar 25, 2013 at 1:35 AM, Rami Rosen [off-list ref] 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 [off-list ref] wrote:quoted
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