blob: c043894fc2bd8f337da5e8e68c53cb3707d15d7f [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"
Mike Marshall575e9462015-12-04 12:56:14 -05008#include "orangefs-kernel.h"
9#include "orangefs-bufmap.h"
Mike Marshall5db11c22015-07-17 10:38:12 -040010
11struct readdir_handle_s {
12 int buffer_index;
Yi Liu8bb8aef2015-11-24 15:12:14 -050013 struct orangefs_readdir_response_s readdir_response;
Mike Marshall5db11c22015-07-17 10:38:12 -040014 void *dents_buf;
15};
16
17/*
18 * decode routine needed by kmod to make sense of the shared page for readdirs.
19 */
Al Viro80928952015-10-09 18:11:10 -040020static long decode_dirents(char *ptr, size_t size,
Yi Liu8bb8aef2015-11-24 15:12:14 -050021 struct orangefs_readdir_response_s *readdir)
Mike Marshall5db11c22015-07-17 10:38:12 -040022{
23 int i;
Yi Liu8bb8aef2015-11-24 15:12:14 -050024 struct orangefs_readdir_response_s *rd =
25 (struct orangefs_readdir_response_s *) ptr;
Mike Marshall5db11c22015-07-17 10:38:12 -040026 char *buf = ptr;
Mike Marshall5db11c22015-07-17 10:38:12 -040027
Yi Liu8bb8aef2015-11-24 15:12:14 -050028 if (size < offsetof(struct orangefs_readdir_response_s, dirent_array))
Al Viro80928952015-10-09 18:11:10 -040029 return -EINVAL;
30
Mike Marshall5db11c22015-07-17 10:38:12 -040031 readdir->token = rd->token;
Yi Liu8bb8aef2015-11-24 15:12:14 -050032 readdir->orangefs_dirent_outcount = rd->orangefs_dirent_outcount;
33 readdir->dirent_array = kcalloc(readdir->orangefs_dirent_outcount,
Mike Marshall5db11c22015-07-17 10:38:12 -040034 sizeof(*readdir->dirent_array),
35 GFP_KERNEL);
36 if (readdir->dirent_array == NULL)
37 return -ENOMEM;
Al Viro80928952015-10-09 18:11:10 -040038
Yi Liu8bb8aef2015-11-24 15:12:14 -050039 buf += offsetof(struct orangefs_readdir_response_s, dirent_array);
40 size -= offsetof(struct orangefs_readdir_response_s, dirent_array);
Al Viro80928952015-10-09 18:11:10 -040041
Yi Liu8bb8aef2015-11-24 15:12:14 -050042 for (i = 0; i < readdir->orangefs_dirent_outcount; i++) {
Al Viro80928952015-10-09 18:11:10 -040043 __u32 len;
44
45 if (size < 4)
46 goto Einval;
47
48 len = *(__u32 *)buf;
49 if (len >= (unsigned)-24)
50 goto Einval;
51
Al Viro9be68b02015-10-09 17:43:15 -040052 readdir->dirent_array[i].d_name = buf + 4;
Al Viro9be68b02015-10-09 17:43:15 -040053 readdir->dirent_array[i].d_length = len;
Al Viro80928952015-10-09 18:11:10 -040054
55 len = roundup8(4 + len + 1);
56 if (size < len + 16)
57 goto Einval;
58 size -= len + 16;
59
60 buf += len;
61
Mike Marshall5db11c22015-07-17 10:38:12 -040062 readdir->dirent_array[i].khandle =
Yi Liu8bb8aef2015-11-24 15:12:14 -050063 *(struct orangefs_khandle *) buf;
Al Viro9be68b02015-10-09 17:43:15 -040064 buf += 16;
Mike Marshall5db11c22015-07-17 10:38:12 -040065 }
Al Viro9be68b02015-10-09 17:43:15 -040066 return buf - ptr;
Al Viro80928952015-10-09 18:11:10 -040067Einval:
68 kfree(readdir->dirent_array);
69 readdir->dirent_array = NULL;
70 return -EINVAL;
Mike Marshall5db11c22015-07-17 10:38:12 -040071}
72
73static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
Al Viro80928952015-10-09 18:11:10 -040074 size_t size, int buffer_index)
Mike Marshall5db11c22015-07-17 10:38:12 -040075{
76 long ret;
77
78 if (buf == NULL) {
79 gossip_err
80 ("Invalid NULL buffer specified in readdir_handle_ctor\n");
81 return -ENOMEM;
82 }
83 if (buffer_index < 0) {
84 gossip_err
85 ("Invalid buffer index specified in readdir_handle_ctor\n");
86 return -EINVAL;
87 }
88 rhandle->buffer_index = buffer_index;
89 rhandle->dents_buf = buf;
Al Viro80928952015-10-09 18:11:10 -040090 ret = decode_dirents(buf, size, &rhandle->readdir_response);
Mike Marshall5db11c22015-07-17 10:38:12 -040091 if (ret < 0) {
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);
95 vfree(buf);
96 rhandle->dents_buf = NULL;
97 }
98 return ret;
99}
100
Yi Liu8bb8aef2015-11-24 15:12:14 -0500101static void readdir_handle_dtor(struct orangefs_bufmap *bufmap,
Mike Marshall5db11c22015-07-17 10:38:12 -0400102 struct readdir_handle_s *rhandle)
103{
104 if (rhandle == NULL)
105 return;
106
107 /* kfree(NULL) is safe */
108 kfree(rhandle->readdir_response.dirent_array);
109 rhandle->readdir_response.dirent_array = NULL;
110
111 if (rhandle->buffer_index >= 0) {
112 readdir_index_put(bufmap, rhandle->buffer_index);
113 rhandle->buffer_index = -1;
114 }
115 if (rhandle->dents_buf) {
116 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n",
117 rhandle->dents_buf);
118 vfree(rhandle->dents_buf);
119 rhandle->dents_buf = NULL;
120 }
121}
122
123/*
124 * Read directory entries from an instance of an open directory.
Mike Marshall5db11c22015-07-17 10:38:12 -0400125 */
Yi Liu8bb8aef2015-11-24 15:12:14 -0500126static int orangefs_readdir(struct file *file, struct dir_context *ctx)
Mike Marshall5db11c22015-07-17 10:38:12 -0400127{
Yi Liu8bb8aef2015-11-24 15:12:14 -0500128 struct orangefs_bufmap *bufmap = NULL;
Mike Marshall5db11c22015-07-17 10:38:12 -0400129 int ret = 0;
130 int buffer_index;
Mike Marshall88309aa2015-09-23 16:48:40 -0400131 /*
132 * ptoken supports Orangefs' distributed directory logic, added
133 * in 2.9.2.
134 */
Mike Marshall5db11c22015-07-17 10:38:12 -0400135 __u64 *ptoken = file->private_data;
136 __u64 pos = 0;
137 ino_t ino = 0;
138 struct dentry *dentry = file->f_path.dentry;
Yi Liu8bb8aef2015-11-24 15:12:14 -0500139 struct orangefs_kernel_op_s *new_op = NULL;
140 struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(dentry->d_inode);
Mike Marshall5db11c22015-07-17 10:38:12 -0400141 int buffer_full = 0;
142 struct readdir_handle_s rhandle;
143 int i = 0;
144 int len = 0;
145 ino_t current_ino = 0;
146 char *current_entry = NULL;
147 long bytes_decoded;
148
Mike Marshall88309aa2015-09-23 16:48:40 -0400149 gossip_debug(GOSSIP_DIR_DEBUG,
150 "%s: ctx->pos:%lld, ptoken = %llu\n",
151 __func__,
152 lld(ctx->pos),
153 llu(*ptoken));
Mike Marshall5db11c22015-07-17 10:38:12 -0400154
155 pos = (__u64) ctx->pos;
156
157 /* are we done? */
Yi Liu8bb8aef2015-11-24 15:12:14 -0500158 if (pos == ORANGEFS_READDIR_END) {
Mike Marshall5db11c22015-07-17 10:38:12 -0400159 gossip_debug(GOSSIP_DIR_DEBUG,
160 "Skipping to termination path\n");
161 return 0;
162 }
163
164 gossip_debug(GOSSIP_DIR_DEBUG,
Yi Liu8bb8aef2015-11-24 15:12:14 -0500165 "orangefs_readdir called on %s (pos=%llu)\n",
Mike Marshall5db11c22015-07-17 10:38:12 -0400166 dentry->d_name.name, llu(pos));
167
168 rhandle.buffer_index = -1;
169 rhandle.dents_buf = NULL;
170 memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response));
171
Yi Liu8bb8aef2015-11-24 15:12:14 -0500172 new_op = op_alloc(ORANGEFS_VFS_OP_READDIR);
Mike Marshall5db11c22015-07-17 10:38:12 -0400173 if (!new_op)
174 return -ENOMEM;
175
176 new_op->uses_shared_memory = 1;
Yi Liu8bb8aef2015-11-24 15:12:14 -0500177 new_op->upcall.req.readdir.refn = orangefs_inode->refn;
Mike Marshall5db11c22015-07-17 10:38:12 -0400178 new_op->upcall.req.readdir.max_dirent_count = MAX_DIRENT_COUNT_READDIR;
179
180 gossip_debug(GOSSIP_DIR_DEBUG,
181 "%s: upcall.req.readdir.refn.khandle: %pU\n",
182 __func__,
183 &new_op->upcall.req.readdir.refn.khandle);
184
Mike Marshall5db11c22015-07-17 10:38:12 -0400185 new_op->upcall.req.readdir.token = *ptoken;
186
187get_new_buffer_index:
188 ret = readdir_index_get(&bufmap, &buffer_index);
189 if (ret < 0) {
Yi Liu8bb8aef2015-11-24 15:12:14 -0500190 gossip_lerr("orangefs_readdir: readdir_index_get() failure (%d)\n",
Mike Marshall5db11c22015-07-17 10:38:12 -0400191 ret);
192 goto out_free_op;
193 }
194 new_op->upcall.req.readdir.buf_index = buffer_index;
195
196 ret = service_operation(new_op,
Yi Liu8bb8aef2015-11-24 15:12:14 -0500197 "orangefs_readdir",
Mike Marshall5db11c22015-07-17 10:38:12 -0400198 get_interruptible_flag(dentry->d_inode));
199
200 gossip_debug(GOSSIP_DIR_DEBUG,
201 "Readdir downcall status is %d. ret:%d\n",
202 new_op->downcall.status,
203 ret);
204
205 if (ret == -EAGAIN && op_state_purged(new_op)) {
206 /*
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.
210 */
211 gossip_debug(GOSSIP_DIR_DEBUG,
212 "%s: Getting new buffer_index for retry of readdir..\n",
213 __func__);
214 readdir_index_put(bufmap, buffer_index);
215 goto get_new_buffer_index;
216 }
217
218 if (ret == -EIO && op_state_purged(new_op)) {
219 gossip_err("%s: Client is down. Aborting readdir call.\n",
220 __func__);
221 readdir_index_put(bufmap, buffer_index);
222 goto out_free_op;
223 }
224
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);
230 if (ret >= 0)
231 ret = new_op->downcall.status;
232 goto out_free_op;
233 }
234
235 bytes_decoded =
236 readdir_handle_ctor(&rhandle,
237 new_op->downcall.trailer_buf,
Al Viro80928952015-10-09 18:11:10 -0400238 new_op->downcall.trailer_size,
Mike Marshall5db11c22015-07-17 10:38:12 -0400239 buffer_index);
240 if (bytes_decoded < 0) {
Yi Liu8bb8aef2015-11-24 15:12:14 -0500241 gossip_err("orangefs_readdir: Could not decode trailer buffer into a readdir response %d\n",
Mike Marshall5db11c22015-07-17 10:38:12 -0400242 ret);
243 ret = bytes_decoded;
244 readdir_index_put(bufmap, buffer_index);
245 goto out_free_op;
246 }
247
248 if (bytes_decoded != new_op->downcall.trailer_size) {
Yi Liu8bb8aef2015-11-24 15:12:14 -0500249 gossip_err("orangefs_readdir: # bytes decoded (%ld) "
Mike Marshall88309aa2015-09-23 16:48:40 -0400250 "!= trailer size (%ld)\n",
251 bytes_decoded,
252 (long)new_op->downcall.trailer_size);
Mike Marshall5db11c22015-07-17 10:38:12 -0400253 ret = -EINVAL;
254 goto out_destroy_handle;
255 }
256
Mike Marshall88309aa2015-09-23 16:48:40 -0400257 /*
Yi Liu8bb8aef2015-11-24 15:12:14 -0500258 * orangefs doesn't actually store dot and dot-dot, but
Mike Marshall88309aa2015-09-23 16:48:40 -0400259 * we need to have them represented.
260 */
Mike Marshall5db11c22015-07-17 10:38:12 -0400261 if (pos == 0) {
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",
265 __func__,
266 llu(pos));
267 ret = dir_emit(ctx, ".", 1, ino, DT_DIR);
Mike Marshall88309aa2015-09-23 16:48:40 -0400268 pos += 1;
Mike Marshall5db11c22015-07-17 10:38:12 -0400269 }
270
271 if (pos == 1) {
272 ino = get_parent_ino_from_dentry(dentry);
273 gossip_debug(GOSSIP_DIR_DEBUG,
274 "%s: calling dir_emit of \"..\" with pos = %llu\n",
275 __func__,
276 llu(pos));
277 ret = dir_emit(ctx, "..", 2, ino, DT_DIR);
Mike Marshall88309aa2015-09-23 16:48:40 -0400278 pos += 1;
Mike Marshall5db11c22015-07-17 10:38:12 -0400279 }
280
Mike Marshall88309aa2015-09-23 16:48:40 -0400281 /*
Yi Liu8bb8aef2015-11-24 15:12:14 -0500282 * we stored ORANGEFS_ITERATE_NEXT in ctx->pos last time around
Mike Marshall88309aa2015-09-23 16:48:40 -0400283 * to prevent "finding" dot and dot-dot on any iteration
284 * other than the first.
285 */
Yi Liu8bb8aef2015-11-24 15:12:14 -0500286 if (ctx->pos == ORANGEFS_ITERATE_NEXT)
Mike Marshall88309aa2015-09-23 16:48:40 -0400287 ctx->pos = 0;
288
289 for (i = ctx->pos;
Yi Liu8bb8aef2015-11-24 15:12:14 -0500290 i < rhandle.readdir_response.orangefs_dirent_outcount;
Mike Marshall88309aa2015-09-23 16:48:40 -0400291 i++) {
Mike Marshall5db11c22015-07-17 10:38:12 -0400292 len = rhandle.readdir_response.dirent_array[i].d_length;
293 current_entry = rhandle.readdir_response.dirent_array[i].d_name;
Yi Liu8bb8aef2015-11-24 15:12:14 -0500294 current_ino = orangefs_khandle_to_ino(
Mike Marshall5db11c22015-07-17 10:38:12 -0400295 &(rhandle.readdir_response.dirent_array[i].khandle));
296
297 gossip_debug(GOSSIP_DIR_DEBUG,
Mike Marshall88309aa2015-09-23 16:48:40 -0400298 "calling dir_emit for %s with len %d"
299 ", ctx->pos %ld\n",
Mike Marshall5db11c22015-07-17 10:38:12 -0400300 current_entry,
301 len,
Mike Marshall88309aa2015-09-23 16:48:40 -0400302 (unsigned long)ctx->pos);
303 /*
304 * type is unknown. We don't return object type
305 * in the dirent_array. This leaves getdents
306 * clueless about type.
307 */
Mike Marshall5db11c22015-07-17 10:38:12 -0400308 ret =
309 dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN);
Mike Marshall88309aa2015-09-23 16:48:40 -0400310 if (!ret)
311 break;
Mike Marshall5db11c22015-07-17 10:38:12 -0400312 ctx->pos++;
Mike Marshall88309aa2015-09-23 16:48:40 -0400313 gossip_debug(GOSSIP_DIR_DEBUG,
Mike Marshall5db11c22015-07-17 10:38:12 -0400314 "%s: ctx->pos:%lld\n",
315 __func__,
316 lld(ctx->pos));
317
Mike Marshall5db11c22015-07-17 10:38:12 -0400318 }
319
Mike Marshall54804942015-10-05 13:44:24 -0400320 /*
Mike Marshall88309aa2015-09-23 16:48:40 -0400321 * we ran all the way through the last batch, set up for
322 * getting another batch...
323 */
324 if (ret) {
Mike Marshall5db11c22015-07-17 10:38:12 -0400325 *ptoken = rhandle.readdir_response.token;
Yi Liu8bb8aef2015-11-24 15:12:14 -0500326 ctx->pos = ORANGEFS_ITERATE_NEXT;
Mike Marshall5db11c22015-07-17 10:38:12 -0400327 }
328
329 /*
330 * Did we hit the end of the directory?
331 */
Yi Liu8bb8aef2015-11-24 15:12:14 -0500332 if (rhandle.readdir_response.token == ORANGEFS_READDIR_END &&
Mike Marshall5db11c22015-07-17 10:38:12 -0400333 !buffer_full) {
Mike Marshall88309aa2015-09-23 16:48:40 -0400334 gossip_debug(GOSSIP_DIR_DEBUG,
Yi Liu8bb8aef2015-11-24 15:12:14 -0500335 "End of dir detected; setting ctx->pos to ORANGEFS_READDIR_END.\n");
336 ctx->pos = ORANGEFS_READDIR_END;
Mike Marshall5db11c22015-07-17 10:38:12 -0400337 }
338
Mike Marshall5db11c22015-07-17 10:38:12 -0400339out_destroy_handle:
340 readdir_handle_dtor(bufmap, &rhandle);
341out_free_op:
342 op_release(new_op);
Yi Liu8bb8aef2015-11-24 15:12:14 -0500343 gossip_debug(GOSSIP_DIR_DEBUG, "orangefs_readdir returning %d\n", ret);
Mike Marshall5db11c22015-07-17 10:38:12 -0400344 return ret;
345}
346
Yi Liu8bb8aef2015-11-24 15:12:14 -0500347static int orangefs_dir_open(struct inode *inode, struct file *file)
Mike Marshall5db11c22015-07-17 10:38:12 -0400348{
349 __u64 *ptoken;
350
351 file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL);
352 if (!file->private_data)
353 return -ENOMEM;
354
355 ptoken = file->private_data;
Yi Liu8bb8aef2015-11-24 15:12:14 -0500356 *ptoken = ORANGEFS_READDIR_START;
Mike Marshall5db11c22015-07-17 10:38:12 -0400357 return 0;
358}
359
Yi Liu8bb8aef2015-11-24 15:12:14 -0500360static int orangefs_dir_release(struct inode *inode, struct file *file)
Mike Marshall5db11c22015-07-17 10:38:12 -0400361{
Yi Liu8bb8aef2015-11-24 15:12:14 -0500362 orangefs_flush_inode(inode);
Mike Marshall5db11c22015-07-17 10:38:12 -0400363 kfree(file->private_data);
364 return 0;
365}
366
Yi Liu8bb8aef2015-11-24 15:12:14 -0500367/** ORANGEFS implementation of VFS directory operations */
368const struct file_operations orangefs_dir_operations = {
Mike Marshall5db11c22015-07-17 10:38:12 -0400369 .read = generic_read_dir,
Yi Liu8bb8aef2015-11-24 15:12:14 -0500370 .iterate = orangefs_readdir,
371 .open = orangefs_dir_open,
372 .release = orangefs_dir_release,
Mike Marshall5db11c22015-07-17 10:38:12 -0400373};