Skip to content

Commit

Permalink
RHEL 7.5 compat: FMODE_KABI_ITERATE
Browse files Browse the repository at this point in the history
As of RHEL 7.5 the mainline fops.iterate() method was added to
the file_operations structure and is correctly detected by the
configure script.

Normally this is what we want, but in order to maintain KABI
compatibility the RHEL change additionally does the following:

* Requires that callers intending to use this extended interface
  set the FMODE_KABI_ITERATE flag on the file structure when
  opening the directory.
* Adds the fops.iterate() method to the end of the structure,
  without removing fops.readdir().

This change updates the configure check to ignore the RHEL 7.5+
variant of fops.iterate() when detected.  Instead fallback to
the fops.readdir() interface which will be available.

Finally, add the 'zpl_' prefix to the directory context wrappers
to avoid colliding with the kernel provided symbols when both
the fops.iterate() and fops.readdir() are provided by the kernel.

Reviewed-by: Olaf Faaland <faaland1@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #7460 
Closes #7463
  • Loading branch information
behlendorf authored May 2, 2018
1 parent bc8a6a6 commit 9464b95
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 39 deletions.
21 changes: 16 additions & 5 deletions config/kernel-vfs-iterate.m4
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,27 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [
dnl #
dnl # 3.11 API change
dnl #
dnl # RHEL 7.5 compatibility; the fops.iterate() method was
dnl # added to the file_operations structure but in order to
dnl # maintain KABI compatibility all callers must set
dnl # FMODE_KABI_ITERATE which is checked in iterate_dir().
dnl # When detected ignore this interface and fallback to
dnl # to using fops.readdir() to retain KABI compatibility.
dnl #
AC_MSG_CHECKING([whether fops->iterate() is available])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
int iterate(struct file *filp, struct dir_context * context)
{ return 0; }
int iterate(struct file *filp,
struct dir_context *context) { return 0; }
static const struct file_operations fops
__attribute__ ((unused)) = {
.iterate = iterate,
};
#if defined(FMODE_KABI_ITERATE)
#error "RHEL 7.5, FMODE_KABI_ITERATE interface"
#endif
],[
],[
AC_MSG_RESULT(yes)
Expand All @@ -44,8 +55,8 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [
AC_MSG_CHECKING([whether fops->readdir() is available])
ZFS_LINUX_TRY_COMPILE([
#include <linux/fs.h>
int readdir(struct file *filp, void *entry, filldir_t func)
{ return 0; }
int readdir(struct file *filp, void *entry,
filldir_t func) { return 0; }
static const struct file_operations fops
__attribute__ ((unused)) = {
Expand All @@ -57,7 +68,7 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [
AC_DEFINE(HAVE_VFS_READDIR, 1,
[fops->readdir() is available])
],[
AC_MSG_ERROR(no; file a bug report with ZFSOnLinux)
AC_MSG_ERROR(no; file a bug report with ZoL)
])
])
])
Expand Down
2 changes: 1 addition & 1 deletion include/sys/zfs_vnops.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ extern int zfs_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
struct inode **ipp, cred_t *cr, int flags, vsecattr_t *vsecp);
extern int zfs_rmdir(struct inode *dip, char *name, struct inode *cwd,
cred_t *cr, int flags);
extern int zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr);
extern int zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr);
extern int zfs_fsync(struct inode *ip, int syncflag, cred_t *cr);
extern int zfs_getattr(struct inode *ip, vattr_t *vap, int flag, cred_t *cr);
extern int zfs_getattr_fast(struct inode *ip, struct kstat *sp);
Expand Down
27 changes: 17 additions & 10 deletions include/sys/zpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,56 +125,63 @@ extern const struct inode_operations zpl_ops_shares;

#if defined(HAVE_VFS_ITERATE) || defined(HAVE_VFS_ITERATE_SHARED)

#define DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \
#define ZPL_DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \
.actor = _actor, \
.pos = _pos, \
}

typedef struct dir_context zpl_dir_context_t;

#define zpl_dir_emit dir_emit
#define zpl_dir_emit_dot dir_emit_dot
#define zpl_dir_emit_dotdot dir_emit_dotdot
#define zpl_dir_emit_dots dir_emit_dots

