]> asedeno.scripts.mit.edu Git - linux.git/blob - fs/orangefs/dir.c
orangefs: skip forward to the next directory entry if seek is short
[linux.git] / fs / orangefs / dir.c
1 /*
2  * Copyright 2017 Omnibond Systems, L.L.C.
3  */
4
5 #include "protocol.h"
6 #include "orangefs-kernel.h"
7 #include "orangefs-bufmap.h"
8
9 struct orangefs_dir_part {
10         struct orangefs_dir_part *next;
11         size_t len;
12 };
13
14 struct orangefs_dir {
15         __u64 token;
16         struct orangefs_dir_part *part;
17         loff_t end;
18         int error;
19 };
20
21 #define PART_SHIFT (24)
22 #define PART_SIZE (1<<24)
23 #define PART_MASK (~(PART_SIZE - 1))
24
25 /*
26  * There can be up to 512 directory entries.  Each entry is encoded as
27  * follows:
28  * 4 bytes: string size (n)
29  * n bytes: string
30  * 1 byte: trailing zero
31  * padding to 8 bytes
32  * 16 bytes: khandle
33  * padding to 8 bytes
34  *
35  * The trailer_buf starts with a struct orangefs_readdir_response_s
36  * which must be skipped to get to the directory data.
37  *
38  * The data which is received from the userspace daemon is termed a
39  * part and is stored in a linked list in case more than one part is
40  * needed for a large directory.
41  *
42  * The position pointer (ctx->pos) encodes the part and offset on which
43  * to begin reading at.  Bits above PART_SHIFT encode the part and bits
44  * below PART_SHIFT encode the offset.  Parts are stored in a linked
45  * list which grows as data is received from the server.  The overhead
46  * associated with managing the list is presumed to be small compared to
47  * the overhead of communicating with the server.
48  *
49  * As data is received from the server, it is placed at the end of the
50  * part list.  Data is parsed from the current position as it is needed.
51  * When data is determined to be corrupt, it is either because the
52  * userspace component has sent back corrupt data or because the file
53  * pointer has been moved to an invalid location.  Since the two cannot
54  * be differentiated, return EIO.
55  *
56  * Part zero is synthesized to contains `.' and `..'.  Part one is the
57  * first part of the part list.
58  */
59
60 static int do_readdir(struct orangefs_inode_s *oi,
61     struct orangefs_dir *od, struct dentry *dentry,
62     struct orangefs_kernel_op_s *op)
63 {
64         struct orangefs_readdir_response_s *resp;
65         int bufi, r;
66
67         /*
68          * Despite the badly named field, readdir does not use shared
69          * memory.  However, there are a limited number of readdir
70          * slots, which must be allocated here.  This flag simply tells
71          * the op scheduler to return the op here for retry.
72          */
73         op->uses_shared_memory = 1;
74         op->upcall.req.readdir.refn = oi->refn;
75         op->upcall.req.readdir.token = od->token;
76         op->upcall.req.readdir.max_dirent_count =
77             ORANGEFS_MAX_DIRENT_COUNT_READDIR;
78
79 again:
80         bufi = orangefs_readdir_index_get();
81         if (bufi < 0) {
82                 od->error = bufi;
83                 return bufi;
84         }
85
86         op->upcall.req.readdir.buf_index = bufi;
87
88         r = service_operation(op, "orangefs_readdir",
89             get_interruptible_flag(dentry->d_inode));
90
91         orangefs_readdir_index_put(bufi);
92
93         if (op_state_purged(op)) {
94                 if (r == -EAGAIN) {
95                         vfree(op->downcall.trailer_buf);
96                         goto again;
97                 } else if (r == -EIO) {
98                         vfree(op->downcall.trailer_buf);
99                         od->error = r;
100                         return r;
101                 }
102         }
103
104         if (r < 0) {
105                 vfree(op->downcall.trailer_buf);
106                 od->error = r;
107                 return r;
108         } else if (op->downcall.status) {
109                 vfree(op->downcall.trailer_buf);
110                 od->error = op->downcall.status;
111                 return op->downcall.status;
112         }
113
114         /*
115          * The maximum size is size per entry times the 512 entries plus
116          * the header.  This is well under the limit.
117          */
118         if (op->downcall.trailer_size > PART_SIZE) {
119                 vfree(op->downcall.trailer_buf);
120                 od->error = -EIO;
121                 return -EIO;
122         }
123
124         resp = (struct orangefs_readdir_response_s *)
125             op->downcall.trailer_buf;
126         od->token = resp->token;
127         return 0;
128 }
129
130 static int parse_readdir(struct orangefs_dir *od,
131     struct orangefs_kernel_op_s *op)
132 {
133         struct orangefs_dir_part *part, *new;
134         size_t count;
135
136         count = 1;
137         part = od->part;
138         while (part && part->next) {
139                 part = part->next;
140                 count++;
141         }
142
143         new = (void *)op->downcall.trailer_buf;
144         new->next = NULL;
145         new->len = op->downcall.trailer_size -
146             sizeof(struct orangefs_readdir_response_s);
147         if (!od->part)
148                 od->part = new;
149         else
150                 part->next = new;
151         count++;
152         od->end = count << PART_SHIFT;
153
154         return 0;
155 }
156
157 static int orangefs_dir_more(struct orangefs_inode_s *oi,
158     struct orangefs_dir *od, struct dentry *dentry)
159 {
160         struct orangefs_kernel_op_s *op;
161         int r;
162
163         op = op_alloc(ORANGEFS_VFS_OP_READDIR);
164         if (!op) {
165                 od->error = -ENOMEM;
166                 return -ENOMEM;
167         }
168         r = do_readdir(oi, od, dentry, op);
169         if (r) {
170                 od->error = r;
171                 goto out;
172         }
173         r = parse_readdir(od, op);
174         if (r) {
175                 od->error = r;
176                 goto out;
177         }
178
179         od->error = 0;
180 out:
181         op_release(op);
182         return od->error;
183 }
184
185 static int fill_from_part(struct orangefs_dir_part *part,
186     struct dir_context *ctx)
187 {
188         const int offset = sizeof(struct orangefs_readdir_response_s);
189         struct orangefs_khandle *khandle;
190         __u32 *len, padlen;
191         loff_t i;
192         char *s;
193         i = ctx->pos & ~PART_MASK;
194
195         /* The file offset from userspace is too large. */
196         if (i > part->len)
197                 return 1;
198
199         /*
200          * If the seek pointer is positioned just before an entry it
201          * should find the next entry.
202          */
203         if (i % 8)
204                 i = i + (8 - i%8)%8;
205
206         while (i < part->len) {
207                 if (part->len < i + sizeof *len)
208                         break;
209                 len = (void *)part + offset + i;
210                 /*
211                  * len is the size of the string itself.  padlen is the
212                  * total size of the encoded string.
213                  */
214                 padlen = (sizeof *len + *len + 1) +
215                     (8 - (sizeof *len + *len + 1)%8)%8;
216                 if (part->len < i + padlen + sizeof *khandle)
217                         goto next;
218                 s = (void *)part + offset + i + sizeof *len;
219                 if (s[*len] != 0)
220                         goto next;
221                 khandle = (void *)part + offset + i + padlen;
222                 if (!dir_emit(ctx, s, *len,
223                     orangefs_khandle_to_ino(khandle),
224                     DT_UNKNOWN))
225                         return 0;
226                 i += padlen + sizeof *khandle;
227                 i = i + (8 - i%8)%8;
228                 BUG_ON(i > part->len);
229                 ctx->pos = (ctx->pos & PART_MASK) | i;
230                 continue;
231 next:
232                 i += 8;
233         }
234         return 1;
235 }
236
237 static int orangefs_dir_fill(struct orangefs_inode_s *oi,
238     struct orangefs_dir *od, struct dentry *dentry,
239     struct dir_context *ctx)
240 {
241         struct orangefs_dir_part *part;
242         size_t count;
243
244         count = ((ctx->pos & PART_MASK) >> PART_SHIFT) - 1;
245
246         part = od->part;
247         while (part->next && count) {
248                 count--;
249                 part = part->next;
250         }
251         /* This means the userspace file offset is invalid. */
252         if (count) {
253                 od->error = -EIO;
254                 return -EIO;
255         }
256
257         while (part && part->len) {
258                 int r;
259                 r = fill_from_part(part, ctx);
260                 if (r < 0) {
261                         od->error = r;
262                         return r;
263                 } else if (r == 0) {
264                         /* Userspace buffer is full. */
265                         break;
266                 } else {
267                         /*
268                          * The part ran out of data.  Move to the next
269                          * part. */
270                         ctx->pos = (ctx->pos & PART_MASK) +
271                             (1 << PART_SHIFT);
272                         part = part->next;
273                 }
274         }
275         return 0;
276 }
277
278 static int orangefs_dir_iterate(struct file *file,
279     struct dir_context *ctx)
280 {
281         struct orangefs_inode_s *oi;
282         struct orangefs_dir *od;
283         struct dentry *dentry;
284         int r;
285
286         dentry = file->f_path.dentry;
287         oi = ORANGEFS_I(dentry->d_inode);
288         od = file->private_data;
289
290         if (od->error)
291                 return od->error;
292
293         if (ctx->pos == 0) {
294                 if (!dir_emit_dot(file, ctx))
295                         return 0;
296                 ctx->pos++;
297         }
298         if (ctx->pos == 1) {
299                 if (!dir_emit_dotdot(file, ctx))
300                         return 0;
301                 ctx->pos = 1 << PART_SHIFT;
302         }
303
304         /*
305          * The seek position is in the first synthesized part but is not
306          * valid.
307          */
308         if ((ctx->pos & PART_MASK) == 0)
309                 return -EIO;
310
311         r = 0;
312
313         /*
314          * Must read more if the user has sought past what has been read
315          * so far.  Stop a user who has sought past the end.
316          */
317         while (od->token != ORANGEFS_ITERATE_END &&
318             ctx->pos > od->end) {
319                 r = orangefs_dir_more(oi, od, dentry);
320                 if (r)
321                         return r;
322         }
323         if (od->token == ORANGEFS_ITERATE_END && ctx->pos > od->end)
324                 return -EIO;
325
326         /* Then try to fill if there's any left in the buffer. */
327         if (ctx->pos < od->end) {
328                 r = orangefs_dir_fill(oi, od, dentry, ctx);
329                 if (r)
330                         return r;
331         }
332
333         /* Finally get some more and try to fill. */
334         if (od->token != ORANGEFS_ITERATE_END) {
335                 r = orangefs_dir_more(oi, od, dentry);
336                 if (r)
337                         return r;
338                 r = orangefs_dir_fill(oi, od, dentry, ctx);
339         }
340
341         return r;
342 }
343
344 static int orangefs_dir_open(struct inode *inode, struct file *file)
345 {
346         struct orangefs_dir *od;
347         file->private_data = kmalloc(sizeof(struct orangefs_dir),
348             GFP_KERNEL);
349         if (!file->private_data)
350                 return -ENOMEM;
351         od = file->private_data;
352         od->token = ORANGEFS_ITERATE_START;
353         od->part = NULL;
354         od->end = 1 << PART_SHIFT;
355         od->error = 0;
356         return 0;
357 }
358
359 static int orangefs_dir_release(struct inode *inode, struct file *file)
360 {
361         struct orangefs_dir *od = file->private_data;
362         struct orangefs_dir_part *part = od->part;
363         orangefs_flush_inode(inode);
364         while (part) {
365                 struct orangefs_dir_part *next = part->next;
366                 vfree(part);
367                 part = next;
368         }
369         kfree(od);
370         return 0;
371 }
372
373 const struct file_operations orangefs_dir_operations = {
374         .llseek = default_llseek,
375         .read = generic_read_dir,
376         .iterate = orangefs_dir_iterate,
377         .open = orangefs_dir_open,
378         .release = orangefs_dir_release
379 };