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 needed by kmod to make sense of the shared page for readdirs.
20 static long decode_dirents(char *ptr
, size_t size
,
21 struct orangefs_readdir_response_s
*readdir
)
24 struct orangefs_readdir_response_s
*rd
=
25 (struct orangefs_readdir_response_s
*) ptr
;
28 if (size
< offsetof(struct orangefs_readdir_response_s
, dirent_array
))
31 readdir
->token
= rd
->token
;
32 readdir
->orangefs_dirent_outcount
= rd
->orangefs_dirent_outcount
;
33 readdir
->dirent_array
= kcalloc(readdir
->orangefs_dirent_outcount
,
34 sizeof(*readdir
->dirent_array
),
36 if (readdir
->dirent_array
== NULL
)
39 buf
+= offsetof(struct orangefs_readdir_response_s
, dirent_array
);
40 size
-= offsetof(struct orangefs_readdir_response_s
, dirent_array
);
42 for (i
= 0; i
< readdir
->orangefs_dirent_outcount
; i
++) {
49 if (len
>= (unsigned)-24)
52 readdir
->dirent_array
[i
].d_name
= buf
+ 4;
53 readdir
->dirent_array
[i
].d_length
= len
;
55 len
= roundup8(4 + len
+ 1);
62 readdir
->dirent_array
[i
].khandle
=
63 *(struct orangefs_khandle
*) buf
;
68 kfree(readdir
->dirent_array
);
69 readdir
->dirent_array
= NULL
;
73 static long readdir_handle_ctor(struct readdir_handle_s
*rhandle
, void *buf
,
74 size_t size
, int buffer_index
)
80 ("Invalid NULL buffer specified in readdir_handle_ctor\n");
83 if (buffer_index
< 0) {
85 ("Invalid buffer index specified in readdir_handle_ctor\n");
88 rhandle
->buffer_index
= buffer_index
;
89 rhandle
->dents_buf
= buf
;
90 ret
= decode_dirents(buf
, size
, &rhandle
->readdir_response
);
92 gossip_err("Could not decode readdir from buffer %ld\n", ret
);
93 rhandle
->buffer_index
= -1;
94 gossip_debug(GOSSIP_DIR_DEBUG
, "vfree %p\n", buf
);
96 rhandle
->dents_buf
= NULL
;
101 static void readdir_handle_dtor(struct orangefs_bufmap
*bufmap
,
102 struct readdir_handle_s
*rhandle
)
107 /* kfree(NULL) is safe */
108 kfree(rhandle
->readdir_response
.dirent_array
);
109 rhandle
->readdir_response
.dirent_array
= NULL
;
111 if (rhandle
->buffer_index
>= 0) {
112 readdir_index_put(bufmap
, rhandle
->buffer_index
);
113 rhandle
->buffer_index
= -1;
115 if (rhandle
->dents_buf
) {
116 gossip_debug(GOSSIP_DIR_DEBUG
, "vfree %p\n",
118 vfree(rhandle
->dents_buf
);
119 rhandle
->dents_buf
= NULL
;
124 * Read directory entries from an instance of an open directory.
126 static int orangefs_readdir(struct file
*file
, struct dir_context
*ctx
)
128 struct orangefs_bufmap
*bufmap
= NULL
;
132 * ptoken supports Orangefs' distributed directory logic, added
135 __u64
*ptoken
= file
->private_data
;
138 struct dentry
*dentry
= file
->f_path
.dentry
;
139 struct orangefs_kernel_op_s
*new_op
= NULL
;
140 struct orangefs_inode_s
*orangefs_inode
= ORANGEFS_I(dentry
->d_inode
);
142 struct readdir_handle_s rhandle
;
145 ino_t current_ino
= 0;
146 char *current_entry
= NULL
;
149 gossip_debug(GOSSIP_DIR_DEBUG
,
150 "%s: ctx->pos:%lld, ptoken = %llu\n",
155 pos
= (__u64
) ctx
->pos
;
158 if (pos
== ORANGEFS_READDIR_END
) {
159 gossip_debug(GOSSIP_DIR_DEBUG
,
160 "Skipping to termination path\n");
164 gossip_debug(GOSSIP_DIR_DEBUG
,
165 "orangefs_readdir called on %s (pos=%llu)\n",
166 dentry
->d_name
.name
, llu(pos
));
168 rhandle
.buffer_index
= -1;
169 rhandle
.dents_buf
= NULL
;
170 memset(&rhandle
.readdir_response
, 0, sizeof(rhandle
.readdir_response
));
172 new_op
= op_alloc(ORANGEFS_VFS_OP_READDIR
);
176 new_op
->uses_shared_memory
= 1;
177 new_op
->upcall
.req
.readdir
.refn
= orangefs_inode
->refn
;
178 new_op
->upcall
.req
.readdir
.max_dirent_count
= MAX_DIRENT_COUNT_READDIR
;
180 gossip_debug(GOSSIP_DIR_DEBUG
,
181 "%s: upcall.req.readdir.refn.khandle: %pU\n",
183 &new_op
->upcall
.req
.readdir
.refn
.khandle
);
185 new_op
->upcall
.req
.readdir
.token
= *ptoken
;
187 get_new_buffer_index
:
188 ret
= readdir_index_get(&bufmap
, &buffer_index
);
190 gossip_lerr("orangefs_readdir: readdir_index_get() failure (%d)\n",
194 new_op
->upcall
.req
.readdir
.buf_index
= buffer_index
;
196 ret
= service_operation(new_op
,
198 get_interruptible_flag(dentry
->d_inode
));
200 gossip_debug(GOSSIP_DIR_DEBUG
,
201 "Readdir downcall status is %d. ret:%d\n",
202 new_op
->downcall
.status
,
205 if (ret
== -EAGAIN
&& op_state_purged(new_op
)) {
207 * readdir shared memory aread has been wiped due to
208 * pvfs2-client-core restarting, so we must get a new
209 * index into the shared memory.
211 gossip_debug(GOSSIP_DIR_DEBUG
,
212 "%s: Getting new buffer_index for retry of readdir..\n",
214 readdir_index_put(bufmap
, buffer_index
);
215 goto get_new_buffer_index
;
218 if (ret
== -EIO
&& op_state_purged(new_op
)) {
219 gossip_err("%s: Client is down. Aborting readdir call.\n",
221 readdir_index_put(bufmap
, buffer_index
);
225 if (ret
< 0 || new_op
->downcall
.status
!= 0) {
226 gossip_debug(GOSSIP_DIR_DEBUG
,
227 "Readdir request failed. Status:%d\n",
228 new_op
->downcall
.status
);
229 readdir_index_put(bufmap
, buffer_index
);
231 ret
= new_op
->downcall
.status
;
236 readdir_handle_ctor(&rhandle
,
237 new_op
->downcall
.trailer_buf
,
238 new_op
->downcall
.trailer_size
,
240 if (bytes_decoded
< 0) {
241 gossip_err("orangefs_readdir: Could not decode trailer buffer into a readdir response %d\n",
244 readdir_index_put(bufmap
, buffer_index
);
248 if (bytes_decoded
!= new_op
->downcall
.trailer_size
) {
249 gossip_err("orangefs_readdir: # bytes decoded (%ld) "
250 "!= trailer size (%ld)\n",
252 (long)new_op
->downcall
.trailer_size
);
254 goto out_destroy_handle
;
258 * orangefs doesn't actually store dot and dot-dot, but
259 * we need to have them represented.
262 ino
= get_ino_from_khandle(dentry
->d_inode
);
263 gossip_debug(GOSSIP_DIR_DEBUG
,
264 "%s: calling dir_emit of \".\" with pos = %llu\n",
267 ret
= dir_emit(ctx
, ".", 1, ino
, DT_DIR
);
272 ino
= get_parent_ino_from_dentry(dentry
);
273 gossip_debug(GOSSIP_DIR_DEBUG
,
274 "%s: calling dir_emit of \"..\" with pos = %llu\n",
277 ret
= dir_emit(ctx
, "..", 2, ino
, DT_DIR
);
282 * we stored ORANGEFS_ITERATE_NEXT in ctx->pos last time around
283 * to prevent "finding" dot and dot-dot on any iteration
284 * other than the first.
286 if (ctx
->pos
== ORANGEFS_ITERATE_NEXT
)
290 i
< rhandle
.readdir_response
.orangefs_dirent_outcount
;
292 len
= rhandle
.readdir_response
.dirent_array
[i
].d_length
;
293 current_entry
= rhandle
.readdir_response
.dirent_array
[i
].d_name
;
294 current_ino
= orangefs_khandle_to_ino(
295 &(rhandle
.readdir_response
.dirent_array
[i
].khandle
));
297 gossip_debug(GOSSIP_DIR_DEBUG
,
298 "calling dir_emit for %s with len %d"
302 (unsigned long)ctx
->pos
);
304 * type is unknown. We don't return object type
305 * in the dirent_array. This leaves getdents
306 * clueless about type.
309 dir_emit(ctx
, current_entry
, len
, current_ino
, DT_UNKNOWN
);
313 gossip_debug(GOSSIP_DIR_DEBUG
,
314 "%s: ctx->pos:%lld\n",
321 * we ran all the way through the last batch, set up for
322 * getting another batch...
325 *ptoken
= rhandle
.readdir_response
.token
;
326 ctx
->pos
= ORANGEFS_ITERATE_NEXT
;
330 * Did we hit the end of the directory?
332 if (rhandle
.readdir_response
.token
== ORANGEFS_READDIR_END
&&
334 gossip_debug(GOSSIP_DIR_DEBUG
,
335 "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
336 ctx
->pos
= ORANGEFS_READDIR_END
;
340 readdir_handle_dtor(bufmap
, &rhandle
);
343 gossip_debug(GOSSIP_DIR_DEBUG
, "orangefs_readdir returning %d\n", ret
);
347 static int orangefs_dir_open(struct inode
*inode
, struct file
*file
)
351 file
->private_data
= kmalloc(sizeof(__u64
), GFP_KERNEL
);
352 if (!file
->private_data
)
355 ptoken
= file
->private_data
;
356 *ptoken
= ORANGEFS_READDIR_START
;
360 static int orangefs_dir_release(struct inode
*inode
, struct file
*file
)
362 orangefs_flush_inode(inode
);
363 kfree(file
->private_data
);
367 /** ORANGEFS implementation of VFS directory operations */
368 const struct file_operations orangefs_dir_operations
= {
369 .read
= generic_read_dir
,
370 .iterate
= orangefs_readdir
,
371 .open
= orangefs_dir_open
,
372 .release
= orangefs_dir_release
,