#else

typedef struct dir_context {
typedef struct zpl_dir_context {
void *dirent;
const filldir_t actor;
loff_t pos;
} dir_context_t;
} zpl_dir_context_t;

#define DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \
#define ZPL_DIR_CONTEXT_INIT(_dirent, _actor, _pos) { \
.dirent = _dirent, \
.actor = _actor, \
.pos = _pos, \
}

static inline bool
dir_emit(struct dir_context *ctx, const char *name, int namelen,
zpl_dir_emit(zpl_dir_context_t *ctx, const char *name, int namelen,
uint64_t ino, unsigned type)
{
return (!ctx->actor(ctx->dirent, name, namelen, ctx->pos, ino, type));
}

static inline bool
dir_emit_dot(struct file *file, struct dir_context *ctx)
zpl_dir_emit_dot(struct file *file, zpl_dir_context_t *ctx)
{
return (ctx->actor(ctx->dirent, ".", 1, ctx->pos,
file_inode(file)->i_ino, DT_DIR) == 0);
}

static inline bool
dir_emit_dotdot(struct file *file, struct dir_context *ctx)
zpl_dir_emit_dotdot(struct file *file, zpl_dir_context_t *ctx)
{
return (ctx->actor(ctx->dirent, "..", 2, ctx->pos,
parent_ino(file_dentry(file)), DT_DIR) == 0);
}

static inline bool
dir_emit_dots(struct file *file, struct dir_context *ctx)
zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx)
{
if (ctx->pos == 0) {
if (!dir_emit_dot(file, ctx))
if (!zpl_dir_emit_dot(file, ctx))
return (false);
ctx->pos = 1;
}
if (ctx->pos == 1) {
if (!dir_emit_dotdot(file, ctx))
if (!zpl_dir_emit_dotdot(file, ctx))
return (false);
ctx->pos = 2;
}
Expand Down
4 changes: 2 additions & 2 deletions module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -2273,7 +2273,7 @@ zfs_rmdir(struct inode *dip, char *name, struct inode *cwd, cred_t *cr,
*/
/* ARGSUSED */
int
zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr)
{
znode_t *zp = ITOZ(ip);
zfsvfs_t *zfsvfs = ITOZSB(ip);
Expand Down Expand Up @@ -2378,7 +2378,7 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
type = ZFS_DIRENT_TYPE(zap.za_first_integer);
}

done = !dir_emit(ctx, zap.za_name, strlen(zap.za_name),
done = !zpl_dir_emit(ctx, zap.za_name, strlen(zap.za_name),
objnum, type);
if (done)
break;
Expand Down
37 changes: 20 additions & 17 deletions module/zfs/zpl_ctldir.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,27 @@ zpl_common_open(struct inode *ip, struct file *filp)
* Get root directory contents.
*/
static int
zpl_root_iterate(struct file *filp, struct dir_context *ctx)
zpl_root_iterate(struct file *filp, zpl_dir_context_t *ctx)
{
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
int error = 0;

ZFS_ENTER(zfsvfs);

if (!dir_emit_dots(filp, ctx))
if (!zpl_dir_emit_dots(filp, ctx))
goto out;

if (ctx->pos == 2) {
if (!dir_emit(ctx, ZFS_SNAPDIR_NAME, strlen(ZFS_SNAPDIR_NAME),
ZFSCTL_INO_SNAPDIR, DT_DIR))
if (!zpl_dir_emit(ctx, ZFS_SNAPDIR_NAME,
strlen(ZFS_SNAPDIR_NAME), ZFSCTL_INO_SNAPDIR, DT_DIR))
goto out;

ctx->pos++;
}

if (ctx->pos == 3) {
if (!dir_emit(ctx, ZFS_SHAREDIR_NAME, strlen(ZFS_SHAREDIR_NAME),
ZFSCTL_INO_SHARES, DT_DIR))
if (!zpl_dir_emit(ctx, ZFS_SHAREDIR_NAME,
strlen(ZFS_SHAREDIR_NAME), ZFSCTL_INO_SHARES, DT_DIR))
goto out;

ctx->pos++;
Expand All @@ -85,15 +85,16 @@ zpl_root_iterate(struct file *filp, struct dir_context *ctx)
static int
zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
zpl_dir_context_t ctx =
ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
int error;

error = zpl_root_iterate(filp, &ctx);
filp->f_pos = ctx.pos;

return (error);
}
#endif /* HAVE_VFS_ITERATE */
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */

/*
* Get root directory attributes.
Expand Down Expand Up @@ -248,7 +249,7 @@ zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
}

static int
zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
zpl_snapdir_iterate(struct file *filp, zpl_dir_context_t *ctx)
{
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
fstrans_cookie_t cookie;
Expand All @@ -260,7 +261,7 @@ zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
ZFS_ENTER(zfsvfs);
cookie = spl_fstrans_mark();

if (!dir_emit_dots(filp, ctx))
if (!zpl_dir_emit_dots(filp, ctx))
goto out;

pos = ctx->pos;
Expand All @@ -272,7 +273,7 @@ zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
if (error)
goto out;

if (!dir_emit(ctx, snapname, strlen(snapname),
if (!zpl_dir_emit(ctx, snapname, strlen(snapname),
ZFSCTL_INO_SHARES - id, DT_DIR))
goto out;

Expand All @@ -292,15 +293,16 @@ zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
static int
zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
zpl_dir_context_t ctx =
ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
int error;

error = zpl_snapdir_iterate(filp, &ctx);
filp->f_pos = ctx.pos;

return (error);
}
#endif /* HAVE_VFS_ITERATE */
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */

static int
zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry,
Expand Down Expand Up @@ -463,7 +465,7 @@ zpl_shares_lookup(struct inode *dip, struct dentry *dentry,
}

static int
zpl_shares_iterate(struct file *filp, struct dir_context *ctx)
zpl_shares_iterate(struct file *filp, zpl_dir_context_t *ctx)
{
fstrans_cookie_t cookie;
cred_t *cr = CRED();
Expand All @@ -475,7 +477,7 @@ zpl_shares_iterate(struct file *filp, struct dir_context *ctx)
cookie = spl_fstrans_mark();

if (zfsvfs->z_shares_dir == 0) {
dir_emit_dots(filp, ctx);
zpl_dir_emit_dots(filp, ctx);
goto out;
}

Expand All @@ -500,15 +502,16 @@ zpl_shares_iterate(struct file *filp, struct dir_context *ctx)
static int
zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
zpl_dir_context_t ctx =
ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
int error;

error = zpl_shares_iterate(filp, &ctx);
filp->f_pos = ctx.pos;

return (error);
}
#endif /* HAVE_VFS_ITERATE */
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */

/* ARGSUSED */
static int
Expand Down
9 changes: 5 additions & 4 deletions module/zfs/zpl_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ zpl_release(struct inode *ip, struct file *filp)
}

static int
zpl_iterate(struct file *filp, struct dir_context *ctx)
zpl_iterate(struct file *filp, zpl_dir_context_t *ctx)
{
cred_t *cr = CRED();
int error;
Expand All @@ -96,15 +96,16 @@ zpl_iterate(struct file *filp, struct dir_context *ctx)
static int
zpl_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct dir_context ctx = DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
zpl_dir_context_t ctx =
ZPL_DIR_CONTEXT_INIT(dirent, filldir, filp->f_pos);
int error;

error = zpl_iterate(filp, &ctx);
filp->f_pos = ctx.pos;

return (error);
}
#endif /* HAVE_VFS_ITERATE */
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */

#if defined(HAVE_FSYNC_WITH_DENTRY)
/*
Expand Down Expand Up @@ -965,7 +966,7 @@ const struct file_operations zpl_file_operations = {
const struct file_operations zpl_dir_file_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
#ifdef HAVE_VFS_ITERATE_SHARED
#if defined(HAVE_VFS_ITERATE_SHARED)
.iterate_shared = zpl_iterate,
#elif defined(HAVE_VFS_ITERATE)
.iterate = zpl_iterate,
Expand Down

0 comments on commit 9464b95

Please sign in to comment.