18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2017 Omnibond Systems, L.L.C.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "protocol.h"
78c2ecf20Sopenharmony_ci#include "orangefs-kernel.h"
88c2ecf20Sopenharmony_ci#include "orangefs-bufmap.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_cistruct orangefs_dir_part {
118c2ecf20Sopenharmony_ci	struct orangefs_dir_part *next;
128c2ecf20Sopenharmony_ci	size_t len;
138c2ecf20Sopenharmony_ci};
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistruct orangefs_dir {
168c2ecf20Sopenharmony_ci	__u64 token;
178c2ecf20Sopenharmony_ci	struct orangefs_dir_part *part;
188c2ecf20Sopenharmony_ci	loff_t end;
198c2ecf20Sopenharmony_ci	int error;
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define PART_SHIFT (24)
238c2ecf20Sopenharmony_ci#define PART_SIZE (1<<24)
248c2ecf20Sopenharmony_ci#define PART_MASK (~(PART_SIZE - 1))
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * There can be up to 512 directory entries.  Each entry is encoded as
288c2ecf20Sopenharmony_ci * follows:
298c2ecf20Sopenharmony_ci * 4 bytes: string size (n)
308c2ecf20Sopenharmony_ci * n bytes: string
318c2ecf20Sopenharmony_ci * 1 byte: trailing zero
328c2ecf20Sopenharmony_ci * padding to 8 bytes
338c2ecf20Sopenharmony_ci * 16 bytes: khandle
348c2ecf20Sopenharmony_ci * padding to 8 bytes
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * The trailer_buf starts with a struct orangefs_readdir_response_s
378c2ecf20Sopenharmony_ci * which must be skipped to get to the directory data.
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * The data which is received from the userspace daemon is termed a
408c2ecf20Sopenharmony_ci * part and is stored in a linked list in case more than one part is
418c2ecf20Sopenharmony_ci * needed for a large directory.
428c2ecf20Sopenharmony_ci *
438c2ecf20Sopenharmony_ci * The position pointer (ctx->pos) encodes the part and offset on which
448c2ecf20Sopenharmony_ci * to begin reading at.  Bits above PART_SHIFT encode the part and bits
458c2ecf20Sopenharmony_ci * below PART_SHIFT encode the offset.  Parts are stored in a linked
468c2ecf20Sopenharmony_ci * list which grows as data is received from the server.  The overhead
478c2ecf20Sopenharmony_ci * associated with managing the list is presumed to be small compared to
488c2ecf20Sopenharmony_ci * the overhead of communicating with the server.
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * As data is received from the server, it is placed at the end of the
518c2ecf20Sopenharmony_ci * part list.  Data is parsed from the current position as it is needed.
528c2ecf20Sopenharmony_ci * When data is determined to be corrupt, it is either because the
538c2ecf20Sopenharmony_ci * userspace component has sent back corrupt data or because the file
548c2ecf20Sopenharmony_ci * pointer has been moved to an invalid location.  Since the two cannot
558c2ecf20Sopenharmony_ci * be differentiated, return EIO.
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * Part zero is synthesized to contains `.' and `..'.  Part one is the
588c2ecf20Sopenharmony_ci * first part of the part list.
598c2ecf20Sopenharmony_ci */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int do_readdir(struct orangefs_inode_s *oi,
628c2ecf20Sopenharmony_ci    struct orangefs_dir *od, struct dentry *dentry,
638c2ecf20Sopenharmony_ci    struct orangefs_kernel_op_s *op)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct orangefs_readdir_response_s *resp;
668c2ecf20Sopenharmony_ci	int bufi, r;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/*
698c2ecf20Sopenharmony_ci	 * Despite the badly named field, readdir does not use shared
708c2ecf20Sopenharmony_ci	 * memory.  However, there are a limited number of readdir
718c2ecf20Sopenharmony_ci	 * slots, which must be allocated here.  This flag simply tells
728c2ecf20Sopenharmony_ci	 * the op scheduler to return the op here for retry.
738c2ecf20Sopenharmony_ci	 */
748c2ecf20Sopenharmony_ci	op->uses_shared_memory = 1;
758c2ecf20Sopenharmony_ci	op->upcall.req.readdir.refn = oi->refn;
768c2ecf20Sopenharmony_ci	op->upcall.req.readdir.token = od->token;
778c2ecf20Sopenharmony_ci	op->upcall.req.readdir.max_dirent_count =
788c2ecf20Sopenharmony_ci	    ORANGEFS_MAX_DIRENT_COUNT_READDIR;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciagain:
818c2ecf20Sopenharmony_ci	bufi = orangefs_readdir_index_get();
828c2ecf20Sopenharmony_ci	if (bufi < 0) {
838c2ecf20Sopenharmony_ci		od->error = bufi;
848c2ecf20Sopenharmony_ci		return bufi;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	op->upcall.req.readdir.buf_index = bufi;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	r = service_operation(op, "orangefs_readdir",
908c2ecf20Sopenharmony_ci	    get_interruptible_flag(dentry->d_inode));
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	orangefs_readdir_index_put(bufi);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (op_state_purged(op)) {
958c2ecf20Sopenharmony_ci		if (r == -EAGAIN) {
968c2ecf20Sopenharmony_ci			vfree(op->downcall.trailer_buf);
978c2ecf20Sopenharmony_ci			goto again;
988c2ecf20Sopenharmony_ci		} else if (r == -EIO) {
998c2ecf20Sopenharmony_ci			vfree(op->downcall.trailer_buf);
1008c2ecf20Sopenharmony_ci			od->error = r;
1018c2ecf20Sopenharmony_ci			return r;
1028c2ecf20Sopenharmony_ci		}
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (r < 0) {
1068c2ecf20Sopenharmony_ci		vfree(op->downcall.trailer_buf);
1078c2ecf20Sopenharmony_ci		od->error = r;
1088c2ecf20Sopenharmony_ci		return r;
1098c2ecf20Sopenharmony_ci	} else if (op->downcall.status) {
1108c2ecf20Sopenharmony_ci		vfree(op->downcall.trailer_buf);
1118c2ecf20Sopenharmony_ci		od->error = op->downcall.status;
1128c2ecf20Sopenharmony_ci		return op->downcall.status;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/*
1168c2ecf20Sopenharmony_ci	 * The maximum size is size per entry times the 512 entries plus
1178c2ecf20Sopenharmony_ci	 * the header.  This is well under the limit.
1188c2ecf20Sopenharmony_ci	 */
1198c2ecf20Sopenharmony_ci	if (op->downcall.trailer_size > PART_SIZE) {
1208c2ecf20Sopenharmony_ci		vfree(op->downcall.trailer_buf);
1218c2ecf20Sopenharmony_ci		od->error = -EIO;
1228c2ecf20Sopenharmony_ci		return -EIO;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	resp = (struct orangefs_readdir_response_s *)
1268c2ecf20Sopenharmony_ci	    op->downcall.trailer_buf;
1278c2ecf20Sopenharmony_ci	od->token = resp->token;
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic int parse_readdir(struct orangefs_dir *od,
1328c2ecf20Sopenharmony_ci    struct orangefs_kernel_op_s *op)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct orangefs_dir_part *part, *new;
1358c2ecf20Sopenharmony_ci	size_t count;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	count = 1;
1388c2ecf20Sopenharmony_ci	part = od->part;
1398c2ecf20Sopenharmony_ci	while (part) {
1408c2ecf20Sopenharmony_ci		count++;
1418c2ecf20Sopenharmony_ci		if (part->next)
1428c2ecf20Sopenharmony_ci			part = part->next;
1438c2ecf20Sopenharmony_ci		else
1448c2ecf20Sopenharmony_ci			break;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	new = (void *)op->downcall.trailer_buf;
1488c2ecf20Sopenharmony_ci	new->next = NULL;
1498c2ecf20Sopenharmony_ci	new->len = op->downcall.trailer_size -
1508c2ecf20Sopenharmony_ci	    sizeof(struct orangefs_readdir_response_s);
1518c2ecf20Sopenharmony_ci	if (!od->part)
1528c2ecf20Sopenharmony_ci		od->part = new;
1538c2ecf20Sopenharmony_ci	else
1548c2ecf20Sopenharmony_ci		part->next = new;
1558c2ecf20Sopenharmony_ci	count++;
1568c2ecf20Sopenharmony_ci	od->end = count << PART_SHIFT;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return 0;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int orangefs_dir_more(struct orangefs_inode_s *oi,
1628c2ecf20Sopenharmony_ci    struct orangefs_dir *od, struct dentry *dentry)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct orangefs_kernel_op_s *op;
1658c2ecf20Sopenharmony_ci	int r;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	op = op_alloc(ORANGEFS_VFS_OP_READDIR);
1688c2ecf20Sopenharmony_ci	if (!op) {
1698c2ecf20Sopenharmony_ci		od->error = -ENOMEM;
1708c2ecf20Sopenharmony_ci		return -ENOMEM;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci	r = do_readdir(oi, od, dentry, op);
1738c2ecf20Sopenharmony_ci	if (r) {
1748c2ecf20Sopenharmony_ci		od->error = r;
1758c2ecf20Sopenharmony_ci		goto out;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci	r = parse_readdir(od, op);
1788c2ecf20Sopenharmony_ci	if (r) {
1798c2ecf20Sopenharmony_ci		od->error = r;
1808c2ecf20Sopenharmony_ci		goto out;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	od->error = 0;
1848c2ecf20Sopenharmony_ciout:
1858c2ecf20Sopenharmony_ci	op_release(op);
1868c2ecf20Sopenharmony_ci	return od->error;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int fill_from_part(struct orangefs_dir_part *part,
1908c2ecf20Sopenharmony_ci    struct dir_context *ctx)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	const int offset = sizeof(struct orangefs_readdir_response_s);
1938c2ecf20Sopenharmony_ci	struct orangefs_khandle *khandle;
1948c2ecf20Sopenharmony_ci	__u32 *len, padlen;
1958c2ecf20Sopenharmony_ci	loff_t i;
1968c2ecf20Sopenharmony_ci	char *s;
1978c2ecf20Sopenharmony_ci	i = ctx->pos & ~PART_MASK;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/* The file offset from userspace is too large. */
2008c2ecf20Sopenharmony_ci	if (i > part->len)
2018c2ecf20Sopenharmony_ci		return 1;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/*
2048c2ecf20Sopenharmony_ci	 * If the seek pointer is positioned just before an entry it
2058c2ecf20Sopenharmony_ci	 * should find the next entry.
2068c2ecf20Sopenharmony_ci	 */
2078c2ecf20Sopenharmony_ci	if (i % 8)
2088c2ecf20Sopenharmony_ci		i = i + (8 - i%8)%8;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	while (i < part->len) {
2118c2ecf20Sopenharmony_ci		if (part->len < i + sizeof *len)
2128c2ecf20Sopenharmony_ci			break;
2138c2ecf20Sopenharmony_ci		len = (void *)part + offset + i;
2148c2ecf20Sopenharmony_ci		/*
2158c2ecf20Sopenharmony_ci		 * len is the size of the string itself.  padlen is the
2168c2ecf20Sopenharmony_ci		 * total size of the encoded string.
2178c2ecf20Sopenharmony_ci		 */
2188c2ecf20Sopenharmony_ci		padlen = (sizeof *len + *len + 1) +
2198c2ecf20Sopenharmony_ci		    (8 - (sizeof *len + *len + 1)%8)%8;
2208c2ecf20Sopenharmony_ci		if (part->len < i + padlen + sizeof *khandle)
2218c2ecf20Sopenharmony_ci			goto next;
2228c2ecf20Sopenharmony_ci		s = (void *)part + offset + i + sizeof *len;
2238c2ecf20Sopenharmony_ci		if (s[*len] != 0)
2248c2ecf20Sopenharmony_ci			goto next;
2258c2ecf20Sopenharmony_ci		khandle = (void *)part + offset + i + padlen;
2268c2ecf20Sopenharmony_ci		if (!dir_emit(ctx, s, *len,
2278c2ecf20Sopenharmony_ci		    orangefs_khandle_to_ino(khandle),
2288c2ecf20Sopenharmony_ci		    DT_UNKNOWN))
2298c2ecf20Sopenharmony_ci			return 0;
2308c2ecf20Sopenharmony_ci		i += padlen + sizeof *khandle;
2318c2ecf20Sopenharmony_ci		i = i + (8 - i%8)%8;
2328c2ecf20Sopenharmony_ci		BUG_ON(i > part->len);
2338c2ecf20Sopenharmony_ci		ctx->pos = (ctx->pos & PART_MASK) | i;
2348c2ecf20Sopenharmony_ci		continue;
2358c2ecf20Sopenharmony_cinext:
2368c2ecf20Sopenharmony_ci		i += 8;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	return 1;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int orangefs_dir_fill(struct orangefs_inode_s *oi,
2428c2ecf20Sopenharmony_ci    struct orangefs_dir *od, struct dentry *dentry,
2438c2ecf20Sopenharmony_ci    struct dir_context *ctx)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct orangefs_dir_part *part;
2468c2ecf20Sopenharmony_ci	size_t count;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	count = ((ctx->pos & PART_MASK) >> PART_SHIFT) - 1;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	part = od->part;
2518c2ecf20Sopenharmony_ci	while (part->next && count) {
2528c2ecf20Sopenharmony_ci		count--;
2538c2ecf20Sopenharmony_ci		part = part->next;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci	/* This means the userspace file offset is invalid. */
2568c2ecf20Sopenharmony_ci	if (count) {
2578c2ecf20Sopenharmony_ci		od->error = -EIO;
2588c2ecf20Sopenharmony_ci		return -EIO;
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	while (part && part->len) {
2628c2ecf20Sopenharmony_ci		int r;
2638c2ecf20Sopenharmony_ci		r = fill_from_part(part, ctx);
2648c2ecf20Sopenharmony_ci		if (r < 0) {
2658c2ecf20Sopenharmony_ci			od->error = r;
2668c2ecf20Sopenharmony_ci			return r;
2678c2ecf20Sopenharmony_ci		} else if (r == 0) {
2688c2ecf20Sopenharmony_ci			/* Userspace buffer is full. */
2698c2ecf20Sopenharmony_ci			break;
2708c2ecf20Sopenharmony_ci		} else {
2718c2ecf20Sopenharmony_ci			/*
2728c2ecf20Sopenharmony_ci			 * The part ran out of data.  Move to the next
2738c2ecf20Sopenharmony_ci			 * part. */
2748c2ecf20Sopenharmony_ci			ctx->pos = (ctx->pos & PART_MASK) +
2758c2ecf20Sopenharmony_ci			    (1 << PART_SHIFT);
2768c2ecf20Sopenharmony_ci			part = part->next;
2778c2ecf20Sopenharmony_ci		}
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	return 0;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic loff_t orangefs_dir_llseek(struct file *file, loff_t offset,
2838c2ecf20Sopenharmony_ci    int whence)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct orangefs_dir *od = file->private_data;
2868c2ecf20Sopenharmony_ci	/*
2878c2ecf20Sopenharmony_ci	 * Delete the stored data so userspace sees new directory
2888c2ecf20Sopenharmony_ci	 * entries.
2898c2ecf20Sopenharmony_ci	 */
2908c2ecf20Sopenharmony_ci	if (!whence && offset < od->end) {
2918c2ecf20Sopenharmony_ci		struct orangefs_dir_part *part = od->part;
2928c2ecf20Sopenharmony_ci		while (part) {
2938c2ecf20Sopenharmony_ci			struct orangefs_dir_part *next = part->next;
2948c2ecf20Sopenharmony_ci			vfree(part);
2958c2ecf20Sopenharmony_ci			part = next;
2968c2ecf20Sopenharmony_ci		}
2978c2ecf20Sopenharmony_ci		od->token = ORANGEFS_ITERATE_START;
2988c2ecf20Sopenharmony_ci		od->part = NULL;
2998c2ecf20Sopenharmony_ci		od->end = 1 << PART_SHIFT;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci	return default_llseek(file, offset, whence);
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int orangefs_dir_iterate(struct file *file,
3058c2ecf20Sopenharmony_ci    struct dir_context *ctx)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct orangefs_inode_s *oi;
3088c2ecf20Sopenharmony_ci	struct orangefs_dir *od;
3098c2ecf20Sopenharmony_ci	struct dentry *dentry;
3108c2ecf20Sopenharmony_ci	int r;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	dentry = file->f_path.dentry;
3138c2ecf20Sopenharmony_ci	oi = ORANGEFS_I(dentry->d_inode);
3148c2ecf20Sopenharmony_ci	od = file->private_data;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (od->error)
3178c2ecf20Sopenharmony_ci		return od->error;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (ctx->pos == 0) {
3208c2ecf20Sopenharmony_ci		if (!dir_emit_dot(file, ctx))
3218c2ecf20Sopenharmony_ci			return 0;
3228c2ecf20Sopenharmony_ci		ctx->pos++;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci	if (ctx->pos == 1) {
3258c2ecf20Sopenharmony_ci		if (!dir_emit_dotdot(file, ctx))
3268c2ecf20Sopenharmony_ci			return 0;
3278c2ecf20Sopenharmony_ci		ctx->pos = 1 << PART_SHIFT;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/*
3318c2ecf20Sopenharmony_ci	 * The seek position is in the first synthesized part but is not
3328c2ecf20Sopenharmony_ci	 * valid.
3338c2ecf20Sopenharmony_ci	 */
3348c2ecf20Sopenharmony_ci	if ((ctx->pos & PART_MASK) == 0)
3358c2ecf20Sopenharmony_ci		return -EIO;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	r = 0;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/*
3408c2ecf20Sopenharmony_ci	 * Must read more if the user has sought past what has been read
3418c2ecf20Sopenharmony_ci	 * so far.  Stop a user who has sought past the end.
3428c2ecf20Sopenharmony_ci	 */
3438c2ecf20Sopenharmony_ci	while (od->token != ORANGEFS_ITERATE_END &&
3448c2ecf20Sopenharmony_ci	    ctx->pos > od->end) {
3458c2ecf20Sopenharmony_ci		r = orangefs_dir_more(oi, od, dentry);
3468c2ecf20Sopenharmony_ci		if (r)
3478c2ecf20Sopenharmony_ci			return r;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci	if (od->token == ORANGEFS_ITERATE_END && ctx->pos > od->end)
3508c2ecf20Sopenharmony_ci		return -EIO;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* Then try to fill if there's any left in the buffer. */
3538c2ecf20Sopenharmony_ci	if (ctx->pos < od->end) {
3548c2ecf20Sopenharmony_ci		r = orangefs_dir_fill(oi, od, dentry, ctx);
3558c2ecf20Sopenharmony_ci		if (r)
3568c2ecf20Sopenharmony_ci			return r;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* Finally get some more and try to fill. */
3608c2ecf20Sopenharmony_ci	if (od->token != ORANGEFS_ITERATE_END) {
3618c2ecf20Sopenharmony_ci		r = orangefs_dir_more(oi, od, dentry);
3628c2ecf20Sopenharmony_ci		if (r)
3638c2ecf20Sopenharmony_ci			return r;
3648c2ecf20Sopenharmony_ci		r = orangefs_dir_fill(oi, od, dentry, ctx);
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	return r;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int orangefs_dir_open(struct inode *inode, struct file *file)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct orangefs_dir *od;
3738c2ecf20Sopenharmony_ci	file->private_data = kmalloc(sizeof(struct orangefs_dir),
3748c2ecf20Sopenharmony_ci	    GFP_KERNEL);
3758c2ecf20Sopenharmony_ci	if (!file->private_data)
3768c2ecf20Sopenharmony_ci		return -ENOMEM;
3778c2ecf20Sopenharmony_ci	od = file->private_data;
3788c2ecf20Sopenharmony_ci	od->token = ORANGEFS_ITERATE_START;
3798c2ecf20Sopenharmony_ci	od->part = NULL;
3808c2ecf20Sopenharmony_ci	od->end = 1 << PART_SHIFT;
3818c2ecf20Sopenharmony_ci	od->error = 0;
3828c2ecf20Sopenharmony_ci	return 0;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic int orangefs_dir_release(struct inode *inode, struct file *file)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	struct orangefs_dir *od = file->private_data;
3888c2ecf20Sopenharmony_ci	struct orangefs_dir_part *part = od->part;
3898c2ecf20Sopenharmony_ci	while (part) {
3908c2ecf20Sopenharmony_ci		struct orangefs_dir_part *next = part->next;
3918c2ecf20Sopenharmony_ci		vfree(part);
3928c2ecf20Sopenharmony_ci		part = next;
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci	kfree(od);
3958c2ecf20Sopenharmony_ci	return 0;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ciconst struct file_operations orangefs_dir_operations = {
3998c2ecf20Sopenharmony_ci	.llseek = orangefs_dir_llseek,
4008c2ecf20Sopenharmony_ci	.read = generic_read_dir,
4018c2ecf20Sopenharmony_ci	.iterate = orangefs_dir_iterate,
4028c2ecf20Sopenharmony_ci	.open = orangefs_dir_open,
4038c2ecf20Sopenharmony_ci	.release = orangefs_dir_release
4048c2ecf20Sopenharmony_ci};
405