mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 11:19:32 +03:00
Linux 3.11 compat: fops->iterate()
Commit torvalds/linux@2233f31aad 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
This commit is contained in:
parent
34e143323e
commit
0f37d0c8be
43
config/kernel-vfs-iterate.m4
Normal file
43
config/kernel-vfs-iterate.m4
Normal file
@ -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)
|
||||||
|
])
|
||||||
|
|
||||||
|
])
|
||||||
|
])
|
@ -80,6 +80,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
|
|||||||
ZFS_AC_KERNEL_ELEVATOR_CHANGE
|
ZFS_AC_KERNEL_ELEVATOR_CHANGE
|
||||||
ZFS_AC_KERNEL_5ARG_SGET
|
ZFS_AC_KERNEL_5ARG_SGET
|
||||||
ZFS_AC_KERNEL_LSEEK_EXECUTE
|
ZFS_AC_KERNEL_LSEEK_EXECUTE
|
||||||
|
ZFS_AC_KERNEL_VFS_ITERATE
|
||||||
|
|
||||||
AS_IF([test "$LINUX_OBJ" != "$LINUX"], [
|
AS_IF([test "$LINUX_OBJ" != "$LINUX"], [
|
||||||
KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
|
KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <sys/cred.h>
|
#include <sys/cred.h>
|
||||||
#include <sys/fcntl.h>
|
#include <sys/fcntl.h>
|
||||||
#include <sys/pathname.h>
|
#include <sys/pathname.h>
|
||||||
|
#include <sys/zpl.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -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);
|
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, void *dirent, filldir_t filldir,
|
extern int zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr);
|
||||||
loff_t *pos, 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);
|
||||||
|
@ -89,4 +89,63 @@ extern const struct inode_operations zpl_ops_snapdirs;
|
|||||||
extern const struct file_operations zpl_fops_shares;
|
extern const struct file_operations zpl_fops_shares;
|
||||||
extern const struct inode_operations zpl_ops_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 */
|
#endif /* _SYS_ZPL_H */
|
||||||
|
@ -1997,8 +1997,7 @@ EXPORT_SYMBOL(zfs_rmdir);
|
|||||||
*/
|
*/
|
||||||
/* ARGSUSED */
|
/* ARGSUSED */
|
||||||
int
|
int
|
||||||
zfs_readdir(struct inode *ip, void *dirent, filldir_t filldir,
|
zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
|
||||||
loff_t *pos, cred_t *cr)
|
|
||||||
{
|
{
|
||||||
znode_t *zp = ITOZ(ip);
|
znode_t *zp = ITOZ(ip);
|
||||||
zfs_sb_t *zsb = ITOZSB(ip);
|
zfs_sb_t *zsb = ITOZSB(ip);
|
||||||
@ -2010,6 +2009,7 @@ zfs_readdir(struct inode *ip, void *dirent, filldir_t filldir,
|
|||||||
uint8_t prefetch;
|
uint8_t prefetch;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
uint64_t parent;
|
uint64_t parent;
|
||||||
|
loff_t *pos = &(ctx->pos);
|
||||||
|
|
||||||
ZFS_ENTER(zsb);
|
ZFS_ENTER(zsb);
|
||||||
ZFS_VERIFY_ZP(zp);
|
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);
|
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));
|
done = !dir_emit(ctx, zap.za_name, strlen(zap.za_name),
|
||||||
if (done) {
|
objnum, ZFS_DIRENT_TYPE(zap.za_first_integer));
|
||||||
|
if (done)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/* Prefetch znode */
|
/* Prefetch znode */
|
||||||
if (prefetch) {
|
if (prefetch) {
|
||||||
|
@ -46,79 +46,34 @@ zpl_common_open(struct inode *ip, struct file *filp)
|
|||||||
return generic_file_open(ip, 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.
|
* Get root directory contents.
|
||||||
*/
|
*/
|
||||||
static int
|
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;
|
zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
|
||||||
struct inode *ip = dentry->d_inode;
|
|
||||||
zfs_sb_t *zsb = ITOZSB(ip);
|
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
ZFS_ENTER(zsb);
|
ZFS_ENTER(zsb);
|
||||||
|
|
||||||
switch (filp->f_pos) {
|
if (!dir_emit_dots(filp, ctx))
|
||||||
case 0:
|
|
||||||
error = filldir(dirent, ".", 1, 0, ip->i_ino, DT_DIR);
|
|
||||||
if (error)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
filp->f_pos++;
|
if (ctx->pos == 2) {
|
||||||
/* fall-thru */
|
if (!dir_emit(ctx, ZFS_SNAPDIR_NAME, strlen(ZFS_SNAPDIR_NAME),
|
||||||
case 1:
|
ZFSCTL_INO_SNAPDIR, DT_DIR))
|
||||||
error = filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR);
|
|
||||||
if (error)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
filp->f_pos++;
|
ctx->pos++;
|
||||||
/* fall-thru */
|
}
|
||||||
case 2:
|
|
||||||
error = filldir(dirent, ZFS_SNAPDIR_NAME,
|
if (ctx->pos == 3) {
|
||||||
strlen(ZFS_SNAPDIR_NAME), 2, ZFSCTL_INO_SNAPDIR, DT_DIR);
|
if (!dir_emit(ctx, ZFS_SHAREDIR_NAME, strlen(ZFS_SHAREDIR_NAME),
|
||||||
if (error)
|
ZFSCTL_INO_SHARES, DT_DIR))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
filp->f_pos++;
|
ctx->pos++;
|
||||||
/* fall-thru */
|
|
||||||
case 3:
|
|
||||||
error = filldir(dirent, ZFS_SHAREDIR_NAME,
|
|
||||||
strlen(ZFS_SHAREDIR_NAME), 3, ZFSCTL_INO_SHARES, DT_DIR);
|
|
||||||
if (error)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
filp->f_pos++;
|
|
||||||
/* fall-thru */
|
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
ZFS_EXIT(zsb);
|
ZFS_EXIT(zsb);
|
||||||
@ -126,6 +81,20 @@ out:
|
|||||||
return (error);
|
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.
|
* Get root directory attributes.
|
||||||
*/
|
*/
|
||||||
@ -175,7 +144,11 @@ const struct file_operations zpl_fops_root = {
|
|||||||
.open = zpl_common_open,
|
.open = zpl_common_open,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
|
#ifdef HAVE_VFS_ITERATE
|
||||||
|
.iterate = zpl_root_iterate,
|
||||||
|
#else
|
||||||
.readdir = zpl_root_readdir,
|
.readdir = zpl_root_readdir,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct inode_operations zpl_ops_root = {
|
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);
|
return d_splice_alias(ip, dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
|
||||||
static int
|
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;
|
zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
|
||||||
struct inode *dip = dentry->d_inode;
|
|
||||||
zfs_sb_t *zsb = ITOZSB(dip);
|
|
||||||
char snapname[MAXNAMELEN];
|
char snapname[MAXNAMELEN];
|
||||||
uint64_t id, cookie;
|
|
||||||
boolean_t case_conflict;
|
boolean_t case_conflict;
|
||||||
|
uint64_t id;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
ZFS_ENTER(zsb);
|
ZFS_ENTER(zsb);
|
||||||
|
|
||||||
cookie = filp->f_pos;
|
if (!dir_emit_dots(filp, ctx))
|
||||||
switch (filp->f_pos) {
|
|
||||||
case 0:
|
|
||||||
error = filldir(dirent, ".", 1, 0, dip->i_ino, DT_DIR);
|
|
||||||
if (error)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
filp->f_pos++;
|
|
||||||
/* fall-thru */
|
|
||||||
case 1:
|
|
||||||
error = filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR);
|
|
||||||
if (error)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
filp->f_pos++;
|
|
||||||
/* fall-thru */
|
|
||||||
default:
|
|
||||||
while (error == 0) {
|
while (error == 0) {
|
||||||
error = -dmu_snapshot_list_next(zsb->z_os, MAXNAMELEN,
|
error = -dmu_snapshot_list_next(zsb->z_os, MAXNAMELEN,
|
||||||
snapname, &id, &cookie, &case_conflict);
|
snapname, &id, &(ctx->pos), &case_conflict);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
error = filldir(dirent, snapname, strlen(snapname),
|
if (!dir_emit(ctx, snapname, strlen(snapname),
|
||||||
filp->f_pos, ZFSCTL_INO_SHARES - id, DT_DIR);
|
ZFSCTL_INO_SHARES - id, DT_DIR))
|
||||||
if (error)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
filp->f_pos = cookie;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
ZFS_EXIT(zsb);
|
ZFS_EXIT(zsb);
|
||||||
@ -327,6 +279,20 @@ out:
|
|||||||
return (error);
|
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
|
int
|
||||||
zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry,
|
zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry,
|
||||||
struct inode *tdip, struct dentry *tdentry)
|
struct inode *tdip, struct dentry *tdentry)
|
||||||
@ -413,7 +379,12 @@ const struct file_operations zpl_fops_snapdir = {
|
|||||||
.open = zpl_common_open,
|
.open = zpl_common_open,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
|
#ifdef HAVE_VFS_ITERATE
|
||||||
|
.iterate = zpl_snapdir_iterate,
|
||||||
|
#else
|
||||||
.readdir = zpl_snapdir_readdir,
|
.readdir = zpl_snapdir_readdir,
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -458,42 +429,51 @@ zpl_shares_lookup(struct inode *dip, struct dentry *dentry,
|
|||||||
return d_splice_alias(ip, dentry);
|
return d_splice_alias(ip, dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARGSUSED */
|
|
||||||
static int
|
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();
|
cred_t *cr = CRED();
|
||||||
struct dentry *dentry = filp->f_path.dentry;
|
zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
|
||||||
struct inode *ip = dentry->d_inode;
|
|
||||||
zfs_sb_t *zsb = ITOZSB(ip);
|
|
||||||
znode_t *dzp;
|
znode_t *dzp;
|
||||||
int error;
|
int error = 0;
|
||||||
|
|
||||||
ZFS_ENTER(zsb);
|
ZFS_ENTER(zsb);
|
||||||
|
|
||||||
if (zsb->z_shares_dir == 0) {
|
if (zsb->z_shares_dir == 0) {
|
||||||
error = zpl_common_readdir(filp, dirent, filldir);
|
dir_emit_dots(filp, ctx);
|
||||||
ZFS_EXIT(zsb);
|
goto out;
|
||||||
return (error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error = -zfs_zget(zsb, zsb->z_shares_dir, &dzp);
|
error = -zfs_zget(zsb, zsb->z_shares_dir, &dzp);
|
||||||
if (error) {
|
if (error)
|
||||||
ZFS_EXIT(zsb);
|
goto out;
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
|
|
||||||
crhold(cr);
|
crhold(cr);
|
||||||
error = -zfs_readdir(ZTOI(dzp), dirent, filldir, &filp->f_pos, cr);
|
error = -zfs_readdir(ZTOI(dzp), ctx, cr);
|
||||||
crfree(cr);
|
crfree(cr);
|
||||||
|
|
||||||
iput(ZTOI(dzp));
|
iput(ZTOI(dzp));
|
||||||
|
out:
|
||||||
ZFS_EXIT(zsb);
|
ZFS_EXIT(zsb);
|
||||||
ASSERT3S(error, <=, 0);
|
ASSERT3S(error, <=, 0);
|
||||||
|
|
||||||
return (error);
|
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 */
|
/* ARGSUSED */
|
||||||
static int
|
static int
|
||||||
zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
zpl_shares_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||||
@ -532,7 +512,12 @@ const struct file_operations zpl_fops_shares = {
|
|||||||
.open = zpl_common_open,
|
.open = zpl_common_open,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = generic_read_dir,
|
.read = generic_read_dir,
|
||||||
|
#ifdef HAVE_VFS_ITERATE
|
||||||
|
.iterate = zpl_shares_iterate,
|
||||||
|
#else
|
||||||
.readdir = zpl_shares_readdir,
|
.readdir = zpl_shares_readdir,
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -64,21 +64,34 @@ zpl_release(struct inode *ip, struct file *filp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
struct dentry *dentry = filp->f_path.dentry;
|
||||||
cred_t *cr = CRED();
|
cred_t *cr = CRED();
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
crhold(cr);
|
crhold(cr);
|
||||||
error = -zfs_readdir(dentry->d_inode, dirent, filldir,
|
error = -zfs_readdir(dentry->d_inode, ctx, cr);
|
||||||
&filp->f_pos, cr);
|
|
||||||
crfree(cr);
|
crfree(cr);
|
||||||
ASSERT3S(error, <=, 0);
|
ASSERT3S(error, <=, 0);
|
||||||
|
|
||||||
return (error);
|
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)
|
#if defined(HAVE_FSYNC_WITH_DENTRY)
|
||||||
/*
|
/*
|
||||||
* Linux 2.6.x - 2.6.34 API,
|
* 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 = {
|
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
|
||||||
|
.iterate = zpl_iterate,
|
||||||
|
#else
|
||||||
.readdir = zpl_readdir,
|
.readdir = zpl_readdir,
|
||||||
|
#endif
|
||||||
.fsync = zpl_fsync,
|
.fsync = zpl_fsync,
|
||||||
.unlocked_ioctl = zpl_ioctl,
|
.unlocked_ioctl = zpl_ioctl,
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
#include <sys/zfs_vfsops.h>
|
#include <sys/zfs_vfsops.h>
|
||||||
#include <sys/zfs_vnops.h>
|
#include <sys/zfs_vnops.h>
|
||||||
#include <sys/zfs_znode.h>
|
#include <sys/zfs_znode.h>
|
||||||
|
#include <sys/zap.h>
|
||||||
#include <sys/vfs.h>
|
#include <sys/vfs.h>
|
||||||
#include <sys/zpl.h>
|
#include <sys/zpl.h>
|
||||||
|
|
||||||
@ -91,11 +92,8 @@ typedef struct xattr_filldir {
|
|||||||
} xattr_filldir_t;
|
} xattr_filldir_t;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
zpl_xattr_filldir(void *arg, const char *name, int name_len,
|
zpl_xattr_filldir(xattr_filldir_t *xf, const char *name, int name_len)
|
||||||
loff_t offset, uint64_t objnum, unsigned int d_type)
|
|
||||||
{
|
{
|
||||||
xattr_filldir_t *xf = arg;
|
|
||||||
|
|
||||||
if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
|
if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
|
||||||
if (!(ITOZSB(xf->inode)->z_flags & ZSB_XATTR))
|
if (!(ITOZSB(xf->inode)->z_flags & ZSB_XATTR))
|
||||||
return (0);
|
return (0);
|
||||||
@ -118,12 +116,46 @@ zpl_xattr_filldir(void *arg, const char *name, int name_len,
|
|||||||
return (0);
|
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
|
static ssize_t
|
||||||
zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr)
|
zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr)
|
||||||
{
|
{
|
||||||
struct inode *ip = xf->inode;
|
struct inode *ip = xf->inode;
|
||||||
struct inode *dxip = NULL;
|
struct inode *dxip = NULL;
|
||||||
loff_t pos = 3; /* skip '.', '..', and '.zfs' entries. */
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* Lookup the xattr directory */
|
/* Lookup the xattr directory */
|
||||||
@ -135,8 +167,7 @@ zpl_xattr_list_dir(xattr_filldir_t *xf, cred_t *cr)
|
|||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill provided buffer via zpl_zattr_filldir helper */
|
error = zpl_xattr_readdir(dxip, xf);
|
||||||
error = -zfs_readdir(dxip, (void *)xf, zpl_xattr_filldir, &pos, cr);
|
|
||||||
iput(dxip);
|
iput(dxip);
|
||||||
|
|
||||||
return (error);
|
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) {
|
while ((nvp = nvlist_next_nvpair(zp->z_xattr_cached, nvp)) != NULL) {
|
||||||
ASSERT3U(nvpair_type(nvp), ==, DATA_TYPE_BYTE_ARRAY);
|
ASSERT3U(nvpair_type(nvp), ==, DATA_TYPE_BYTE_ARRAY);
|
||||||
|
|
||||||
error = zpl_xattr_filldir((void *)xf, nvpair_name(nvp),
|
error = zpl_xattr_filldir(xf, nvpair_name(nvp),
|
||||||
strlen(nvpair_name(nvp)), 0, 0, 0);
|
strlen(nvpair_name(nvp)));
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user