[patch 4/7] mm: merge populate and nopage into fault (fixes nonlinear)
Nonlinear mappings are (AFAIKS) simply a virtual memory concept that encodes the virtual address -> file offset differently from linear mappings. I can't see why the filesystem/pagecache code should need to know anything about it, except for the fact that the ->nopage handler didn't quite pass down enough information (ie. pgoff). But it is more logical to pass pgoff rather than have the ->nopage function calculate it itself anyway. And having the nopage handler install the pte itself is sort of nasty. This patch introduces a new fault handler that replaces ->nopage and ->populate and (later) ->nopfn. Most of the old mechanism is still in place so there is a lot of duplication and nice cleanups that can be removed if everyone switches over. The rationale for doing this in the first place is that nonlinear mappings are subject to the pagefault vs invalidate/truncate race too, and it seemed stupid to duplicate the synchronisation logic rather than just consolidate the two. After this patch, MAP_NONBLOCK no longer sets up ptes for pages present in pagecache. Seems like a fringe functionality anyway. NOPAGE_REFAULT is removed. This should be implemented with ->fault, and no users have hit mainline yet. Signed-off-by: Nick Piggin <[EMAIL PROTECTED]> Index: linux-2.6/include/linux/mm.h === --- linux-2.6.orig/include/linux/mm.h +++ linux-2.6/include/linux/mm.h @@ -168,11 +168,12 @@ extern unsigned int kobjsize(const void #define VM_NONLINEAR 0x0080 /* Is non-linear (remap_file_pages) */ #define VM_MAPPED_COPY 0x0100 /* T if mapped copy of data (nommu mmap) */ #define VM_INSERTPAGE 0x0200 /* The vma has had "vm_insert_page()" done on it */ -#define VM_CAN_INVALIDATE 0x0400 /* The mapping may be invalidated, +#define VM_CAN_INVALIDATE 0x0400 /* The mapping may be invalidated, * eg. truncate or invalidate_inode_*. * In this case, do_no_page must * return with the page locked. */ +#define VM_CAN_NONLINEAR 0x0800/* Has ->fault & does nonlinear pages */ #ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */ #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS @@ -196,6 +197,26 @@ extern unsigned int kobjsize(const void */ extern pgprot_t protection_map[16]; +#define FAULT_FLAG_WRITE 0x01 +#define FAULT_FLAG_NONLINEAR 0x02 + +/* + * fault_data is filled in the the pagefault handler and passed to the + * vma's ->fault function. That function is responsible for filling in + * 'type', which is the type of fault if a page is returned, or the type + * of error if NULL is returned. + * + * pgoff should be used in favour of address, if possible. If pgoff is + * used, one may set VM_CAN_NONLINEAR in the vma->vm_flags to get + * nonlinear mapping support. + */ +struct fault_data { + unsigned long address; + pgoff_t pgoff; + unsigned int flags; + + int type; +}; /* * These are the virtual MM functions - opening of an area, closing and @@ -205,6 +226,7 @@ extern pgprot_t protection_map[16]; struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); + struct page * (*fault)(struct vm_area_struct *vma, struct fault_data * fdata); struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type); unsigned long (*nopfn)(struct vm_area_struct * area, unsigned long address); int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock); @@ -635,7 +657,6 @@ static inline int page_mapped(struct pag */ #define NOPAGE_SIGBUS (NULL) #define NOPAGE_OOM ((struct page *) (-1)) -#define NOPAGE_REFAULT ((struct page *) (-2)) /* Return to userspace, rerun */ /* * Error return values for the *_nopfn functions @@ -669,14 +690,13 @@ extern void pagefault_out_of_memory(void extern void show_free_areas(void); #ifdef CONFIG_SHMEM -struct page *shmem_nopage(struct vm_area_struct *vma, - unsigned long address, int *type); +struct page *shmem_fault(struct vm_area_struct *vma, struct fault_data *fdata); int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new); struct mempolicy *shmem_get_policy(struct vm_area_struct *vma, unsigned long addr); int shmem_lock(struct file *file, int lock, struct user_struct *user); #else -#define shmem_nopage filemap_nopage +#define shmem_fault filemap_fault static inline int shmem_lock(struct file *file, int lock, struct user_struct *user) @@ -1069,9 +1089,11 @@ extern void truncate_inode_pages_range(s
[patch 4/7] mm: merge populate and nopage into fault (fixes nonlinear)
Nonlinear mappings are (AFAIKS) simply a virtual memory concept that encodes the virtual address - file offset differently from linear mappings. I can't see why the filesystem/pagecache code should need to know anything about it, except for the fact that the -nopage handler didn't quite pass down enough information (ie. pgoff). But it is more logical to pass pgoff rather than have the -nopage function calculate it itself anyway. And having the nopage handler install the pte itself is sort of nasty. This patch introduces a new fault handler that replaces -nopage and -populate and (later) -nopfn. Most of the old mechanism is still in place so there is a lot of duplication and nice cleanups that can be removed if everyone switches over. The rationale for doing this in the first place is that nonlinear mappings are subject to the pagefault vs invalidate/truncate race too, and it seemed stupid to duplicate the synchronisation logic rather than just consolidate the two. After this patch, MAP_NONBLOCK no longer sets up ptes for pages present in pagecache. Seems like a fringe functionality anyway. NOPAGE_REFAULT is removed. This should be implemented with -fault, and no users have hit mainline yet. Signed-off-by: Nick Piggin [EMAIL PROTECTED] Index: linux-2.6/include/linux/mm.h === --- linux-2.6.orig/include/linux/mm.h +++ linux-2.6/include/linux/mm.h @@ -168,11 +168,12 @@ extern unsigned int kobjsize(const void #define VM_NONLINEAR 0x0080 /* Is non-linear (remap_file_pages) */ #define VM_MAPPED_COPY 0x0100 /* T if mapped copy of data (nommu mmap) */ #define VM_INSERTPAGE 0x0200 /* The vma has had vm_insert_page() done on it */ -#define VM_CAN_INVALIDATE 0x0400 /* The mapping may be invalidated, +#define VM_CAN_INVALIDATE 0x0400 /* The mapping may be invalidated, * eg. truncate or invalidate_inode_*. * In this case, do_no_page must * return with the page locked. */ +#define VM_CAN_NONLINEAR 0x0800/* Has -fault does nonlinear pages */ #ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */ #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS @@ -196,6 +197,26 @@ extern unsigned int kobjsize(const void */ extern pgprot_t protection_map[16]; +#define FAULT_FLAG_WRITE 0x01 +#define FAULT_FLAG_NONLINEAR 0x02 + +/* + * fault_data is filled in the the pagefault handler and passed to the + * vma's -fault function. That function is responsible for filling in + * 'type', which is the type of fault if a page is returned, or the type + * of error if NULL is returned. + * + * pgoff should be used in favour of address, if possible. If pgoff is + * used, one may set VM_CAN_NONLINEAR in the vma-vm_flags to get + * nonlinear mapping support. + */ +struct fault_data { + unsigned long address; + pgoff_t pgoff; + unsigned int flags; + + int type; +}; /* * These are the virtual MM functions - opening of an area, closing and @@ -205,6 +226,7 @@ extern pgprot_t protection_map[16]; struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); + struct page * (*fault)(struct vm_area_struct *vma, struct fault_data * fdata); struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type); unsigned long (*nopfn)(struct vm_area_struct * area, unsigned long address); int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock); @@ -635,7 +657,6 @@ static inline int page_mapped(struct pag */ #define NOPAGE_SIGBUS (NULL) #define NOPAGE_OOM ((struct page *) (-1)) -#define NOPAGE_REFAULT ((struct page *) (-2)) /* Return to userspace, rerun */ /* * Error return values for the *_nopfn functions @@ -669,14 +690,13 @@ extern void pagefault_out_of_memory(void extern void show_free_areas(void); #ifdef CONFIG_SHMEM -struct page *shmem_nopage(struct vm_area_struct *vma, - unsigned long address, int *type); +struct page *shmem_fault(struct vm_area_struct *vma, struct fault_data *fdata); int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new); struct mempolicy *shmem_get_policy(struct vm_area_struct *vma, unsigned long addr); int shmem_lock(struct file *file, int lock, struct user_struct *user); #else -#define shmem_nopage filemap_nopage +#define shmem_fault filemap_fault static inline int shmem_lock(struct file *file, int lock, struct user_struct *user) @@ -1069,9 +1089,11 @@ extern void truncate_inode_pages_range(s loff_t