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"
12 * decode routine used by kmod to deal with the blob sent from
13 * userspace for readdirs. The blob contains zero or more of these
15 * __u32 - represents length of the character string that follows.
16 * string - between 1 and ORANGEFS_NAME_MAX bytes long.
17 * padding - (if needed) to cause the __u32 plus the string to be
19 * khandle - sizeof(khandle) bytes.
21 static long decode_dirents(char *ptr
, size_t size
,
22 struct orangefs_readdir_response_s
*readdir
)
25 struct orangefs_readdir_response_s
*rd
=
26 (struct orangefs_readdir_response_s
*) ptr
;
28 int khandle_size
= sizeof(struct orangefs_khandle
);
29 size_t offset
= offsetof(struct orangefs_readdir_response_s
,
31 /* 8 reflects eight byte alignment */
32 int smallest_blob
= khandle_size
+ 8;
35 int sizeof_u32
= sizeof(__u32
);
38 gossip_debug(GOSSIP_DIR_DEBUG
, "%s: size:%zu:\n", __func__
, size
);
40 /* size is = offset on empty dirs, > offset on non-empty dirs... */
42 gossip_err("%s: size:%zu: offset:%zu:\n",
50 if ((size
== offset
) && (readdir
->orangefs_dirent_outcount
!= 0)) {
51 gossip_err("%s: size:%zu: dirent_outcount:%d:\n",
54 readdir
->orangefs_dirent_outcount
);
59 readdir
->token
= rd
->token
;
60 readdir
->orangefs_dirent_outcount
= rd
->orangefs_dirent_outcount
;
61 readdir
->dirent_array
= kcalloc(readdir
->orangefs_dirent_outcount
,
62 sizeof(*readdir
->dirent_array
),
64 if (readdir
->dirent_array
== NULL
) {
65 gossip_err("%s: kcalloc failed.\n", __func__
);
73 for (i
= 0; i
< readdir
->orangefs_dirent_outcount
; i
++) {
74 if (size
< smallest_blob
) {
75 gossip_err("%s: size:%zu: smallest_blob:%d:\n",
84 if ((len
< 1) || (len
> ORANGEFS_NAME_MAX
)) {
85 gossip_err("%s: len:%d:\n", __func__
, len
);
90 gossip_debug(GOSSIP_DIR_DEBUG
,
91 "%s: size:%zu: len:%d:\n",
96 readdir
->dirent_array
[i
].d_name
= buf
+ sizeof_u32
;
97 readdir
->dirent_array
[i
].d_length
= len
;
100 * Calculate "aligned" length of this string and its
101 * associated __u32 descriptor.
103 aligned_len
= ((sizeof_u32
+ len
+ 1) + 7) & ~7;
104 gossip_debug(GOSSIP_DIR_DEBUG
,
105 "%s: aligned_len:%d:\n",
110 * The end of the blob should coincide with the end
111 * of the last sub-blob.
113 if (size
< aligned_len
+ khandle_size
) {
114 gossip_err("%s: ran off the end of the blob.\n",
119 size
-= aligned_len
+ khandle_size
;
123 readdir
->dirent_array
[i
].khandle
=
124 *(struct orangefs_khandle
*) buf
;
128 gossip_debug(GOSSIP_DIR_DEBUG
, "%s: returning:%ld:\n", __func__
, ret
);
132 kfree(readdir
->dirent_array
);
133 readdir
->dirent_array
= NULL
;
140 * Read directory entries from an instance of an open directory.
142 static int orangefs_readdir(struct file
*file
, struct dir_context
*ctx
)
147 * ptoken supports Orangefs' distributed directory logic, added
150 __u64
*ptoken
= file
->private_data
;
153 struct dentry
*dentry
= file
->f_path
.dentry
;
154 struct orangefs_kernel_op_s
*new_op
= NULL
;
155 struct orangefs_inode_s
*orangefs_inode
= ORANGEFS_I(dentry
->d_inode
);
157 struct orangefs_readdir_response_s readdir_response
;
161 ino_t current_ino
= 0;
162 char *current_entry
= NULL
;
165 gossip_debug(GOSSIP_DIR_DEBUG
,
166 "%s: ctx->pos:%lld, ptoken = %llu\n",
171 pos
= (__u64
) ctx
->pos
;
174 if (pos
== ORANGEFS_READDIR_END
) {
175 gossip_debug(GOSSIP_DIR_DEBUG
,
176 "Skipping to termination path\n");
180 gossip_debug(GOSSIP_DIR_DEBUG
,
181 "orangefs_readdir called on %s (pos=%llu)\n",
182 dentry
->d_name
.name
, llu(pos
));
184 memset(&readdir_response
, 0, sizeof(readdir_response
));
186 new_op
= op_alloc(ORANGEFS_VFS_OP_READDIR
);
191 * Only the indices are shared. No memory is actually shared, but the
194 new_op
->uses_shared_memory
= 1;
195 new_op
->upcall
.req
.readdir
.refn
= orangefs_inode
->refn
;
196 new_op
->upcall
.req
.readdir
.max_dirent_count
=
197 ORANGEFS_MAX_DIRENT_COUNT_READDIR
;
199 gossip_debug(GOSSIP_DIR_DEBUG
,
200 "%s: upcall.req.readdir.refn.khandle: %pU\n",
202 &new_op
->upcall
.req
.readdir
.refn
.khandle
);
204 new_op
->upcall
.req
.readdir
.token
= *ptoken
;
206 get_new_buffer_index
:
207 buffer_index
= orangefs_readdir_index_get();
208 if (buffer_index
< 0) {
210 gossip_lerr("orangefs_readdir: orangefs_readdir_index_get() failure (%d)\n",
214 new_op
->upcall
.req
.readdir
.buf_index
= buffer_index
;
216 ret
= service_operation(new_op
,
218 get_interruptible_flag(dentry
->d_inode
));
220 gossip_debug(GOSSIP_DIR_DEBUG
,
221 "Readdir downcall status is %d. ret:%d\n",
222 new_op
->downcall
.status
,
225 orangefs_readdir_index_put(buffer_index
);
227 if (ret
== -EAGAIN
&& op_state_purged(new_op
)) {
228 /* Client-core indices are invalid after it restarted. */
229 gossip_debug(GOSSIP_DIR_DEBUG
,
230 "%s: Getting new buffer_index for retry of readdir..\n",
232 goto get_new_buffer_index
;
235 if (ret
== -EIO
&& op_state_purged(new_op
)) {
236 gossip_err("%s: Client is down. Aborting readdir call.\n",
241 if (ret
< 0 || new_op
->downcall
.status
!= 0) {
242 gossip_debug(GOSSIP_DIR_DEBUG
,
243 "Readdir request failed. Status:%d\n",
244 new_op
->downcall
.status
);
246 ret
= new_op
->downcall
.status
;
250 dents_buf
= new_op
->downcall
.trailer_buf
;
251 if (dents_buf
== NULL
) {
252 gossip_err("Invalid NULL buffer in readdir response\n");
257 bytes_decoded
= decode_dirents(dents_buf
, new_op
->downcall
.trailer_size
,
259 if (bytes_decoded
< 0) {
261 gossip_err("Could not decode readdir from buffer %d\n", ret
);
265 if (bytes_decoded
!= new_op
->downcall
.trailer_size
) {
266 gossip_err("orangefs_readdir: # bytes decoded (%ld) "
267 "!= trailer size (%ld)\n",
269 (long)new_op
->downcall
.trailer_size
);
271 goto out_destroy_handle
;
275 * orangefs doesn't actually store dot and dot-dot, but
276 * we need to have them represented.
279 ino
= get_ino_from_khandle(dentry
->d_inode
);
280 gossip_debug(GOSSIP_DIR_DEBUG
,
281 "%s: calling dir_emit of \".\" with pos = %llu\n",
284 ret
= dir_emit(ctx
, ".", 1, ino
, DT_DIR
);
289 ino
= get_parent_ino_from_dentry(dentry
);
290 gossip_debug(GOSSIP_DIR_DEBUG
,
291 "%s: calling dir_emit of \"..\" with pos = %llu\n",
294 ret
= dir_emit(ctx
, "..", 2, ino
, DT_DIR
);
299 * we stored ORANGEFS_ITERATE_NEXT in ctx->pos last time around
300 * to prevent "finding" dot and dot-dot on any iteration
301 * other than the first.
303 if (ctx
->pos
== ORANGEFS_ITERATE_NEXT
)
306 gossip_debug(GOSSIP_DIR_DEBUG
,
307 "%s: dirent_outcount:%d:\n",
309 readdir_response
.orangefs_dirent_outcount
);
311 i
< readdir_response
.orangefs_dirent_outcount
;
313 len
= readdir_response
.dirent_array
[i
].d_length
;
314 current_entry
= readdir_response
.dirent_array
[i
].d_name
;
315 current_ino
= orangefs_khandle_to_ino(
316 &readdir_response
.dirent_array
[i
].khandle
);
318 gossip_debug(GOSSIP_DIR_DEBUG
,
319 "calling dir_emit for %s with len %d"
323 (unsigned long)ctx
->pos
);
325 * type is unknown. We don't return object type
326 * in the dirent_array. This leaves getdents
327 * clueless about type.
330 dir_emit(ctx
, current_entry
, len
, current_ino
, DT_UNKNOWN
);
334 gossip_debug(GOSSIP_DIR_DEBUG
,
335 "%s: ctx->pos:%lld\n",
342 * we ran all the way through the last batch, set up for
343 * getting another batch...
346 *ptoken
= readdir_response
.token
;
347 ctx
->pos
= ORANGEFS_ITERATE_NEXT
;
351 * Did we hit the end of the directory?
353 if (readdir_response
.token
== ORANGEFS_READDIR_END
&&
355 gossip_debug(GOSSIP_DIR_DEBUG
,
356 "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
357 ctx
->pos
= ORANGEFS_READDIR_END
;
361 /* kfree(NULL) is safe */
362 kfree(readdir_response
.dirent_array
);
364 gossip_debug(GOSSIP_DIR_DEBUG
, "vfree %p\n", dents_buf
);
367 orangefs_readdir_index_put(buffer_index
);
370 gossip_debug(GOSSIP_DIR_DEBUG
, "orangefs_readdir returning %d\n", ret
);
374 static int orangefs_dir_open(struct inode
*inode
, struct file
*file
)
378 file
->private_data
= kmalloc(sizeof(__u64
), GFP_KERNEL
);
379 if (!file
->private_data
)
382 ptoken
= file
->private_data
;
383 *ptoken
= ORANGEFS_READDIR_START
;
387 static int orangefs_dir_release(struct inode
*inode
, struct file
*file
)
389 orangefs_flush_inode(inode
);
390 kfree(file
->private_data
);
394 /** ORANGEFS implementation of VFS directory operations */
395 const struct file_operations orangefs_dir_operations
= {
396 .read
= generic_read_dir
,
397 .iterate
= orangefs_readdir
,
398 .open
= orangefs_dir_open
,
399 .release
= orangefs_dir_release
,