Linux 4.11 compat: iops.getattr and friends

In torvalds/linux@a528d35, there are changes to the getattr family of functions,
struct kstat, and the interface of inode_operations .getattr.

The inode_operations .getattr and simple_getattr() interface changed to:

int (*getattr) (const struct path *, struct dentry *, struct kstat *,
    u32 request_mask, unsigned int query_flags)

The request_mask argument indicates which field(s) the caller intends to use.
Fields the caller has not specified via request_mask may be set in the returned
struct anyway, but their values may be approximate.

The query_flags argument indicates whether the filesystem must update
the attributes from the backing store.

Currently both fields are ignored.  It is possible that getattr-related
functions within zfs could be optimized based on the request_mask.

struct kstat includes new fields:
u32               result_mask;  /* What fields the user got */
u64               attributes;   /* See STATX_ATTR_* flags */
struct timespec   btime;        /* File creation time */

Fields attribute and btime are cleared; the result_mask reflects this.  These
appear to be optional based on simple_getattr() and vfs_getattr() within the
kernel, which take the same approach.

Reviewed-by: Chunwei Chen <david.chen@osnexus.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Olaf Faaland <faaland1@llnl.gov>
Closes #5875
This commit is contained in:
Olaf Faaland 2017-03-20 17:51:16 -07:00 committed by Brian Behlendorf
parent f974e41426
commit a3478c0747
5 changed files with 138 additions and 19 deletions

View File

@ -0,0 +1,67 @@
dnl #
dnl # Linux 4.11 API
dnl # See torvalds/linux@a528d35
dnl #
AC_DEFUN([ZFS_AC_PATH_KERNEL_IOPS_GETATTR], [
AC_MSG_CHECKING([whether iops->getattr() takes a path])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
int test_getattr(
const struct path *p, struct kstat *k,
u32 request_mask, unsigned int query_flags)
{ return 0; }
static const struct inode_operations
iops __attribute__ ((unused)) = {
.getattr = test_getattr,
};
],[
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_PATH_IOPS_GETATTR, 1,
[iops->getattr() takes a path])
],[
AC_MSG_RESULT(no)
])
])
dnl #
dnl # Linux 3.9 - 4.10 API
dnl #
AC_DEFUN([ZFS_AC_VFSMOUNT_KERNEL_IOPS_GETATTR], [
AC_MSG_CHECKING([whether iops->getattr() takes a vfsmount])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
int test_getattr(
struct vfsmount *mnt, struct dentry *d,
struct kstat *k)
{ return 0; }
static const struct inode_operations
iops __attribute__ ((unused)) = {
.getattr = test_getattr,
};
],[
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_VFSMOUNT_IOPS_GETATTR, 1,
[iops->getattr() takes a vfsmount])
],[
AC_MSG_RESULT(no)
])
])
dnl #
dnl # The interface of the getattr callback from the inode_operations
dnl # structure changed. Also, the interface of the simple_getattr()
dnl # function provided by the kernel changed.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_GETATTR], [
ZFS_AC_PATH_KERNEL_IOPS_GETATTR
ZFS_AC_VFSMOUNT_KERNEL_IOPS_GETATTR
])

View File

@ -59,6 +59,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL_WITH_FLAGS ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL_WITH_FLAGS
ZFS_AC_KERNEL_INODE_OPERATIONS_GET_ACL ZFS_AC_KERNEL_INODE_OPERATIONS_GET_ACL
ZFS_AC_KERNEL_INODE_OPERATIONS_SET_ACL ZFS_AC_KERNEL_INODE_OPERATIONS_SET_ACL
ZFS_AC_KERNEL_INODE_OPERATIONS_GETATTR
ZFS_AC_KERNEL_INODE_SET_FLAGS ZFS_AC_KERNEL_INODE_SET_FLAGS
ZFS_AC_KERNEL_GET_ACL_HANDLE_CACHE ZFS_AC_KERNEL_GET_ACL_HANDLE_CACHE
ZFS_AC_KERNEL_SHOW_OPTIONS ZFS_AC_KERNEL_SHOW_OPTIONS

View File

