Skip to contentSkip to conversation

Kernel memory allocation and page used counter

DISCUSSION Hans Berglund 1 participant 1 message Oct 14, 2003

lore
Share & tools
lore
#0 lore raw

I have reserved a bounch of 128k sized pieces of kernel memory using addr[i] = __get_free_pages (GFP_KERNEL, 5); repeated times.

The first time the pages are used, I can DMA to this memory, and get the data without problems. After freeing the memory with free_pages (addr[i], 5); and allocating next time, the kernel crashes in different ways each time when I use the memory. Usually an oops with the message: "Unable to handle kernel paging request at virtual address xxxxxxxx".

I have noticed that the struct page->count.counter of the first page of each 128k chunk is incremented, but not of the remaining pages. Then I tried to increment the counter "manually" by using get_page() just after allocation, and the system seemed to become stable.

Do I really have to mark the pages as used, just after allocation, and is there a kernel call to du this in one operation?
If the pages are used by others, why does the kernel crash after the second allocation, and not the first?

I am running kernel 2.4.19, and I use the code below to do the mapping.

All answers are appreciated.

Hans

struct page *xxx_vma_nopage (struct vm_area_struct *vma,
unsigned long addr, int write)

{
    int offset, block;
    void *virt_addr;
    card_t *cp;
    struct page *cpage;

    cp = vma->vm_private_data;
    offset = addr - vma->vm_start;
    if ((addr < vma->vm_start) || (addr >= vma->vm_end))
    {
	PWARNING ("nopage: Mapping out of range, start=0x%x, addr=0x%x,"
		  "end=0x%x\n",
		  (int)vma->vm_start, (int)addr, (int)vma->vm_end);
	return (0);
    }
    block = offset / KM_SIZE;         /* KM_SIZE = 128k */
    virt_addr = cp->list[block].address + (offset % KM_SIZE);
    cpage = virt_to_page (virt_addr);
    get_page (cpage);
    return (cpage);
}

struct vm_operations_struct xxx_vmops =
{
open: xxx_vma_open,
close: xxx_vma_close,
nopage: xxx_vma_nopage,
};

int
xxx_mmap (struct file *filp, struct vm_area_struct *vma)

{
    card_t *cp = &xxxarr[MINOR(filp->f_dentry->d_inode->i_rdev)];
    vma->vm_flags |= VM_RESERVED;

    vma->vm_ops = &xxx_vmops;
    vma->vm_private_data = cp;
    xxx_vma_open(vma);
    return (0);
}