cregit-Linux how code gets into the kernel

Release 4.16 fs/orangefs/dir.c

Directory: fs/orangefs
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2017 Omnibond Systems, L.L.C.
 */

#include "protocol.h"
#include "orangefs-kernel.h"
#include "orangefs-bufmap.h"


struct orangefs_dir_part {
	
struct orangefs_dir_part *next;
	
size_t len;
};


struct orangefs_dir {
	
__u64 token;
	
struct orangefs_dir_part *part;
	
loff_t end;
	
int error;
};


#define PART_SHIFT (24)

#define PART_SIZE (1<<24)

#define PART_MASK (~(PART_SIZE - 1))

/*
 * There can be up to 512 directory entries.  Each entry is encoded as
 * follows:
 * 4 bytes: string size (n)
 * n bytes: string
 * 1 byte: trailing zero
 * padding to 8 bytes
 * 16 bytes: khandle
 * padding to 8 bytes
 *
 * The trailer_buf starts with a struct orangefs_readdir_response_s
 * which must be skipped to get to the directory data.
 *
 * The data which is received from the userspace daemon is termed a
 * part and is stored in a linked list in case more than one part is
 * needed for a large directory.
 *
 * The position pointer (ctx->pos) encodes the part and offset on which
 * to begin reading at.  Bits above PART_SHIFT encode the part and bits
 * below PART_SHIFT encode the offset.  Parts are stored in a linked
 * list which grows as data is received from the server.  The overhead
 * associated with managing the list is presumed to be small compared to
 * the overhead of communicating with the server.
 *
 * As data is received from the server, it is placed at the end of the
 * part list.  Data is parsed from the current position as it is needed.
 * When data is determined to be corrupt, it is either because the
 * userspace component has sent back corrupt data or because the file
 * pointer has been moved to an invalid location.  Since the two cannot
 * be differentiated, return EIO.
 *
 * Part zero is synthesized to contains `.' and `..'.  Part one is the
 * first part of the part list.
 */


