Skip to content

Commit

Permalink
Linux 3.11 compat: fops->iterate()
Browse files Browse the repository at this point in the history
Commit torvalds/linux@2233f31
replaced ->readdir() with ->iterate() in struct file_operations.
All filesystems must now use the new ->iterate method.

To handle this the code was reworked to use the new ->iterate
interface.  Care was taken to keep the majority of changes
confined to the ZPL layer which is already Linux specific.
However, minor changes were required to the common zfs_readdir()
function.

Compatibility with older kernels was accomplished by adding
versions of the trivial dir_emit* helper functions.  Also the
various *_readdir() functions were reworked in to wrappers
which create a dir_context structure to pass to the new
*_iterate() functions.

Unfortunately, the new dir_emit* functions prevent us from
passing a private pointer to the filldir function.  The xattr
directory code leveraged this ability through zfs_readdir()
to generate the list of xattr names.  Since we can no longer
use zfs_readdir() a simplified zpl_xattr_readdir() function
was added to perform the same task.

Signed-off-by: Richard Yao <ryao@cs.stonybrook.edu>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1653
Issue #1591
  • Loading branch information
ryao authored and behlendorf committed Aug 15, 2013
1 parent 34e1433 commit 0f37d0c
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 124 deletions.
43 changes: 43 additions & 0 deletions config/kernel-vfs-iterate.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
dnl #
dnl # 3.11 API change
dnl #
AC_DEFUN([ZFS_AC_KERNEL_VFS_ITERATE], [
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; }
static const struct file_operations fops
__attribute__ ((unused)) = {
.iterate = iterate,
};
],[
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_VFS_ITERATE, 1,
[fops->iterate() is available])
],[
AC_MSG_RESULT(no)
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; }
static const struct file_operations fops
__attribute__ ((unused)) = {
.readdir = readdir,
};
],[
],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_VFS_READDIR, 1,
[fops->readdir() is available])
],[
AC_MSG_ERROR(no; file a bug report with ZFSOnLinux)
])
])
])
1 change: 1 addition & 0 deletions config/kernel.m4
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL_ELEVATOR_CHANGE
ZFS_AC_KERNEL_5ARG_SGET
ZFS_AC_KERNEL_LSEEK_EXECUTE
ZFS_AC_KERNEL_VFS_ITERATE
AS_IF([test "$LINUX_OBJ" != "$LINUX"], [
KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
Expand Down
4 changes: 2 additions & 2 deletions include/sys/zfs_vnops.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <sys/cred.h>
#include <sys/fcntl.h>
#include <sys/pathname.h>
#include <sys/zpl.h>

#ifdef __cplusplus
extern "C" {
Expand All @@ -51,8 +52,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, void *dirent, filldir_t filldir,
loff_t *pos, cred_t *cr);
extern int zfs_readdir(struct inode *ip, struct dir_context *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
59 changes: 59 additions & 0 deletions include/sys/zpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,63 @@ extern const struct inode_operations zpl_ops_snapdirs;
extern const struct file_operations zpl_fops_shares;
extern const struct inode_operations zpl_ops_shares;

#ifdef HAVE_VFS_ITERATE

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

#else

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

#define 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,
uint64_t ino, unsigned type)
{
return ctx->actor(ctx->dirent, name, namelen, ctx->pos, ino, type) == 0;
}

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

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

static inline bool
dir_emit_dots(struct file *file, struct dir_context *ctx)
{
if (ctx->pos == 0) {
if (!dir_emit_dot(file, ctx))
return false;
ctx->pos = 1;
}
if (ctx->pos == 1) {
if (!dir_emit_dotdot(file, ctx))
return false;
ctx->pos = 2;
}
return true;
}
#endif /* HAVE_VFS_ITERATE */

#endif /* _SYS_ZPL_H */
12 changes: 6 additions & 6 deletions module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1997,8 +1997,7 @@ EXPORT_SYMBOL(zfs_rmdir);
*/
/* ARGSUSED */
int
zfs_readdir(struct inode *ip, void *dirent, filldir_t filldir,
loff_t *pos, cred_t *cr)
zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
{
znode_t *zp = ITOZ(ip);
zfs_sb_t *zsb = ITOZSB(ip);
Expand All @@ -2010,6 +2009,7 @@ zfs_readdir(struct inode *ip, void *dirent, filldir_t filldir,
uint8_t prefetch;
int done = 0;
uint64_t parent;
loff_t *pos = &(ctx->pos);

ZFS_ENTER(zsb);
ZFS_VERIFY_ZP(zp);
Expand Down Expand Up @@ -2098,11 +2098,11 @@ zfs_readdir(struct inode *ip, void *dirent, filldir_t filldir,

objnum = ZFS_DIRENT_OBJ(zap.za_first_integer);
}
done = filldir(dirent, zap.za_name, strlen(zap.za_name),
*pos, objnum, ZFS_DIRENT_TYPE(zap.za_first_integer));
if (done) {

done = !dir_emit(ctx, zap.za_name, strlen(zap.za_name),
objnum, ZFS_DIRENT_TYPE(zap.za_first_integer));
if (done)
break;
}

/* Prefetch znode */
if (prefetch) {
Expand Down
Loading

0 comments on commit 0f37d0c

Please sign in to comment.