linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Mysterious driver-related oops in vm system
@ 2003-11-15  6:02 Steve Holland
  2003-11-15  6:26 ` Linus Torvalds
  0 siblings, 1 reply; 2+ messages in thread
From: Steve Holland @ 2003-11-15  6:02 UTC (permalink / raw)
  To: linux-kernel


I've been trying to debug a nasty driver related oops
in the VM system on 2.4 kernels, and have reduced the 
problem to a relatively simple test case that seems to cause an 
oops on most Linux kernels. The oops occurs when the
test program calls exit(). It requires more than one execution
of the test program to cause an oops. Not all kernels generate 
the oops, but there doesn't seem to be any particular pattern. 

I have seen the problem on a variety of 2.4 kernels (2.4.18-2.4.22)
including both i586 and x86-64 platforms. 


The oops is in mm/page_alloc.c, __free_pages_ok()
                if (BAD_RANGE(zone,buddy2))
                        BUG();

crashes here -> list_del(&buddy1->list);
                mask <<= 1;
                area++;
                index >>= 1;

sample call trace: __free_pte zap_pte_range do_page_fault
zap_page_range exit_mmap mmput do_exit schedule do_group_exit
system_call 

The crash is in the inline expansion of __list_del (linux/list.h):

static inline void __list_del(struct list_head *prev, struct list_head
*next)
{
        next->prev = prev;
        prev->next = next;
}

which is called by list_del: (linux/list.h)

static inline void list_del(struct list_head *entry)
{
        __list_del(entry->prev, entry->next);
        entry->next = (void *) 0;
        entry->prev = (void *) 0;
}


And the crash is because both entry->prev and entry->next are NULL. 


The problem seems to be related to the munmapping of a shared memory
segment. Modifying the test program to explicitly munmap() before
calling exit() causes instead a hang at the munmap() call. 
This is particularly intriguing, since the driver does not implement
munmap() itself, but rather relies on the kernel default behavior. 
The driver is memory mapping space originally allocated with 
pci_alloc_consistent. 

As far as I can tell, the driver implements mmap() and nopage()
correctly.

Here is mmap:

static int das4020_mmap( struct file *filePtr, struct vm_area_struct
*vma ) 
{
  int board = 0;
  int chan  = 0;
  int size  = vma->vm_end - vma->vm_start;
  unsigned int minor = MINOR(filePtr->f_dentry->d_inode->i_rdev);

  board = BOARD(minor);            /* get which board   */
  chan =  (minor & 0xf);           /* get which channel */

  if (chan >= 0 && chan < AD_CHANNELS) {

    
    if(vma->vm_pgoff != 0) {     // You have to map the entire buffer.
      return(-EINVAL);
    }

    if (size > BoardData[board].dma_phy_size) {     // You cannot
request more than the max buffer
      return(-EINVAL);
    }

    vma->vm_ops = &das4020_vops;
    vma->vm_flags |= VM_RESERVED;
    vma->vm_private_data = (void *) minor;
  }
  return 0;
}



And here is nopage(): 

static struct page *das4020_nopage(struct vm_area_struct *vma, unsigned
long address, int write_access)
{
  struct page  *page = NOPAGE_SIGBUS;      // page to be mapped
  unsigned char *v_addr = NULL;            // kernel virtual address to
be mapped to user space
  unsigned int minor = (unsigned int) vma->vm_private_data;
  int board = 0;
  int chan = 0;
  unsigned long offset;   // offset to test for valid address

  board = BOARD(minor);
  chan = (minor & 0xf);

  offset = (address - vma->vm_start) + vma->vm_pgoff * PAGE_SIZE;
  if (offset >=  BoardData[board].dma_phy_size) {
    return NOPAGE_SIGBUS;
  }
  
  v_addr =  BoardData[board].dma_virt_addr + (address - vma->vm_start);
  page = virt_to_page(v_addr);
  get_page (page);
  return (page);
}


It was suggested last night that perhaps the VM_RESERVED flag was the
problem. Removing this flag does not change the behavior. 

The test case can be downloaded from:
http://69.5.151.193/~sdh4/drvbug.tar.gz
The test case does not require specialized hardware. 

A Makefile is included with instructions for demonstrating the kernel
oops. Some kernels do not seem to show the symptoms, while others do. 
A list of tests and results is included in the makefile. 

      Thanks for your help in tracking down this bug. 

      Steve Holland     11/14/03 

sdh4 AT cornell D nospam O nospam T edu


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Mysterious driver-related oops in vm system
  2003-11-15  6:02 Mysterious driver-related oops in vm system Steve Holland
@ 2003-11-15  6:26 ` Linus Torvalds
  0 siblings, 0 replies; 2+ messages in thread
From: Linus Torvalds @ 2003-11-15  6:26 UTC (permalink / raw)
  To: Steve Holland; +Cc: linux-kernel


On 15 Nov 2003, Steve Holland wrote:
>   
nopage():
>   v_addr =  BoardData[board].dma_virt_addr + (address - vma->vm_start);
>   page = virt_to_page(v_addr);
>   get_page (page);
>   return (page);

You can't do single-page memory management once you've already allocated 
the board data as one big memory allocation.

In short: remove the "get_page()", since the thing that keeps the pages in 
memory is actually the "pci_alloc_consistent()". 

To make sure that the swapout logic doesn't try to touch these pages 
as "normal" pages either, you should mark them all reserved.

Then, in the release() function you should unmark the pages, and finally 
do the pci_free_consistent() on the area.

We really should have helper functions to do that. Right now every driver 
that wants to do this needs to have its own logic for it (sound drivers 
use "snd_malloc_pages()" that does it for them etc etc).

			Linus


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2003-11-15  6:26 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-11-15  6:02 Mysterious driver-related oops in vm system Steve Holland
2003-11-15  6:26 ` Linus Torvalds

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).