From: Boaz Harrosh <boazh@xxxxxxxxxx> Establish protocol with Server for readdir Signed-off-by: Boaz Harrosh <boazh@xxxxxxxxxx> --- fs/zuf/_extern.h | 3 ++ fs/zuf/directory.c | 69 +++++++++++++++++++++++++++++++++ fs/zuf/zuf-core.c | 1 + fs/zuf/zus_api.h | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) diff --git a/fs/zuf/_extern.h b/fs/zuf/_extern.h index 76634904eca3..ec9816d51aa3 100644 --- a/fs/zuf/_extern.h +++ b/fs/zuf/_extern.h @@ -39,6 +39,9 @@ int zuf_setattr(struct dentry *dentry, struct iattr *attr); int zuf_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags); void zuf_set_inode_flags(struct inode *inode, struct zus_inode *zi); +bool zuf_dir_emit(struct super_block *sb, struct dir_context *ctx, + ulong ino, const char *name, int length); + /* rw.c */ int zuf_trim_edge(struct inode *inode, ulong filepos, uint len); diff --git a/fs/zuf/directory.c b/fs/zuf/directory.c index eb73a5c7cabf..645dd367fd8c 100644 --- a/fs/zuf/directory.c +++ b/fs/zuf/directory.c @@ -17,6 +17,74 @@ #include <linux/vmalloc.h> #include "zuf.h" +static int zuf_readdir(struct file *file, struct dir_context *ctx) +{ + struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + loff_t i_size = i_size_read(inode); + struct zufs_ioc_readdir ioc_readdir = { + .hdr.in_len = sizeof(ioc_readdir), + .hdr.out_len = sizeof(ioc_readdir), + .hdr.operation = ZUFS_OP_READDIR, + .dir_ii = ZUII(inode)->zus_ii, + }; + struct zufs_readdir_iter rdi; + struct page *pages[ZUS_API_MAP_MAX_PAGES]; + struct zufs_dir_entry *zde; + void *addr, *__a; + uint nump, i; + int err; + + if (ctx->pos && i_size <= ctx->pos) + return 0; + if (!i_size) + i_size = PAGE_SIZE; /* Just for the . && .. */ + if (i_size - ctx->pos < PAGE_SIZE) + ioc_readdir.hdr.len = PAGE_SIZE; + else + ioc_readdir.hdr.len = min_t(loff_t, i_size - ctx->pos, + ZUS_API_MAP_MAX_SIZE); + nump = md_o2p_up(ioc_readdir.hdr.len); + addr = vzalloc(md_p2o(nump)); + if (unlikely(!addr)) + return -ENOMEM; + + WARN_ON((ulong)addr & (PAGE_SIZE - 1)); + + __a = addr; + for (i = 0; i < nump; ++i) { + pages[i] = vmalloc_to_page(__a); + __a += PAGE_SIZE; + } + +more: + ioc_readdir.pos = ctx->pos; + + err = zufc_dispatch(ZUF_ROOT(SBI(sb)), &ioc_readdir.hdr, pages, nump); + if (unlikely(err && err != -EINTR)) { + zuf_err("zufc_dispatch failed => %d\n", err); + goto out; + } + + zufs_readdir_iter_init(&rdi, &ioc_readdir, addr); + while ((zde = zufs_next_zde(&rdi)) != NULL) { + zuf_dbg_verbose("%s pos=0x%lx\n", + zde->zstr.name, (ulong)zde->pos); + ctx->pos = zde->pos; + if (!dir_emit(ctx, zde->zstr.name, zde->zstr.len, zde->ino, + zde->type)) + goto out; + } + ctx->pos = ioc_readdir.pos; + if (ioc_readdir.more) { + zuf_dbg_err("more\n"); + goto more; + } +out: + vfree(addr); + return err; +} + /* *FIXME comment to full git diff */ @@ -90,5 +158,6 @@ int zuf_remove_dentry(struct inode *dir, struct qstr *str, struct inode *inode) const struct file_operations zuf_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, + .iterate_shared = zuf_readdir, .fsync = noop_fsync, }; diff --git a/fs/zuf/zuf-core.c b/fs/zuf/zuf-core.c index 3b61a4845af7..3d38f284d387 100644 --- a/fs/zuf/zuf-core.c +++ b/fs/zuf/zuf-core.c @@ -773,6 +773,7 @@ const char *zuf_op_name(enum e_zufs_operation op) CASE_ENUM_NAME(ZUFS_OP_ADD_DENTRY ); CASE_ENUM_NAME(ZUFS_OP_REMOVE_DENTRY ); CASE_ENUM_NAME(ZUFS_OP_RENAME ); + CASE_ENUM_NAME(ZUFS_OP_READDIR ); CASE_ENUM_NAME(ZUFS_OP_SETATTR ); CASE_ENUM_NAME(ZUFS_OP_BREAK ); default: diff --git a/fs/zuf/zus_api.h b/fs/zuf/zus_api.h index 9d66a38ab585..8a4e597414a8 100644 --- a/fs/zuf/zus_api.h +++ b/fs/zuf/zus_api.h @@ -336,6 +336,7 @@ enum e_zufs_operation { ZUFS_OP_ADD_DENTRY, ZUFS_OP_REMOVE_DENTRY, ZUFS_OP_RENAME, + ZUFS_OP_READDIR, ZUFS_OP_SETATTR, @@ -421,6 +422,101 @@ struct zufs_ioc_rename { __u32 flags; }; +/* ZUFS_OP_READDIR */ +struct zufs_ioc_readdir { + struct zufs_ioc_hdr hdr; + /* IN */ + struct zus_inode_info *dir_ii; + loff_t pos; + + /* OUT */ + __u8 more; +}; + +struct zufs_dir_entry { + __le64 ino; + struct { + unsigned type : 8; + ulong pos : 56; + }; + struct zufs_str zstr; +}; + +struct zufs_readdir_iter { + void *__zde, *last; + struct zufs_ioc_readdir *ioc_readdir; +}; + +enum {E_ZDE_HDR_SIZE = + offsetof(struct zufs_dir_entry, zstr) + offsetof(struct zufs_str, name), +}; + +static inline void zufs_readdir_iter_init(struct zufs_readdir_iter *rdi, + struct zufs_ioc_readdir *ioc_readdir, + void *app_ptr) +{ + rdi->__zde = app_ptr; + rdi->last = app_ptr + ioc_readdir->hdr.len; + rdi->ioc_readdir = ioc_readdir; + ioc_readdir->more = false; +} + +static inline uint zufs_dir_entry_len(__u8 name_len) +{ + return ALIGN(E_ZDE_HDR_SIZE + name_len, sizeof(__u64)); +} + +static inline +struct zufs_dir_entry *zufs_next_zde(struct zufs_readdir_iter *rdi) +{ + struct zufs_dir_entry *zde = rdi->__zde; + uint len; + + if (rdi->last <= rdi->__zde + E_ZDE_HDR_SIZE) + return NULL; + if (zde->zstr.len == 0) + return NULL; + len = zufs_dir_entry_len(zde->zstr.len); + if (rdi->last <= rdi->__zde + len) + return NULL; + + rdi->__zde += len; + return zde; +} + +static inline bool zufs_zde_emit(struct zufs_readdir_iter *rdi, __u64 ino, + __u8 type, __u64 pos, const char *name, + __u8 len) +{ + struct zufs_dir_entry *zde = rdi->__zde; + + if (rdi->last <= rdi->__zde + zufs_dir_entry_len(len)) { + rdi->ioc_readdir->more = true; + return false; + } + + rdi->ioc_readdir->more = 0; + zde->ino = ino; + zde->type = type; + /*ASSERT(0 == (pos && (1 << 56 - 1)));*/ + zde->pos = pos; + strncpy(zde->zstr.name, name, len); + zde->zstr.len = len; + zufs_next_zde(rdi); + + return true; +} + +/* ZUFS_OP_GET_SYMLINK */ +struct zufs_ioc_get_link { + struct zufs_ioc_hdr hdr; + /* IN */ + struct zus_inode_info *zus_ii; + + /* OUT */ + zu_dpp_t _link; +}; + /* ZUFS_OP_SETATTR */ struct zufs_ioc_attr { struct zufs_ioc_hdr hdr; -- 2.20.1