diff options
author | Richard Yao <[email protected]> | 2013-08-07 08:53:45 -0400 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2013-08-15 16:19:07 -0700 |
commit | 0f37d0c8bed442dd0d2c1b1dddd68653fa6eec66 (patch) | |
tree | bbd56b426b2b72bed0e3f81afaab2ddf5e613e3e /module | |
parent | 34e143323e359b42bc9d06dd19cc4b1f13091283 (diff) |
Linux 3.11 compat: fops->iterate()
Commit torvalds/linux@2233f31aade393641f0eaed43a71110e629bb900
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 <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #1653
Issue #1591
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/zfs_vnops.c | 12 | ||||
-rw-r--r-- | module/zfs/zpl_ctldir.c | 193 | ||||
-rw-r--r-- | module/zfs/zpl_file.c | 23 | ||||
-rw-r--r-- | module/zfs/zpl_xattr.c | 49 |
4 files changed, 155 insertions, 122 deletions
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index db5d3856a..876d44b35 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -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); @@ -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); @@ -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) { diff --git a/module/zfs/zpl_ctldir.c b/module/zfs/zpl_ctldir.c index 089701707..1bb646fdf 100644 --- a/module/zfs/zpl_ctldir.c +++ b/module/zfs/zpl_ctldir.c @@ -46,79 +46,34 @@ zpl_common_open(struct inode *ip, struct file *filp) return generic_file_open(ip, filp); } -static int -zpl_common_readdir(struct file *filp, void *dirent, filldir_t filldir) -{ - struct dentry *dentry = filp->f_path.dentry; - struct inode *ip = dentry->d_inode; - int error = 0; - - switch (filp->f_pos) { - case 0: - error = filldir(dirent, ".", 1, 0, ip->i_ino, DT_DIR); - if (error) - break; - - filp->f_pos++; - /* fall-thru */ - case 1: - error = filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR); - if (error) - break; - - filp->f_pos++; - /* fall-thru */ - default: - break; - } - - return (error); -} - /* * Get root directory contents. */ static int -zpl_root_readdir(struct file *filp, void *dirent, filldir_t filldir) +zpl_root_iterate(struct file *filp, struct dir_context *ctx) { - struct dentry *dentry = filp->f_path.dentry; - struct inode *ip = dentry->d_inode; - zfs_sb_t *zsb = ITOZSB(ip); + zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode); int error = 0; ZFS_ENTER(zsb); - switch (filp->f_pos) { - case 0: - error = filldir(dirent, ".", 1, 0, ip->i_ino, DT_DIR); - if (error) - goto out; + if (!dir_emit_dots(filp, ctx)) + goto out; - filp->f_pos++; - /* fall-thru */ - case 1: - error = filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR); - if (error) + if (ctx->pos == 2) { + if (!dir_emit(ctx, ZFS_SNAPDIR_NAME, strlen(ZFS_SNAPDIR_NAME), + ZFSCTL_INO_SNAPDIR, DT_DIR)) goto out; - filp->f_pos++; - /* fall-thru */ - case 2: - error = filldir(dirent, ZFS_SNAPDIR_NAME, - strlen(ZFS_SNAPDIR_NAME), 2, ZFSCTL_INO_SNAPDIR, DT_DIR); - if (error) - goto out; + ctx->pos++; + } - filp->f_pos++; - /* fall-thru */ - case 3: - error = filldir(dirent, ZFS_SHAREDIR_NAME, - strlen(ZFS_SHAREDIR_NAME), 3, ZFSCTL_INO_SHARES, DT_DIR); - if (error) + if (ctx->pos == 3) { + if (!dir_emit(ctx, ZFS_SHAREDIR_NAME, strlen(ZFS_SHAREDIR_NAME), + ZFSCTL_INO_SHARES, DT_DIR)) goto out; - filp->f_pos++; - /* fall-thru */ + ctx->pos++; } out: ZFS_EXIT(zsb); @@ -126,6 +81,20 @@ out: return (error); } +#if !defined(HAVE_VFS_ITERATE) +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); + int error; + + error = zpl_root_iterate(filp, &ctx); + filp->f_pos = ctx.pos; + + return (error); +} +#endif /* HAVE_VFS_ITERATE */ + /* * Get root directory attributes. */ @@ -175,7 +144,11 @@ const struct file_operations zpl_fops_root = { .open = zpl_common_open, .llseek = generic_file_llseek, .read = generic_read_dir, +#ifdef HAVE_VFS_ITERATE + .iterate = zpl_root_iterate, +#else .readdir = zpl_root_readdir, +#endif }; const struct inode_operations zpl_ops_root = { @@ -273,50 +246,29 @@ zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry, return d_splice_alias(ip, dentry); } -/* ARGSUSED */ static int -zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir) +zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx) { - struct dentry *dentry = filp->f_path.dentry; - struct inode *dip = dentry->d_inode; - zfs_sb_t *zsb = ITOZSB(dip); + zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode); char snapname[MAXNAMELEN]; - uint64_t id, cookie; boolean_t case_conflict; + uint64_t id; int error = 0; ZFS_ENTER(zsb); - cookie = filp->f_pos; - switch (filp->f_pos) { - case 0: - error = filldir(dirent, ".", 1, 0, dip->i_ino, DT_DIR); - if (error) - goto out; + if (!dir_emit_dots(filp, ctx)) + goto out; - filp->f_pos++; - /* fall-thru */ - case 1: - error = filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR); + while (error == 0) { + error = -dmu_snapshot_list_next(zsb->z_os, MAXNAMELEN, + snapname, &id, &(ctx->pos), &case_conflict); if (error) goto out; - filp->f_pos++; - /* fall-thru */ - default: - while (error == 0) { - error = -dmu_snapshot_list_next(zsb->z_os, MAXNAMELEN, - snapname, &id, &cookie, &case_conflict); - if (error) - goto out; - - error = filldir(dirent, snapname, strlen(snapname), - filp->f_pos, ZFSCTL_INO_SHARES - id, DT_DIR); - if (error) - goto out; - - filp->f_pos = cookie; - } + if (!dir_emit(ctx, snapname, strlen(snapname), + ZFSCTL_INO_SHARES - id, DT_DIR)) + goto out; } out: ZFS_EXIT(zsb); @@ -327,6 +279,20 @@ out: return (error); } +#if !defined(HAVE_VFS_ITERATE) +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); + int error; + + error = zpl_snapdir_iterate(filp, &ctx); + filp->f_pos = ctx.pos; + + return (error); +} +#endif /* HAVE_VFS_ITERATE */ + int zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry) @@ -413,7 +379,12 @@ const struct file_operations zpl_fops_snapdir = { .open = zpl_common_open, .llseek = generic_file_llseek, .read = generic_read_dir, +#ifdef HAVE_VFS_ITERATE + .iterate = zpl_snapdir_iterate, +#else .readdir = zpl_snapdir_readdir, +#endif + }; /* @@ -458,42 +429,51 @@ zpl_shares_lookup(struct inode *dip, struct dentry *dentry, return d_splice_alias(ip, dentry); } -/* ARGSUSED */ static int -zpl_shares_readdir(struct file *filp, void *dirent, filldir_t filldir) +zpl_shares_iterate(struct file *filp, struct dir_context *ctx) { cred_t *cr = CRED(); - struct dentry *dentry = filp->f_path.dentry; - struct inode *ip = dentry->d_inode; - zfs_sb_t *zsb = ITOZSB(ip); + zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode); znode_t *dzp; - int error; + int error = 0; ZFS_ENTER(zsb); if (zsb->z_shares_dir == 0) { - error = zpl_common_readdir(filp, dirent, filldir); - ZFS_EXIT(zsb); - return (error); + dir_emit_dots(filp, ctx); + goto out; } error = -zfs_zget(zsb, zsb->z_shares_dir, &dzp); - if (error) { - ZFS_EXIT(zsb); - return (error); - } + if (error) + goto out; crhold(cr); - error = -zfs_readdir(ZTOI(dzp), dirent, filldir, &filp->f_pos, cr); + error = -zfs_readdir(ZTOI(dzp), ctx, cr); crfree(cr); iput(ZTOI(dzp)); +out: ZFS_EXIT(zsb); ASSERT3S(error, <=, 0); return (error); } +#if !defined(HAVE_VFS_ITERATE) +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); + int error; + + error = zpl_shares_iterate(filp, &ctx); + filp->f_pos = ctx.pos; + + return (error); +} +#endif /* HAVE_VFS_ITERATE */ + /* ARGSUSED */ static int zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry, @@ -532,7 +512,12 @@ const struct file_operations zpl_fops_shares = { .open = zpl_common_open, .llseek = generic_file_llseek, .read = generic_read_dir, +#ifdef HAVE_VFS_ITERATE + .iterate = zpl_shares_iterate, +#else .readdir = zpl_shares_readdir, +#endif + }; /* diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index 299589193..6598c1779 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -64,21 +64,34 @@ zpl_release(struct inode *ip, struct file *filp) } static int -zpl_readdir(struct file *filp, void *dirent, filldir_t filldir) +zpl_iterate(struct file *filp, struct dir_context *ctx) { struct dentry *dentry = filp->f_path.dentry; cred_t *cr = CRED(); int error; crhold(cr); - error = -zfs_readdir(dentry->d_inode, dirent, filldir, - &filp->f_pos, cr); + error = -zfs_readdir(dentry->d_inode, ctx, cr); crfree(cr); ASSERT3S(error, <=, 0); return (error); } +#if !defined(HAVE_VFS_ITERATE) +static int +zpl_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct dir_context ctx = 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 */ + #if defined(HAVE_FSYNC_WITH_DENTRY) /* * Linux 2.6.x - 2.6.34 API, @@ -506,7 +519,11 @@ 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 + .iterate = zpl_iterate, +#else .readdir = zpl_readdir, +#endif .fsync = zpl_fsync, .unlocked_ioctl = zpl_ioctl, #ifdef CONFIG_COMPAT diff --git a/module/zfs/zpl_xattr.c b/module/zfs/zpl_xattr.c index eb2c00dfb..dca1ad668 100644 --- a/module/zfs/zpl_xattr.c +++ b/module/zfs/zpl_xattr.c @@ -80,6 +80,7 @@ #include <sys/zfs_vfsops.h> #include <sys/zfs_vnops.h> #include <sys/zfs_znode.h> +#include <sys/zap.h> #include <sys/vfs.h> #include <sys/zpl.h> @@ -91,11 +92,8 @@ typedef struct xattr_filldir { } xattr_filldir_t; static int -zpl_xattr_filldir(void *arg, const char *name, int name_len, - loff_t offset, uint64_t objnum, unsigned int d_type) +zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len) { - xattr_filldir_t *xf = arg; - if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) if (!(ITOZSB(xf->inode)->z_flags & ZSB_XATTR)) return (0); @@ -118,12 +116,46 @@ zpl_xattr_filldir(void *arg, const char *name, int name_len, return (0); } +/* + * Read as many directory entry names as will fit in to the provided buffer, + * or when no buffer is provided calculate the required buffer size. + */ +int +zpl_xattr_readdir(struct inode *dxip, xattr_filldir_t *xf) +{ + zap_cursor_t zc; + zap_attribute_t zap; + int error; + + zap_cursor_init(&zc, ITOZSB(dxip)->z_os, ITOZ(dxip)->z_id); + + while ((error = -zap_cursor_retrieve(&zc, &zap)) == 0) { + + if (zap.za_integer_length != 8 || zap.za_num_integers != 1) { + error = -ENXIO; + break; + } + + error = zpl_xattr_filldir(xf, zap.za_name, strlen(zap.za_name)); + if (error) + break; + + zap_cursor_advance(&zc); + } + + zap_cursor_fini(&zc); + + if (error == -ENOENT) + error = 0; + + return (error); +} + static ssize_t zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr) { struct inode *ip = xf->inode; struct inode *dxip = NULL; - loff_t pos = 3; /* skip '.', '..', and '.zfs' entries. */ int error; /* Lookup the xattr directory */ @@ -135,8 +167,7 @@ zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr) return (error); } - /* Fill provided buffer via zpl_zattr_filldir helper */ - error = -zfs_readdir(dxip, (void *)xf, zpl_xattr_filldir, &pos, cr); + error = zpl_xattr_readdir(dxip, xf); iput(dxip); return (error); @@ -162,8 +193,8 @@ zpl_xattr_list_sa(xattr_filldir_t *xf) while ((nvp = nvlist_next_nvpair(zp->z_xattr_cached, nvp)) != NULL) { ASSERT3U(nvpair_type(nvp), ==, DATA_TYPE_BYTE_ARRAY); - error = zpl_xattr_filldir((void *)xf, nvpair_name(nvp), - strlen(nvpair_name(nvp)), 0, 0, 0); + error = zpl_xattr_filldir(xf, nvpair_name(nvp), + strlen(nvpair_name(nvp))); if (error) return (error); } |