blob: eb4c3d334088e96dd51b5dbd75a0b6a2da0e5e20 [file] [log] [blame]
Mike Marshall5db11c22015-07-17 10:38:12 -04001/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7#include "protocol.h"
8#include "pvfs2-kernel.h"
9#include "pvfs2-bufmap.h"
10
11struct readdir_handle_s {
12 int buffer_index;
13 struct pvfs2_readdir_response_s readdir_response;
14 void *dents_buf;
15};
16
17/*
18 * decode routine needed by kmod to make sense of the shared page for readdirs.
19 */
20static long decode_dirents(char *ptr, struct pvfs2_readdir_response_s *readdir)
21{
22 int i;
23 struct pvfs2_readdir_response_s *rd =
24 (struct pvfs2_readdir_response_s *) ptr;
25 char *buf = ptr;
Mike Marshall5db11c22015-07-17 10:38:12 -040026
27 readdir->token = rd->token;
28 readdir->pvfs_dirent_outcount = rd->pvfs_dirent_outcount;
Al Viroef4af942015-10-09 13:23:16 -040029 readdir->dirent_array = kcalloc(readdir->pvfs_dirent_outcount,
Mike Marshall5db11c22015-07-17 10:38:12 -040030 sizeof(*readdir->dirent_array),
31 GFP_KERNEL);
32 if (readdir->dirent_array == NULL)
33 return -ENOMEM;
Al Viro9be68b02015-10-09 17:43:15 -040034 buf += offsetof(struct pvfs2_readdir_response_s, dirent_array);
Mike Marshall5db11c22015-07-17 10:38:12 -040035 for (i = 0; i < readdir->pvfs_dirent_outcount; i++) {
Al Viro9be68b02015-10-09 17:43:15 -040036 __u32 len = *(__u32 *)buf;
37 readdir->dirent_array[i].d_name = buf + 4;
38 buf += roundup8(4 + len + 1);
39 readdir->dirent_array[i].d_length = len;
Mike Marshall5db11c22015-07-17 10:38:12 -040040 readdir->dirent_array[i].khandle =
Al Viro9be68b02015-10-09 17:43:15 -040041 *(struct pvfs2_khandle *) buf;
42 buf += 16;
Mike Marshall5db11c22015-07-17 10:38:12 -040043 }
Al Viro9be68b02015-10-09 17:43:15 -040044 return buf - ptr;
Mike Marshall5db11c22015-07-17 10:38:12 -040045}
46
47static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
48 int buffer_index)
49{
50 long ret;
51
52 if (buf == NULL) {
53 gossip_err
54 ("Invalid NULL buffer specified in readdir_handle_ctor\n");
55 return -ENOMEM;
56 }
57 if (buffer_index < 0) {
58 gossip_err
59 ("Invalid buffer index specified in readdir_handle_ctor\n");
60 return -EINVAL;
61 }
62 rhandle->buffer_index = buffer_index;
63 rhandle->dents_buf = buf;
64 ret = decode_dirents(buf, &rhandle->readdir_response);
65 if (ret < 0) {
66 gossip_err("Could not decode readdir from buffer %ld\n", ret);
67 rhandle->buffer_index = -1;
68 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf);
69 vfree(buf);
70 rhandle->dents_buf = NULL;
71 }
72 return ret;
73}
74
75static void readdir_handle_dtor(struct pvfs2_bufmap *bufmap,
76 struct readdir_handle_s *rhandle)
77{
78 if (rhandle == NULL)
79 return;
80
81 /* kfree(NULL) is safe */
82 kfree(rhandle->readdir_response.dirent_array);
83 rhandle->readdir_response.dirent_array = NULL;
84
85 if (rhandle->buffer_index >= 0) {
86 readdir_index_put(bufmap, rhandle->buffer_index);
87 rhandle->buffer_index = -1;
88 }
89 if (rhandle->dents_buf) {
90 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n",
91 rhandle->dents_buf);
92 vfree(rhandle->dents_buf);
93 rhandle->dents_buf = NULL;
94 }
95}
96
97/*
98 * Read directory entries from an instance of an open directory.
Mike Marshall5db11c22015-07-17 10:38:12 -040099 */
100static int pvfs2_readdir(struct file *file, struct dir_context *ctx)
101{
102 struct pvfs2_bufmap *bufmap = NULL;
103 int ret = 0;
104 int buffer_index;
Mike Marshall88309aa2015-09-23 16:48:40 -0400105 /*
106 * ptoken supports Orangefs' distributed directory logic, added
107 * in 2.9.2.
108 */
Mike Marshall5db11c22015-07-17 10:38:12 -0400109 __u64 *ptoken = file->private_data;
110 __u64 pos = 0;
111 ino_t ino = 0;
112 struct dentry *dentry = file->f_path.dentry;
113 struct pvfs2_kernel_op_s *new_op = NULL;
114 struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(dentry->d_inode);
115 int buffer_full = 0;
116 struct readdir_handle_s rhandle;
117 int i = 0;
118 int len = 0;
119 ino_t current_ino = 0;
120 char *current_entry = NULL;
121 long bytes_decoded;
122
Mike Marshall88309aa2015-09-23 16:48:40 -0400123 gossip_debug(GOSSIP_DIR_DEBUG,
124 "%s: ctx->pos:%lld, ptoken = %llu\n",
125 __func__,
126 lld(ctx->pos),
127 llu(*ptoken));
Mike Marshall5db11c22015-07-17 10:38:12 -0400128
129 pos = (__u64) ctx->pos;
130
131 /* are we done? */
132 if (pos == PVFS_READDIR_END) {
133 gossip_debug(GOSSIP_DIR_DEBUG,
134 "Skipping to termination path\n");
135 return 0;
136 }
137
138 gossip_debug(GOSSIP_DIR_DEBUG,
139 "pvfs2_readdir called on %s (pos=%llu)\n",
140 dentry->d_name.name, llu(pos));
141
142 rhandle.buffer_index = -1;
143 rhandle.dents_buf = NULL;
144 memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response));
145
146 new_op = op_alloc(PVFS2_VFS_OP_READDIR);
147 if (!new_op)
148 return -ENOMEM;
149
150 new_op->uses_shared_memory = 1;
151 new_op->upcall.req.readdir.refn = pvfs2_inode->refn;
152 new_op->upcall.req.readdir.max_dirent_count = MAX_DIRENT_COUNT_READDIR;
153
154 gossip_debug(GOSSIP_DIR_DEBUG,
155 "%s: upcall.req.readdir.refn.khandle: %pU\n",
156 __func__,
157 &new_op->upcall.req.readdir.refn.khandle);
158
Mike Marshall5db11c22015-07-17 10:38:12 -0400159 new_op->upcall.req.readdir.token = *ptoken;
160
161get_new_buffer_index:
162 ret = readdir_index_get(&bufmap, &buffer_index);
163 if (ret < 0) {
164 gossip_lerr("pvfs2_readdir: readdir_index_get() failure (%d)\n",
165 ret);
166 goto out_free_op;
167 }
168 new_op->upcall.req.readdir.buf_index = buffer_index;
169
170 ret = service_operation(new_op,
171 "pvfs2_readdir",
172 get_interruptible_flag(dentry->d_inode));
173
174 gossip_debug(GOSSIP_DIR_DEBUG,
175 "Readdir downcall status is %d. ret:%d\n",
176 new_op->downcall.status,
177 ret);
178
179 if (ret == -EAGAIN && op_state_purged(new_op)) {
180 /*
181 * readdir shared memory aread has been wiped due to
182 * pvfs2-client-core restarting, so we must get a new
183 * index into the shared memory.
184 */
185 gossip_debug(GOSSIP_DIR_DEBUG,
186 "%s: Getting new buffer_index for retry of readdir..\n",
187 __func__);
188 readdir_index_put(bufmap, buffer_index);
189 goto get_new_buffer_index;
190 }
191
192 if (ret == -EIO && op_state_purged(new_op)) {
193 gossip_err("%s: Client is down. Aborting readdir call.\n",
194 __func__);
195 readdir_index_put(bufmap, buffer_index);
196 goto out_free_op;
197 }
198
199 if (ret < 0 || new_op->downcall.status != 0) {
200 gossip_debug(GOSSIP_DIR_DEBUG,
201 "Readdir request failed. Status:%d\n",
202 new_op->downcall.status);
203 readdir_index_put(bufmap, buffer_index);
204 if (ret >= 0)
205 ret = new_op->downcall.status;
206 goto out_free_op;
207 }
208
209 bytes_decoded =
210 readdir_handle_ctor(&rhandle,
211 new_op->downcall.trailer_buf,
212 buffer_index);
213 if (bytes_decoded < 0) {
214 gossip_err("pvfs2_readdir: Could not decode trailer buffer into a readdir response %d\n",
215 ret);
216 ret = bytes_decoded;
217 readdir_index_put(bufmap, buffer_index);
218 goto out_free_op;
219 }
220
221 if (bytes_decoded != new_op->downcall.trailer_size) {
Mike Marshall88309aa2015-09-23 16:48:40 -0400222 gossip_err("pvfs2_readdir: # bytes decoded (%ld) "
223 "!= trailer size (%ld)\n",
224 bytes_decoded,
225 (long)new_op->downcall.trailer_size);
Mike Marshall5db11c22015-07-17 10:38:12 -0400226 ret = -EINVAL;
227 goto out_destroy_handle;
228 }
229
Mike Marshall88309aa2015-09-23 16:48:40 -0400230 /*
231 * pvfs2 doesn't actually store dot and dot-dot, but
232 * we need to have them represented.
233 */
Mike Marshall5db11c22015-07-17 10:38:12 -0400234 if (pos == 0) {
235 ino = get_ino_from_khandle(dentry->d_inode);
236 gossip_debug(GOSSIP_DIR_DEBUG,
237 "%s: calling dir_emit of \".\" with pos = %llu\n",
238 __func__,
239 llu(pos));
240 ret = dir_emit(ctx, ".", 1, ino, DT_DIR);
Mike Marshall88309aa2015-09-23 16:48:40 -0400241 pos += 1;
Mike Marshall5db11c22015-07-17 10:38:12 -0400242 }
243
244 if (pos == 1) {
245 ino = get_parent_ino_from_dentry(dentry);
246 gossip_debug(GOSSIP_DIR_DEBUG,
247 "%s: calling dir_emit of \"..\" with pos = %llu\n",
248 __func__,
249 llu(pos));
250 ret = dir_emit(ctx, "..", 2, ino, DT_DIR);
Mike Marshall88309aa2015-09-23 16:48:40 -0400251 pos += 1;
Mike Marshall5db11c22015-07-17 10:38:12 -0400252 }
253
Mike Marshall88309aa2015-09-23 16:48:40 -0400254 /*
255 * we stored PVFS_ITERATE_NEXT in ctx->pos last time around
256 * to prevent "finding" dot and dot-dot on any iteration
257 * other than the first.
258 */
259 if (ctx->pos == PVFS_ITERATE_NEXT)
260 ctx->pos = 0;
261
262 for (i = ctx->pos;
263 i < rhandle.readdir_response.pvfs_dirent_outcount;
264 i++) {
Mike Marshall5db11c22015-07-17 10:38:12 -0400265 len = rhandle.readdir_response.dirent_array[i].d_length;
266 current_entry = rhandle.readdir_response.dirent_array[i].d_name;
267 current_ino = pvfs2_khandle_to_ino(
268 &(rhandle.readdir_response.dirent_array[i].khandle));
269
270 gossip_debug(GOSSIP_DIR_DEBUG,
Mike Marshall88309aa2015-09-23 16:48:40 -0400271 "calling dir_emit for %s with len %d"
272 ", ctx->pos %ld\n",
Mike Marshall5db11c22015-07-17 10:38:12 -0400273 current_entry,
274 len,
Mike Marshall88309aa2015-09-23 16:48:40 -0400275 (unsigned long)ctx->pos);
276 /*
277 * type is unknown. We don't return object type
278 * in the dirent_array. This leaves getdents
279 * clueless about type.
280 */
Mike Marshall5db11c22015-07-17 10:38:12 -0400281 ret =
282 dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN);
Mike Marshall88309aa2015-09-23 16:48:40 -0400283 if (!ret)
284 break;
Mike Marshall5db11c22015-07-17 10:38:12 -0400285 ctx->pos++;
Mike Marshall88309aa2015-09-23 16:48:40 -0400286 gossip_debug(GOSSIP_DIR_DEBUG,
Mike Marshall5db11c22015-07-17 10:38:12 -0400287 "%s: ctx->pos:%lld\n",
288 __func__,
289 lld(ctx->pos));
290
Mike Marshall5db11c22015-07-17 10:38:12 -0400291 }
292
Mike Marshall54804942015-10-05 13:44:24 -0400293 /*
Mike Marshall88309aa2015-09-23 16:48:40 -0400294 * we ran all the way through the last batch, set up for
295 * getting another batch...
296 */
297 if (ret) {
Mike Marshall5db11c22015-07-17 10:38:12 -0400298 *ptoken = rhandle.readdir_response.token;
Mike Marshall88309aa2015-09-23 16:48:40 -0400299 ctx->pos = PVFS_ITERATE_NEXT;
Mike Marshall5db11c22015-07-17 10:38:12 -0400300 }
301
302 /*
303 * Did we hit the end of the directory?
304 */
305 if (rhandle.readdir_response.token == PVFS_READDIR_END &&
306 !buffer_full) {
Mike Marshall88309aa2015-09-23 16:48:40 -0400307 gossip_debug(GOSSIP_DIR_DEBUG,
308 "End of dir detected; setting ctx->pos to PVFS_READDIR_END.\n");
Mike Marshall5db11c22015-07-17 10:38:12 -0400309 ctx->pos = PVFS_READDIR_END;
310 }
311
Mike Marshall5db11c22015-07-17 10:38:12 -0400312out_destroy_handle:
313 readdir_handle_dtor(bufmap, &rhandle);
314out_free_op:
315 op_release(new_op);
316 gossip_debug(GOSSIP_DIR_DEBUG, "pvfs2_readdir returning %d\n", ret);
317 return ret;
318}
319
320static int pvfs2_dir_open(struct inode *inode, struct file *file)
321{
322 __u64 *ptoken;
323
324 file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL);
325 if (!file->private_data)
326 return -ENOMEM;
327
328 ptoken = file->private_data;
329 *ptoken = PVFS_READDIR_START;
330 return 0;
331}
332
333static int pvfs2_dir_release(struct inode *inode, struct file *file)
334{
335 pvfs2_flush_inode(inode);
336 kfree(file->private_data);
337 return 0;
338}
339
340/** PVFS2 implementation of VFS directory operations */
341const struct file_operations pvfs2_dir_operations = {
342 .read = generic_read_dir,
343 .iterate = pvfs2_readdir,
344 .open = pvfs2_dir_open,
345 .release = pvfs2_dir_release,
346};