Skip to content

Commit

Permalink
Linux 4.11 compat: iops.getattr and friends
Browse files Browse the repository at this point in the history
In torvalds/linux@a528d35, there are several changes to the getattr
family of functions, struct kstat, and the interface of inode_operations
.getattr.

The inode_operations .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 he 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.

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 */

XXX result_mask is set but may be incorrect.  attributes and btime
are not set by zfs, may need to be.

The interface to simple_getattr() has changed to:

int simple_getattr(const struct path *, struct kstat *, u32,
    unsigned int);

Requires-spl: refs/pull/608/head

Signed-off-by: Olaf Faaland <[email protected]>
  • Loading branch information
ofaaland committed Mar 15, 2017
1 parent 8614ddf commit 8f86252
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 13 deletions.
67 changes: 67 additions & 0 deletions config/kernel-inode-getattr.m4
Original file line number Diff line number Diff line change
@@ -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
])
21 changes: 21 additions & 0 deletions config/kernel-struct-kstat.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
dnl #
dnl # Linux 4.11 API
dnl # See torvalds/linux@a528d35
dnl # Two members were added to 'struct kstat':
dnl # results_mask
dnl # query_flags
dnl #
AC_DEFUN([ZFS_AC_KERNEL_STAT_RESULT_MASK], [
AC_MSG_CHECKING([whether ((struct kstat *) stat)->results_mask exists])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
],[
struct kstat stat = { .result_mask = 0 };
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_STAT_RESULT_MASK, 1,
[((struct kstat *) stat)->results_mask exists])
],[
AC_MSG_RESULT(no)
])
])
2 changes: 2 additions & 0 deletions config/kernel.m4
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL_INODE_OPERATIONS_CHECK_ACL_WITH_FLAGS
ZFS_AC_KERNEL_INODE_OPERATIONS_GET_ACL
ZFS_AC_KERNEL_INODE_OPERATIONS_SET_ACL
ZFS_AC_KERNEL_INODE_OPERATIONS_GETATTR
ZFS_AC_KERNEL_INODE_SET_FLAGS
ZFS_AC_KERNEL_STAT_RESULT_MASK
ZFS_AC_KERNEL_GET_ACL_HANDLE_CACHE
ZFS_AC_KERNEL_SHOW_OPTIONS
ZFS_AC_KERNEL_FILE_INODE
Expand Down
34 changes: 34 additions & 0 deletions include/sys/zfs_ctldir.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,40 @@
(zfs_has_ctldir(zdp) && \
(ZTOZSB(zdp)->z_show_ctldir))

/*
* Linux 4.11 compat
* When building for kernel < 4.11, these constants are not defined by the
* kernel. We define them so that we can use the 4.11 interface for
* getattr-related functions. They are set to 0 so that it will create obvious
* failures if they are accidentally used.
*/

#if !defined(HAVE_PATH_IOPS_GETATTR)
#define STATX_BASIC_STATS 0
#define AT_STATX_SYNC_AS_STAT 0
#endif

#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

extern int zfs_expire_snapshot;

/* zfsctl generic functions */
Expand Down
9 changes: 9 additions & 0 deletions module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -2609,6 +2609,15 @@ zfs_getattr_fast(struct inode *ip, struct kstat *sp)

generic_fillattr(ip, sp);

#if defined(HAVE_STAT_RESULT_MASK)
/*
* generic_fillattr() does not set stat->result_mask, but toggles a
* few individual bits. So set it to BASIC_STATS first and then
* result should be correct.
*/
stat->result_mask = STATX_BASIC_STATS;
#endif /* defined(HAVE_STAT_RESULT_MASK) */

sa_object_size(zp->z_sa_hdl, &blksize, &nblocks);
sp->blksize = blksize;
sp->blocks = nblocks;
Expand Down
46 changes: 35 additions & 11 deletions module/zfs/zpl_ctldir.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,21 +95,41 @@ zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
#endif /* HAVE_VFS_ITERATE */

/*
* Used by zpl*getattr* functions below.
*/
static int
zpl_simple_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
{
int error;

#ifdef HAVE_VFSMOUNT_IOPS_GETATTR
error = simple_getattr(path->mnt, path->dentry, stat);
#elif defined(HAVE_PATH_IOPS_GETATTR)
error = simple_getattr(path, stat, request_mask, query_flags);
#else
#error
#endif
return (error);
}

/*
* Get root directory attributes.
*/
/* ARGSUSED */
static int
zpl_root_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
zpl_root_getattr_impl(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
{
int error;

error = simple_getattr(mnt, dentry, stat);
error = zpl_simple_getattr(path, stat, request_mask, query_flags);
stat->atime = CURRENT_TIME;

return (error);
}
ZPL_GETATTR_WRAPPER(zpl_root_getattr);

static struct dentry *
#ifdef HAVE_LOOKUP_NAMEIDATA
Expand Down Expand Up @@ -375,21 +395,23 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, zpl_umode_t mode)
*/
/* ARGSUSED */
static int
zpl_snapdir_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
zpl_snapdir_getattr_impl(const struct path *path, 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);
error = simple_getattr(mnt, dentry, stat);
error = zpl_simple_getattr(path, stat, request_mask, query_flags);

stat->nlink = stat->size = 2;
stat->ctime = stat->mtime = dmu_objset_snap_cmtime(zfsvfs->z_os);
stat->atime = CURRENT_TIME;
ZFS_EXIT(zfsvfs);

return (error);
}
ZPL_GETATTR_WRAPPER(zpl_snapdir_getattr);

/*
* The '.zfs/snapshot' directory file operations. These mainly control
Expand Down Expand Up @@ -509,18 +531,19 @@ zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir)

/* ARGSUSED */
static int
zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
zpl_shares_getattr_impl(const struct path *path, 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);
znode_t *dzp;
int error;

ZFS_ENTER(zfsvfs);

if (zfsvfs->z_shares_dir == 0) {
error = simple_getattr(mnt, dentry, stat);
error = zpl_simple_getattr(path, stat, request_mask,
query_flags);
stat->nlink = stat->size = 2;
stat->atime = CURRENT_TIME;
ZFS_EXIT(zfsvfs);
Expand All @@ -538,6 +561,7 @@ zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry,

return (error);
}
ZPL_GETATTR_WRAPPER(zpl_shares_getattr);

/*
* The '.zfs/shares' directory file operations.
Expand Down
11 changes: 9 additions & 2 deletions module/zfs/zpl_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,18 +340,25 @@ zpl_rmdir(struct inode *dir, struct dentry *dentry)
}

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;
fstrans_cookie_t cookie;

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);
ASSERT3S(error, <=, 0);

return (error);
}
ZPL_GETATTR_WRAPPER(zpl_getattr);

static int
zpl_setattr(struct dentry *dentry, struct iattr *ia)
Expand Down

0 comments on commit 8f86252

Please sign in to comment.