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