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