RHEL 7.5 compat: FMODE_KABI_ITERATE
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
This commit is contained in:
parent
bc8a6a60e9
commit
9464b9591e
|
@ -23,16 +23,27 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [
|
||||||
dnl #
|
dnl #
|
||||||
dnl # 3.11 API change
|
dnl # 3.11 API change
|
||||||
dnl #
|
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])
|
AC_MSG_CHECKING([whether fops->iterate() is available])
|
||||||
ZFS_LINUX_TRY_COMPILE([
|
ZFS_LINUX_TRY_COMPILE([
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
int iterate(struct file *filp, struct dir_context * context)
|
int iterate(struct file *filp,
|
||||||
{ return 0; }
|
struct dir_context *context) { return 0; }
|
||||||
|
|
||||||
static const struct file_operations fops
|
static const struct file_operations fops
|
||||||
__attribute__ ((unused)) = {
|
__attribute__ ((unused)) = {
|
||||||
.iterate = iterate,
|
.iterate = iterate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(FMODE_KABI_ITERATE)
|
||||||
|
#error "RHEL 7.5, FMODE_KABI_ITERATE interface"
|
||||||
|
#endif
|
||||||
],[
|
],[
|
||||||
],[
|
],[
|
||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
|
@ -44,8 +55,8 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [
|
||||||
AC_MSG_CHECKING([whether fops->readdir() is available])
|
AC_MSG_CHECKING([whether fops->readdir() is available])
|
||||||
ZFS_LINUX_TRY_COMPILE([
|
ZFS_LINUX_TRY_COMPILE([
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
int readdir(struct file *filp, void *entry, filldir_t func)
|
int readdir(struct file *filp, void *entry,
|
||||||
{ return 0; }
|
filldir_t func) { return 0; }
|
||||||
|
|
||||||
static const struct file_operations fops
|
static const struct file_operations fops
|
||||||
__attribute__ ((unused)) = {
|
__attribute__ ((unused)) = {
|
||||||
|
@ -57,7 +68,7 @@ AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [
|
||||||
AC_DEFINE(HAVE_VFS_READDIR, 1,
|
AC_DEFINE(HAVE_VFS_READDIR, 1,
|
||||||
[fops->readdir() is available])
|
[fops->readdir() is available])
|
||||||
],[
|
],[
|
||||||
AC_MSG_ERROR(no; file a bug report with ZFSOnLinux)
|
AC_MSG_ERROR(no; file a bug report with ZoL)
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
|
@ -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);
|
struct inode **ipp, cred_t *cr, int flags, vsecattr_t *vsecp);
|
||||||
extern int zfs_rmdir(struct inode *dip, char *name, struct inode *cwd,
|
extern int zfs_rmdir(struct inode *dip, char *name, struct inode *cwd,
|
||||||
cred_t *cr, int flags);
|
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_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(struct inode *ip, vattr_t *vap, int flag, cred_t *cr);
|
||||||
extern int zfs_getattr_fast(struct inode *ip, struct kstat *sp);
|
extern int zfs_getattr_fast(struct inode *ip, struct kstat *sp);
|
||||||
|
|
|
@ -125,56 +125,63 @@ extern const struct inode_operations zpl_ops_shares;
|
||||||
|
|
||||||
#if defined(HAVE_VFS_ITERATE) || defined(HAVE_VFS_ITERATE_SHARED)
|
#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, \
|
.actor = _actor, \
|
||||||
.pos = _pos, \
|
.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
|
#else
|
||||||
|
|
||||||
typedef struct dir_context {
|
typedef struct zpl_dir_context {
|
||||||
void *dirent;
|
void *dirent;
|
||||||
const filldir_t actor;
|
const filldir_t actor;
|
||||||
loff_t pos;
|
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, \
|
.dirent = _dirent, \
|
||||||
.actor = _actor, \
|
.actor = _actor, \
|
||||||
.pos = _pos, \
|
.pos = _pos, \
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
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)
|
uint64_t ino, unsigned type)
|
||||||
{
|
{
|
||||||
return (!ctx->actor(ctx->dirent, name, namelen, ctx->pos, ino, type));
|
return (!ctx->actor(ctx->dirent, name, namelen, ctx->pos, ino, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
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,
|
return (ctx->actor(ctx->dirent, ".", 1, ctx->pos,
|
||||||
file_inode(file)->i_ino, DT_DIR) == 0);
|
file_inode(file)->i_ino, DT_DIR) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
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,
|
return (ctx->actor(ctx->dirent, "..", 2, ctx->pos,
|
||||||
parent_ino(file_dentry(file)), DT_DIR) == 0);
|
parent_ino(file_dentry(file)), DT_DIR) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
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 (ctx->pos == 0) {
|
||||||
if (!dir_emit_dot(file, ctx))
|
if (!zpl_dir_emit_dot(file, ctx))
|
||||||
return (false);
|
return (false);
|
||||||
ctx->pos = 1;
|
ctx->pos = 1;
|
||||||
}
|
}
|
||||||
if (ctx->pos == 1) {
|
if (ctx->pos == 1) {
|
||||||
if (!dir_emit_dotdot(file, ctx))
|
if (!zpl_dir_emit_dotdot(file, ctx))
|
||||||
return (false);
|
return (false);
|
||||||
ctx->pos = 2;
|
ctx->pos = 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2273,7 +2273,7 @@ out:
|
||||||
*/
|
*/
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
int
|
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);
|
znode_t *zp = ITOZ(ip);
|
||||||
zfsvfs_t *zfsvfs = ITOZSB(ip);
|
zfsvfs_t *zfsvfs = ITOZSB(ip);
|
||||||
|
@ -2378,7 +2378,7 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
|
||||||
type = ZFS_DIRENT_TYPE(zap.za_first_integer);
|
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);
|
objnum, type);
|
||||||
if (done)
|
if (done)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -50,27 +50,27 @@ zpl_common_open(struct inode *ip, struct file *filp)
|
||||||
* Get root directory contents.
|
* Get root directory contents.
|
||||||
*/
|
*/
|
||||||
static int
|
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));
|
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
ZFS_ENTER(zfsvfs);
|
ZFS_ENTER(zfsvfs);
|
||||||
|
|
||||||
if (!dir_emit_dots(filp, ctx))
|
if (!zpl_dir_emit_dots(filp, ctx))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (ctx->pos == 2) {
|
if (ctx->pos == 2) {
|
||||||
if (!dir_emit(ctx, ZFS_SNAPDIR_NAME, strlen(ZFS_SNAPDIR_NAME),
|
if (!zpl_dir_emit(ctx, ZFS_SNAPDIR_NAME,
|
||||||
ZFSCTL_INO_SNAPDIR, DT_DIR))
|
strlen(ZFS_SNAPDIR_NAME), ZFSCTL_INO_SNAPDIR, DT_DIR))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ctx->pos++;
|
ctx->pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->pos == 3) {
|
if (ctx->pos == 3) {
|
||||||
if (!dir_emit(ctx, ZFS_SHAREDIR_NAME, strlen(ZFS_SHAREDIR_NAME),
|
if (!zpl_dir_emit(ctx, ZFS_SHAREDIR_NAME,
|
||||||
ZFSCTL_INO_SHARES, DT_DIR))
|
strlen(ZFS_SHAREDIR_NAME), ZFSCTL_INO_SHARES, DT_DIR))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ctx->pos++;
|
ctx->pos++;
|
||||||
|
@ -85,7 +85,8 @@ out:
|
||||||
static int
|
static int
|
||||||
zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
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;
|
int error;
|
||||||
|
|
||||||
error = zpl_root_iterate(filp, &ctx);
|
error = zpl_root_iterate(filp, &ctx);
|
||||||
|
@ -93,7 +94,7 @@ zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_VFS_ITERATE */
|
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get root directory attributes.
|
* Get root directory attributes.
|
||||||
|
@ -248,7 +249,7 @@ zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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));
|
zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp));
|
||||||
fstrans_cookie_t cookie;
|
fstrans_cookie_t cookie;
|
||||||
|
@ -260,7 +261,7 @@ zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
|
||||||
ZFS_ENTER(zfsvfs);
|
ZFS_ENTER(zfsvfs);
|
||||||
cookie = spl_fstrans_mark();
|
cookie = spl_fstrans_mark();
|
||||||
|
|
||||||
if (!dir_emit_dots(filp, ctx))
|
if (!zpl_dir_emit_dots(filp, ctx))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
pos = ctx->pos;
|
pos = ctx->pos;
|
||||||
|
@ -272,7 +273,7 @@ zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!dir_emit(ctx, snapname, strlen(snapname),
|
if (!zpl_dir_emit(ctx, snapname, strlen(snapname),
|
||||||
ZFSCTL_INO_SHARES - id, DT_DIR))
|
ZFSCTL_INO_SHARES - id, DT_DIR))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -292,7 +293,8 @@ out:
|
||||||
static int
|
static int
|
||||||
zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
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;
|
int error;
|
||||||
|
|
||||||
error = zpl_snapdir_iterate(filp, &ctx);
|
error = zpl_snapdir_iterate(filp, &ctx);
|
||||||
|
@ -300,7 +302,7 @@ zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_VFS_ITERATE */
|
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry,
|
zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry,
|
||||||
|
@ -463,7 +465,7 @@ zpl_shares_lookup(struct inode *dip, struct dentry *dentry,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
fstrans_cookie_t cookie;
|
||||||
cred_t *cr = CRED();
|
cred_t *cr = CRED();
|
||||||
|
@ -475,7 +477,7 @@ zpl_shares_iterate(struct file *filp, struct dir_context *ctx)
|
||||||
cookie = spl_fstrans_mark();
|
cookie = spl_fstrans_mark();
|
||||||
|
|
||||||
if (zfsvfs->z_shares_dir == 0) {
|
if (zfsvfs->z_shares_dir == 0) {
|
||||||
dir_emit_dots(filp, ctx);
|
zpl_dir_emit_dots(filp, ctx);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,7 +502,8 @@ out:
|
||||||
static int
|
static int
|
||||||
zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
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;
|
int error;
|
||||||
|
|
||||||
error = zpl_shares_iterate(filp, &ctx);
|
error = zpl_shares_iterate(filp, &ctx);
|
||||||
|
@ -508,7 +511,7 @@ zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_VFS_ITERATE */
|
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */
|
||||||
|
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -76,7 +76,7 @@ zpl_release(struct inode *ip, struct file *filp)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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();
|
cred_t *cr = CRED();
|
||||||
int error;
|
int error;
|
||||||
|
@ -96,7 +96,8 @@ zpl_iterate(struct file *filp, struct dir_context *ctx)
|
||||||
static int
|
static int
|
||||||
zpl_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
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;
|
int error;
|
||||||
|
|
||||||
error = zpl_iterate(filp, &ctx);
|
error = zpl_iterate(filp, &ctx);
|
||||||
|
@ -104,7 +105,7 @@ zpl_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
#endif /* HAVE_VFS_ITERATE */
|
#endif /* !HAVE_VFS_ITERATE && !HAVE_VFS_ITERATE_SHARED */
|
||||||
|
|
||||||
#if defined(HAVE_FSYNC_WITH_DENTRY)
|
#if defined(HAVE_FSYNC_WITH_DENTRY)
|
||||||
/*
|
/*
|
||||||
|
@ -965,7 +966,7 @@ const struct file_operations zpl_file_operations = {
|
||||||
const struct file_operations zpl_dir_file_operations = {
|
const struct file_operations zpl_dir_file_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
#ifdef HAVE_VFS_ITERATE_SHARED
|
#if defined(HAVE_VFS_ITERATE_SHARED)
|
||||||
.iterate_shared = zpl_iterate,
|
.iterate_shared = zpl_iterate,
|
||||||
#elif defined(HAVE_VFS_ITERATE)
|
#elif defined(HAVE_VFS_ITERATE)
|
||||||
.iterate = zpl_iterate,
|
.iterate = zpl_iterate,
|
||||||
|
|
Loading…
Reference in New Issue