~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/orangefs/dir.c

Version: ~ [ linux-5.1-rc1 ] ~ [ linux-5.0.3 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.30 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.107 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.164 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.176 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.136 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.63 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp