NFS: readdirplus optimization by cache mechanism
authorluanshi <zhangliguang@linux.alibaba.com>
Tue, 29 Jan 2019 07:34:17 +0000 (15:34 +0800)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 20 Feb 2019 22:33:55 +0000 (17:33 -0500)
commitbe4c2d4723a4a637f0d1b4f7c66447141a4b3564
tree8b78cfcd65a43420fd5172e4d5f3793a583d3ee3
parent40cc394be1aa18848b8757e03bd8ed23281f572e
NFS: readdirplus optimization by cache mechanism

When listing very large directories via NFS, clients may take a long
time to complete. There are about three factors involved:

First of all, ls and practically every other method of listing a
directory including python os.listdir and find rely on libc readdir().
However readdir() only reads 32K of directory entries at a time, which
means that if you have a lot of files in the same directory, it is going
to take an insanely long time to read all the directory entries.

Secondly, libc readdir() reads 32K of directory entries at a time, in
kernel space 32K buffer split into 8 pages. One NFS readdirplus rpc will
be called for one page, which introduces many readdirplus rpc calls.

Lastly, one NFS readdirplus rpc asks for 32K data (filled by nfs_dentry)
to fill one page (filled by dentry), we found that nearly one third of
data was wasted.

To solve above problems, pagecache mechanism was introduced. One NFS
readdirplus rpc will ask for a large data (more than 32k), the data can
fill more than one page, the cached pages can be used for next readdir
call. This can reduce many readdirplus rpc calls and improve readdirplus
performance.

TESTING:
When listing very large directories(include 300 thousand files) via NFS

time ls -l /nfs_mount | wc -l

without the patch:
300001
real    1m53.524s
user    0m2.314s
sys     0m2.599s

with the patch:
300001
real    0m23.487s
user    0m2.305s
sys     0m2.558s

Improved performance: 79.6%
readdirplus rpc calls decrease: 85%

Signed-off-by: Liguang Zhang <zhangliguang@linux.alibaba.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/dir.c
fs/nfs/internal.h