Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright 2017 Omnibond Systems, L.L.C.
0004  */
0005 
0006 #include "protocol.h"
0007 #include "orangefs-kernel.h"
0008 #include "orangefs-bufmap.h"
0009 
0010 struct orangefs_dir_part {
0011     struct orangefs_dir_part *next;
0012     size_t len;
0013 };
0014 
0015 struct orangefs_dir {
0016     __u64 token;
0017     struct orangefs_dir_part *part;
0018     loff_t end;
0019     int error;
0020 };
0021 
0022 #define PART_SHIFT (24)
0023 #define PART_SIZE (1<<24)
0024 #define PART_MASK (~(PART_SIZE - 1))
0025 
0026 /*
0027  * There can be up to 512 directory entries.  Each entry is encoded as
0028  * follows:
0029  * 4 bytes: string size (n)
0030  * n bytes: string
0031  * 1 byte: trailing zero
0032  * padding to 8 bytes
0033  * 16 bytes: khandle
0034  * padding to 8 bytes
0035  *
0036  * The trailer_buf starts with a struct orangefs_readdir_response_s
0037  * which must be skipped to get to the directory data.
0038  *
0039  * The data which is received from the userspace daemon is termed a
0040  * part and is stored in a linked list in case more than one part is
0041  * needed for a large directory.
0042  *
0043  * The position pointer (ctx->pos) encodes the part and offset on which
0044  * to begin reading at.  Bits above PART_SHIFT encode the part and bits
0045  * below PART_SHIFT encode the offset.  Parts are stored in a linked
0046  * list which grows as data is received from the server.  The overhead
0047  * associated with managing the list is presumed to be small compared to
0048  * the overhead of communicating with the server.
0049  *
0050  * As data is received from the server, it is placed at the end of the
0051  * part list.  Data is parsed from the current position as it is needed.
0052  * When data is determined to be corrupt, it is either because the
0053  * userspace component has sent back corrupt data or because the file
0054  * pointer has been moved to an invalid location.  Since the two cannot
0055  * be differentiated, return EIO.
0056  *
0057  * Part zero is synthesized to contains `.' and `..'.  Part one is the
0058  * first part of the part list.
0059  */
0060 
0061 static int do_readdir(struct orangefs_inode_s *oi,
0062     struct orangefs_dir *od, struct dentry *dentry,
0063     struct orangefs_kernel_op_s *op)
0064 {
0065     struct orangefs_readdir_response_s *resp;
0066     int bufi, r;
0067 
0068     /*
0069      * Despite the badly named field, readdir does not use shared
0070      * memory.  However, there are a limited number of readdir
0071      * slots, which must be allocated here.  This flag simply tells
0072      * the op scheduler to return the op here for retry.
0073      */
0074     op->uses_shared_memory = 1;
0075     op->upcall.req.readdir.refn = oi->refn;
0076     op->upcall.req.readdir.token = od->token;
0077     op->upcall.req.readdir.max_dirent_count =
0078         ORANGEFS_MAX_DIRENT_COUNT_READDIR;
0079 
0080 again:
0081     bufi = orangefs_readdir_index_get();
0082     if (bufi < 0) {
0083         od->error = bufi;
0084         return bufi;
0085     }
0086 
0087     op->upcall.req.readdir.buf_index = bufi;
0088 
0089     r = service_operation(op, "orangefs_readdir",
0090         get_interruptible_flag(dentry->d_inode));
0091 
0092     orangefs_readdir_index_put(bufi);
0093 
0094     if (op_state_purged(op)) {
0095         if (r == -EAGAIN) {
0096             vfree(op->downcall.trailer_buf);
0097             goto again;
0098         } else if (r == -EIO) {
0099             vfree(op->downcall.trailer_buf);
0100             od->error = r;
0101             return r;
0102         }
0103     }
0104 
0105     if (r < 0) {
0106         vfree(op->downcall.trailer_buf);
0107         od->error = r;
0108         return r;
0109     } else if (op->downcall.status) {
0110         vfree(op->downcall.trailer_buf);
0111         od->error = op->downcall.status;
0112         return op->downcall.status;
0113     }
0114 
0115     /*
0116      * The maximum size is size per entry times the 512 entries plus
0117      * the header.  This is well under the limit.
0118      */
0119     if (op->downcall.trailer_size > PART_SIZE) {
0120         vfree(op->downcall.trailer_buf);
0121         od->error = -EIO;
0122         return -EIO;
0123     }
0124 
0125     resp = (struct orangefs_readdir_response_s *)
0126         op->downcall.trailer_buf;
0127     od->token = resp->token;
0128     return 0;
0129 }
0130 
0131 static int parse_readdir(struct orangefs_dir *od,
0132     struct orangefs_kernel_op_s *op)
0133 {
0134     struct orangefs_dir_part *part, *new;
0135     size_t count;
0136 
0137     count = 1;
0138     part = od->part;
0139     while (part) {
0140         count++;
0141         if (part->next)
0142             part = part->next;
0143         else
0144             break;
0145     }
0146 
0147     new = (void *)op->downcall.trailer_buf;
0148     new->next = NULL;
0149     new->len = op->downcall.trailer_size -
0150         sizeof(struct orangefs_readdir_response_s);
0151     if (!od->part)
0152         od->part = new;
0153     else
0154         part->next = new;
0155     count++;
0156     od->end = count << PART_SHIFT;
0157 
0158     return 0;
0159 }
0160 
0161 static int orangefs_dir_more(struct orangefs_inode_s *oi,
0162     struct orangefs_dir *od, struct dentry *dentry)
0163 {
0164     struct orangefs_kernel_op_s *op;
0165     int r;
0166 
0167     op = op_alloc(ORANGEFS_VFS_OP_READDIR);
0168     if (!op) {
0169         od->error = -ENOMEM;
0170         return -ENOMEM;
0171     }
0172     r = do_readdir(oi, od, dentry, op);
0173     if (r) {
0174         od->error = r;
0175         goto out;
0176     }
0177     r = parse_readdir(od, op);
0178     if (r) {
0179         od->error = r;
0180         goto out;
0181     }
0182 
0183     od->error = 0;
0184 out:
0185     op_release(op);
0186     return od->error;
0187 }
0188 
0189 static int fill_from_part(struct orangefs_dir_part *part,
0190     struct dir_context *ctx)
0191 {
0192     const int offset = sizeof(struct orangefs_readdir_response_s);
0193     struct orangefs_khandle *khandle;
0194     __u32 *len, padlen;
0195     loff_t i;
0196     char *s;
0197     i = ctx->pos & ~PART_MASK;
0198 
0199     /* The file offset from userspace is too large. */
0200     if (i > part->len)
0201         return 1;
0202 
0203     /*
0204      * If the seek pointer is positioned just before an entry it
0205      * should find the next entry.
0206      */
0207     if (i % 8)
0208         i = i + (8 - i%8)%8;
0209 
0210     while (i < part->len) {
0211         if (part->len < i + sizeof *len)
0212             break;
0213         len = (void *)part + offset + i;
0214         /*
0215          * len is the size of the string itself.  padlen is the
0216          * total size of the encoded string.
0217          */
0218         padlen = (sizeof *len + *len + 1) +
0219             (8 - (sizeof *len + *len + 1)%8)%8;
0220         if (part->len < i + padlen + sizeof *khandle)
0221             goto next;
0222         s = (void *)part + offset + i + sizeof *len;
0223         if (s[*len] != 0)
0224             goto next;
0225         khandle = (void *)part + offset + i + padlen;
0226         if (!dir_emit(ctx, s, *len,
0227             orangefs_khandle_to_ino(khandle),
0228             DT_UNKNOWN))
0229             return 0;
0230         i += padlen + sizeof *khandle;
0231         i = i + (8 - i%8)%8;
0232         BUG_ON(i > part->len);
0233         ctx->pos = (ctx->pos & PART_MASK) | i;
0234         continue;
0235 next:
0236         i += 8;
0237     }
0238     return 1;
0239 }
0240 
0241 static int orangefs_dir_fill(struct orangefs_inode_s *oi,
0242     struct orangefs_dir *od, struct dentry *dentry,
0243     struct dir_context *ctx)
0244 {
0245     struct orangefs_dir_part *part;
0246     size_t count;
0247 
0248     count = ((ctx->pos & PART_MASK) >> PART_SHIFT) - 1;
0249 
0250     part = od->part;
0251     while (part->next && count) {
0252         count--;
0253         part = part->next;
0254     }
0255     /* This means the userspace file offset is invalid. */
0256     if (count) {
0257         od->error = -EIO;
0258         return -EIO;
0259     }
0260 
0261     while (part && part->len) {
0262         int r;
0263         r = fill_from_part(part, ctx);
0264         if (r < 0) {
0265             od->error = r;
0266             return r;
0267         } else if (r == 0) {
0268             /* Userspace buffer is full. */
0269             break;
0270         } else {
0271             /*
0272              * The part ran out of data.  Move to the next
0273              * part. */
0274             ctx->pos = (ctx->pos & PART_MASK) +
0275                 (1 << PART_SHIFT);
0276             part = part->next;
0277         }
0278     }
0279     return 0;
0280 }
0281 
0282 static loff_t orangefs_dir_llseek(struct file *file, loff_t offset,
0283     int whence)
0284 {
0285     struct orangefs_dir *od = file->private_data;
0286     /*
0287      * Delete the stored data so userspace sees new directory
0288      * entries.
0289      */
0290     if (!whence && offset < od->end) {
0291         struct orangefs_dir_part *part = od->part;
0292         while (part) {
0293             struct orangefs_dir_part *next = part->next;
0294             vfree(part);
0295             part = next;
0296         }
0297         od->token = ORANGEFS_ITERATE_START;
0298         od->part = NULL;
0299         od->end = 1 << PART_SHIFT;
0300     }
0301     return default_llseek(file, offset, whence);
0302 }
0303 
0304 static int orangefs_dir_iterate(struct file *file,
0305     struct dir_context *ctx)
0306 {
0307     struct orangefs_inode_s *oi;
0308     struct orangefs_dir *od;
0309     struct dentry *dentry;
0310     int r;
0311 
0312     dentry = file->f_path.dentry;
0313     oi = ORANGEFS_I(dentry->d_inode);
0314     od = file->private_data;
0315 
0316     if (od->error)
0317         return od->error;
0318 
0319     if (ctx->pos == 0) {
0320         if (!dir_emit_dot(file, ctx))
0321             return 0;
0322         ctx->pos++;
0323     }
0324     if (ctx->pos == 1) {
0325         if (!dir_emit_dotdot(file, ctx))
0326             return 0;
0327         ctx->pos = 1 << PART_SHIFT;
0328     }
0329 
0330     /*
0331      * The seek position is in the first synthesized part but is not
0332      * valid.
0333      */
0334     if ((ctx->pos & PART_MASK) == 0)
0335         return -EIO;
0336 
0337     r = 0;
0338 
0339     /*
0340      * Must read more if the user has sought past what has been read
0341      * so far.  Stop a user who has sought past the end.
0342      */
0343     while (od->token != ORANGEFS_ITERATE_END &&
0344         ctx->pos > od->end) {
0345         r = orangefs_dir_more(oi, od, dentry);
0346         if (r)
0347             return r;
0348     }
0349     if (od->token == ORANGEFS_ITERATE_END && ctx->pos > od->end)
0350         return -EIO;
0351 
0352     /* Then try to fill if there's any left in the buffer. */
0353     if (ctx->pos < od->end) {
0354         r = orangefs_dir_fill(oi, od, dentry, ctx);
0355         if (r)
0356             return r;
0357     }
0358 
0359     /* Finally get some more and try to fill. */
0360     if (od->token != ORANGEFS_ITERATE_END) {
0361         r = orangefs_dir_more(oi, od, dentry);
0362         if (r)
0363             return r;
0364         r = orangefs_dir_fill(oi, od, dentry, ctx);
0365     }
0366 
0367     return r;
0368 }
0369 
0370 static int orangefs_dir_open(struct inode *inode, struct file *file)
0371 {
0372     struct orangefs_dir *od;
0373     file->private_data = kmalloc(sizeof(struct orangefs_dir),
0374         GFP_KERNEL);
0375     if (!file->private_data)
0376         return -ENOMEM;
0377     od = file->private_data;
0378     od->token = ORANGEFS_ITERATE_START;
0379     od->part = NULL;
0380     od->end = 1 << PART_SHIFT;
0381     od->error = 0;
0382     return 0;
0383 }
0384 
0385 static int orangefs_dir_release(struct inode *inode, struct file *file)
0386 {
0387     struct orangefs_dir *od = file->private_data;
0388     struct orangefs_dir_part *part = od->part;
0389     while (part) {
0390         struct orangefs_dir_part *next = part->next;
0391         vfree(part);
0392         part = next;
0393     }
0394     kfree(od);
0395     return 0;
0396 }
0397 
0398 const struct file_operations orangefs_dir_operations = {
0399     .llseek = orangefs_dir_llseek,
0400     .read = generic_read_dir,
0401     .iterate = orangefs_dir_iterate,
0402     .open = orangefs_dir_open,
0403     .release = orangefs_dir_release
0404 };