@ -454,4 +454,47 @@ setattr_prepare(struct dentry *dentry, struct iattr *ia)
} }
#endif #endif
/*
* 4.11 API change
* These macros are defined by kernel 4.11. We define them so that the same
* code builds under kernels < 4.11 and >= 4.11. The macros are set to 0 so
* that it will create obvious failures if they are accidentally used when built
* against a kernel >= 4.11.
*/
#ifndef STATX_BASIC_STATS
#define STATX_BASIC_STATS 0
#endif
#ifndef AT_STATX_SYNC_AS_STAT
#define AT_STATX_SYNC_AS_STAT 0
#endif
/*
* 4.11 API change
* 4.11 takes struct path *, < 4.11 takes vfsmount *
*/
#ifdef HAVE_VFSMOUNT_IOPS_GETATTR
#define ZPL_GETATTR_WRAPPER(func) \
static int \
func(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) \
{ \
struct path path = { .mnt = mnt, .dentry = dentry }; \
return func##_impl(&path, stat, STATX_BASIC_STATS, \
AT_STATX_SYNC_AS_STAT); \
}
#elif defined(HAVE_PATH_IOPS_GETATTR)
#define ZPL_GETATTR_WRAPPER(func) \
static int \
func(const struct path *path, struct kstat *stat, u32 request_mask, \
unsigned int query_flags) \
{ \
return (func##_impl(path, stat, request_mask, query_flags)); \
}
#else
#error
#endif
#endif /* _ZFS_VFS_H */ #endif /* _ZFS_VFS_H */

View File

@ -100,16 +100,15 @@ zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
*/ */
/* ARGSUSED */ /* ARGSUSED */
static int static int
zpl_root_getattr(struct vfsmount *mnt, struct dentry *dentry, zpl_root_getattr_impl(const struct path *path, struct kstat *stat,
struct kstat *stat) u32 request_mask, unsigned int query_flags)
{ {
int error; generic_fillattr(path->dentry->d_inode, stat);
error = simple_getattr(mnt, dentry, stat);
stat->atime = CURRENT_TIME; stat->atime = CURRENT_TIME;
return (error); return (0);
} }
ZPL_GETATTR_WRAPPER(zpl_root_getattr);
static struct dentry * static struct dentry *
#ifdef HAVE_LOOKUP_NAMEIDATA #ifdef HAVE_LOOKUP_NAMEIDATA
@ -375,21 +374,22 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, zpl_umode_t mode)
*/ */
/* ARGSUSED */ /* ARGSUSED */
static int static int
zpl_snapdir_getattr(struct vfsmount *mnt, struct dentry *dentry, zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat,
struct kstat *stat) u32 request_mask, unsigned int query_flags)
{ {
zfsvfs_t *zfsvfs = ITOZSB(dentry->d_inode); zfsvfs_t *zfsvfs = ITOZSB(path->dentry->d_inode);
int error;
ZFS_ENTER(zfsvfs); ZFS_ENTER(zfsvfs);
error = simple_getattr(mnt, dentry, stat); generic_fillattr(path->dentry->d_inode, stat);
stat->nlink = stat->size = 2; stat->nlink = stat->size = 2;
stat->ctime = stat->mtime = dmu_objset_snap_cmtime(zfsvfs->z_os); stat->ctime = stat->mtime = dmu_objset_snap_cmtime(zfsvfs->z_os);
stat->atime = CURRENT_TIME; stat->atime = CURRENT_TIME;
ZFS_EXIT(zfsvfs); ZFS_EXIT(zfsvfs);
return (error); return (0);
} }
ZPL_GETATTR_WRAPPER(zpl_snapdir_getattr);
/* /*
* The '.zfs/snapshot' directory file operations. These mainly control * The '.zfs/snapshot' directory file operations. These mainly control
@ -509,10 +509,10 @@ zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir)
/* ARGSUSED */ /* ARGSUSED */
static int static int
zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry, zpl_shares_getattr_impl(const struct path *path, struct kstat *stat,
struct kstat *stat) u32 request_mask, unsigned int query_flags)
{ {
struct inode *ip = dentry->d_inode; struct inode *ip = path->dentry->d_inode;
zfsvfs_t *zfsvfs = ITOZSB(ip); zfsvfs_t *zfsvfs = ITOZSB(ip);
znode_t *dzp; znode_t *dzp;
int error; int error;
@ -520,11 +520,11 @@ zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry,
ZFS_ENTER(zfsvfs); ZFS_ENTER(zfsvfs);
if (zfsvfs->z_shares_dir == 0) { if (zfsvfs->z_shares_dir == 0) {
error = simple_getattr(mnt, dentry, stat); generic_fillattr(path->dentry->d_inode, stat);
stat->nlink = stat->size = 2; stat->nlink = stat->size = 2;
stat->atime = CURRENT_TIME; stat->atime = CURRENT_TIME;
ZFS_EXIT(zfsvfs); ZFS_EXIT(zfsvfs);
return (error); return (0);
} }
error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp); error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp);
@ -538,6 +538,7 @@ zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry,
return (error); return (error);
} }
ZPL_GETATTR_WRAPPER(zpl_shares_getattr);
/* /*
* The '.zfs/shares' directory file operations. * The '.zfs/shares' directory file operations.

View File

@ -340,18 +340,25 @@ zpl_rmdir(struct inode *dir, struct dentry *dentry)
} }
static int static int
zpl_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) zpl_getattr_impl(const struct path *path, struct kstat *stat, u32 request_mask,
unsigned int query_flags)
{ {
int error; int error;
fstrans_cookie_t cookie; fstrans_cookie_t cookie;
cookie = spl_fstrans_mark(); cookie = spl_fstrans_mark();
error = -zfs_getattr_fast(dentry->d_inode, stat);
/*
* XXX request_mask and query_flags currently ignored.
*/
error = -zfs_getattr_fast(path->dentry->d_inode, stat);
spl_fstrans_unmark(cookie); spl_fstrans_unmark(cookie);
ASSERT3S(error, <=, 0); ASSERT3S(error, <=, 0);
return (error); return (error);
} }
ZPL_GETATTR_WRAPPER(zpl_getattr);
static int static int
zpl_setattr(struct dentry *dentry, struct iattr *ia) zpl_setattr(struct dentry *dentry, struct iattr *ia)