]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - fs/orangefs/dir.c
Merge remote-tracking branch 'orangefs/for-next'
[karo-tx-linux.git] / fs / orangefs / dir.c
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"
8 #include "pvfs2-kernel.h"
9 #include "pvfs2-bufmap.h"
10
11 struct 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  */
20 static 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;
26         char **pptr = &buf;
27
28         readdir->token = rd->token;
29         readdir->pvfs_dirent_outcount = rd->pvfs_dirent_outcount;
30         readdir->dirent_array = kmalloc(readdir->pvfs_dirent_outcount *
31                                         sizeof(*readdir->dirent_array),
32                                         GFP_KERNEL);
33         if (readdir->dirent_array == NULL)
34                 return -ENOMEM;
35         *pptr += offsetof(struct pvfs2_readdir_response_s, dirent_array);
36         for (i = 0; i < readdir->pvfs_dirent_outcount; i++) {
37                 dec_string(pptr, &readdir->dirent_array[i].d_name,
38                            &readdir->dirent_array[i].d_length);
39                 readdir->dirent_array[i].khandle =
40                         *(struct pvfs2_khandle *) *pptr;
41                 *pptr += 16;
42         }
43         return (unsigned long)*pptr - (unsigned long)ptr;
44 }
45
46 static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf,
47                                 int buffer_index)
48 {
49         long ret;
50
51         if (buf == NULL) {
52                 gossip_err
53                     ("Invalid NULL buffer specified in readdir_handle_ctor\n");
54                 return -ENOMEM;
55         }
56         if (buffer_index < 0) {
57                 gossip_err
58                     ("Invalid buffer index specified in readdir_handle_ctor\n");
59                 return -EINVAL;
60         }
61         rhandle->buffer_index = buffer_index;
62         rhandle->dents_buf = buf;
63         ret = decode_dirents(buf, &rhandle->readdir_response);
64         if (ret < 0) {
65                 gossip_err("Could not decode readdir from buffer %ld\n", ret);
66                 rhandle->buffer_index = -1;
67                 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf);
68                 vfree(buf);
69                 rhandle->dents_buf = NULL;
70         }
71         return ret;
72 }
73
74 static void readdir_handle_dtor(struct pvfs2_bufmap *bufmap,
75                 struct readdir_handle_s *rhandle)
76 {
77         if (rhandle == NULL)
78                 return;
79
80         /* kfree(NULL) is safe */
81         kfree(rhandle->readdir_response.dirent_array);
82         rhandle->readdir_response.dirent_array = NULL;
83
84         if (rhandle->buffer_index >= 0) {
85                 readdir_index_put(bufmap, rhandle->buffer_index);
86                 rhandle->buffer_index = -1;
87         }
88         if (rhandle->dents_buf) {
89                 gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n",
90                              rhandle->dents_buf);
91                 vfree(rhandle->dents_buf);
92                 rhandle->dents_buf = NULL;
93         }
94 }
95
96 /*
97  * Read directory entries from an instance of an open directory.
98  */
99 static int pvfs2_readdir(struct file *file, struct dir_context *ctx)
100 {
101         struct pvfs2_bufmap *bufmap = NULL;
102         int ret = 0;
103         int buffer_index;
104         /*
105          * ptoken supports Orangefs' distributed directory logic, added
106          * in 2.9.2.
107          */
108         __u64 *ptoken = file->private_data;
109         __u64 pos = 0;
110         ino_t ino = 0;
111         struct dentry *dentry = file->f_path.dentry;
112         struct pvfs2_kernel_op_s *new_op = NULL;
113         struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(dentry->d_inode);
114         int buffer_full = 0;
115         struct readdir_handle_s rhandle;
116         int i = 0;
117         int len = 0;
118         ino_t current_ino = 0;
119         char *current_entry = NULL;
120         long bytes_decoded;
121
122         gossip_debug(GOSSIP_DIR_DEBUG,
123                      "%s: ctx->pos:%lld, ptoken = %llu\n",
124                      __func__,
125                      lld(ctx->pos),
126                      llu(*ptoken));
127
128         pos = (__u64) ctx->pos;
129
130         /* are we done? */
131         if (pos == PVFS_READDIR_END) {
132                 gossip_debug(GOSSIP_DIR_DEBUG,
133                              "Skipping to termination path\n");
134                 return 0;
135         }
136
137         gossip_debug(GOSSIP_DIR_DEBUG,
138                      "pvfs2_readdir called on %s (pos=%llu)\n",
139                      dentry->d_name.name, llu(pos));
140
141         rhandle.buffer_index = -1;
142         rhandle.dents_buf = NULL;
143         memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response));
144
145         new_op = op_alloc(PVFS2_VFS_OP_READDIR);
146         if (!new_op)
147                 return -ENOMEM;
148
149         new_op->uses_shared_memory = 1;
150         new_op->upcall.req.readdir.refn = pvfs2_inode->refn;
151         new_op->upcall.req.readdir.max_dirent_count = MAX_DIRENT_COUNT_READDIR;
152
153         gossip_debug(GOSSIP_DIR_DEBUG,
154                      "%s: upcall.req.readdir.refn.khandle: %pU\n",
155                      __func__,
156                      &new_op->upcall.req.readdir.refn.khandle);
157
158         new_op->upcall.req.readdir.token = *ptoken;
159
160 get_new_buffer_index:
161         ret = readdir_index_get(&bufmap, &buffer_index);
162         if (ret < 0) {
163                 gossip_lerr("pvfs2_readdir: readdir_index_get() failure (%d)\n",
164                             ret);
165                 goto out_free_op;
166         }
167         new_op->upcall.req.readdir.buf_index = buffer_index;
168
169         ret = service_operation(new_op,
170                                 "pvfs2_readdir",
171                                 get_interruptible_flag(dentry->d_inode));
172
173         gossip_debug(GOSSIP_DIR_DEBUG,
174                      "Readdir downcall status is %d.  ret:%d\n",
175                      new_op->downcall.status,
176                      ret);
177
178         if (ret == -EAGAIN && op_state_purged(new_op)) {
179                 /*
180                  * readdir shared memory aread has been wiped due to
181                  * pvfs2-client-core restarting, so we must get a new
182                  * index into the shared memory.
183                  */
184                 gossip_debug(GOSSIP_DIR_DEBUG,
185                         "%s: Getting new buffer_index for retry of readdir..\n",
186                          __func__);
187                 readdir_index_put(bufmap, buffer_index);
188                 goto get_new_buffer_index;
189         }
190
191         if (ret == -EIO && op_state_purged(new_op)) {
192                 gossip_err("%s: Client is down. Aborting readdir call.\n",
193                         __func__);
194                 readdir_index_put(bufmap, buffer_index);
195                 goto out_free_op;
196         }
197
198         if (ret < 0 || new_op->downcall.status != 0) {
199                 gossip_debug(GOSSIP_DIR_DEBUG,
200                              "Readdir request failed.  Status:%d\n",
201                              new_op->downcall.status);
202                 readdir_index_put(bufmap, buffer_index);
203                 if (ret >= 0)
204                         ret = new_op->downcall.status;
205                 goto out_free_op;
206         }
207
208         bytes_decoded =
209                 readdir_handle_ctor(&rhandle,
210                                     new_op->downcall.trailer_buf,
211                                     buffer_index);
212         if (bytes_decoded < 0) {
213                 gossip_err("pvfs2_readdir: Could not decode trailer buffer into a readdir response %d\n",
214                         ret);
215                 ret = bytes_decoded;
216                 readdir_index_put(bufmap, buffer_index);
217                 goto out_free_op;
218         }
219
220         if (bytes_decoded != new_op->downcall.trailer_size) {
221                 gossip_err("pvfs2_readdir: # bytes decoded (%ld) "
222                            "!= trailer size (%ld)\n",
223                            bytes_decoded,
224                            (long)new_op->downcall.trailer_size);
225                 ret = -EINVAL;
226                 goto out_destroy_handle;
227         }
228
229         /*
230          *  pvfs2 doesn't actually store dot and dot-dot, but
231          *  we need to have them represented.
232          */
233         if (pos == 0) {
234                 ino = get_ino_from_khandle(dentry->d_inode);
235                 gossip_debug(GOSSIP_DIR_DEBUG,
236                              "%s: calling dir_emit of \".\" with pos = %llu\n",
237                              __func__,
238                              llu(pos));
239                 ret = dir_emit(ctx, ".", 1, ino, DT_DIR);
240                 pos += 1;
241         }
242
243         if (pos == 1) {
244                 ino = get_parent_ino_from_dentry(dentry);
245                 gossip_debug(GOSSIP_DIR_DEBUG,
246                              "%s: calling dir_emit of \"..\" with pos = %llu\n",
247                              __func__,
248                              llu(pos));
249                 ret = dir_emit(ctx, "..", 2, ino, DT_DIR);
250                 pos += 1;
251         }
252
253         /*
254          * we stored PVFS_ITERATE_NEXT in ctx->pos last time around
255          * to prevent "finding" dot and dot-dot on any iteration
256          * other than the first.
257          */
258         if (ctx->pos == PVFS_ITERATE_NEXT)
259                 ctx->pos = 0;
260
261         for (i = ctx->pos;
262              i < rhandle.readdir_response.pvfs_dirent_outcount;
263              i++) {
264                 len = rhandle.readdir_response.dirent_array[i].d_length;
265                 current_entry = rhandle.readdir_response.dirent_array[i].d_name;
266                 current_ino = pvfs2_khandle_to_ino(
267                         &(rhandle.readdir_response.dirent_array[i].khandle));
268
269                 gossip_debug(GOSSIP_DIR_DEBUG,
270                              "calling dir_emit for %s with len %d"
271                              ", ctx->pos %ld\n",
272                              current_entry,
273                              len,
274                              (unsigned long)ctx->pos);
275                 /*
276                  * type is unknown. We don't return object type
277                  * in the dirent_array. This leaves getdents
278                  * clueless about type.
279                  */
280                 ret =
281                     dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN);
282                 if (!ret)
283                         break;
284                 ctx->pos++;
285                 gossip_debug(GOSSIP_DIR_DEBUG,
286                               "%s: ctx->pos:%lld\n",
287                               __func__,
288                               lld(ctx->pos));
289
290         }
291
292         /*
293          * we ran all the way through the last batch, set up for
294          * getting another batch...
295          */
296         if (ret) {
297                 *ptoken = rhandle.readdir_response.token;
298                 ctx->pos = PVFS_ITERATE_NEXT;
299         }
300
301         /*
302          * Did we hit the end of the directory?
303          */
304         if (rhandle.readdir_response.token == PVFS_READDIR_END &&
305             !buffer_full) {
306                 gossip_debug(GOSSIP_DIR_DEBUG,
307                 "End of dir detected; setting ctx->pos to PVFS_READDIR_END.\n");
308                 ctx->pos = PVFS_READDIR_END;
309         }
310
311 out_destroy_handle:
312         readdir_handle_dtor(bufmap, &rhandle);
313 out_free_op:
314         op_release(new_op);
315         gossip_debug(GOSSIP_DIR_DEBUG, "pvfs2_readdir returning %d\n", ret);
316         return ret;
317 }
318
319 static int pvfs2_dir_open(struct inode *inode, struct file *file)
320 {
321         __u64 *ptoken;
322
323         file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL);
324         if (!file->private_data)
325                 return -ENOMEM;
326
327         ptoken = file->private_data;
328         *ptoken = PVFS_READDIR_START;
329         return 0;
330 }
331
332 static int pvfs2_dir_release(struct inode *inode, struct file *file)
333 {
334         pvfs2_flush_inode(inode);
335         kfree(file->private_data);
336         return 0;
337 }
338
339 /** PVFS2 implementation of VFS directory operations */
340 const struct file_operations pvfs2_dir_operations = {
341         .read = generic_read_dir,
342         .iterate = pvfs2_readdir,
343         .open = pvfs2_dir_open,
344         .release = pvfs2_dir_release,
345 };