2013/6/11 Michael Holzheu <holzheu at linux.vnet.ibm.com>: > On Mon, 10 Jun 2013 22:40:24 +0900 > HATAYAMA Daisuke <d.hatayama at gmail.com> wrote: > >> 2013/6/8 Michael Holzheu <holzheu at linux.vnet.ibm.com>: >> <cut> >> > @@ -225,6 +251,56 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer, >> > return acc; >> > } >> > >> > +static ssize_t read_vmcore(struct file *file, char __user *buffer, >> > + size_t buflen, loff_t *fpos) >> > +{ >> > + return __read_vmcore(buffer, buflen, fpos, 1); >> > +} >> > + >> > +/* >> > + * The vmcore fault handler uses the page cache and fills data using the >> > + * standard __vmcore_read() function. >> > + */ >> > +static int mmap_vmcore_fault(struct vm_area_struct *vma, struct vm_fault *vmf) >> > +{ >> > + struct address_space *mapping = vma->vm_private_data; >> > + pgoff_t index = vmf->pgoff; >> > + struct page *page; >> > + loff_t src; >> > + char *buf; >> > + int rc; >> > + >> > +find_page: >> > + page = find_lock_page(mapping, index); >> > + if (page) { >> > + unlock_page(page); >> > + rc = VM_FAULT_MINOR; >> > + } else { >> > + page = page_cache_alloc_cold(mapping); >> > + if (!page) >> > + return VM_FAULT_OOM; >> > + rc = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL); >> > + if (rc) { >> > + page_cache_release(page); >> > + if (rc == -EEXIST) >> > + goto find_page; >> > + /* Probably ENOMEM for radix tree node */ >> > + return VM_FAULT_OOM; >> > + } >> > + buf = (void *) (page_to_pfn(page) << PAGE_SHIFT); >> > + src = index << PAGE_CACHE_SHIFT; >> > + __read_vmcore(buf, PAGE_SIZE, &src, 0); >> > + unlock_page(page); >> > + rc = VM_FAULT_MAJOR; >> > + } >> > + vmf->page = page; >> > + return rc; >> > +} >> >> How about reusing find_or_create_page()? > > The function would then look like the following: > > static int mmap_vmcore_fault(struct vm_area_struct *vma, struct vm_fault *vmf) > { > struct address_space *mapping = vma->vm_private_data; > pgoff_t index = vmf->pgoff; > struct page *page; > loff_t src; > char *buf; > > page = find_or_create_page(mapping, index, GFP_KERNEL); > if (!page) > return VM_FAULT_OOM; > src = index << PAGE_CACHE_SHIFT; > buf = (void *) (page_to_pfn(page) << PAGE_SHIFT); > __read_vmcore(buf, PAGE_SIZE, &src, 0); > unlock_page(page); > vmf->page = page; > return 0; > } > > I agree that this makes the function simpler but we have to copy > the page also if it has already been filled, correct? > You can use for the purpose PG_uptodate flag. > But since normally only one process uses /proc/vmcore this might be > acceptable. > > BTW: I also removed the VM_FAULT_MAJOR/MINOR because I think the fault > handler should return 0 if a page has been found. > > Michael > Thanks. HATAYAMA, Daisuke