Orangefs: add protocol information to Documentation/filesystems/orangefs.txt
[linux-2.6-block.git] / fs / orangefs / dir.c
CommitLineData
5db11c21
MM
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7#include "protocol.h"
575e9461
MM
8#include "orangefs-kernel.h"
9#include "orangefs-bufmap.h"
5db11c21
MM
10
11struct readdir_handle_s {
12 int buffer_index;
8bb8aefd 13 struct orangefs_readdir_response_s readdir_response;
5db11c21
MM
14 void *dents_buf;
15};
16
17/*
18 * decode routine needed by kmod to make sense of the shared page for readdirs.
19 */
8092895f 20static long decode_dirents(char *ptr, size_t size,
8bb8aefd 21 struct orangefs_readdir_response_s *readdir)
5db11c21
MM
22{
23 int i;
8bb8aefd
YL
24 struct orangefs_readdir_response_s *rd =
25 (struct orangefs_readdir_response_s *) ptr;
5db11c21 26 char *buf = ptr;
5db11c21 27
8bb8aefd 28 if (size < offsetof(struct orangefs_readdir_response_s, dirent_array))
8092895f
AV
29 return -EINVAL;
30
5db11c21 31 readdir->token = rd->token;
8bb8aefd
YL
32 readdir->orangefs_dirent_outcount = rd->orangefs_dirent_outcount;
33 readdir->dirent_array = kcalloc(readdir->orangefs_dirent_outcount,
5db11c21
MM
34 sizeof(*readdir->dirent_array),
35 GFP_KERNEL);
36 if (readdir->dirent_array == NULL)
37 return -ENOMEM;
8092895f 38
8bb8aefd
YL
39 buf += offsetof(struct orangefs_readdir_response_s, dirent_array);
40 size -= offsetof(struct orangefs_readdir_response_s, dirent_array);
8092895f 41
8bb8aefd 42 for (i = 0; i < readdir->orangefs_dirent_outcount; i++) {
8092895f
AV
43 __u32 len;
44
45 if (size < 4)
46 goto Einval;
47
48 len = *(__u32 *)buf;
49 if (len >= (unsigned)-24)
50 goto Einval;
51
9be68b08 52 readdir->dirent_array[i].d_name = buf + 4;
9be68b08 53 readdir->dirent_array[i].d_length = len;
8092895f 54
7d221485
MB
55 /*
56 * Round 4 + len + 1, which is the encoded size plus the string
57 * plus the null terminator to the nearest eight byte boundry.
58 */
59 len = ((4 + len + 1) + 7) & ~7;
8092895f
AV
60 if (size < len + 16)
61 goto Einval;
62 size -= len + 16;
63
64 buf += len;
65
5db11c21 66 readdir->dirent_array[i].khandle =
8bb8aefd 67 *(struct orangefs_khandle *) buf;
9be68b08 68 buf += 16;
5db11c21 69 }
9be68b08 70 return buf - ptr;
8092895f
AV
71Einval:
72 kfree(readdir->dirent_array);
73 readdir->dirent_array = NULL;
74 return -EINVAL;
5db11c21
MM
75}
76
77static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
8092895f 78 size_t size, int buffer_index)
5db11c21
MM
79{
80 long ret;
81
82 if (buf == NULL) {
83 gossip_err
84 ("Invalid NULL buffer specified in readdir_handle_ctor\n");
85 return -ENOMEM;
86 }
87 if (buffer_index < 0) {
88 gossip_err
89 ("Invalid buffer index specified in readdir_handle_ctor\n");
90 return -EINVAL;
91 }
92 rhandle->buffer_index = buffer_index;
93 rhandle->dents_buf = buf;
8092895f 94 ret = decode_dirents(buf, size, &rhandle->readdir_response);
5db11c21
MM
95 if (ret < 0) {
96 gossip_err("Could not decode readdir from buffer %ld\n", ret);
97 rhandle->buffer_index = -1;
98 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf);
99 vfree(buf);
100 rhandle->dents_buf = NULL;
101 }
102 return ret;
103}
104
8bb8aefd 105static void readdir_handle_dtor(struct orangefs_bufmap *bufmap,
5db11c21
MM
106 struct readdir_handle_s *rhandle)
107{
108 if (rhandle == NULL)
109 return;
110
111 /* kfree(NULL) is safe */
112 kfree(rhandle->readdir_response.dirent_array);
113 rhandle->readdir_response.dirent_array = NULL;
114
115 if (rhandle->buffer_index >= 0) {
7d221485 116 orangefs_readdir_index_put(bufmap, rhandle->buffer_index);
5db11c21
MM
117 rhandle->buffer_index = -1;
118 }
119 if (rhandle->dents_buf) {
120 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n",
121 rhandle->dents_buf);
122 vfree(rhandle->dents_buf);
123 rhandle->dents_buf = NULL;
124 }
125}
126
127/*
128 * Read directory entries from an instance of an open directory.
5db11c21 129 */
8bb8aefd 130static int orangefs_readdir(struct file *file, struct dir_context *ctx)
5db11c21 131{
8bb8aefd 132 struct orangefs_bufmap *bufmap = NULL;
5db11c21
MM
133 int ret = 0;
134 int buffer_index;
88309aae
MM
135 /*
136 * ptoken supports Orangefs' distributed directory logic, added
137 * in 2.9.2.
138 */
5db11c21
MM
139 __u64 *ptoken = file->private_data;
140 __u64 pos = 0;
141 ino_t ino = 0;
142 struct dentry *dentry = file->f_path.dentry;
8bb8aefd
YL
143 struct orangefs_kernel_op_s *new_op = NULL;
144 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode);
5db11c21
MM
145 int buffer_full = 0;
146 struct readdir_handle_s rhandle;
147 int i = 0;
148 int len = 0;
149 ino_t current_ino = 0;
150 char *current_entry = NULL;
151 long bytes_decoded;
152
88309aae
MM
153 gossip_debug(GOSSIP_DIR_DEBUG,
154 "%s: ctx->pos:%lld, ptoken = %llu\n",
155 __func__,
156 lld(ctx->pos),
157 llu(*ptoken));
5db11c21
MM
158
159 pos = (__u64) ctx->pos;
160
161 /* are we done? */
8bb8aefd 162 if (pos == ORANGEFS_READDIR_END) {
5db11c21
MM
163 gossip_debug(GOSSIP_DIR_DEBUG,
164 "Skipping to termination path\n");
165 return 0;
166 }
167
168 gossip_debug(GOSSIP_DIR_DEBUG,
8bb8aefd 169 "orangefs_readdir called on %s (pos=%llu)\n",
5db11c21
MM
170 dentry->d_name.name, llu(pos));
171
172 rhandle.buffer_index = -1;
173 rhandle.dents_buf = NULL;
174 memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response));
175
8bb8aefd 176 new_op = op_alloc(ORANGEFS_VFS_OP_READDIR);
5db11c21
MM
177 if (!new_op)
178 return -ENOMEM;
179
180 new_op->uses_shared_memory = 1;
8bb8aefd 181 new_op->upcall.req.readdir.refn = orangefs_inode->refn;
7d221485
MB
182 new_op->upcall.req.readdir.max_dirent_count =
183 ORANGEFS_MAX_DIRENT_COUNT_READDIR;
5db11c21
MM
184
185 gossip_debug(GOSSIP_DIR_DEBUG,
186 "%s: upcall.req.readdir.refn.khandle: %pU\n",
187 __func__,
188 &new_op->upcall.req.readdir.refn.khandle);
189
5db11c21
MM
190 new_op->upcall.req.readdir.token = *ptoken;
191
192get_new_buffer_index:
7d221485 193 ret = orangefs_readdir_index_get(&bufmap, &buffer_index);
5db11c21 194 if (ret < 0) {
7d221485 195 gossip_lerr("orangefs_readdir: orangefs_readdir_index_get() failure (%d)\n",
5db11c21
MM
196 ret);
197 goto out_free_op;
198 }
199 new_op->upcall.req.readdir.buf_index = buffer_index;
200
201 ret = service_operation(new_op,
8bb8aefd 202 "orangefs_readdir",
5db11c21
MM
203 get_interruptible_flag(dentry->d_inode));
204
205 gossip_debug(GOSSIP_DIR_DEBUG,
206 "Readdir downcall status is %d. ret:%d\n",
207 new_op->downcall.status,
208 ret);
209
210 if (ret == -EAGAIN && op_state_purged(new_op)) {
211 /*
212 * readdir shared memory aread has been wiped due to
213 * pvfs2-client-core restarting, so we must get a new
214 * index into the shared memory.
215 */
216 gossip_debug(GOSSIP_DIR_DEBUG,
217 "%s: Getting new buffer_index for retry of readdir..\n",
218 __func__);
7d221485 219 orangefs_readdir_index_put(bufmap, buffer_index);
5db11c21
MM
220 goto get_new_buffer_index;
221 }
222
223 if (ret == -EIO && op_state_purged(new_op)) {
224 gossip_err("%s: Client is down. Aborting readdir call.\n",
225 __func__);
7d221485 226 orangefs_readdir_index_put(bufmap, buffer_index);
5db11c21
MM
227 goto out_free_op;
228 }
229
230 if (ret < 0 || new_op->downcall.status != 0) {
231 gossip_debug(GOSSIP_DIR_DEBUG,
232 "Readdir request failed. Status:%d\n",
233 new_op->downcall.status);
7d221485 234 orangefs_readdir_index_put(bufmap, buffer_index);
5db11c21
MM
235 if (ret >= 0)
236 ret = new_op->downcall.status;
237 goto out_free_op;
238 }
239
240 bytes_decoded =
241 readdir_handle_ctor(&rhandle,
242 new_op->downcall.trailer_buf,
8092895f 243 new_op->downcall.trailer_size,
5db11c21
MM
244 buffer_index);
245 if (bytes_decoded < 0) {
8bb8aefd 246 gossip_err("orangefs_readdir: Could not decode trailer buffer into a readdir response %d\n",
5db11c21
MM
247 ret);
248 ret = bytes_decoded;
7d221485 249 orangefs_readdir_index_put(bufmap, buffer_index);
5db11c21
MM
250 goto out_free_op;
251 }
252
253 if (bytes_decoded != new_op->downcall.trailer_size) {
8bb8aefd 254 gossip_err("orangefs_readdir: # bytes decoded (%ld) "
88309aae
MM
255 "!= trailer size (%ld)\n",
256 bytes_decoded,
257 (long)new_op->downcall.trailer_size);
5db11c21
MM
258 ret = -EINVAL;
259 goto out_destroy_handle;
260 }
261
88309aae 262 /*
8bb8aefd 263 * orangefs doesn't actually store dot and dot-dot, but
88309aae
MM
264 * we need to have them represented.
265 */
5db11c21
MM
266 if (pos == 0) {
267 ino = get_ino_from_khandle(dentry->d_inode);
268 gossip_debug(GOSSIP_DIR_DEBUG,
269 "%s: calling dir_emit of \".\" with pos = %llu\n",
270 __func__,
271 llu(pos));
272 ret = dir_emit(ctx, ".", 1, ino, DT_DIR);
88309aae 273 pos += 1;
5db11c21
MM
274 }
275
276 if (pos == 1) {
277 ino = get_parent_ino_from_dentry(dentry);
278 gossip_debug(GOSSIP_DIR_DEBUG,
279 "%s: calling dir_emit of \"..\" with pos = %llu\n",
280 __func__,
281 llu(pos));
282 ret = dir_emit(ctx, "..", 2, ino, DT_DIR);
88309aae 283 pos += 1;
5db11c21
MM
284 }
285
88309aae 286 /*
8bb8aefd 287 * we stored ORANGEFS_ITERATE_NEXT in ctx->pos last time around
88309aae
MM
288 * to prevent "finding" dot and dot-dot on any iteration
289 * other than the first.
290 */
8bb8aefd 291 if (ctx->pos == ORANGEFS_ITERATE_NEXT)
88309aae
MM
292 ctx->pos = 0;
293
294 for (i = ctx->pos;
8bb8aefd 295 i < rhandle.readdir_response.orangefs_dirent_outcount;
88309aae 296 i++) {
5db11c21
MM
297 len = rhandle.readdir_response.dirent_array[i].d_length;
298 current_entry = rhandle.readdir_response.dirent_array[i].d_name;
8bb8aefd 299 current_ino = orangefs_khandle_to_ino(
5db11c21
MM
300 &(rhandle.readdir_response.dirent_array[i].khandle));
301
302 gossip_debug(GOSSIP_DIR_DEBUG,
88309aae
MM
303 "calling dir_emit for %s with len %d"
304 ", ctx->pos %ld\n",
5db11c21
MM
305 current_entry,
306 len,
88309aae
MM
307 (unsigned long)ctx->pos);
308 /*
309 * type is unknown. We don't return object type
310 * in the dirent_array. This leaves getdents
311 * clueless about type.
312 */
5db11c21
MM
313 ret =
314 dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN);
88309aae
MM
315 if (!ret)
316 break;
5db11c21 317 ctx->pos++;
88309aae 318 gossip_debug(GOSSIP_DIR_DEBUG,
5db11c21
MM
319 "%s: ctx->pos:%lld\n",
320 __func__,
321 lld(ctx->pos));
322
5db11c21
MM
323 }
324
54804949 325 /*
88309aae
MM
326 * we ran all the way through the last batch, set up for
327 * getting another batch...
328 */
329 if (ret) {
5db11c21 330 *ptoken = rhandle.readdir_response.token;
8bb8aefd 331 ctx->pos = ORANGEFS_ITERATE_NEXT;
5db11c21
MM
332 }
333
334 /*
335 * Did we hit the end of the directory?
336 */
8bb8aefd 337 if (rhandle.readdir_response.token == ORANGEFS_READDIR_END &&
5db11c21 338 !buffer_full) {
88309aae 339 gossip_debug(GOSSIP_DIR_DEBUG,
8bb8aefd
YL
340 "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
341 ctx->pos = ORANGEFS_READDIR_END;
5db11c21
MM
342 }
343
5db11c21
MM
344out_destroy_handle:
345 readdir_handle_dtor(bufmap, &rhandle);
346out_free_op:
347 op_release(new_op);
8bb8aefd 348 gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret);
5db11c21
MM
349 return ret;
350}
351
8bb8aefd 352static int orangefs_dir_open(struct inode *inode, struct file *file)
5db11c21
MM
353{
354 __u64 *ptoken;
355
356 file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL);
357 if (!file->private_data)
358 return -ENOMEM;
359
360 ptoken = file->private_data;
8bb8aefd 361 *ptoken = ORANGEFS_READDIR_START;
5db11c21
MM
362 return 0;
363}
364
8bb8aefd 365static int orangefs_dir_release(struct inode *inode, struct file *file)
5db11c21 366{
8bb8aefd 367 orangefs_flush_inode(inode);
5db11c21
MM
368 kfree(file->private_data);
369 return 0;
370}
371
8bb8aefd
YL
372/** ORANGEFS implementation of VFS directory operations */
373const struct file_operations orangefs_dir_operations = {
5db11c21 374 .read = generic_read_dir,
8bb8aefd
YL
375 .iterate = orangefs_readdir,
376 .open = orangefs_dir_open,
377 .release = orangefs_dir_release,
5db11c21 378};