Why we Use both mm_users and mm_count in struct mm_struct{ }
Rami Rosen
roszenrami at gmail.com
Sun Mar 24 16:05:25 EDT 2013
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.
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
>
More information about the Kernelnewbies
mailing list