linux/Documentation/filesystems
Ross Zwisler 91d25ba8a6 dax: use common 4k zero page for dax mmap reads
When servicing mmap() reads from file holes the current DAX code
allocates a page cache page of all zeroes and places the struct page
pointer in the mapping->page_tree radix tree.

This has three major drawbacks:

1) It consumes memory unnecessarily. For every 4k page that is read via
   a DAX mmap() over a hole, we allocate a new page cache page. This
   means that if you read 1GiB worth of pages, you end up using 1GiB of
   zeroed memory. This is easily visible by looking at the overall
   memory consumption of the system or by looking at /proc/[pid]/smaps:

	7f62e72b3000-7f63272b3000 rw-s 00000000 103:00 12   /root/dax/data
	Size:            1048576 kB
	Rss:             1048576 kB
	Pss:             1048576 kB
	Shared_Clean:          0 kB
	Shared_Dirty:          0 kB
	Private_Clean:   1048576 kB
	Private_Dirty:         0 kB
	Referenced:      1048576 kB
	Anonymous:             0 kB
	LazyFree:              0 kB
	AnonHugePages:         0 kB
	ShmemPmdMapped:        0 kB
	Shared_Hugetlb:        0 kB
	Private_Hugetlb:       0 kB
	Swap:                  0 kB
	SwapPss:               0 kB
	KernelPageSize:        4 kB
	MMUPageSize:           4 kB
	Locked:                0 kB

2) It is slower than using a common zero page because each page fault
   has more work to do. Instead of just inserting a common zero page we
   have to allocate a page cache page, zero it, and then insert it. Here
   are the average latencies of dax_load_hole() as measured by ftrace on
   a random test box:

    Old method, using zeroed page cache pages:	3.4 us
    New method, using the common 4k zero page:	0.8 us

   This was the average latency over 1 GiB of sequential reads done by
   this simple fio script:

     [global]
     size=1G
     filename=/root/dax/data
     fallocate=none
     [io]
     rw=read
     ioengine=mmap

3) The fact that we had to check for both DAX exceptional entries and
   for page cache pages in the radix tree made the DAX code more
   complex.

Solve these issues by following the lead of the DAX PMD code and using a
common 4k zero page instead.  As with the PMD code we will now insert a
DAX exceptional entry into the radix tree instead of a struct page
pointer which allows us to remove all the special casing in the DAX
code.

Note that we do still pretty aggressively check for regular pages in the
DAX radix tree, especially where we take action based on the bits set in
the page.  If we ever find a regular page in our radix tree now that
most likely means that someone besides DAX is inserting pages (which has
happened lots of times in the past), and we want to find that out early
and fail loudly.

This solution also removes the extra memory consumption.  Here is that
same /proc/[pid]/smaps after 1GiB of reading from a hole with the new
code:

	7f2054a74000-7f2094a74000 rw-s 00000000 103:00 12   /root/dax/data
	Size:            1048576 kB
	Rss:                   0 kB
	Pss:                   0 kB
	Shared_Clean:          0 kB
	Shared_Dirty:          0 kB
	Private_Clean:         0 kB
	Private_Dirty:         0 kB
	Referenced:            0 kB
	Anonymous:             0 kB
	LazyFree:              0 kB
	AnonHugePages:         0 kB
	ShmemPmdMapped:        0 kB
	Shared_Hugetlb:        0 kB
	Private_Hugetlb:       0 kB
	Swap:                  0 kB
	SwapPss:               0 kB
	KernelPageSize:        4 kB
	MMUPageSize:           4 kB
	Locked:                0 kB

Overall system memory consumption is similarly improved.

Another major change is that we remove dax_pfn_mkwrite() from our fault
flow, and instead rely on the page fault itself to make the PTE dirty
and writeable.  The following description from the patch adding the
vm_insert_mixed_mkwrite() call explains this a little more:

   "To be able to use the common 4k zero page in DAX we need to have our
    PTE fault path look more like our PMD fault path where a PTE entry
    can be marked as dirty and writeable as it is first inserted rather
    than waiting for a follow-up dax_pfn_mkwrite() =>
    finish_mkwrite_fault() call.

    Right now we can rely on having a dax_pfn_mkwrite() call because we
    can distinguish between these two cases in do_wp_page():

            case 1: 4k zero page => writable DAX storage
            case 2: read-only DAX storage => writeable DAX storage

    This distinction is made by via vm_normal_page(). vm_normal_page()
    returns false for the common 4k zero page, though, just as it does
    for DAX ptes. Instead of special casing the DAX + 4k zero page case
    we will simplify our DAX PTE page fault sequence so that it matches
    our DAX PMD sequence, and get rid of the dax_pfn_mkwrite() helper.
    We will instead use dax_iomap_fault() to handle write-protection
    faults.

    This means that insert_pfn() needs to follow the lead of
    insert_pfn_pmd() and allow us to pass in a 'mkwrite' flag. If
    'mkwrite' is set insert_pfn() will do the work that was previously
    done by wp_page_reuse() as part of the dax_pfn_mkwrite() call path"

