zfsonlinux/zfs — pull request #2232 by ryao (2014-04-02 19:39:00+00:00)
Title: Improve dirty page writeout performance and fsync correctness

This refactors the internal layering in the ZPL to promote greater
performance and improved correctness. In specific, ->fsync, ->writepages
and ->writepagehave been changed to more closely match other Open ZFS
platforms.

->fsync() will now call write_inode_now() to ensure that all dirty pages
have been moved to ARC prior to zil_commit(). This is equivalent to
calling VOP_PUTPAGE() on Illumos because we do not implement
->write_inode at this time.

->writepages has been refactored to call zfs_range_lock() once per call.
Each zfs_range_lock() does its own memory allocation and various tree
operations, so making it occur only once reduces the computational
complexity of writepages, but at least a factor of log(N) where N is the
number of pages. This brings us to parity with other Open ZFS
implementations and also avoids significant virtual memory contention
that is prevalent in Linux's vmalloc(). In addition, we now pass
WB_SYNC_NONE to write_cache_pages, which eliminates an opportunity for
unnecessary blocking. This moves responsibility for ensuring synchronous
semantics entirely to zil_commit(), where it should have been in the
first place. It also eliminates an opportunity for concurrent threads
block each other on writeback.

->writepage has been refactored to permit the changes to ->writepages.
Situations where it is told to write out an invalidated page is now
properly handled by ignoring them. This avoids a theoretical NULL
pointer dereference.

These changes substantially improve 32-thread 4K randomwrite IO on a RAM
disk in filebench's randomwrite benchmark. This has been tested with the
following:

modprobe brd ramdisk_size=8388604
modprobe loop
losetup loop0 /dev/ram0
zpool create -o ashift=12 -O recordsize=4K test /dev/loop0
zpool export test
losetup -D
zpool import -d /dev test

filebench << END
load randomwrite
set \$dir=/test
set \$nthreads=32
set \$iosize=4096
run 60
END

zpool destroy test
modprobe -r brd
modprobe -r loop

Previous tests on Gentoo Linux using a kernel compiled from CentOS
2.6.32-431.11.2.el6.x86_64 kernel with the default .config showed single
threaded performance at roughly 10k to 11k IOPS with 32-thread
performance at 5k-6k in this benchmark. Tests with this patch show a
performance improvement to 15k to 17k in the 32-thread case. These tests
were conducted on a single processor Xeon E5-2620 with 64GB of RAM.

Signed-off-by: Richard Yao