From: David Howells <dhowells@redhat.com>

The attached patch replaces backing_dev_info::memory_backed with capabilitied
bitmap. The capabilities available include:

  (*) BDI_CAP_NO_ACCT_DIRTY

      Set if the pages associated with this backing device should not be
      tracked by the dirty page accounting.

  (*) BDI_CAP_NO_WRITEBACK

      Set if dirty pages associated with this backing device should not have
      writepage() or writepages() invoked upon them to clean them.

  (*) Capability markers that indicate what a backing device is capable of
      with regard to memory mapping facilities. These flags indicate whether a
      device can be mapped directly, whether it can be copied for a mapping,
      and whether direct mappings can be read, written and/or executed. This
      information is primarily aimed at improving no-MMU private mapping
      support.

The patch also provides convenience functions for determining the dirty-page
capabilities available on backing devices directly or on the backing devices
associated with a mapping. These are provided to keep line length down when
checking for the capabilities.

Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/block/ll_rw_blk.c   |    2 -
 25-akpm/drivers/block/rd.c          |    4 +--
 25-akpm/drivers/char/mem.c          |    6 +++++
 25-akpm/fs/buffer.c                 |    2 -
 25-akpm/fs/fs-writeback.c           |    4 +--
 25-akpm/fs/hugetlbfs/inode.c        |    2 -
 25-akpm/fs/ramfs/inode.c            |    4 ++-
 25-akpm/fs/sysfs/inode.c            |    2 -
 25-akpm/include/linux/backing-dev.h |   41 +++++++++++++++++++++++++++++++++++-
 25-akpm/mm/filemap.c                |    6 ++---
 25-akpm/mm/page-writeback.c         |    6 ++---
 25-akpm/mm/readahead.c              |    1 
 25-akpm/mm/shmem.c                  |    4 +--
 25-akpm/mm/swap_state.c             |    2 -
 14 files changed, 67 insertions(+), 19 deletions(-)

diff -puN drivers/block/ll_rw_blk.c~bdi-provide-backing-device-capability-information drivers/block/ll_rw_blk.c
--- 25/drivers/block/ll_rw_blk.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/drivers/block/ll_rw_blk.c	Tue Mar  8 16:33:20 2005
@@ -238,7 +238,7 @@ void blk_queue_make_request(request_queu
 	q->make_request_fn = mfn;
 	q->backing_dev_info.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 	q->backing_dev_info.state = 0;
-	q->backing_dev_info.memory_backed = 0;
+	q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
 	blk_queue_max_sectors(q, MAX_SECTORS);
 	blk_queue_hardsect_size(q, 512);
 	blk_queue_dma_alignment(q, 511);
diff -puN drivers/block/rd.c~bdi-provide-backing-device-capability-information drivers/block/rd.c
--- 25/drivers/block/rd.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/drivers/block/rd.c	Tue Mar  8 16:33:20 2005
@@ -325,7 +325,7 @@ static int rd_ioctl(struct inode *inode,
  */
 static struct backing_dev_info rd_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK | BDI_CAP_MAP_COPY,
 	.unplug_io_fn	= default_unplug_io_fn,
 };
 
@@ -336,7 +336,7 @@ static struct backing_dev_info rd_backin
  */
 static struct backing_dev_info rd_file_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 0,	/* Does contribute to dirty memory */
+	.capabilities	= BDI_CAP_MAP_COPY,	/* Does contribute to dirty memory */
 	.unplug_io_fn	= default_unplug_io_fn,
 };
 
diff -puN drivers/char/mem.c~bdi-provide-backing-device-capability-information drivers/char/mem.c
--- 25/drivers/char/mem.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/drivers/char/mem.c	Tue Mar  8 16:33:20 2005
@@ -23,6 +23,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/ptrace.h>
 #include <linux/device.h>
+#include <linux/backing-dev.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -744,6 +745,10 @@ static struct file_operations zero_fops 
 	.mmap		= mmap_zero,
 };
 
