The backing_dev_info `memory_backed' boolean is presently overloaded. It means both "dirty pages against this device do not contribute to dirty memory accounting" and "there is no point in performing writeback against files which are backed by this device" Both rules indeed hold true for ramfs-type filesystems. But they need to be separated for the ramdisk device. ramdisk-backed files should not contribute to dirty memory but they should get writeback, so we copy data from the regular files' pagecache into the ramdisk blockdev pagecache. Except this still isn't right :( Really, we want regular files which are backed by a ramdisk device to contribute to dirty memory so that the VM will write them into the ramdisk blockdev pagecache. But we don't want the ramdisk blockdev address_space's dirty pages to contribute to dirty memory, because we have no way of cleaning them again. (their dirtiness is the only thing which keeps these pages from being reclaimed by the VM). Ho hum, it's probably OK. kupdate and sync() and VM pressure will still do the right thing. This patch makes no functional changes to anything. --- 25-akpm/arch/ia64/sn/io/hwgfs/ramfs.c | 3 ++- 25-akpm/drivers/block/ll_rw_blk.c | 3 ++- 25-akpm/drivers/block/rd.c | 3 ++- 25-akpm/fs/buffer.c | 2 +- 25-akpm/fs/fs-writeback.c | 2 +- 25-akpm/fs/hugetlbfs/inode.c | 3 ++- 25-akpm/fs/ramfs/inode.c | 3 ++- 25-akpm/fs/sysfs/inode.c | 3 ++- 25-akpm/include/linux/backing-dev.h | 10 +++++++++- 25-akpm/mm/filemap.c | 2 +- 25-akpm/mm/page-writeback.c | 6 +++--- 25-akpm/mm/shmem.c | 3 ++- 25-akpm/mm/swap_state.c | 3 ++- 13 files changed, 31 insertions(+), 15 deletions(-) diff -puN arch/ia64/sn/io/hwgfs/ramfs.c~split-backing_dev-memory-backed arch/ia64/sn/io/hwgfs/ramfs.c --- 25/arch/ia64/sn/io/hwgfs/ramfs.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.949590104 -0700 +++ 25-akpm/arch/ia64/sn/io/hwgfs/ramfs.c 2004-05-17 18:04:46.968587216 -0700 @@ -29,7 +29,8 @@ static struct inode_operations hwgfs_dir static struct backing_dev_info hwgfs_backing_dev_info = { .ra_pages = 0, /* No readahead */ - .memory_backed = 1, /* Does not contribute to dirty memory */ + .no_dirty_acct = 1, /* Does not contribute to dirty memory */ + .no_writeback = 1, /* Does not need writeback */ }; static struct inode *hwgfs_get_inode(struct super_block *sb, int mode, dev_t dev) diff -puN drivers/block/ll_rw_blk.c~split-backing_dev-memory-backed drivers/block/ll_rw_blk.c --- 25/drivers/block/ll_rw_blk.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.951589800 -0700 +++ 25-akpm/drivers/block/ll_rw_blk.c 2004-05-17 18:04:46.971586760 -0700 @@ -242,7 +242,8 @@ 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.no_dirty_acct = 0; + q->backing_dev_info.no_writeback = 0; 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~split-backing_dev-memory-backed drivers/block/rd.c --- 25/drivers/block/rd.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.952589648 -0700 +++ 25-akpm/drivers/block/rd.c 2004-05-17 18:27:46.625847432 -0700 @@ -270,7 +270,8 @@ 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 */ + .no_dirty_acct = 1, /* Does not contribute to dirty memory */ + .no_writeback = 1, /* Does not need writeback */ .unplug_io_fn = default_unplug_io_fn, }; diff -puN include/linux/backing-dev.h~split-backing_dev-memory-backed include/linux/backing-dev.h --- 25/include/linux/backing-dev.h~split-backing_dev-memory-backed 2004-05-17 18:04:46.954589344 -0700 +++ 25-akpm/include/linux/backing-dev.h 2004-05-17 18:04:46.972586608 -0700 @@ -22,10 +22,18 @@ enum bdi_state { typedef int (congested_fn)(void *, int); +/* + * `no_writeback' means that there is no point in the VM trying to write back + * pages against this device: their backing store is their own pagecache. + * + * `no_dirty_acct' means that marking a page dirty against this device does + * not contribute to page_state.nr_dirty, nor to /proc/meminfo:Dirty. + */ 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 */ + int no_dirty_acct; /* Does not contribute to dirty accounting */ + int no_writeback; /* Cannot clean pages with writepage */ 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 *); diff -puN fs/sysfs/inode.c~split-backing_dev-memory-backed fs/sysfs/inode.c --- 25/fs/sysfs/inode.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.955589192 -0700 +++ 25-akpm/fs/sysfs/inode.c 2004-05-17 18:04:46.972586608 -0700 @@ -23,7 +23,8 @@ 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 */ + .no_dirty_acct = 1, /* Does not contribute to dirty memory */ + .no_writeback = 1, /* Does not need VM writeback */ }; struct inode * sysfs_new_inode(mode_t mode) diff -puN fs/hugetlbfs/inode.c~split-backing_dev-memory-backed fs/hugetlbfs/inode.c --- 25/fs/hugetlbfs/inode.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.956589040 -0700 +++ 25-akpm/fs/hugetlbfs/inode.c 2004-05-17 18:04:46.973586456 -0700 @@ -40,7 +40,8 @@ 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 */ + .no_dirty_acct = 1, /* Does not contribute to dirty memory */ + .no_writeback = 1, /* Does not need VM writeback */ }; int sysctl_hugetlb_shm_group; diff -puN fs/ramfs/inode.c~split-backing_dev-memory-backed fs/ramfs/inode.c --- 25/fs/ramfs/inode.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.958588736 -0700 +++ 25-akpm/fs/ramfs/inode.c 2004-05-17 18:04:46.973586456 -0700 @@ -45,7 +45,8 @@ 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 */ + .no_dirty_acct = 1, /* Does not contribute to dirty memory */ + .no_writeback = 1, /* Does not need VM writeback */ }; static struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev) diff -puN fs/buffer.c~split-backing_dev-memory-backed fs/buffer.c --- 25/fs/buffer.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.959588584 -0700 +++ 25-akpm/fs/buffer.c 2004-05-17 18:04:46.976586000 -0700 @@ -949,7 +949,7 @@ int __set_page_dirty_buffers(struct page if (!TestSetPageDirty(page)) { spin_lock_irq(&mapping->tree_lock); if (page->mapping) { /* Race with truncate? */ - if (!mapping->backing_dev_info->memory_backed) + if (!mapping->backing_dev_info->no_dirty_acct) inc_page_state(nr_dirty); radix_tree_tag_set(&mapping->page_tree, page_index(page), diff -puN fs/fs-writeback.c~split-backing_dev-memory-backed fs/fs-writeback.c --- 25/fs/fs-writeback.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.960588432 -0700 +++ 25-akpm/fs/fs-writeback.c 2004-05-17 18:27:46.626847280 -0700 @@ -301,7 +301,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->no_writeback) { if (sb == blockdev_superblock) { /* * Dirty memory-backed blockdev: the ramdisk diff -puN mm/filemap.c~split-backing_dev-memory-backed mm/filemap.c --- 25/mm/filemap.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.962588128 -0700 +++ 25-akpm/mm/filemap.c 2004-05-17 18:04:47.128562896 -0700 @@ -150,7 +150,7 @@ static int __filemap_fdatawrite(struct a .nr_to_write = mapping->nrpages * 2, }; - if (mapping->backing_dev_info->memory_backed) + if (mapping->backing_dev_info->no_writeback) return 0; ret = do_writepages(mapping, &wbc); diff -puN mm/shmem.c~split-backing_dev-memory-backed mm/shmem.c --- 25/mm/shmem.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.964587824 -0700 +++ 25-akpm/mm/shmem.c 2004-05-17 18:04:47.130562592 -0700 @@ -172,7 +172,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 */ + .no_dirty_acct = 1, /* Does not contribute to dirty memory */ + .no_writeback = 1, /* Does not need VM writeback */ .unplug_io_fn = default_unplug_io_fn, }; diff -puN mm/page-writeback.c~split-backing_dev-memory-backed mm/page-writeback.c --- 25/mm/page-writeback.c~split-backing_dev-memory-backed 2004-05-17 18:04:46.965587672 -0700 +++ 25-akpm/mm/page-writeback.c 2004-05-17 18:04:47.131562440 -0700 @@ -570,7 +570,7 @@ int __set_page_dirty_nobuffers(struct pa mapping = page_mapping(page); if (page_mapping(page)) { /* Race with truncate? */ BUG_ON(page_mapping(page) != mapping); - if (!mapping->backing_dev_info->memory_backed) + if (!mapping->backing_dev_info->no_dirty_acct) inc_page_state(nr_dirty); radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); @@ -656,7 +656,7 @@ int test_clear_page_dirty(struct page *p page_index(page), PAGECACHE_TAG_DIRTY); spin_unlock_irqrestore(&mapping->tree_lock, flags); - if (!mapping->backing_dev_info->memory_backed) + if (!mapping->backing_dev_info->no_dirty_acct) dec_page_state(nr_dirty); return 1; } @@ -687,7 +687,7 @@ int clear_page_dirty_for_io(struct page if (mapping) { if (TestClearPageDirty(page)) { - if (!mapping->backing_dev_info->memory_backed) + if (!mapping->backing_dev_info->no_dirty_acct) dec_page_state(nr_dirty); return 1; } diff -puN mm/swap_state.c~split-backing_dev-memory-backed mm/swap_state.c --- 25/mm/swap_state.c~split-backing_dev-memory-backed 2004-05-17 18:27:59.679862920 -0700 +++ 25-akpm/mm/swap_state.c 2004-05-17 18:28:32.211917296 -0700 @@ -28,7 +28,8 @@ static struct address_space_operations s }; static struct backing_dev_info swap_backing_dev_info = { - .memory_backed = 1, /* Does not contribute to dirty memory */ + .no_dirty_acct = 1, /* Does not contribute to dirty memory */ + .no_writeback = 1, /* Does not need VM writeback */ .unplug_io_fn = swap_unplug_io_fn, }; _