Linux: use filemap_range_has_page()

As of the 4.13 kernel filemap_range_has_page() can be used to
check if there is a page mapped in a given file range.  When
available this interface should be used which eliminates the
need for the zp->z_is_mapped boolean.

Reviewed-by: Brian Atkinson <batkinson@lanl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #14493
This commit is contained in:
Brian Behlendorf 2023-02-14 11:04:34 -08:00 committed by Tony Hutter
parent 9e5a297de6
commit 3ad6c1692f
11 changed files with 65 additions and 17 deletions

26
config/kernel-filemap.m4 Normal file
View File

@ -0,0 +1,26 @@
dnl #
dnl # filemap_range_has_page was not available till 4.13
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_FILEMAP], [
ZFS_LINUX_TEST_SRC([filemap_range_has_page], [
#include <linux/fs.h>
],[
struct address_space *mapping = NULL;
loff_t lstart = 0;
loff_t lend = 0;
bool ret __attribute__ ((unused));
ret = filemap_range_has_page(mapping, lstart, lend);
])
])
AC_DEFUN([ZFS_AC_KERNEL_FILEMAP], [
AC_MSG_CHECKING([whether filemap_range_has_page() is available])
ZFS_LINUX_TEST_RESULT([filemap_range_has_page], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_FILEMAP_RANGE_HAS_PAGE, 1,
[filemap_range_has_page() is available])
],[
AC_MSG_RESULT(no)
])
])

View File

@ -144,6 +144,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_KTHREAD ZFS_AC_KERNEL_SRC_KTHREAD
ZFS_AC_KERNEL_SRC_ZERO_PAGE ZFS_AC_KERNEL_SRC_ZERO_PAGE
ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC
ZFS_AC_KERNEL_SRC_FILEMAP
AC_MSG_CHECKING([for available kernel interfaces]) AC_MSG_CHECKING([for available kernel interfaces])
ZFS_LINUX_TEST_COMPILE_ALL([kabi]) ZFS_LINUX_TEST_COMPILE_ALL([kabi])
@ -261,6 +262,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_KTHREAD ZFS_AC_KERNEL_KTHREAD
ZFS_AC_KERNEL_ZERO_PAGE ZFS_AC_KERNEL_ZERO_PAGE
ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC
ZFS_AC_KERNEL_FILEMAP
]) ])
dnl # dnl #

View File

@ -118,7 +118,8 @@ extern minor_t zfsdev_minor_alloc(void);
#define Z_ISLNK(type) ((type) == VLNK) #define Z_ISLNK(type) ((type) == VLNK)
#define Z_ISDIR(type) ((type) == VDIR) #define Z_ISDIR(type) ((type) == VDIR)
#define zn_has_cached_data(zp) vn_has_cached_data(ZTOV(zp)) #define zn_has_cached_data(zp, start, end) \
vn_has_cached_data(ZTOV(zp))
#define zn_flush_cached_data(zp, sync) vn_flush_cached_data(ZTOV(zp), sync) #define zn_flush_cached_data(zp, sync) vn_flush_cached_data(ZTOV(zp), sync)
#define zn_rlimit_fsize(zp, uio) \ #define zn_rlimit_fsize(zp, uio) \
vn_rlimit_fsize(ZTOV(zp), GET_UIO_STRUCT(uio), zfs_uio_td(uio)) vn_rlimit_fsize(ZTOV(zp), GET_UIO_STRUCT(uio), zfs_uio_td(uio))

View File