Link: http://lkml.kernel.org/r/20170724170616.25810-4-ross.zwisler@linux.intel.com
Signed-off-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Cc: "Darrick J. Wong" <darrick.wong@oracle.com>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Andreas Dilger <adilger.kernel@dilger.ca>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Matthew Wilcox <mawilcox@microsoft.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-09-06 17:27:24 -07:00
..
caching
cifs
configfs fs: configfs: don't return anything from drop_link 2016-12-01 10:50:49 +01:00
nfs doc: ReSTify keys-request-key.txt 2017-05-18 10:33:51 -06:00
pohmelfs
00-INDEX logfs: remove from tree 2016-12-14 23:48:11 -05:00
9p.txt
adfs.txt
affs.txt
afs.txt rxrpc: Change module filename to rxrpc.ko 2017-02-17 15:09:19 -05:00
autofs4-mount-control.txt autofs: update ioctl documentation regarding struct autofs_dev_ioctl 2017-02-27 18:43:45 -08:00
autofs4.txt Fix up over-eager 'wait_queue_t' renaming 2017-07-10 11:40:19 -07:00
automount-support.txt
befs.txt
bfs.txt Tigran has moved 2017-05-12 15:57:15 -07:00
btrfs.txt
ceph.txt ceph: set io_pages bdi hint 2017-02-20 12:16:05 +01:00
coda.txt
conf.py docs-rst: convert filesystems book to ReST 2017-05-16 08:44:08 -03:00
cramfs.txt
dax.txt dax: use common 4k zero page for dax mmap reads 2017-09-06 17:27:24 -07:00
debugfs.txt
devpts.txt devpts: Make each mount of devpts an independent filesystem. 2016-06-05 10:36:01 -07:00
directory-locking vfs: remove unused i_op->rename 2016-09-27 11:03:58 +02:00
dlmfs.txt
dnotify.txt
ecryptfs.txt
efivarfs.txt
exofs.txt
ext2.txt
ext3.txt
ext4.txt Documentation: Fix dead URLs to ftp.kernel.org 2017-03-29 15:46:06 -06:00
f2fs.txt f2fs: support plain user/group quota 2017-07-08 23:12:27 -07:00
fiemap.txt
files.txt
fuse.txt
gfs2-glocks.txt
gfs2-uevents.txt
gfs2.txt
hfs.txt
hfsplus.txt
hpfs.txt
index.rst docs-rst: don't ignore internal functions for jbd2 docs 2017-05-16 08:44:09 -03:00
inotify.txt
isofs.txt
jfs.txt
Locking Documentation/filesystems: fix documentation for ->getattr() 2017-04-03 01:05:56 -04:00
locks.txt docs: fix locations of several documents that got moved 2016-10-24 08:12:35 -02:00
mandatory-locking.txt
ncpfs.txt
nilfs2.txt nilfs2: move ioctl interface and disk layout to uapi separately 2016-08-02 19:35:21 -04:00
ntfs.txt
ocfs2-online-filecheck.txt Doc: ocfs: Fix typo in filesystems/ocfs2-online-filecheck.txt 2016-07-01 16:17:15 -06:00
ocfs2.txt
omfs.txt
orangefs.txt Orangefs: update orangefs.txt 2016-08-02 15:39:14 -04:00
overlayfs.txt ovl: document copying layers restrictions with inodes index 2017-07-04 22:03:19 +02:00
path-lookup.md
path-lookup.txt
porting Documentation/filesystems: fix documentation for ->getattr() 2017-04-03 01:05:56 -04:00
proc.txt procfs: fdinfo: extend information about epoll target files 2017-07-12 16:26:01 -07:00
qnx6.txt
quota.txt scripts/spelling.txt: add "an user" pattern and fix typo instances 2017-02-27 18:43:46 -08:00
ramfs-rootfs-initramfs.txt
relay.txt
romfs.txt
seq_file.txt
sharedsubtree.txt
spufs.txt
squashfs.txt
sysfs-pci.txt PCI: Add pci_mmap_resource_range() and use it for ARM64 2017-04-20 08:47:47 -05:00
sysfs-tagging.txt
sysfs.txt
sysv-fs.txt
tmpfs.txt Documenation: update cgroup's document path 2016-08-03 15:43:58 -06:00
ubifs.txt
udf.txt
ufs.txt
vfat.txt
vfs.txt swap: Remove obsolete sentence 2017-08-26 15:55:38 -06:00
xfs-delayed-logging-design.txt
xfs-self-describing-metadata.txt
xfs.txt xfs: deprecate barrier/nobarrier mount option 2016-12-09 16:49:54 +11:00