mirror of
https://github.com/versity/scoutfs.git
synced 2026-04-16 03:46:59 +00:00
scoutfs: support newer ->iterate readdir
The modern upstream kernel has a ->iterate() readdir file_operattions method which takes a context and calls dir_emit(). We add some kernelcompat helpers to juggle the various function definitions, types, and arguments to support both the old ->readdir(filldir) and the new ->iterate(ctx) interfaces. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -5,3 +5,32 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
ccflags-y += -include $(src)/kernelcompat.h
|
ccflags-y += -include $(src)/kernelcompat.h
|
||||||
|
|
||||||
|
#
|
||||||
|
# v3.10-rc6-21-gbb6f619b3a49
|
||||||
|
#
|
||||||
|
# _readdir changes from fop->readdir() to fop->iterate() and from
|
||||||
|
# filldir(dirent) to dir_emit(ctx).
|
||||||
|
#
|
||||||
|
ifneq (,$(shell grep 'iterate.*dir_context' include/linux/fs.h))
|
||||||
|
ccflags-y += -DKC_ITERATE_DIR_CONTEXT
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# v3.10-rc6-23-g5f99f4e79abc
|
||||||
|
#
|
||||||
|
# Helpers including dir_emit_dots() are added in the process of
|
||||||
|
# switching dcache_readdir() from fop->readdir() to fop->iterate()
|
||||||
|
#
|
||||||
|
ifneq (,$(shell grep 'dir_emit_dots' include/linux/fs.h))
|
||||||
|
ccflags-y += -DKC_DIR_EMIT_DOTS
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# RHEL extended the fop struct so to use it we have to set
|
||||||
|
# a flag to indicate that the struct is large enough and
|
||||||
|
# contains the pointer.
|
||||||
|
#
|
||||||
|
ifneq (,$(shell grep 'FMODE_KABI_ITERATE' include/linux/fs.h))
|
||||||
|
ccflags-y += -DKC_FMODE_KABI_ITERATE
|
||||||
|
endif
|
||||||
|
|||||||
@@ -436,28 +436,6 @@ out:
|
|||||||
return d_splice_alias(inode, dentry);
|
return d_splice_alias(inode, dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this exists upstream so we can just delete it in a forward port */
|
|
||||||
static int dir_emit_dots(struct file *file, void *dirent, filldir_t filldir)
|
|
||||||
{
|
|
||||||
struct dentry *dentry = file->f_path.dentry;
|
|
||||||
struct inode *inode = dentry->d_inode;
|
|
||||||
struct inode *parent = dentry->d_parent->d_inode;
|
|
||||||
|
|
||||||
if (file->f_pos == 0) {
|
|
||||||
if (filldir(dirent, ".", 1, 1, scoutfs_ino(inode), DT_DIR))
|
|
||||||
return 0;
|
|
||||||
file->f_pos = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file->f_pos == 1) {
|
|
||||||
if (filldir(dirent, "..", 2, 1, scoutfs_ino(parent), DT_DIR))
|
|
||||||
return 0;
|
|
||||||
file->f_pos = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* readdir simply iterates over the dirent items for the dir inode and
|
* readdir simply iterates over the dirent items for the dir inode and
|
||||||
* uses their offset as the readdir position.
|
* uses their offset as the readdir position.
|
||||||
@@ -465,7 +443,8 @@ static int dir_emit_dots(struct file *file, void *dirent, filldir_t filldir)
|
|||||||
* It will need to be careful not to read past the region of the dirent
|
* It will need to be careful not to read past the region of the dirent
|
||||||
* hash offset keys that it has access to.
|
* hash offset keys that it has access to.
|
||||||
*/
|
*/
|
||||||
static int scoutfs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
static int KC_DECLARE_READDIR(scoutfs_readdir, struct file *file,
|
||||||
|
void *dirent, kc_readdir_ctx_t ctx)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
@@ -478,7 +457,7 @@ static int scoutfs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
|||||||
u64 pos;
|
u64 pos;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!dir_emit_dots(file, dirent, filldir))
|
if (!kc_dir_emit_dots(file, dirent, ctx))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dent = alloc_dirent(SCOUTFS_NAME_LEN);
|
dent = alloc_dirent(SCOUTFS_NAME_LEN);
|
||||||
@@ -497,7 +476,7 @@ static int scoutfs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
init_dirent_key(&key, SCOUTFS_READDIR_TYPE, scoutfs_ino(inode),
|
init_dirent_key(&key, SCOUTFS_READDIR_TYPE, scoutfs_ino(inode),
|
||||||
file->f_pos, 0);
|
kc_readdir_pos(file, ctx), 0);
|
||||||
|
|
||||||
ret = scoutfs_item_next(sb, &key, &last_key, &val, dir_lock);
|
ret = scoutfs_item_next(sb, &key, &last_key, &val, dir_lock);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -511,21 +490,24 @@ static int scoutfs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
|||||||
scoutfs_corruption(sb, SC_DIRENT_READDIR_NAME_LEN,
|
scoutfs_corruption(sb, SC_DIRENT_READDIR_NAME_LEN,
|
||||||
corrupt_dirent_readdir_name_len,
|
corrupt_dirent_readdir_name_len,
|
||||||
"dir_ino %llu pos %llu key "SK_FMT" len %d",
|
"dir_ino %llu pos %llu key "SK_FMT" len %d",
|
||||||
scoutfs_ino(inode), file->f_pos,
|
scoutfs_ino(inode),
|
||||||
|
kc_readdir_pos(file, ctx),
|
||||||
SK_ARG(&key), name_len);
|
SK_ARG(&key), name_len);
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = le64_to_cpu(key.skd_major);
|
pos = le64_to_cpu(key.skd_major);
|
||||||
|
kc_readdir_pos(file, ctx) = pos;
|
||||||
|
|
||||||
if (filldir(dirent, dent->name, name_len, pos,
|
if (!kc_dir_emit(ctx, dent, dent->name, name_len, pos,
|
||||||
le64_to_cpu(dent->ino), dentry_type(dent->type))) {
|
le64_to_cpu(dent->ino),
|
||||||
|
dentry_type(dent->type))) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
file->f_pos = pos + 1;
|
kc_readdir_pos(file, ctx) = pos + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -1737,8 +1719,20 @@ out_unlock:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef KC_FMODE_KABI_ITERATE
|
||||||
|
/* we only need this to set the iterate flag for kabi :/ */
|
||||||
|
static int scoutfs_dir_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
file->f_mode |= FMODE_KABI_ITERATE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const struct file_operations scoutfs_dir_fops = {
|
const struct file_operations scoutfs_dir_fops = {
|
||||||
.readdir = scoutfs_readdir,
|
.KC_FOP_READDIR = scoutfs_readdir,
|
||||||
|
#ifdef KC_FMODE_KABI_ITERATE
|
||||||
|
.open = scoutfs_dir_open,
|
||||||
|
#endif
|
||||||
.unlocked_ioctl = scoutfs_ioctl,
|
.unlocked_ioctl = scoutfs_ioctl,
|
||||||
.fsync = scoutfs_file_fsync,
|
.fsync = scoutfs_file_fsync,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
|
|||||||
@@ -1,4 +1,49 @@
|
|||||||
#ifndef _SCOUTFS_KERNELCOMPAT_H_
|
#ifndef _SCOUTFS_KERNELCOMPAT_H_
|
||||||
#define _SCOUTFS_KERNELCOMPAT_H_
|
#define _SCOUTFS_KERNELCOMPAT_H_
|
||||||
|
|
||||||
|
#ifndef KC_ITERATE_DIR_CONTEXT
|
||||||
|
#include <linux/fs.h>
|
||||||
|
typedef filldir_t kc_readdir_ctx_t;
|
||||||
|
#define KC_DECLARE_READDIR(name, file, dirent, ctx) name(file, dirent, ctx)
|
||||||
|
#define KC_FOP_READDIR readdir
|
||||||
|
#define kc_readdir_pos(filp, ctx) (filp)->f_pos
|
||||||
|
#define kc_dir_emit_dots(file, dirent, ctx) dir_emit_dots(file, dirent, ctx)
|
||||||
|
#define kc_dir_emit(ctx, dentry, name, name_len, pos, ino, dt) \
|
||||||
|
(ctx(dentry, name, name_len, pos, ino, dt) == 0)
|
||||||
|
#else
|
||||||
|
typedef struct dir_context * kc_readdir_ctx_t;
|
||||||
|
#define KC_DECLARE_READDIR(name, file, dirent, ctx) name(file, ctx)
|
||||||
|
#define KC_FOP_READDIR iterate
|
||||||
|
#define kc_readdir_pos(filp, ctx) (ctx)->pos
|
||||||
|
#define kc_dir_emit_dots(file, dirent, ctx) dir_emit_dots(file, ctx)
|
||||||
|
#define kc_dir_emit(ctx, dentry, name, name_len, pos, ino, dt) \
|
||||||
|
dir_emit(ctx, name, name_len, ino, dt)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef KC_DIR_EMIT_DOTS
|
||||||
|
/*
|
||||||
|
* Kernels before ->iterate and don't have dir_emit_dots so we give them
|
||||||
|
* one that works with the ->readdir() filldir() method.
|
||||||
|
*/
|
||||||
|
static inline int dir_emit_dots(struct file *file, void *dirent,
|
||||||
|
filldir_t filldir)
|
||||||
|
{
|
||||||
|
if (file->f_pos == 0) {
|
||||||
|
if (filldir(dirent, ".", 1, 1,
|
||||||
|
file->f_path.dentry->d_inode->i_ino, DT_DIR))
|
||||||
|
return 0;
|
||||||
|
file->f_pos = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file->f_pos == 1) {
|
||||||
|
if (filldir(dirent, "..", 2, 1,
|
||||||
|
parent_ino(file->f_path.dentry), DT_DIR))
|
||||||
|
return 0;
|
||||||
|
file->f_pos = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user