[patch 4/7] mm: merge populate and nopage into fault (fixes nonlinear)

2007-01-12 Thread Nick Piggin
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)

2007-01-12 Thread Nick Piggin
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