cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vfs_dir.c (5361B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * This file contains vfs directory ops for the 9P2000 protocol.
      4 *
      5 *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
      6 *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/errno.h>
     11#include <linux/fs.h>
     12#include <linux/file.h>
     13#include <linux/stat.h>
     14#include <linux/string.h>
     15#include <linux/sched.h>
     16#include <linux/inet.h>
     17#include <linux/idr.h>
     18#include <linux/slab.h>
     19#include <linux/uio.h>
     20#include <linux/fscache.h>
     21#include <net/9p/9p.h>
     22#include <net/9p/client.h>
     23
     24#include "v9fs.h"
     25#include "v9fs_vfs.h"
     26#include "fid.h"
     27
     28/**
     29 * struct p9_rdir - readdir accounting
     30 * @head: start offset of current dirread buffer
     31 * @tail: end offset of current dirread buffer
     32 * @buf: dirread buffer
     33 *
     34 * private structure for keeping track of readdir
     35 * allocated on demand
     36 */
     37
     38struct p9_rdir {
     39	int head;
     40	int tail;
     41	uint8_t buf[];
     42};
     43
     44/**
     45 * dt_type - return file type
     46 * @mistat: mistat structure
     47 *
     48 */
     49
     50static inline int dt_type(struct p9_wstat *mistat)
     51{
     52	unsigned long perm = mistat->mode;
     53	int rettype = DT_REG;
     54
     55	if (perm & P9_DMDIR)
     56		rettype = DT_DIR;
     57	if (perm & P9_DMSYMLINK)
     58		rettype = DT_LNK;
     59
     60	return rettype;
     61}
     62
     63/**
     64 * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
     65 * @filp: opened file structure
     66 * @buflen: Length in bytes of buffer to allocate
     67 *
     68 */
     69
     70static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
     71{
     72	struct p9_fid *fid = filp->private_data;
     73
     74	if (!fid->rdir)
     75		fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
     76	return fid->rdir;
     77}
     78
     79/**
     80 * v9fs_dir_readdir - iterate through a directory
     81 * @file: opened file structure
     82 * @ctx: actor we feed the entries to
     83 *
     84 */
     85
     86static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
     87{
     88	bool over;
     89	struct p9_wstat st;
     90	int err = 0;
     91	struct p9_fid *fid;
     92	int buflen;
     93	struct p9_rdir *rdir;
     94	struct kvec kvec;
     95
     96	p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
     97	fid = file->private_data;
     98
     99	buflen = fid->clnt->msize - P9_IOHDRSZ;
    100
    101	rdir = v9fs_alloc_rdir_buf(file, buflen);
    102	if (!rdir)
    103		return -ENOMEM;
    104	kvec.iov_base = rdir->buf;
    105	kvec.iov_len = buflen;
    106
    107	while (1) {
    108		if (rdir->tail == rdir->head) {
    109			struct iov_iter to;
    110			int n;
    111
    112			iov_iter_kvec(&to, READ, &kvec, 1, buflen);
    113			n = p9_client_read(file->private_data, ctx->pos, &to,
    114					   &err);
    115			if (err)
    116				return err;
    117			if (n == 0)
    118				return 0;
    119
    120			rdir->head = 0;
    121			rdir->tail = n;
    122		}
    123		while (rdir->head < rdir->tail) {
    124			err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
    125					  rdir->tail - rdir->head, &st);
    126			if (err <= 0) {
    127				p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
    128				return -EIO;
    129			}
    130
    131			over = !dir_emit(ctx, st.name, strlen(st.name),
    132					 v9fs_qid2ino(&st.qid), dt_type(&st));
    133			p9stat_free(&st);
    134			if (over)
    135				return 0;
    136
    137			rdir->head += err;
    138			ctx->pos += err;
    139		}
    140	}
    141}
    142
    143/**
    144 * v9fs_dir_readdir_dotl - iterate through a directory
    145 * @file: opened file structure
    146 * @ctx: actor we feed the entries to
    147 *
    148 */
    149static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
    150{
    151	int err = 0;
    152	struct p9_fid *fid;
    153	int buflen;
    154	struct p9_rdir *rdir;
    155	struct p9_dirent curdirent;
    156
    157	p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
    158	fid = file->private_data;
    159
    160	buflen = fid->clnt->msize - P9_READDIRHDRSZ;
    161
    162	rdir = v9fs_alloc_rdir_buf(file, buflen);
    163	if (!rdir)
    164		return -ENOMEM;
    165
    166	while (1) {
    167		if (rdir->tail == rdir->head) {
    168			err = p9_client_readdir(fid, rdir->buf, buflen,
    169						ctx->pos);
    170			if (err <= 0)
    171				return err;
    172
    173			rdir->head = 0;
    174			rdir->tail = err;
    175		}
    176
    177		while (rdir->head < rdir->tail) {
    178
    179			err = p9dirent_read(fid->clnt, rdir->buf + rdir->head,
    180					    rdir->tail - rdir->head,
    181					    &curdirent);
    182			if (err < 0) {
    183				p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
    184				return -EIO;
    185			}
    186
    187			if (!dir_emit(ctx, curdirent.d_name,
    188				      strlen(curdirent.d_name),
    189				      v9fs_qid2ino(&curdirent.qid),
    190				      curdirent.d_type))
    191				return 0;
    192
    193			ctx->pos = curdirent.d_off;
    194			rdir->head += err;
    195		}
    196	}
    197}
    198
    199
    200/**
    201 * v9fs_dir_release - close a directory
    202 * @inode: inode of the directory
    203 * @filp: file pointer to a directory
    204 *
    205 */
    206
    207int v9fs_dir_release(struct inode *inode, struct file *filp)
    208{
    209	struct v9fs_inode *v9inode = V9FS_I(inode);
    210	struct p9_fid *fid;
    211	__le32 version;
    212	loff_t i_size;
    213
    214	fid = filp->private_data;
    215	p9_debug(P9_DEBUG_VFS, "inode: %p filp: %p fid: %d\n",
    216		 inode, filp, fid ? fid->fid : -1);
    217	if (fid) {
    218		spin_lock(&inode->i_lock);
    219		hlist_del(&fid->ilist);
    220		spin_unlock(&inode->i_lock);
    221		p9_client_clunk(fid);
    222	}
    223
    224	if ((filp->f_mode & FMODE_WRITE)) {
    225		version = cpu_to_le32(v9inode->qid.version);
    226		i_size = i_size_read(inode);
    227		fscache_unuse_cookie(v9fs_inode_cookie(v9inode),
    228				     &version, &i_size);
    229	} else {
    230		fscache_unuse_cookie(v9fs_inode_cookie(v9inode), NULL, NULL);
    231	}
    232	return 0;
    233}
    234
    235const struct file_operations v9fs_dir_operations = {
    236	.read = generic_read_dir,
    237	.llseek = generic_file_llseek,
    238	.iterate_shared = v9fs_dir_readdir,
    239	.open = v9fs_file_open,
    240	.release = v9fs_dir_release,
    241};
    242
    243const struct file_operations v9fs_dir_operations_dotl = {
    244	.read = generic_read_dir,
    245	.llseek = generic_file_llseek,
    246	.iterate_shared = v9fs_dir_readdir_dotl,
    247	.open = v9fs_file_open,
    248	.release = v9fs_dir_release,
    249	.fsync = v9fs_file_fsync_dotl,
    250};