Add Linux posix_fadvise support

The purpose of this PR is to accepts fadvise ioctl from userland
to do read-ahead by demand.

It could dramatically improve sequential read performance especially
when primarycache is set to metadata or zfs_prefetch_disable is 1.

If the file is mmaped, generic_fadvise is also called for page cache
read-ahead besides dmu_prefetch.

Only POSIX_FADV_WILLNEED and POSIX_FADV_SEQUENTIAL are supported in
this PR currently.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Finix Yan <yancw@info2soft.com>
Closes #13694
This commit is contained in:
Finix1979
2022-09-09 01:29:41 +08:00
committed by GitHub
parent 380b08098e
commit 320f0c6022
15 changed files with 365 additions and 2 deletions
+62
View File
@@ -27,6 +27,7 @@
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
#endif
#include <linux/fs.h>
#include <sys/file.h>
#include <sys/dmu_objset.h>
#include <sys/zfs_znode.h>
@@ -37,6 +38,9 @@
defined(HAVE_VFS_FILEMAP_DIRTY_FOLIO)
#include <linux/pagemap.h>
#endif
#ifdef HAVE_FILE_FADVISE
#include <linux/fadvise.h>
#endif
#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
#include <linux/writeback.h>
#endif
@@ -906,6 +910,61 @@ zpl_ioctl_getversion(struct file *filp, void __user *arg)
return (copy_to_user(arg, &generation, sizeof (generation)));
}
#ifdef HAVE_FILE_FADVISE
static int
zpl_fadvise(struct file *filp, loff_t offset, loff_t len, int advice)
{
struct inode *ip = file_inode(filp);
znode_t *zp = ITOZ(ip);
zfsvfs_t *zfsvfs = ITOZSB(ip);
objset_t *os = zfsvfs->z_os;
int error = 0;
if (S_ISFIFO(ip->i_mode))
return (-ESPIPE);
if (offset < 0 || len < 0)
return (-EINVAL);
ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zp);
switch (advice) {
case POSIX_FADV_SEQUENTIAL:
case POSIX_FADV_WILLNEED:
#ifdef HAVE_GENERIC_FADVISE
if (zn_has_cached_data(zp))
error = generic_fadvise(filp, offset, len, advice);
#endif
/*
* Pass on the caller's size directly, but note that
* dmu_prefetch_max will effectively cap it. If there
* really is a larger sequential access pattern, perhaps
* dmu_zfetch will detect it.
*/
if (len == 0)
len = i_size_read(ip) - offset;
dmu_prefetch(os, zp->z_id, 0, offset, len,
ZIO_PRIORITY_ASYNC_READ);
break;
case POSIX_FADV_NORMAL:
case POSIX_FADV_RANDOM:
case POSIX_FADV_DONTNEED:
case POSIX_FADV_NOREUSE:
/* ignored for now */
break;
default:
error = -EINVAL;
break;
}
ZFS_EXIT(zfsvfs);
return (error);
}
#endif /* HAVE_FILE_FADVISE */
#define ZFS_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | ZFS_PROJINHERIT_FL)
#define ZFS_FL_USER_MODIFIABLE (FS_FL_USER_MODIFIABLE | ZFS_PROJINHERIT_FL)
@@ -1259,6 +1318,9 @@ const struct file_operations zpl_file_operations = {
.aio_fsync = zpl_aio_fsync,
#endif
.fallocate = zpl_fallocate,
#ifdef HAVE_FILE_FADVISE
.fadvise = zpl_fadvise,
#endif
.unlocked_ioctl = zpl_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = zpl_compat_ioctl,