@ -62,7 +62,6 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
__field(uint32_t, z_async_writes_cnt) __field(uint32_t, z_async_writes_cnt)
__field(mode_t, z_mode) __field(mode_t, z_mode)
__field(boolean_t, z_is_sa) __field(boolean_t, z_is_sa)
__field(boolean_t, z_is_mapped)
__field(boolean_t, z_is_ctldir) __field(boolean_t, z_is_ctldir)
__field(uint32_t, i_uid) __field(uint32_t, i_uid)
@ -96,7 +95,6 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
__entry->z_async_writes_cnt = zn->z_async_writes_cnt; __entry->z_async_writes_cnt = zn->z_async_writes_cnt;
__entry->z_mode = zn->z_mode; __entry->z_mode = zn->z_mode;
__entry->z_is_sa = zn->z_is_sa; __entry->z_is_sa = zn->z_is_sa;
__entry->z_is_mapped = zn->z_is_mapped;
__entry->z_is_ctldir = zn->z_is_ctldir; __entry->z_is_ctldir = zn->z_is_ctldir;
__entry->i_uid = KUID_TO_SUID(ZTOI(zn)->i_uid); __entry->i_uid = KUID_TO_SUID(ZTOI(zn)->i_uid);
@ -119,8 +117,8 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
"zn_prefetch %u blksz %u seq %u " "zn_prefetch %u blksz %u seq %u "
"mapcnt %llu size %llu pflags %llu " "mapcnt %llu size %llu pflags %llu "
"sync_cnt %u sync_writes_cnt %u async_writes_cnt %u " "sync_cnt %u sync_writes_cnt %u async_writes_cnt %u "
"mode 0x%x is_sa %d is_mapped %d is_ctldir %d inode { " "mode 0x%x is_sa %d is_ctldir %d "
"uid %u gid %u ino %lu nlink %u size %lli " "inode { uid %u gid %u ino %lu nlink %u size %lli "
"blkbits %u bytes %u mode 0x%x generation %x } } " "blkbits %u bytes %u mode 0x%x generation %x } } "
"ace { type %u flags %u access_mask %u } mask_matched %u", "ace { type %u flags %u access_mask %u } mask_matched %u",
__entry->z_id, __entry->z_unlinked, __entry->z_atime_dirty, __entry->z_id, __entry->z_unlinked, __entry->z_atime_dirty,
@ -128,9 +126,8 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
__entry->z_seq, __entry->z_mapcnt, __entry->z_size, __entry->z_seq, __entry->z_mapcnt, __entry->z_size,
__entry->z_pflags, __entry->z_sync_cnt, __entry->z_pflags, __entry->z_sync_cnt,
__entry->z_sync_writes_cnt, __entry->z_async_writes_cnt, __entry->z_sync_writes_cnt, __entry->z_async_writes_cnt,
__entry->z_mode, __entry->z_is_sa, __entry->z_is_mapped, __entry->z_mode, __entry->z_is_sa, __entry->z_is_ctldir,
__entry->z_is_ctldir, __entry->i_uid, __entry->i_uid, __entry->i_gid, __entry->i_ino, __entry->i_nlink,
__entry->i_gid, __entry->i_ino, __entry->i_nlink,
__entry->i_size, __entry->i_blkbits, __entry->i_size, __entry->i_blkbits,
__entry->i_bytes, __entry->i_mode, __entry->i_generation, __entry->i_bytes, __entry->i_mode, __entry->i_generation,
__entry->z_type, __entry->z_flags, __entry->z_access_mask, __entry->z_type, __entry->z_flags, __entry->z_access_mask,

View File

