Why we Use both mm_users and mm_count in struct mm_struct{ }

Niroj Pokhrel nirojpokhrel at gmail.com
Mon Mar 25 02:32:17 EDT 2013


On Mon, Mar 25, 2013 at 11:32 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
>

Hi Anish,

The kernel_thread doesn't have user context so it basically has its mm
space pointing to NULL. So, if any kernel threads has preempted the kernel
then it still needs page table entries to access the kernel memory space
but since its mm space is pointing to the NULL it wouldn't have luxury. So,
how does kernel gets that entry then ?? It basically uses the page table
entry of the process which it preempted ( this is the previous thread as
mentioned in the answer by Rami). So, when it starts using this thread then
mm_count (primary reference) of that memory is increased by 1.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20130325/ceebea9c/attachment-0001.html 


More information about the Kernelnewbies mailing list