+static struct backing_dev_info zero_bdi = {
+	.capabilities	= BDI_CAP_MAP_COPY,
+};
+
 static struct file_operations full_fops = {
 	.llseek		= full_lseek,
 	.read		= read_full,
@@ -790,6 +795,7 @@ static int memory_open(struct inode * in
 			break;
 #endif
 		case 5:
+			filp->f_mapping->backing_dev_info = &zero_bdi;
 			filp->f_op = &zero_fops;
 			break;
 		case 7:
diff -puN fs/buffer.c~bdi-provide-backing-device-capability-information fs/buffer.c
--- 25/fs/buffer.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/fs/buffer.c	Tue Mar  8 16:33:20 2005
@@ -878,7 +878,7 @@ int __set_page_dirty_buffers(struct page
 	if (!TestSetPageDirty(page)) {
 		write_lock_irq(&mapping->tree_lock);
 		if (page->mapping) {	/* Race with truncate? */
-			if (!mapping->backing_dev_info->memory_backed)
+			if (mapping_cap_account_dirty(mapping))
 				inc_page_state(nr_dirty);
 			radix_tree_tag_set(&mapping->page_tree,
 						page_index(page),
diff -puN fs/fs-writeback.c~bdi-provide-backing-device-capability-information fs/fs-writeback.c
--- 25/fs/fs-writeback.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/fs/fs-writeback.c	Tue Mar  8 16:33:20 2005
@@ -315,7 +315,7 @@ sync_sb_inodes(struct super_block *sb, s
 		struct backing_dev_info *bdi = mapping->backing_dev_info;
 		long pages_skipped;
 
-		if (bdi->memory_backed) {
+		if (!bdi_cap_writeback_dirty(bdi)) {
 			list_move(&inode->i_list, &sb->s_dirty);
 			if (sb == blockdev_superblock) {
 				/*
@@ -566,7 +566,7 @@ int write_inode_now(struct inode *inode,
 		.sync_mode = WB_SYNC_ALL,
 	};
 
-	if (inode->i_mapping->backing_dev_info->memory_backed)
+	if (!mapping_cap_writeback_dirty(inode->i_mapping))
 		return 0;
 
 	might_sleep();
diff -puN fs/hugetlbfs/inode.c~bdi-provide-backing-device-capability-information fs/hugetlbfs/inode.c
--- 25/fs/hugetlbfs/inode.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/fs/hugetlbfs/inode.c	Tue Mar  8 16:33:20 2005
@@ -40,7 +40,7 @@ static struct inode_operations hugetlbfs
 
 static struct backing_dev_info hugetlbfs_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 };
 
 int sysctl_hugetlb_shm_group;
diff -puN fs/ramfs/inode.c~bdi-provide-backing-device-capability-information fs/ramfs/inode.c
--- 25/fs/ramfs/inode.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/fs/ramfs/inode.c	Tue Mar  8 16:33:20 2005
@@ -45,7 +45,9 @@ static struct inode_operations ramfs_dir
 
 static struct backing_dev_info ramfs_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK |
+			  BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
+			  BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
 };
 
 struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
diff -puN fs/sysfs/inode.c~bdi-provide-backing-device-capability-information fs/sysfs/inode.c
--- 25/fs/sysfs/inode.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/fs/sysfs/inode.c	Tue Mar  8 16:33:20 2005
@@ -23,7 +23,7 @@ static struct address_space_operations s
 
 static struct backing_dev_info sysfs_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 };
 
 struct inode * sysfs_new_inode(mode_t mode)
diff -puN include/linux/backing-dev.h~bdi-provide-backing-device-capability-information include/linux/backing-dev.h
--- 25/include/linux/backing-dev.h~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/include/linux/backing-dev.h	Tue Mar  8 16:33:20 2005
@@ -25,13 +25,39 @@ typedef int (congested_fn)(void *, int);
 struct backing_dev_info {
 	unsigned long ra_pages;	/* max readahead in PAGE_CACHE_SIZE units */
 	unsigned long state;	/* Always use atomic bitops on this */
-	int memory_backed;	/* Cannot clean pages with writepage */
+	unsigned int capabilities; /* Device capabilities */
 	congested_fn *congested_fn; /* Function pointer if device is md/dm */
 	void *congested_data;	/* Pointer to aux data for congested func */
 	void (*unplug_io_fn)(struct backing_dev_info *, struct page *);
 	void *unplug_io_data;
 };
 
+
+/*
+ * Flags in backing_dev_info::capability
+ * - The first two flags control whether dirty pages will contribute to the
+ *   VM's accounting and whether writepages() should be called for dirty pages
+ *   (something that would not, for example, be appropriate for ramfs)
+ * - These flags let !MMU mmap() govern direct device mapping vs immediate
+ *   copying more easily for MAP_PRIVATE, especially for ROM filesystems
+ */
+#define BDI_CAP_NO_ACCT_DIRTY	0x00000001	/* Dirty pages shouldn't contribute to accounting */
+#define BDI_CAP_NO_WRITEBACK	0x00000002	/* Don't write pages back */
+#define BDI_CAP_MAP_COPY	0x00000004	/* Copy can be mapped (MAP_PRIVATE) */
+#define BDI_CAP_MAP_DIRECT	0x00000008	/* Can be mapped directly (MAP_SHARED) */
+#define BDI_CAP_READ_MAP	0x00000010	/* Can be mapped for reading */
+#define BDI_CAP_WRITE_MAP	0x00000020	/* Can be mapped for writing */
+#define BDI_CAP_EXEC_MAP	0x00000040	/* Can be mapped for execution */
+#define BDI_CAP_VMFLAGS \
+	(BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP)
+
+#if defined(VM_MAYREAD) && \
+	(BDI_CAP_READ_MAP != VM_MAYREAD || \
+	 BDI_CAP_WRITE_MAP != VM_MAYWRITE || \
+	 BDI_CAP_EXEC_MAP != VM_MAYEXEC)
+#error please change backing_dev_info::capabilities flags
+#endif
+
 extern struct backing_dev_info default_backing_dev_info;
 void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page);
 
@@ -62,4 +88,17 @@ static inline int bdi_rw_congested(struc
 				  (1 << BDI_write_congested));
 }
 
+#define bdi_cap_writeback_dirty(bdi) \
+	(!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))
+
+#define bdi_cap_account_dirty(bdi) \
+	(!((bdi)->capabilities & BDI_CAP_NO_ACCT_DIRTY))
+
+#define mapping_cap_writeback_dirty(mapping) \
+	bdi_cap_writeback_dirty((mapping)->backing_dev_info)
+
+#define mapping_cap_account_dirty(mapping) \
+	bdi_cap_account_dirty((mapping)->backing_dev_info)
+
+
 #endif		/* _LINUX_BACKING_DEV_H */
diff -puN mm/filemap.c~bdi-provide-backing-device-capability-information mm/filemap.c
--- 25/mm/filemap.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/mm/filemap.c	Tue Mar  8 16:33:20 2005
@@ -172,7 +172,7 @@ static int __filemap_fdatawrite_range(st
 		.end = end,
 	};
 
-	if (mapping->backing_dev_info->memory_backed)
+	if (!mapping_cap_writeback_dirty(mapping))
 		return 0;
 
 	ret = do_writepages(mapping, &wbc);
@@ -269,7 +269,7 @@ int sync_page_range(struct inode *inode,
 	pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT;
 	int ret;
 
-	if (mapping->backing_dev_info->memory_backed || !count)
+	if (!mapping_cap_writeback_dirty(mapping) || !count)
 		return 0;
 	ret = filemap_fdatawrite_range(mapping, pos, pos + count - 1);
 	if (ret == 0) {
@@ -295,7 +295,7 @@ int sync_page_range_nolock(struct inode 
 	pgoff_t end = (pos + count - 1) >> PAGE_CACHE_SHIFT;
 	int ret;
 
-	if (mapping->backing_dev_info->memory_backed || !count)
+	if (!mapping_cap_writeback_dirty(mapping) || !count)
 		return 0;
 	ret = filemap_fdatawrite_range(mapping, pos, pos + count - 1);
 	if (ret == 0)
diff -puN mm/page-writeback.c~bdi-provide-backing-device-capability-information mm/page-writeback.c
--- 25/mm/page-writeback.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/mm/page-writeback.c	Tue Mar  8 16:33:53 2005
@@ -627,7 +627,7 @@ int __set_page_dirty_nobuffers(struct pa
 			mapping2 = page_mapping(page);
 			if (mapping2) { /* Race with truncate? */
 				BUG_ON(mapping2 != mapping);
-				if (!mapping->backing_dev_info->memory_backed)
+				if (mapping_cap_account_dirty(mapping))
 					inc_page_state(nr_dirty);
 				radix_tree_tag_set(&mapping->page_tree,
 					page_index(page), PAGECACHE_TAG_DIRTY);
@@ -713,7 +713,7 @@ int test_clear_page_dirty(struct page *p
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
 			write_unlock_irqrestore(&mapping->tree_lock, flags);
-			if (!mapping->backing_dev_info->memory_backed)
+			if (mapping_cap_account_dirty(mapping))
 				dec_page_state(nr_dirty);
 			return 1;
 		}
@@ -744,7 +744,7 @@ int clear_page_dirty_for_io(struct page 
 
 	if (mapping) {
 		if (TestClearPageDirty(page)) {
-			if (!mapping->backing_dev_info->memory_backed)
+			if (mapping_cap_account_dirty(mapping))
 				dec_page_state(nr_dirty);
 			return 1;
 		}
diff -puN mm/readahead.c~bdi-provide-backing-device-capability-information mm/readahead.c
--- 25/mm/readahead.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/mm/readahead.c	Tue Mar  8 16:33:20 2005
@@ -23,6 +23,7 @@ EXPORT_SYMBOL(default_unplug_io_fn);
 struct backing_dev_info default_backing_dev_info = {
 	.ra_pages	= (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE,
 	.state		= 0,
+	.capabilities	= BDI_CAP_MAP_COPY,
 	.unplug_io_fn	= default_unplug_io_fn,
 };
 EXPORT_SYMBOL_GPL(default_backing_dev_info);
diff -puN mm/shmem.c~bdi-provide-backing-device-capability-information mm/shmem.c
--- 25/mm/shmem.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/mm/shmem.c	Tue Mar  8 16:33:20 2005
@@ -184,8 +184,8 @@ static struct vm_operations_struct shmem
 
 static struct backing_dev_info shmem_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
-	.unplug_io_fn = default_unplug_io_fn,
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+	.unplug_io_fn	= default_unplug_io_fn,
 };
 
 static LIST_HEAD(shmem_swaplist);
diff -puN mm/swap_state.c~bdi-provide-backing-device-capability-information mm/swap_state.c
--- 25/mm/swap_state.c~bdi-provide-backing-device-capability-information	Tue Mar  8 16:33:20 2005
+++ 25-akpm/mm/swap_state.c	Tue Mar  8 16:33:20 2005
@@ -29,7 +29,7 @@ static struct address_space_operations s
 };
 
 static struct backing_dev_info swap_backing_dev_info = {
-	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+	.capabilities	= BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
 	.unplug_io_fn	= swap_unplug_io_fn,
 };
 
_