From: David Howells 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 Signed-off-by: Andrew Morton --- 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 #include #include +#include #include #include @@ -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, }; _