@ -47,9 +47,16 @@
extern "C" { extern "C" {
#endif #endif
#if defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
#define ZNODE_OS_FIELDS \ #define ZNODE_OS_FIELDS \
inode_timespec_t z_btime; /* creation/birth time (cached) */ \ inode_timespec_t z_btime; /* creation/birth time (cached) */ \
struct inode z_inode; struct inode z_inode;
#else
#define ZNODE_OS_FIELDS \
inode_timespec_t z_btime; /* creation/birth time (cached) */ \
struct inode z_inode; \
boolean_t z_is_mapped; /* we are mmap'ed */
#endif
/* /*
* Convert between znode pointers and inode pointers * Convert between znode pointers and inode pointers
@ -70,7 +77,14 @@ extern "C" {
#define Z_ISDEV(type) (S_ISCHR(type) || S_ISBLK(type) || S_ISFIFO(type)) #define Z_ISDEV(type) (S_ISCHR(type) || S_ISBLK(type) || S_ISFIFO(type))
#define Z_ISDIR(type) S_ISDIR(type) #define Z_ISDIR(type) S_ISDIR(type)
#define zn_has_cached_data(zp) ((zp)->z_is_mapped) #if defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
#define zn_has_cached_data(zp, start, end) \
filemap_range_has_page(ZTOI(zp)->i_mapping, start, end)
#else
#define zn_has_cached_data(zp, start, end) \
((zp)->z_is_mapped)
#endif
#define zn_flush_cached_data(zp, sync) write_inode_now(ZTOI(zp), sync) #define zn_flush_cached_data(zp, sync) write_inode_now(ZTOI(zp), sync)
#define zn_rlimit_fsize(zp, uio) (0) #define zn_rlimit_fsize(zp, uio) (0)

View File

@ -188,7 +188,6 @@ typedef struct znode {
boolean_t z_atime_dirty; /* atime needs to be synced */ boolean_t z_atime_dirty; /* atime needs to be synced */
boolean_t z_zn_prefetch; /* Prefetch znodes? */ boolean_t z_zn_prefetch; /* Prefetch znodes? */
boolean_t z_is_sa; /* are we native sa? */ boolean_t z_is_sa; /* are we native sa? */
boolean_t z_is_mapped; /* are we mmap'ed */
boolean_t z_is_ctldir; /* are we .zfs entry */ boolean_t z_is_ctldir; /* are we .zfs entry */
boolean_t z_suspended; /* extra ref from a suspend? */ boolean_t z_suspended; /* extra ref from a suspend? */
uint_t z_blksz; /* block size in bytes */ uint_t z_blksz; /* block size in bytes */

View File

@ -468,7 +468,9 @@ zfsctl_inode_alloc(zfsvfs_t *zfsvfs, uint64_t id,
zp->z_atime_dirty = B_FALSE; zp->z_atime_dirty = B_FALSE;
zp->z_zn_prefetch = B_FALSE; zp->z_zn_prefetch = B_FALSE;
zp->z_is_sa = B_FALSE; zp->z_is_sa = B_FALSE;
#if !defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
zp->z_is_mapped = B_FALSE; zp->z_is_mapped = B_FALSE;
#endif
zp->z_is_ctldir = B_TRUE; zp->z_is_ctldir = B_TRUE;
zp->z_sa_hdl = NULL; zp->z_sa_hdl = NULL;
zp->z_blksz = 0; zp->z_blksz = 0;

View File

@ -1021,7 +1021,7 @@ top:
mutex_enter(&zp->z_lock); mutex_enter(&zp->z_lock);
may_delete_now = atomic_read(&ZTOI(zp)->i_count) == 1 && may_delete_now = atomic_read(&ZTOI(zp)->i_count) == 1 &&
!(zp->z_is_mapped); !zn_has_cached_data(zp, 0, LLONG_MAX);
mutex_exit(&zp->z_lock); mutex_exit(&zp->z_lock);
/* /*
@ -1109,7 +1109,8 @@ top:
&xattr_obj_unlinked, sizeof (xattr_obj_unlinked)); &xattr_obj_unlinked, sizeof (xattr_obj_unlinked));
delete_now = may_delete_now && !toobig && delete_now = may_delete_now && !toobig &&
atomic_read(&ZTOI(zp)->i_count) == 1 && atomic_read(&ZTOI(zp)->i_count) == 1 &&
!(zp->z_is_mapped) && xattr_obj == xattr_obj_unlinked && !zn_has_cached_data(zp, 0, LLONG_MAX) &&
xattr_obj == xattr_obj_unlinked &&
zfs_external_acl(zp) == acl_obj; zfs_external_acl(zp) == acl_obj;
} }

View File

@ -546,7 +546,9 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
ASSERT3P(zp->z_xattr_cached, ==, NULL); ASSERT3P(zp->z_xattr_cached, ==, NULL);
zp->z_unlinked = B_FALSE; zp->z_unlinked = B_FALSE;
zp->z_atime_dirty = B_FALSE; zp->z_atime_dirty = B_FALSE;
#if !defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
zp->z_is_mapped = B_FALSE; zp->z_is_mapped = B_FALSE;
#endif
zp->z_is_ctldir = B_FALSE; zp->z_is_ctldir = B_FALSE;
zp->z_suspended = B_FALSE; zp->z_suspended = B_FALSE;
zp->z_sa_hdl = NULL; zp->z_sa_hdl = NULL;
@ -1636,7 +1638,7 @@ zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
* Zero partial page cache entries. This must be done under a * Zero partial page cache entries. This must be done under a
* range lock in order to keep the ARC and page cache in sync. * range lock in order to keep the ARC and page cache in sync.
*/ */
if (zp->z_is_mapped) { if (zn_has_cached_data(zp, off, off + len - 1)) {
loff_t first_page, last_page, page_len; loff_t first_page, last_page, page_len;
loff_t first_page_offset, last_page_offset; loff_t first_page_offset, last_page_offset;

View File

@ -618,7 +618,6 @@ static int
zpl_mmap(struct file *filp, struct vm_area_struct *vma) zpl_mmap(struct file *filp, struct vm_area_struct *vma)
{ {
struct inode *ip = filp->f_mapping->host; struct inode *ip = filp->f_mapping->host;
znode_t *zp = ITOZ(ip);
int error; int error;
fstrans_cookie_t cookie; fstrans_cookie_t cookie;
@ -633,9 +632,12 @@ zpl_mmap(struct file *filp, struct vm_area_struct *vma)
if (error) if (error)
return (error); return (error);
#if !defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
znode_t *zp = ITOZ(ip);
mutex_enter(&zp->z_lock); mutex_enter(&zp->z_lock);
zp->z_is_mapped = B_TRUE; zp->z_is_mapped = B_TRUE;
mutex_exit(&zp->z_lock); mutex_exit(&zp->z_lock);
#endif
return (error); return (error);
} }

View File

@ -104,7 +104,7 @@ zfs_holey_common(znode_t *zp, ulong_t cmd, loff_t *off)
hole = B_FALSE; hole = B_FALSE;
/* Flush any mmap()'d data to disk */ /* Flush any mmap()'d data to disk */
if (zn_has_cached_data(zp)) if (zn_has_cached_data(zp, 0, file_sz - 1))
zn_flush_cached_data(zp, B_FALSE); zn_flush_cached_data(zp, B_FALSE);
lr = zfs_rangelock_enter(&zp->z_rangelock, 0, UINT64_MAX, RL_READER); lr = zfs_rangelock_enter(&zp->z_rangelock, 0, UINT64_MAX, RL_READER);
@ -277,7 +277,8 @@ zfs_read(struct znode *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
error = mappedread_sf(zp, nbytes, uio); error = mappedread_sf(zp, nbytes, uio);
else else
#endif #endif
if (zn_has_cached_data(zp) && !(ioflag & O_DIRECT)) { if (zn_has_cached_data(zp, zfs_uio_offset(uio),
zfs_uio_offset(uio) + nbytes - 1) && !(ioflag & O_DIRECT)) {
error = mappedread(zp, nbytes, uio); error = mappedread(zp, nbytes, uio);
} else { } else {
error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl), error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl),
@ -688,7 +689,8 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
zfs_uioskip(uio, nbytes); zfs_uioskip(uio, nbytes);
tx_bytes = nbytes; tx_bytes = nbytes;
} }
if (tx_bytes && zn_has_cached_data(zp) && if (tx_bytes &&
zn_has_cached_data(zp, woff, woff + tx_bytes - 1) &&
!(ioflag & O_DIRECT)) { !(ioflag & O_DIRECT)) {
update_pages(zp, woff, tx_bytes, zfsvfs->z_os); update_pages(zp, woff, tx_bytes, zfsvfs->z_os);
} }