xref: /openbmc/linux/fs/orangefs/dir.c (revision ee3b8d37)
15db11c21SMike Marshall /*
25db11c21SMike Marshall  * (C) 2001 Clemson University and The University of Chicago
35db11c21SMike Marshall  *
45db11c21SMike Marshall  * See COPYING in top-level directory.
55db11c21SMike Marshall  */
65db11c21SMike Marshall 
75db11c21SMike Marshall #include "protocol.h"
8575e9461SMike Marshall #include "orangefs-kernel.h"
9575e9461SMike Marshall #include "orangefs-bufmap.h"
105db11c21SMike Marshall 
115db11c21SMike Marshall struct readdir_handle_s {
128bb8aefdSYi Liu 	struct orangefs_readdir_response_s readdir_response;
135db11c21SMike Marshall 	void *dents_buf;
145db11c21SMike Marshall };
155db11c21SMike Marshall 
165db11c21SMike Marshall /*
171808f8ccSMike Marshall  * decode routine used by kmod to deal with the blob sent from
181808f8ccSMike Marshall  * userspace for readdirs. The blob contains zero or more of these
191808f8ccSMike Marshall  * sub-blobs:
201808f8ccSMike Marshall  *   __u32 - represents length of the character string that follows.
211808f8ccSMike Marshall  *   string - between 1 and ORANGEFS_NAME_MAX bytes long.
221808f8ccSMike Marshall  *   padding - (if needed) to cause the __u32 plus the string to be
231808f8ccSMike Marshall  *             eight byte aligned.
241808f8ccSMike Marshall  *   khandle - sizeof(khandle) bytes.
255db11c21SMike Marshall  */
268092895fSAl Viro static long decode_dirents(char *ptr, size_t size,
278bb8aefdSYi Liu                            struct orangefs_readdir_response_s *readdir)
285db11c21SMike Marshall {
295db11c21SMike Marshall 	int i;
308bb8aefdSYi Liu 	struct orangefs_readdir_response_s *rd =
318bb8aefdSYi Liu 		(struct orangefs_readdir_response_s *) ptr;
325db11c21SMike Marshall 	char *buf = ptr;
331808f8ccSMike Marshall 	int khandle_size = sizeof(struct orangefs_khandle);
341808f8ccSMike Marshall 	size_t offset = offsetof(struct orangefs_readdir_response_s,
351808f8ccSMike Marshall 				dirent_array);
361808f8ccSMike Marshall 	/* 8 reflects eight byte alignment */
371808f8ccSMike Marshall 	int smallest_blob = khandle_size + 8;
381808f8ccSMike Marshall 	__u32 len;
391808f8ccSMike Marshall 	int aligned_len;
401808f8ccSMike Marshall 	int sizeof_u32 = sizeof(__u32);
411808f8ccSMike Marshall 	long ret;
425db11c21SMike Marshall 
431808f8ccSMike Marshall 	gossip_debug(GOSSIP_DIR_DEBUG, "%s: size:%zu:\n", __func__, size);
441808f8ccSMike Marshall 
451808f8ccSMike Marshall 	/* size is = offset on empty dirs, > offset on non-empty dirs... */
461808f8ccSMike Marshall 	if (size < offset) {
471808f8ccSMike Marshall 		gossip_err("%s: size:%zu: offset:%zu:\n",
481808f8ccSMike Marshall 			   __func__,
491808f8ccSMike Marshall 			   size,
501808f8ccSMike Marshall 			   offset);
511808f8ccSMike Marshall 		ret = -EINVAL;
521808f8ccSMike Marshall 		goto out;
531808f8ccSMike Marshall 	}
541808f8ccSMike Marshall 
551808f8ccSMike Marshall         if ((size == offset) && (readdir->orangefs_dirent_outcount != 0)) {
561808f8ccSMike Marshall 		gossip_err("%s: size:%zu: dirent_outcount:%d:\n",
571808f8ccSMike Marshall 			   __func__,
581808f8ccSMike Marshall 			   size,
591808f8ccSMike Marshall 			   readdir->orangefs_dirent_outcount);
601808f8ccSMike Marshall 		ret = -EINVAL;
611808f8ccSMike Marshall 		goto out;
621808f8ccSMike Marshall 	}
638092895fSAl Viro 
645db11c21SMike Marshall 	readdir->token = rd->token;
658bb8aefdSYi Liu 	readdir->orangefs_dirent_outcount = rd->orangefs_dirent_outcount;
668bb8aefdSYi Liu 	readdir->dirent_array = kcalloc(readdir->orangefs_dirent_outcount,
675db11c21SMike Marshall 					sizeof(*readdir->dirent_array),
685db11c21SMike Marshall 					GFP_KERNEL);
691808f8ccSMike Marshall 	if (readdir->dirent_array == NULL) {
701808f8ccSMike Marshall 		gossip_err("%s: kcalloc failed.\n", __func__);
711808f8ccSMike Marshall 		ret = -ENOMEM;
721808f8ccSMike Marshall 		goto out;
731808f8ccSMike Marshall 	}
748092895fSAl Viro 
751808f8ccSMike Marshall 	buf += offset;
761808f8ccSMike Marshall 	size -= offset;
778092895fSAl Viro 
788bb8aefdSYi Liu 	for (i = 0; i < readdir->orangefs_dirent_outcount; i++) {
791808f8ccSMike Marshall 		if (size < smallest_blob) {
801808f8ccSMike Marshall 			gossip_err("%s: size:%zu: smallest_blob:%d:\n",
811808f8ccSMike Marshall 				   __func__,
821808f8ccSMike Marshall 				   size,
831808f8ccSMike Marshall 				   smallest_blob);
841808f8ccSMike Marshall 			ret = -EINVAL;
851808f8ccSMike Marshall 			goto free;
861808f8ccSMike Marshall 		}
878092895fSAl Viro 
888092895fSAl Viro 		len = *(__u32 *)buf;
891808f8ccSMike Marshall 		if ((len < 1) || (len > ORANGEFS_NAME_MAX)) {
901808f8ccSMike Marshall 			gossip_err("%s: len:%d:\n", __func__, len);
911808f8ccSMike Marshall 			ret = -EINVAL;
921808f8ccSMike Marshall 			goto free;
931808f8ccSMike Marshall 		}
948092895fSAl Viro 
951808f8ccSMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
961808f8ccSMike Marshall 			     "%s: size:%zu: len:%d:\n",
971808f8ccSMike Marshall 			     __func__,
981808f8ccSMike Marshall 			     size,
991808f8ccSMike Marshall 			     len);
1001808f8ccSMike Marshall 
1011808f8ccSMike Marshall 		readdir->dirent_array[i].d_name = buf + sizeof_u32;
1029be68b08SAl Viro 		readdir->dirent_array[i].d_length = len;
1038092895fSAl Viro 
1047d221485SMartin Brandenburg 		/*
1051808f8ccSMike Marshall 		 * Calculate "aligned" length of this string and its
1061808f8ccSMike Marshall 		 * associated __u32 descriptor.
1077d221485SMartin Brandenburg 		 */
1081808f8ccSMike Marshall 		aligned_len = ((sizeof_u32 + len + 1) + 7) & ~7;
1091808f8ccSMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
1101808f8ccSMike Marshall 			     "%s: aligned_len:%d:\n",
1111808f8ccSMike Marshall 			     __func__,
1121808f8ccSMike Marshall 			     aligned_len);
1138092895fSAl Viro 
1141808f8ccSMike Marshall 		/*
1151808f8ccSMike Marshall 		 * The end of the blob should coincide with the end
1161808f8ccSMike Marshall 		 * of the last sub-blob.
1171808f8ccSMike Marshall 		 */
1181808f8ccSMike Marshall 		if (size < aligned_len + khandle_size) {
1191808f8ccSMike Marshall 			gossip_err("%s: ran off the end of the blob.\n",
1201808f8ccSMike Marshall 				   __func__);
1211808f8ccSMike Marshall 			ret = -EINVAL;
1221808f8ccSMike Marshall 			goto free;
1231808f8ccSMike Marshall 		}
1241808f8ccSMike Marshall 		size -= aligned_len + khandle_size;
1251808f8ccSMike Marshall 
1261808f8ccSMike Marshall 		buf += aligned_len;
1278092895fSAl Viro 
1285db11c21SMike Marshall 		readdir->dirent_array[i].khandle =
1298bb8aefdSYi Liu 			*(struct orangefs_khandle *) buf;
1301808f8ccSMike Marshall 		buf += khandle_size;
1315db11c21SMike Marshall 	}
1321808f8ccSMike Marshall 	ret = buf - ptr;
1331808f8ccSMike Marshall 	gossip_debug(GOSSIP_DIR_DEBUG, "%s: returning:%ld:\n", __func__, ret);
1341808f8ccSMike Marshall 	goto out;
1351808f8ccSMike Marshall 
1361808f8ccSMike Marshall free:
1378092895fSAl Viro 	kfree(readdir->dirent_array);
1388092895fSAl Viro 	readdir->dirent_array = NULL;
1391808f8ccSMike Marshall 
1401808f8ccSMike Marshall out:
1411808f8ccSMike Marshall 	return ret;
1425db11c21SMike Marshall }
1435db11c21SMike Marshall 
1445db11c21SMike Marshall static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
145ee3b8d37SMartin Brandenburg 				size_t size)
1465db11c21SMike Marshall {
1475db11c21SMike Marshall 	long ret;
1485db11c21SMike Marshall 
1495db11c21SMike Marshall 	if (buf == NULL) {
1505db11c21SMike Marshall 		gossip_err
1515db11c21SMike Marshall 		    ("Invalid NULL buffer specified in readdir_handle_ctor\n");
1525db11c21SMike Marshall 		return -ENOMEM;
1535db11c21SMike Marshall 	}
1545db11c21SMike Marshall 	rhandle->dents_buf = buf;
1558092895fSAl Viro 	ret = decode_dirents(buf, size, &rhandle->readdir_response);
1565db11c21SMike Marshall 	if (ret < 0) {
1575db11c21SMike Marshall 		gossip_err("Could not decode readdir from buffer %ld\n", ret);
1585db11c21SMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf);
1595db11c21SMike Marshall 		vfree(buf);
1605db11c21SMike Marshall 		rhandle->dents_buf = NULL;
1615db11c21SMike Marshall 	}
1625db11c21SMike Marshall 	return ret;
1635db11c21SMike Marshall }
1645db11c21SMike Marshall 
16582d37f19SAl Viro static void readdir_handle_dtor(struct readdir_handle_s *rhandle)
1665db11c21SMike Marshall {
1675db11c21SMike Marshall 	if (rhandle == NULL)
1685db11c21SMike Marshall 		return;
1695db11c21SMike Marshall 
1705db11c21SMike Marshall 	/* kfree(NULL) is safe */
1715db11c21SMike Marshall 	kfree(rhandle->readdir_response.dirent_array);
1725db11c21SMike Marshall 	rhandle->readdir_response.dirent_array = NULL;
1735db11c21SMike Marshall 
1745db11c21SMike Marshall 	if (rhandle->dents_buf) {
1755db11c21SMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n",
1765db11c21SMike Marshall 			     rhandle->dents_buf);
1775db11c21SMike Marshall 		vfree(rhandle->dents_buf);
1785db11c21SMike Marshall 		rhandle->dents_buf = NULL;
1795db11c21SMike Marshall 	}
1805db11c21SMike Marshall }
1815db11c21SMike Marshall 
1825db11c21SMike Marshall /*
1835db11c21SMike Marshall  * Read directory entries from an instance of an open directory.
1845db11c21SMike Marshall  */
1858bb8aefdSYi Liu static int orangefs_readdir(struct file *file, struct dir_context *ctx)
1865db11c21SMike Marshall {
1878bb8aefdSYi Liu 	struct orangefs_bufmap *bufmap = NULL;
1885db11c21SMike Marshall 	int ret = 0;
1895db11c21SMike Marshall 	int buffer_index;
19088309aaeSMike Marshall 	/*
19188309aaeSMike Marshall 	 * ptoken supports Orangefs' distributed directory logic, added
19288309aaeSMike Marshall 	 * in 2.9.2.
19388309aaeSMike Marshall 	 */
1945db11c21SMike Marshall 	__u64 *ptoken = file->private_data;
1955db11c21SMike Marshall 	__u64 pos = 0;
1965db11c21SMike Marshall 	ino_t ino = 0;
1975db11c21SMike Marshall 	struct dentry *dentry = file->f_path.dentry;
1988bb8aefdSYi Liu 	struct orangefs_kernel_op_s *new_op = NULL;
1998bb8aefdSYi Liu 	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode);
2005db11c21SMike Marshall 	int buffer_full = 0;
2015db11c21SMike Marshall 	struct readdir_handle_s rhandle;
2025db11c21SMike Marshall 	int i = 0;
2035db11c21SMike Marshall 	int len = 0;
2045db11c21SMike Marshall 	ino_t current_ino = 0;
2055db11c21SMike Marshall 	char *current_entry = NULL;
2065db11c21SMike Marshall 	long bytes_decoded;
2075db11c21SMike Marshall 
20888309aaeSMike Marshall 	gossip_debug(GOSSIP_DIR_DEBUG,
20988309aaeSMike Marshall 		     "%s: ctx->pos:%lld, ptoken = %llu\n",
2105db11c21SMike Marshall 		     __func__,
2115db11c21SMike Marshall 		     lld(ctx->pos),
2125db11c21SMike Marshall 		     llu(*ptoken));
2135db11c21SMike Marshall 
2145db11c21SMike Marshall 	pos = (__u64) ctx->pos;
2155db11c21SMike Marshall 
2165db11c21SMike Marshall 	/* are we done? */
2178bb8aefdSYi Liu 	if (pos == ORANGEFS_READDIR_END) {
2185db11c21SMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
2195db11c21SMike Marshall 			     "Skipping to termination path\n");
2205db11c21SMike Marshall 		return 0;
2215db11c21SMike Marshall 	}
2225db11c21SMike Marshall 
2235db11c21SMike Marshall 	gossip_debug(GOSSIP_DIR_DEBUG,
2248bb8aefdSYi Liu 		     "orangefs_readdir called on %s (pos=%llu)\n",
2255db11c21SMike Marshall 		     dentry->d_name.name, llu(pos));
2265db11c21SMike Marshall 
2275db11c21SMike Marshall 	rhandle.dents_buf = NULL;
2285db11c21SMike Marshall 	memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response));
2295db11c21SMike Marshall 
2308bb8aefdSYi Liu 	new_op = op_alloc(ORANGEFS_VFS_OP_READDIR);
2315db11c21SMike Marshall 	if (!new_op)
2325db11c21SMike Marshall 		return -ENOMEM;
2335db11c21SMike Marshall 
234ee3b8d37SMartin Brandenburg 	/*
235ee3b8d37SMartin Brandenburg 	 * Only the indices are shared. No memory is actually shared, but the
236ee3b8d37SMartin Brandenburg 	 * mechanism is used.
237ee3b8d37SMartin Brandenburg 	 */
2385db11c21SMike Marshall 	new_op->uses_shared_memory = 1;
2398bb8aefdSYi Liu 	new_op->upcall.req.readdir.refn = orangefs_inode->refn;
2407d221485SMartin Brandenburg 	new_op->upcall.req.readdir.max_dirent_count =
2417d221485SMartin Brandenburg 	    ORANGEFS_MAX_DIRENT_COUNT_READDIR;
2425db11c21SMike Marshall 
2435db11c21SMike Marshall 	gossip_debug(GOSSIP_DIR_DEBUG,
2445db11c21SMike Marshall 		     "%s: upcall.req.readdir.refn.khandle: %pU\n",
2455db11c21SMike Marshall 		     __func__,
2465db11c21SMike Marshall 		     &new_op->upcall.req.readdir.refn.khandle);
2475db11c21SMike Marshall 
2485db11c21SMike Marshall 	new_op->upcall.req.readdir.token = *ptoken;
2495db11c21SMike Marshall 
2505db11c21SMike Marshall get_new_buffer_index:
2517d221485SMartin Brandenburg 	ret = orangefs_readdir_index_get(&bufmap, &buffer_index);
2525db11c21SMike Marshall 	if (ret < 0) {
2537d221485SMartin Brandenburg 		gossip_lerr("orangefs_readdir: orangefs_readdir_index_get() failure (%d)\n",
2545db11c21SMike Marshall 			    ret);
2555db11c21SMike Marshall 		goto out_free_op;
2565db11c21SMike Marshall 	}
2575db11c21SMike Marshall 	new_op->upcall.req.readdir.buf_index = buffer_index;
2585db11c21SMike Marshall 
2595db11c21SMike Marshall 	ret = service_operation(new_op,
2608bb8aefdSYi Liu 				"orangefs_readdir",
2615db11c21SMike Marshall 				get_interruptible_flag(dentry->d_inode));
2625db11c21SMike Marshall 
2635db11c21SMike Marshall 	gossip_debug(GOSSIP_DIR_DEBUG,
2645db11c21SMike Marshall 		     "Readdir downcall status is %d.  ret:%d\n",
2655db11c21SMike Marshall 		     new_op->downcall.status,
2665db11c21SMike Marshall 		     ret);
2675db11c21SMike Marshall 
268ee3b8d37SMartin Brandenburg 	orangefs_readdir_index_put(buffer_index);
269ee3b8d37SMartin Brandenburg 
2705db11c21SMike Marshall 	if (ret == -EAGAIN && op_state_purged(new_op)) {
271ee3b8d37SMartin Brandenburg 		/* Client-core indices are invalid after it restarted. */
2725db11c21SMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
2735db11c21SMike Marshall 			"%s: Getting new buffer_index for retry of readdir..\n",
2745db11c21SMike Marshall 			 __func__);
2755db11c21SMike Marshall 		goto get_new_buffer_index;
2765db11c21SMike Marshall 	}
2775db11c21SMike Marshall 
2785db11c21SMike Marshall 	if (ret == -EIO && op_state_purged(new_op)) {
2795db11c21SMike Marshall 		gossip_err("%s: Client is down. Aborting readdir call.\n",
2805db11c21SMike Marshall 			__func__);
2815db11c21SMike Marshall 		goto out_free_op;
2825db11c21SMike Marshall 	}
2835db11c21SMike Marshall 
2845db11c21SMike Marshall 	if (ret < 0 || new_op->downcall.status != 0) {
2855db11c21SMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
2865db11c21SMike Marshall 			     "Readdir request failed.  Status:%d\n",
2875db11c21SMike Marshall 			     new_op->downcall.status);
2885db11c21SMike Marshall 		if (ret >= 0)
2895db11c21SMike Marshall 			ret = new_op->downcall.status;
2905db11c21SMike Marshall 		goto out_free_op;
2915db11c21SMike Marshall 	}
2925db11c21SMike Marshall 
2935db11c21SMike Marshall 	bytes_decoded =
2945db11c21SMike Marshall 		readdir_handle_ctor(&rhandle,
2955db11c21SMike Marshall 				    new_op->downcall.trailer_buf,
296ee3b8d37SMartin Brandenburg 				    new_op->downcall.trailer_size);
2975db11c21SMike Marshall 	if (bytes_decoded < 0) {
2988bb8aefdSYi Liu 		gossip_err("orangefs_readdir: Could not decode trailer buffer into a readdir response %d\n",
2995db11c21SMike Marshall 			ret);
3005db11c21SMike Marshall 		ret = bytes_decoded;
3015db11c21SMike Marshall 		goto out_free_op;
3025db11c21SMike Marshall 	}
3035db11c21SMike Marshall 
3045db11c21SMike Marshall 	if (bytes_decoded != new_op->downcall.trailer_size) {
3058bb8aefdSYi Liu 		gossip_err("orangefs_readdir: # bytes decoded (%ld) "
30688309aaeSMike Marshall 			   "!= trailer size (%ld)\n",
3075db11c21SMike Marshall 			   bytes_decoded,
3085db11c21SMike Marshall 			   (long)new_op->downcall.trailer_size);
3095db11c21SMike Marshall 		ret = -EINVAL;
3105db11c21SMike Marshall 		goto out_destroy_handle;
3115db11c21SMike Marshall 	}
3125db11c21SMike Marshall 
31388309aaeSMike Marshall 	/*
3148bb8aefdSYi Liu 	 *  orangefs doesn't actually store dot and dot-dot, but
31588309aaeSMike Marshall 	 *  we need to have them represented.
31688309aaeSMike Marshall 	 */
3175db11c21SMike Marshall 	if (pos == 0) {
3185db11c21SMike Marshall 		ino = get_ino_from_khandle(dentry->d_inode);
3195db11c21SMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
3205db11c21SMike Marshall 			     "%s: calling dir_emit of \".\" with pos = %llu\n",
3215db11c21SMike Marshall 			     __func__,
3225db11c21SMike Marshall 			     llu(pos));
3235db11c21SMike Marshall 		ret = dir_emit(ctx, ".", 1, ino, DT_DIR);
32488309aaeSMike Marshall 		pos += 1;
3255db11c21SMike Marshall 	}
3265db11c21SMike Marshall 
3275db11c21SMike Marshall 	if (pos == 1) {
3285db11c21SMike Marshall 		ino = get_parent_ino_from_dentry(dentry);
3295db11c21SMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
3305db11c21SMike Marshall 			     "%s: calling dir_emit of \"..\" with pos = %llu\n",
3315db11c21SMike Marshall 			     __func__,
3325db11c21SMike Marshall 			     llu(pos));
3335db11c21SMike Marshall 		ret = dir_emit(ctx, "..", 2, ino, DT_DIR);
33488309aaeSMike Marshall 		pos += 1;
3355db11c21SMike Marshall 	}
3365db11c21SMike Marshall 
33788309aaeSMike Marshall 	/*
3388bb8aefdSYi Liu 	 * we stored ORANGEFS_ITERATE_NEXT in ctx->pos last time around
33988309aaeSMike Marshall 	 * to prevent "finding" dot and dot-dot on any iteration
34088309aaeSMike Marshall 	 * other than the first.
34188309aaeSMike Marshall 	 */
3428bb8aefdSYi Liu 	if (ctx->pos == ORANGEFS_ITERATE_NEXT)
34388309aaeSMike Marshall 		ctx->pos = 0;
34488309aaeSMike Marshall 
34588309aaeSMike Marshall 	for (i = ctx->pos;
3468bb8aefdSYi Liu 	     i < rhandle.readdir_response.orangefs_dirent_outcount;
34788309aaeSMike Marshall 	     i++) {
3485db11c21SMike Marshall 		len = rhandle.readdir_response.dirent_array[i].d_length;
3495db11c21SMike Marshall 		current_entry = rhandle.readdir_response.dirent_array[i].d_name;
3508bb8aefdSYi Liu 		current_ino = orangefs_khandle_to_ino(
3515db11c21SMike Marshall 			&(rhandle.readdir_response.dirent_array[i].khandle));
3525db11c21SMike Marshall 
3535db11c21SMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
35488309aaeSMike Marshall 			     "calling dir_emit for %s with len %d"
35588309aaeSMike Marshall 			     ", ctx->pos %ld\n",
3565db11c21SMike Marshall 			     current_entry,
3575db11c21SMike Marshall 			     len,
35888309aaeSMike Marshall 			     (unsigned long)ctx->pos);
35988309aaeSMike Marshall 		/*
36088309aaeSMike Marshall 		 * type is unknown. We don't return object type
36188309aaeSMike Marshall 		 * in the dirent_array. This leaves getdents
36288309aaeSMike Marshall 		 * clueless about type.
36388309aaeSMike Marshall 		 */
3645db11c21SMike Marshall 		ret =
3655db11c21SMike Marshall 		    dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN);
36688309aaeSMike Marshall 		if (!ret)
36788309aaeSMike Marshall 			break;
3685db11c21SMike Marshall 		ctx->pos++;
36988309aaeSMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
3705db11c21SMike Marshall 			      "%s: ctx->pos:%lld\n",
3715db11c21SMike Marshall 			      __func__,
3725db11c21SMike Marshall 			      lld(ctx->pos));
3735db11c21SMike Marshall 
3745db11c21SMike Marshall 	}
3755db11c21SMike Marshall 
37688309aaeSMike Marshall 	/*
37788309aaeSMike Marshall 	 * we ran all the way through the last batch, set up for
37888309aaeSMike Marshall 	 * getting another batch...
37988309aaeSMike Marshall 	 */
38088309aaeSMike Marshall 	if (ret) {
3815db11c21SMike Marshall 		*ptoken = rhandle.readdir_response.token;
3828bb8aefdSYi Liu 		ctx->pos = ORANGEFS_ITERATE_NEXT;
3835db11c21SMike Marshall 	}
3845db11c21SMike Marshall 
3855db11c21SMike Marshall 	/*
3865db11c21SMike Marshall 	 * Did we hit the end of the directory?
3875db11c21SMike Marshall 	 */
3888bb8aefdSYi Liu 	if (rhandle.readdir_response.token == ORANGEFS_READDIR_END &&
3895db11c21SMike Marshall 	    !buffer_full) {
39088309aaeSMike Marshall 		gossip_debug(GOSSIP_DIR_DEBUG,
3918bb8aefdSYi Liu 		"End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
3928bb8aefdSYi Liu 		ctx->pos = ORANGEFS_READDIR_END;
3935db11c21SMike Marshall 	}
3945db11c21SMike Marshall 
3955db11c21SMike Marshall out_destroy_handle:
39682d37f19SAl Viro 	readdir_handle_dtor(&rhandle);
3975db11c21SMike Marshall out_free_op:
3985db11c21SMike Marshall 	op_release(new_op);
3998bb8aefdSYi Liu 	gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret);
4005db11c21SMike Marshall 	return ret;
4015db11c21SMike Marshall }
4025db11c21SMike Marshall 
4038bb8aefdSYi Liu static int orangefs_dir_open(struct inode *inode, struct file *file)
4045db11c21SMike Marshall {
4055db11c21SMike Marshall 	__u64 *ptoken;
4065db11c21SMike Marshall 
4075db11c21SMike Marshall 	file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL);
4085db11c21SMike Marshall 	if (!file->private_data)
4095db11c21SMike Marshall 		return -ENOMEM;
4105db11c21SMike Marshall 
4115db11c21SMike Marshall 	ptoken = file->private_data;
4128bb8aefdSYi Liu 	*ptoken = ORANGEFS_READDIR_START;
4135db11c21SMike Marshall 	return 0;
4145db11c21SMike Marshall }
4155db11c21SMike Marshall 
4168bb8aefdSYi Liu static int orangefs_dir_release(struct inode *inode, struct file *file)
4175db11c21SMike Marshall {
4188bb8aefdSYi Liu 	orangefs_flush_inode(inode);
4195db11c21SMike Marshall 	kfree(file->private_data);
4205db11c21SMike Marshall 	return 0;
4215db11c21SMike Marshall }
4225db11c21SMike Marshall 
4238bb8aefdSYi Liu /** ORANGEFS implementation of VFS directory operations */
4248bb8aefdSYi Liu const struct file_operations orangefs_dir_operations = {
4255db11c21SMike Marshall 	.read = generic_read_dir,
4268bb8aefdSYi Liu 	.iterate = orangefs_readdir,
4278bb8aefdSYi Liu 	.open = orangefs_dir_open,
4288bb8aefdSYi Liu 	.release = orangefs_dir_release,
4295db11c21SMike Marshall };
430