2 * (C) 2001 Clemson University and The University of Chicago
4 * See COPYING in top-level directory.
8 #include "orangefs-kernel.h"
9 #include "orangefs-bufmap.h"
11 struct readdir_handle_s {
12 struct orangefs_readdir_response_s readdir_response;
17 * decode routine used by kmod to deal with the blob sent from
18 * userspace for readdirs. The blob contains zero or more of these
20 * __u32 - represents length of the character string that follows.
21 * string - between 1 and ORANGEFS_NAME_MAX bytes long.
22 * padding - (if needed) to cause the __u32 plus the string to be
24 * khandle - sizeof(khandle) bytes.
26 static long decode_dirents(char *ptr, size_t size,
27 struct orangefs_readdir_response_s *readdir)
30 struct orangefs_readdir_response_s *rd =
31 (struct orangefs_readdir_response_s *) ptr;
33 int khandle_size = sizeof(struct orangefs_khandle);
34 size_t offset = offsetof(struct orangefs_readdir_response_s,
36 /* 8 reflects eight byte alignment */
37 int smallest_blob = khandle_size + 8;
40 int sizeof_u32 = sizeof(__u32);
43 gossip_debug(GOSSIP_DIR_DEBUG, "%s: size:%zu:\n", __func__, size);
45 /* size is = offset on empty dirs, > offset on non-empty dirs... */
47 gossip_err("%s: size:%zu: offset:%zu:\n",
55 if ((size == offset) && (readdir->orangefs_dirent_outcount != 0)) {
56 gossip_err("%s: size:%zu: dirent_outcount:%d:\n",
59 readdir->orangefs_dirent_outcount);
64 readdir->token = rd->token;
65 readdir->orangefs_dirent_outcount = rd->orangefs_dirent_outcount;
66 readdir->dirent_array = kcalloc(readdir->orangefs_dirent_outcount,
67 sizeof(*readdir->dirent_array),
69 if (readdir->dirent_array == NULL) {
70 gossip_err("%s: kcalloc failed.\n", __func__);
78 for (i = 0; i < readdir->orangefs_dirent_outcount; i++) {
79 if (size < smallest_blob) {
80 gossip_err("%s: size:%zu: smallest_blob:%d:\n",
89 if ((len < 1) || (len > ORANGEFS_NAME_MAX)) {
90 gossip_err("%s: len:%d:\n", __func__, len);
95 gossip_debug(GOSSIP_DIR_DEBUG,
96 "%s: size:%zu: len:%d:\n",
101 readdir->dirent_array[i].d_name = buf + sizeof_u32;
102 readdir->dirent_array[i].d_length = len;
105 * Calculate "aligned" length of this string and its
106 * associated __u32 descriptor.
108 aligned_len = ((sizeof_u32 + len + 1) + 7) & ~7;
109 gossip_debug(GOSSIP_DIR_DEBUG,
110 "%s: aligned_len:%d:\n",
115 * The end of the blob should coincide with the end
116 * of the last sub-blob.
118 if (size < aligned_len + khandle_size) {
119 gossip_err("%s: ran off the end of the blob.\n",
124 size -= aligned_len + khandle_size;
128 readdir->dirent_array[i].khandle =
129 *(struct orangefs_khandle *) buf;
133 gossip_debug(GOSSIP_DIR_DEBUG, "%s: returning:%ld:\n", __func__, ret);
137 kfree(readdir->dirent_array);
138 readdir->dirent_array = NULL;
144 static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
151 ("Invalid NULL buffer specified in readdir_handle_ctor\n");
154 rhandle->dents_buf = buf;
155 ret = decode_dirents(buf, size, &rhandle->readdir_response);
157 gossip_err("Could not decode readdir from buffer %ld\n", ret);
158 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf);
160 rhandle->dents_buf = NULL;
165 static void readdir_handle_dtor(struct readdir_handle_s *rhandle)
170 /* kfree(NULL) is safe */
171 kfree(rhandle->readdir_response.dirent_array);
172 rhandle->readdir_response.dirent_array = NULL;
174 if (rhandle->dents_buf) {
175 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n",
177 vfree(rhandle->dents_buf);
178 rhandle->dents_buf = NULL;
183 * Read directory entries from an instance of an open directory.
185 static int orangefs_readdir(struct file *file, struct dir_context *ctx)
187 struct orangefs_bufmap *bufmap = NULL;
191 * ptoken supports Orangefs' distributed directory logic, added
194 __u64 *ptoken = file->private_data;
197 struct dentry *dentry = file->f_path.dentry;
198 struct orangefs_kernel_op_s *new_op = NULL;
199 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode);
201 struct readdir_handle_s rhandle;
204 ino_t current_ino = 0;
205 char *current_entry = NULL;
208 gossip_debug(GOSSIP_DIR_DEBUG,
209 "%s: ctx->pos:%lld, ptoken = %llu\n",
214 pos = (__u64) ctx->pos;
217 if (pos == ORANGEFS_READDIR_END) {
218 gossip_debug(GOSSIP_DIR_DEBUG,
219 "Skipping to termination path\n");
223 gossip_debug(GOSSIP_DIR_DEBUG,
224 "orangefs_readdir called on %s (pos=%llu)\n",
225 dentry->d_name.name, llu(pos));
227 rhandle.dents_buf = NULL;
228 memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response));
230 new_op = op_alloc(ORANGEFS_VFS_OP_READDIR);
235 * Only the indices are shared. No memory is actually shared, but the
238 new_op->uses_shared_memory = 1;
239 new_op->upcall.req.readdir.refn = orangefs_inode->refn;
240 new_op->upcall.req.readdir.max_dirent_count =
241 ORANGEFS_MAX_DIRENT_COUNT_READDIR;
243 gossip_debug(GOSSIP_DIR_DEBUG,
244 "%s: upcall.req.readdir.refn.khandle: %pU\n",
246 &new_op->upcall.req.readdir.refn.khandle);
248 new_op->upcall.req.readdir.token = *ptoken;
250 get_new_buffer_index:
251 ret = orangefs_readdir_index_get(&bufmap, &buffer_index);
253 gossip_lerr("orangefs_readdir: orangefs_readdir_index_get() failure (%d)\n",
257 new_op->upcall.req.readdir.buf_index = buffer_index;
259 ret = service_operation(new_op,
261 get_interruptible_flag(dentry->d_inode));
263 gossip_debug(GOSSIP_DIR_DEBUG,
264 "Readdir downcall status is %d. ret:%d\n",
265 new_op->downcall.status,
268 orangefs_readdir_index_put(buffer_index);
270 if (ret == -EAGAIN && op_state_purged(new_op)) {
271 /* Client-core indices are invalid after it restarted. */
272 gossip_debug(GOSSIP_DIR_DEBUG,
273 "%s: Getting new buffer_index for retry of readdir..\n",
275 goto get_new_buffer_index;
278 if (ret == -EIO && op_state_purged(new_op)) {
279 gossip_err("%s: Client is down. Aborting readdir call.\n",
284 if (ret < 0 || new_op->downcall.status != 0) {
285 gossip_debug(GOSSIP_DIR_DEBUG,
286 "Readdir request failed. Status:%d\n",
287 new_op->downcall.status);
289 ret = new_op->downcall.status;
294 readdir_handle_ctor(&rhandle,
295 new_op->downcall.trailer_buf,
296 new_op->downcall.trailer_size);
297 if (bytes_decoded < 0) {
298 gossip_err("orangefs_readdir: Could not decode trailer buffer into a readdir response %d\n",
304 if (bytes_decoded != new_op->downcall.trailer_size) {
305 gossip_err("orangefs_readdir: # bytes decoded (%ld) "
306 "!= trailer size (%ld)\n",
308 (long)new_op->downcall.trailer_size);
310 goto out_destroy_handle;
314 * orangefs doesn't actually store dot and dot-dot, but
315 * we need to have them represented.
318 ino = get_ino_from_khandle(dentry->d_inode);
319 gossip_debug(GOSSIP_DIR_DEBUG,
320 "%s: calling dir_emit of \".\" with pos = %llu\n",
323 ret = dir_emit(ctx, ".", 1, ino, DT_DIR);
328 ino = get_parent_ino_from_dentry(dentry);
329 gossip_debug(GOSSIP_DIR_DEBUG,
330 "%s: calling dir_emit of \"..\" with pos = %llu\n",
333 ret = dir_emit(ctx, "..", 2, ino, DT_DIR);
338 * we stored ORANGEFS_ITERATE_NEXT in ctx->pos last time around
339 * to prevent "finding" dot and dot-dot on any iteration
340 * other than the first.
342 if (ctx->pos == ORANGEFS_ITERATE_NEXT)
345 gossip_debug(GOSSIP_DIR_DEBUG,
346 "%s: dirent_outcount:%d:\n",
348 rhandle.readdir_response.orangefs_dirent_outcount);
350 i < rhandle.readdir_response.orangefs_dirent_outcount;
352 len = rhandle.readdir_response.dirent_array[i].d_length;
353 current_entry = rhandle.readdir_response.dirent_array[i].d_name;
354 current_ino = orangefs_khandle_to_ino(
355 &(rhandle.readdir_response.dirent_array[i].khandle));
357 gossip_debug(GOSSIP_DIR_DEBUG,
358 "calling dir_emit for %s with len %d"
362 (unsigned long)ctx->pos);
364 * type is unknown. We don't return object type
365 * in the dirent_array. This leaves getdents
366 * clueless about type.
369 dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN);
373 gossip_debug(GOSSIP_DIR_DEBUG,
374 "%s: ctx->pos:%lld\n",
381 * we ran all the way through the last batch, set up for
382 * getting another batch...
385 *ptoken = rhandle.readdir_response.token;
386 ctx->pos = ORANGEFS_ITERATE_NEXT;
390 * Did we hit the end of the directory?
392 if (rhandle.readdir_response.token == ORANGEFS_READDIR_END &&
394 gossip_debug(GOSSIP_DIR_DEBUG,
395 "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
396 ctx->pos = ORANGEFS_READDIR_END;
400 readdir_handle_dtor(&rhandle);
403 gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret);
407 static int orangefs_dir_open(struct inode *inode, struct file *file)
411 file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL);
412 if (!file->private_data)
415 ptoken = file->private_data;
416 *ptoken = ORANGEFS_READDIR_START;
420 static int orangefs_dir_release(struct inode *inode, struct file *file)
422 orangefs_flush_inode(inode);
423 kfree(file->private_data);
427 /** ORANGEFS implementation of VFS directory operations */
428 const struct file_operations orangefs_dir_operations = {
429 .read = generic_read_dir,
430 .iterate = orangefs_readdir,
431 .open = orangefs_dir_open,
432 .release = orangefs_dir_release,