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 {
13 struct orangefs_readdir_response_s readdir_response;
18 * decode routine used by kmod to deal with the blob sent from
19 * userspace for readdirs. The blob contains zero or more of these
21 * __u32 - represents length of the character string that follows.
22 * string - between 1 and ORANGEFS_NAME_MAX bytes long.
23 * padding - (if needed) to cause the __u32 plus the string to be
25 * khandle - sizeof(khandle) bytes.
27 static long decode_dirents(char *ptr, size_t size,
28 struct orangefs_readdir_response_s *readdir)
31 struct orangefs_readdir_response_s *rd =
32 (struct orangefs_readdir_response_s *) ptr;
34 int khandle_size = sizeof(struct orangefs_khandle);
35 size_t offset = offsetof(struct orangefs_readdir_response_s,
37 /* 8 reflects eight byte alignment */
38 int smallest_blob = khandle_size + 8;
41 int sizeof_u32 = sizeof(__u32);
44 gossip_debug(GOSSIP_DIR_DEBUG, "%s: size:%zu:\n", __func__, size);
46 /* size is = offset on empty dirs, > offset on non-empty dirs... */
48 gossip_err("%s: size:%zu: offset:%zu:\n",
56 if ((size == offset) && (readdir->orangefs_dirent_outcount != 0)) {
57 gossip_err("%s: size:%zu: dirent_outcount:%d:\n",
60 readdir->orangefs_dirent_outcount);
65 readdir->token = rd->token;
66 readdir->orangefs_dirent_outcount = rd->orangefs_dirent_outcount;
67 readdir->dirent_array = kcalloc(readdir->orangefs_dirent_outcount,
68 sizeof(*readdir->dirent_array),
70 if (readdir->dirent_array == NULL) {
71 gossip_err("%s: kcalloc failed.\n", __func__);
79 for (i = 0; i < readdir->orangefs_dirent_outcount; i++) {
80 if (size < smallest_blob) {
81 gossip_err("%s: size:%zu: smallest_blob:%d:\n",
90 if ((len < 1) || (len > ORANGEFS_NAME_MAX)) {
91 gossip_err("%s: len:%d:\n", __func__, len);
96 gossip_debug(GOSSIP_DIR_DEBUG,
97 "%s: size:%zu: len:%d:\n",
102 readdir->dirent_array[i].d_name = buf + sizeof_u32;
103 readdir->dirent_array[i].d_length = len;
106 * Calculate "aligned" length of this string and its
107 * associated __u32 descriptor.
109 aligned_len = ((sizeof_u32 + len + 1) + 7) & ~7;
110 gossip_debug(GOSSIP_DIR_DEBUG,
111 "%s: aligned_len:%d:\n",
116 * The end of the blob should coincide with the end
117 * of the last sub-blob.
119 if (size < aligned_len + khandle_size) {
120 gossip_err("%s: ran off the end of the blob.\n",
125 size -= aligned_len + khandle_size;
129 readdir->dirent_array[i].khandle =
130 *(struct orangefs_khandle *) buf;
134 gossip_debug(GOSSIP_DIR_DEBUG, "%s: returning:%ld:\n", __func__, ret);
138 kfree(readdir->dirent_array);
139 readdir->dirent_array = NULL;
145 static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
146 size_t size, int buffer_index)
152 ("Invalid NULL buffer specified in readdir_handle_ctor\n");
155 if (buffer_index < 0) {
157 ("Invalid buffer index specified in readdir_handle_ctor\n");
160 rhandle->buffer_index = buffer_index;
161 rhandle->dents_buf = buf;
162 ret = decode_dirents(buf, size, &rhandle->readdir_response);
164 gossip_err("Could not decode readdir from buffer %ld\n", ret);
165 rhandle->buffer_index = -1;
166 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf);
168 rhandle->dents_buf = NULL;
173 static void readdir_handle_dtor(struct orangefs_bufmap *bufmap,
174 struct readdir_handle_s *rhandle)
179 /* kfree(NULL) is safe */
180 kfree(rhandle->readdir_response.dirent_array);
181 rhandle->readdir_response.dirent_array = NULL;
183 if (rhandle->buffer_index >= 0) {
184 orangefs_readdir_index_put(bufmap, rhandle->buffer_index);
185 rhandle->buffer_index = -1;
187 if (rhandle->dents_buf) {
188 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n",
190 vfree(rhandle->dents_buf);
191 rhandle->dents_buf = NULL;
196 * Read directory entries from an instance of an open directory.
198 static int orangefs_readdir(struct file *file, struct dir_context *ctx)
200 struct orangefs_bufmap *bufmap = NULL;
204 * ptoken supports Orangefs' distributed directory logic, added
207 __u64 *ptoken = file->private_data;
210 struct dentry *dentry = file->f_path.dentry;
211 struct orangefs_kernel_op_s *new_op = NULL;
212 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode);
214 struct readdir_handle_s rhandle;
217 ino_t current_ino = 0;
218 char *current_entry = NULL;
221 gossip_debug(GOSSIP_DIR_DEBUG,
222 "%s: ctx->pos:%lld, ptoken = %llu\n",
227 pos = (__u64) ctx->pos;
230 if (pos == ORANGEFS_READDIR_END) {
231 gossip_debug(GOSSIP_DIR_DEBUG,
232 "Skipping to termination path\n");
236 gossip_debug(GOSSIP_DIR_DEBUG,
237 "orangefs_readdir called on %s (pos=%llu)\n",
238 dentry->d_name.name, llu(pos));
240 rhandle.buffer_index = -1;
241 rhandle.dents_buf = NULL;
242 memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response));
244 new_op = op_alloc(ORANGEFS_VFS_OP_READDIR);
248 new_op->uses_shared_memory = 1;
249 new_op->upcall.req.readdir.refn = orangefs_inode->refn;
250 new_op->upcall.req.readdir.max_dirent_count =
251 ORANGEFS_MAX_DIRENT_COUNT_READDIR;
253 gossip_debug(GOSSIP_DIR_DEBUG,
254 "%s: upcall.req.readdir.refn.khandle: %pU\n",
256 &new_op->upcall.req.readdir.refn.khandle);
258 new_op->upcall.req.readdir.token = *ptoken;
260 get_new_buffer_index:
261 ret = orangefs_readdir_index_get(&bufmap, &buffer_index);
263 gossip_lerr("orangefs_readdir: orangefs_readdir_index_get() failure (%d)\n",
267 new_op->upcall.req.readdir.buf_index = buffer_index;
269 ret = service_operation(new_op,
271 get_interruptible_flag(dentry->d_inode));
273 gossip_debug(GOSSIP_DIR_DEBUG,
274 "Readdir downcall status is %d. ret:%d\n",
275 new_op->downcall.status,
278 if (ret == -EAGAIN && op_state_purged(new_op)) {
280 * readdir shared memory aread has been wiped due to
281 * pvfs2-client-core restarting, so we must get a new
282 * index into the shared memory.
284 gossip_debug(GOSSIP_DIR_DEBUG,
285 "%s: Getting new buffer_index for retry of readdir..\n",
287 orangefs_readdir_index_put(bufmap, buffer_index);
288 goto get_new_buffer_index;
291 if (ret == -EIO && op_state_purged(new_op)) {
292 gossip_err("%s: Client is down. Aborting readdir call.\n",
294 orangefs_readdir_index_put(bufmap, buffer_index);
298 if (ret < 0 || new_op->downcall.status != 0) {
299 gossip_debug(GOSSIP_DIR_DEBUG,
300 "Readdir request failed. Status:%d\n",
301 new_op->downcall.status);
302 orangefs_readdir_index_put(bufmap, buffer_index);
304 ret = new_op->downcall.status;
309 readdir_handle_ctor(&rhandle,
310 new_op->downcall.trailer_buf,
311 new_op->downcall.trailer_size,
313 if (bytes_decoded < 0) {
314 gossip_err("orangefs_readdir: Could not decode trailer buffer into a readdir response %d\n",
317 orangefs_readdir_index_put(bufmap, buffer_index);
321 if (bytes_decoded != new_op->downcall.trailer_size) {
322 gossip_err("orangefs_readdir: # bytes decoded (%ld) "
323 "!= trailer size (%ld)\n",
325 (long)new_op->downcall.trailer_size);
327 goto out_destroy_handle;
331 * orangefs doesn't actually store dot and dot-dot, but
332 * we need to have them represented.
335 ino = get_ino_from_khandle(dentry->d_inode);
336 gossip_debug(GOSSIP_DIR_DEBUG,
337 "%s: calling dir_emit of \".\" with pos = %llu\n",
340 ret = dir_emit(ctx, ".", 1, ino, DT_DIR);
345 ino = get_parent_ino_from_dentry(dentry);
346 gossip_debug(GOSSIP_DIR_DEBUG,
347 "%s: calling dir_emit of \"..\" with pos = %llu\n",
350 ret = dir_emit(ctx, "..", 2, ino, DT_DIR);
355 * we stored ORANGEFS_ITERATE_NEXT in ctx->pos last time around
356 * to prevent "finding" dot and dot-dot on any iteration
357 * other than the first.
359 if (ctx->pos == ORANGEFS_ITERATE_NEXT)
363 i < rhandle.readdir_response.orangefs_dirent_outcount;
365 len = rhandle.readdir_response.dirent_array[i].d_length;
366 current_entry = rhandle.readdir_response.dirent_array[i].d_name;
367 current_ino = orangefs_khandle_to_ino(
368 &(rhandle.readdir_response.dirent_array[i].khandle));
370 gossip_debug(GOSSIP_DIR_DEBUG,
371 "calling dir_emit for %s with len %d"
375 (unsigned long)ctx->pos);
377 * type is unknown. We don't return object type
378 * in the dirent_array. This leaves getdents
379 * clueless about type.
382 dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN);
386 gossip_debug(GOSSIP_DIR_DEBUG,
387 "%s: ctx->pos:%lld\n",
394 * we ran all the way through the last batch, set up for
395 * getting another batch...
398 *ptoken = rhandle.readdir_response.token;
399 ctx->pos = ORANGEFS_ITERATE_NEXT;
403 * Did we hit the end of the directory?
405 if (rhandle.readdir_response.token == ORANGEFS_READDIR_END &&
407 gossip_debug(GOSSIP_DIR_DEBUG,
408 "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
409 ctx->pos = ORANGEFS_READDIR_END;
413 readdir_handle_dtor(bufmap, &rhandle);
416 gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret);
420 static int orangefs_dir_open(struct inode *inode, struct file *file)
424 file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL);
425 if (!file->private_data)
428 ptoken = file->private_data;
429 *ptoken = ORANGEFS_READDIR_START;
433 static int orangefs_dir_release(struct inode *inode, struct file *file)
435 orangefs_flush_inode(inode);
436 kfree(file->private_data);
440 /** ORANGEFS implementation of VFS directory operations */
441 const struct file_operations orangefs_dir_operations = {
442 .read = generic_read_dir,
443 .iterate = orangefs_readdir,
444 .open = orangefs_dir_open,
445 .release = orangefs_dir_release,