@@ -19,7 +19,74 @@
static int zuf_readdir(struct file *file, struct dir_context *ctx)
{
- return -ENOTSUPP;
+ 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;
+ 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);
+ /* Allocating both readdir buffer and the pages-array.
+ * Pages array is at end
+ */
+ addr = vzalloc(md_p2o(nump) + nump * sizeof(*pages));
+ if (unlikely(!addr))
+ return -ENOMEM;
+
+ WARN_ON((ulong)addr & (PAGE_SIZE - 1));
+
+ pages = addr + md_p2o(nump);
+ __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_dispatch(sb, "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;
}
/*
@@ -74,6 +74,8 @@ 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 ZUFS_OP_MAX_OPT:
default:
@@ -454,6 +454,7 @@ enum e_zufs_operation {
ZUFS_OP_ADD_DENTRY = 8,
ZUFS_OP_REMOVE_DENTRY = 9,
ZUFS_OP_RENAME = 10,
+ ZUFS_OP_READDIR = 11,
ZUFS_OP_SETATTR = 19,
@@ -549,6 +550,93 @@ struct zufs_ioc_rename {
__u64 flags;
};
+/* ZUFS_OP_READDIR */
+struct zufs_ioc_readdir {
+ struct zufs_ioc_hdr hdr;
+ /* IN */
+ struct zus_inode_info *dir_ii;
+ __u64 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),
+};
+
+#ifndef __cplusplus
+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;
+}
+#endif /* ndef __cplusplus */
+
/* ZUFS_OP_SETATTR */
struct zufs_ioc_attr {
struct zufs_ioc_hdr hdr;
Implements the file_operations->iterate_shared via info returned from Server. Establish protocol with Server for readdir. The Server fills a zuf allocated buffer (up to 4M at a time) which will contain a zufs encoded dir entries. It will then call the proper emit vector to fill the caller buffer. The buffer is passed to Server not as part of the zufs_ioc_readdir struct but maps this buffer directly into Server space via the zt_map_pages facility. [v2] Fix the gcc warning: directory.c:86:1: warning: the frame size of 8576 bytes is larger than 8192 bytes Fix it by allocating the pages array, which was on stack as part of the allocation we already do for the readdir buffer Reported-by: kbuild test robot <lkp@intel.com> Signed-off-by: Boaz Harrosh <boazh@netapp.com> --- fs/zuf/directory.c | 69 +++++++++++++++++++++++++++++++++++- fs/zuf/zuf-core.c | 2 ++ fs/zuf/zus_api.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 1 deletion(-)