static int do_readdir(struct orangefs_inode_s *oi, struct orangefs_dir *od, struct dentry *dentry, struct orangefs_kernel_op_s *op) { struct orangefs_readdir_response_s *resp; int bufi, r; /* * Despite the badly named field, readdir does not use shared * memory. However, there are a limited number of readdir * slots, which must be allocated here. This flag simply tells * the op scheduler to return the op here for retry. */ op->uses_shared_memory = 1; op->upcall.req.readdir.refn = oi->refn; op->upcall.req.readdir.token = od->token; op->upcall.req.readdir.max_dirent_count = ORANGEFS_MAX_DIRENT_COUNT_READDIR; again: bufi = orangefs_readdir_index_get(); if (bufi < 0) { od->error = bufi; return bufi; } op->upcall.req.readdir.buf_index = bufi; r = service_operation(op, "orangefs_readdir", get_interruptible_flag(dentry->d_inode)); orangefs_readdir_index_put(bufi); if (op_state_purged(op)) { if (r == -EAGAIN) { vfree(op->downcall.trailer_buf); goto again; } else if (r == -EIO) { vfree(op->downcall.trailer_buf); od->error = r; return r; } } if (r < 0) { vfree(op->downcall.trailer_buf); od->error = r; return r; } else if (op->downcall.status) { vfree(op->downcall.trailer_buf); od->error = op->downcall.status; return op->downcall.status; } /* * The maximum size is size per entry times the 512 entries plus * the header. This is well under the limit. */ if (op->downcall.trailer_size > PART_SIZE) { vfree(op->downcall.trailer_buf); od->error = -EIO; return -EIO; } resp = (struct orangefs_readdir_response_s *) op->downcall.trailer_buf; od->token = resp->token; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg24376.42%337.50%
Mike Marshall6219.50%225.00%
Al Viro134.09%337.50%
Total318100.00%8100.00%


static int parse_readdir(struct orangefs_dir *od, struct orangefs_kernel_op_s *op) { struct orangefs_dir_part *part, *new; size_t count; count = 1; part = od->part; while (part) { count++; if (part->next) part = part->next; else break; } new = (void *)op->downcall.trailer_buf; new->next = NULL; new->len = op->downcall.trailer_size - sizeof(struct orangefs_readdir_response_s); if (!od->part) od->part = new; else part->next = new; count++; od->end = count << PART_SHIFT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg12194.53%350.00%
Mike Marshall64.69%233.33%
Al Viro10.78%116.67%
Total128100.00%6100.00%


static int orangefs_dir_more(struct orangefs_inode_s *oi, struct orangefs_dir *od, struct dentry *dentry) { struct orangefs_kernel_op_s *op; int r; op = op_alloc(ORANGEFS_VFS_OP_READDIR); if (!op) { od->error = -ENOMEM; return -ENOMEM; } r = do_readdir(oi, od, dentry, op); if (r) { od->error = r; goto out; } r = parse_readdir(od, op); if (r) { od->error = r; goto out; } od->error = 0; out: op_release(op); return od->error; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg11189.52%240.00%
Mike Marshall86.45%240.00%
Al Viro54.03%120.00%
Total124100.00%5100.00%


static int fill_from_part(struct orangefs_dir_part *part, struct dir_context *ctx) { const int offset = sizeof(struct orangefs_readdir_response_s); struct orangefs_khandle *khandle; __u32 *len, padlen; loff_t i; char *s; i = ctx->pos & ~PART_MASK; /* The file offset from userspace is too large. */ if (i > part->len) return 1; /* * If the seek pointer is positioned just before an entry it * should find the next entry. */ if (i % 8) i = i + (8 - i%8)%8; while (i < part->len) { if (part->len < i + sizeof *len) break; len = (void *)part + offset + i; /* * len is the size of the string itself. padlen is the * total size of the encoded string. */ padlen = (sizeof *len + *len + 1) + (8 - (sizeof *len + *len + 1)%8)%8; if (part->len < i + padlen + sizeof *khandle) goto next; s = (void *)part + offset + i + sizeof *len; if (s[*len] != 0) goto next; khandle = (void *)part + offset + i + padlen; if (!dir_emit(ctx, s, *len, orangefs_khandle_to_ino(khandle), DT_UNKNOWN)) return 0; i += padlen + sizeof *khandle; i = i + (8 - i%8)%8; BUG_ON(i > part->len); ctx->pos = (ctx->pos & PART_MASK) | i; continue; next: i += 8; } return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg23480.14%466.67%
Mike Marshall5318.15%116.67%
Al Viro51.71%116.67%
Total292100.00%6100.00%


static int orangefs_dir_fill(struct orangefs_inode_s *oi, struct orangefs_dir *od, struct dentry *dentry, struct dir_context *ctx) { struct orangefs_dir_part *part; size_t count; count = ((ctx->pos & PART_MASK) >> PART_SHIFT) - 1; part = od->part; while (part->next && count) { count--; part = part->next; } /* This means the userspace file offset is invalid. */ if (count) { od->error = -EIO; return -EIO; } while (part && part->len) { int r; r = fill_from_part(part, ctx); if (r < 0) { od->error = r; return r; } else if (r == 0) { /* Userspace buffer is full. */ break; } else { /* * The part ran out of data. Move to the next * part. */ ctx->pos = (ctx->pos & PART_MASK) + (1 << PART_SHIFT); part = part->next; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg17298.85%266.67%
Mike Marshall21.15%133.33%
Total174100.00%3100.00%


static loff_t orangefs_dir_llseek(struct file *file, loff_t offset, int whence) { struct orangefs_dir *od = file->private_data; /* * Delete the stored data so userspace sees new directory * entries. */ if (!whence && offset < od->end) { struct orangefs_dir_part *part = od->part; while (part) { struct orangefs_dir_part *next = part->next; vfree(part); part = next; } od->token = ORANGEFS_ITERATE_START; od->part = NULL; od->end = 1 << PART_SHIFT; } return default_llseek(file, offset, whence); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg103100.00%1100.00%
Total103100.00%1100.00%


static int orangefs_dir_iterate(struct file *file, struct dir_context *ctx) { struct orangefs_inode_s *oi; struct orangefs_dir *od; struct dentry *dentry; int r; dentry = file->f_path.dentry; oi = ORANGEFS_I(dentry->d_inode); od = file->private_data; if (od->error) return od->error; if (ctx->pos == 0) { if (!dir_emit_dot(file, ctx)) return 0; ctx->pos++; } if (ctx->pos == 1) { if (!dir_emit_dotdot(file, ctx)) return 0; ctx->pos = 1 << PART_SHIFT; } /* * The seek position is in the first synthesized part but is not * valid. */ if ((ctx->pos & PART_MASK) == 0) return -EIO; r = 0; /* * Must read more if the user has sought past what has been read * so far. Stop a user who has sought past the end. */ while (od->token != ORANGEFS_ITERATE_END && ctx->pos > od->end) { r = orangefs_dir_more(oi, od, dentry); if (r) return r; } if (od->token == ORANGEFS_ITERATE_END && ctx->pos > od->end) return -EIO; /* Then try to fill if there's any left in the buffer. */ if (ctx->pos < od->end) { r = orangefs_dir_fill(oi, od, dentry, ctx); if (r) return r; } /* Finally get some more and try to fill. */ if (od->token != ORANGEFS_ITERATE_END) { r = orangefs_dir_more(oi, od, dentry); if (r) return r; r = orangefs_dir_fill(oi, od, dentry, ctx); } return r; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg21877.03%450.00%
Mike Marshall6221.91%337.50%
Al Viro31.06%112.50%
Total283100.00%8100.00%


static int orangefs_dir_open(struct inode *inode, struct file *file) { struct orangefs_dir *od; file->private_data = kmalloc(sizeof(struct orangefs_dir), GFP_KERNEL); if (!file->private_data) return -ENOMEM; od = file->private_data; od->token = ORANGEFS_ITERATE_START; od->part = NULL; od->end = 1 << PART_SHIFT; od->error = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Mike Marshall5162.20%120.00%
Martin Brandenburg3036.59%360.00%
Yi Liu11.22%120.00%
Total82100.00%5100.00%


static int orangefs_dir_release(struct inode *inode, struct file *file) { struct orangefs_dir *od = file->private_data; struct orangefs_dir_part *part = od->part; while (part) { struct orangefs_dir_part *next = part->next; vfree(part); part = next; } kfree(od); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg4466.67%250.00%
Mike Marshall2131.82%125.00%
Yi Liu11.52%125.00%
Total66100.00%4100.00%

const struct file_operations orangefs_dir_operations = { .llseek = orangefs_dir_llseek, .read = generic_read_dir, .iterate = orangefs_dir_iterate, .open = orangefs_dir_open, .release = orangefs_dir_release };

Overall Contributors

PersonTokensPropCommitsCommitProp
Martin Brandenburg132980.16%842.11%
Mike Marshall29617.85%526.32%
Al Viro271.63%421.05%
Yi Liu50.30%15.26%
Greg Kroah-Hartman10.06%15.26%
Total1658100.00%19100.00%
Directory: fs/orangefs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.