Re: Problem with LIST_HEAD and list_add (was Page Fault Handler Hijacking and Oops)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Aug 05, 2005 at 11:37:33 +0000, Vincenzo Mallozzi wrote:
> On Thu 5 Aug 2005, at 07:02, Jan Hudec wrote:
> > Perhaps your code is safe, but I would think you should have the list
> > modification itself (list_add_tail) protected by a spin_lock_irqsave.
> > That's the only way to exclude against interrupts (you can't lock
> > semaphores in interrupt context).
> > 
> 
> But I'm developing a project in a uniprocessor environment, so I think it's 
> unnecessary to lock code with spinlock, or, better, it's redundant.

That's not true since the preempt patch went in. Preempt is equivalent
to SMP.

> Now, I've a problem only with the use of INIT_LIST_HEAD.
> I've modified the code this way.
> 
>  1.  void mtpmc_set_mm_not_writable(struct mm_struct *mm)
>  2.  {
>  3.   struct vm_area_struct *vm;
>  4.   struct mtpmc_wrprotected_pages *wr_page, *temp_page_wr;
>  5.   struct mtpmc_vm_wrprotected *temp_vma_wr;
>  6.   struct page *page;
>  7.   pte_t *pte;
>  8.   unsigned long addr;
>  9.   int initial_page;
> 10.
> 11.  down_write(&mm->mmap_sem);
> 12.   for (vm = mm->mmap; vm!=NULL; vm=vm->vm_next)
> 13.    if(mtpmc_vm_to_save(mm, vm) == 1){
> 14.     temp_vma_wr = mtpmc_mk_vm_wrprotected(vm);
> 15.     list_add_tail(&temp_vma_wr->list, &vm_write_protected);
> 16.     initial_page = 1;
> 17.     for(addr=vm->vm_start;addr<vm->vm_end;addr+=PAGE_SIZE){
> 18.      pte = mtpmc_get_pte_from_address(mm, addr);
> 19.      if (pte)
> 20.       if (pte_write(*pte)){
> 21.        set_pte(pte, pte_wrprotect(*pte));
> 22.        if (initial_page == 1){
> 23.         temp_vma_wr->pages = mtpmc_mk_page_wrprotected(addr);
> 24.         INIT_LIST_HEAD(&(temp_vma_wr->pages)->list);
> 25.         list_add_tail(&(temp_vma_wr->pages)->list, 
>             &(temp_vma_wr->pages)->list);
> 26.         initial_page = 0;
> 27.        }
> 28.        else
> 29.         list_add_tail(&mtpmc_mk_page_wrprotected(addr)->list, 
>             &(temp_vma_wr->pages)->list);
> 30.       }
> 31.     }
> 32.    }
> 33.   up_write(&mm->mmap_sem);
> 34.   
> 35.   return;
> 36.  }
> 
> The problem I encountered is in initialization of pages' list.
> Line regarding this problem are the ones from 22. to 30.
> This lines are executed after having saved the informations of the vma that 
> I'm going to scan in the vm_write_protected list.
> After this, I've to store information regarding the infos of pages included in 
> this vma. To do this, I've to create a new list containing the pages 
> information.
> So,  in line 22, I check (initial ==1) if the list for the pages of this vma 
> is not just created. If so, I create it (line 24) and add to it the first 
> element of this list (line 25). 
> if test is false (initial == 0), then I simply add the new page to the list.

That sounds wrong to me. You should always INIT_LIST_HEAD when you
allocate the structure it is in and then you should simply add the
elements.

Oh, I don't see your structure definitions here, but the rule of thumb
is, that you *NEVER* ever have pointers to list_head in structures. You
should have list_head members.

That is, your temp_vma_wr->pages->list is supposed to be of type 'struct
list_head' -- NOT pointer -- and the call to INIT_LIST_HEAD is supposed
to be INIT_LIST_HEAD(&(temp_vma_wr->pages->list)) (or maybe pages.list,
but the & must apply to the whole argument in any case).

Say you have:

struct something {
    list_head list;
    list_head children;

    some values;
}

struct otherthing {
    list_head list;

    other values;
}

DECLARE_LIST_HEAD(somethings);

And then you do:

struct something *alloc_something(...)
{
    struct something *it = kmem_cache_alloc(something_cache,
					    GFP_KERNEL);
    /* First let's initialize the list of children */
    INIT_LIST_HEAD(&(it->children)); /* NOTE THE PARENTHESIS */
    
    /* Other initialization */

    /* And last, put it to the list */
    list_add(&(it->list), &somethings);
    return it;
}

struct otherthing *alloc_otherthing(struct something *st, ...)
{
    struct otherthing *it = kmem_cache_alloc(otherthing_cache,
					     GFP_KERNEL);
    /* Some initialization */

    /* And last, put it to the list */
    list_add(&(it->list), &(st->children));
    return it;
}

Note, that the parenthesis after & are superfluous in all the cases.
I could have written INIT_LIST_HEAD(&it->children),
list_add(&it->list, &somethings) etc, but I have put them in for
clarity.

> Now, the problem is that, when I scans the list, the first element of the 
> pages' lists is not present. In other word, the insertion of the first 
> element is not correct.
> Can you help me on finding the problem? There's another way to organize this 
> dynamic list?
> Thanks.
> Vincenzo Mallozzi
> 
> 	
> 
> 	
> 		
> ___________________________________ 
> Yahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB 
> http://mail.yahoo.it
> 
-------------------------------------------------------------------------------
						 Jan 'Bulb' Hudec <bulb@xxxxxx>

Attachment: signature.asc
Description: Digital signature


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux