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

export.c (4750B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
      4 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
      5 */
      6
      7#include <linux/spinlock.h>
      8#include <linux/completion.h>
      9#include <linux/buffer_head.h>
     10#include <linux/exportfs.h>
     11#include <linux/gfs2_ondisk.h>
     12#include <linux/crc32.h>
     13
     14#include "gfs2.h"
     15#include "incore.h"
     16#include "dir.h"
     17#include "glock.h"
     18#include "glops.h"
     19#include "inode.h"
     20#include "super.h"
     21#include "rgrp.h"
     22#include "util.h"
     23
     24#define GFS2_SMALL_FH_SIZE 4
     25#define GFS2_LARGE_FH_SIZE 8
     26#define GFS2_OLD_FH_SIZE 10
     27
     28static int gfs2_encode_fh(struct inode *inode, __u32 *p, int *len,
     29			  struct inode *parent)
     30{
     31	__be32 *fh = (__force __be32 *)p;
     32	struct super_block *sb = inode->i_sb;
     33	struct gfs2_inode *ip = GFS2_I(inode);
     34
     35	if (parent && (*len < GFS2_LARGE_FH_SIZE)) {
     36		*len = GFS2_LARGE_FH_SIZE;
     37		return FILEID_INVALID;
     38	} else if (*len < GFS2_SMALL_FH_SIZE) {
     39		*len = GFS2_SMALL_FH_SIZE;
     40		return FILEID_INVALID;
     41	}
     42
     43	fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
     44	fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
     45	fh[2] = cpu_to_be32(ip->i_no_addr >> 32);
     46	fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
     47	*len = GFS2_SMALL_FH_SIZE;
     48
     49	if (!parent || inode == d_inode(sb->s_root))
     50		return *len;
     51
     52	ip = GFS2_I(parent);
     53
     54	fh[4] = cpu_to_be32(ip->i_no_formal_ino >> 32);
     55	fh[5] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
     56	fh[6] = cpu_to_be32(ip->i_no_addr >> 32);
     57	fh[7] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
     58	*len = GFS2_LARGE_FH_SIZE;
     59
     60	return *len;
     61}
     62
     63struct get_name_filldir {
     64	struct dir_context ctx;
     65	struct gfs2_inum_host inum;
     66	char *name;
     67};
     68
     69static int get_name_filldir(struct dir_context *ctx, const char *name,
     70			    int length, loff_t offset, u64 inum,
     71			    unsigned int type)
     72{
     73	struct get_name_filldir *gnfd =
     74		container_of(ctx, struct get_name_filldir, ctx);
     75
     76	if (inum != gnfd->inum.no_addr)
     77		return 0;
     78
     79	memcpy(gnfd->name, name, length);
     80	gnfd->name[length] = 0;
     81
     82	return 1;
     83}
     84
     85static int gfs2_get_name(struct dentry *parent, char *name,
     86			 struct dentry *child)
     87{
     88	struct inode *dir = d_inode(parent);
     89	struct inode *inode = d_inode(child);
     90	struct gfs2_inode *dip, *ip;
     91	struct get_name_filldir gnfd = {
     92		.ctx.actor = get_name_filldir,
     93		.name = name
     94	};
     95	struct gfs2_holder gh;
     96	int error;
     97	struct file_ra_state f_ra = { .start = 0 };
     98
     99	if (!dir)
    100		return -EINVAL;
    101
    102	if (!S_ISDIR(dir->i_mode) || !inode)
    103		return -EINVAL;
    104
    105	dip = GFS2_I(dir);
    106	ip = GFS2_I(inode);
    107
    108	*name = 0;
    109	gnfd.inum.no_addr = ip->i_no_addr;
    110	gnfd.inum.no_formal_ino = ip->i_no_formal_ino;
    111
    112	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
    113	if (error)
    114		return error;
    115
    116	error = gfs2_dir_read(dir, &gnfd.ctx, &f_ra);
    117
    118	gfs2_glock_dq_uninit(&gh);
    119
    120	if (!error && !*name)
    121		error = -ENOENT;
    122
    123	return error;
    124}
    125
    126static struct dentry *gfs2_get_parent(struct dentry *child)
    127{
    128	return d_obtain_alias(gfs2_lookupi(d_inode(child), &gfs2_qdotdot, 1));
    129}
    130
    131static struct dentry *gfs2_get_dentry(struct super_block *sb,
    132				      struct gfs2_inum_host *inum)
    133{
    134	struct gfs2_sbd *sdp = sb->s_fs_info;
    135	struct inode *inode;
    136
    137	if (!inum->no_formal_ino)
    138		return ERR_PTR(-ESTALE);
    139	inode = gfs2_lookup_by_inum(sdp, inum->no_addr, inum->no_formal_ino,
    140				    GFS2_BLKST_DINODE);
    141	if (IS_ERR(inode))
    142		return ERR_CAST(inode);
    143	return d_obtain_alias(inode);
    144}
    145
    146static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
    147		int fh_len, int fh_type)
    148{
    149	struct gfs2_inum_host this;
    150	__be32 *fh = (__force __be32 *)fid->raw;
    151
    152	switch (fh_type) {
    153	case GFS2_SMALL_FH_SIZE:
    154	case GFS2_LARGE_FH_SIZE:
    155	case GFS2_OLD_FH_SIZE:
    156		if (fh_len < GFS2_SMALL_FH_SIZE)
    157			return NULL;
    158		this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
    159		this.no_formal_ino |= be32_to_cpu(fh[1]);
    160		this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
    161		this.no_addr |= be32_to_cpu(fh[3]);
    162		return gfs2_get_dentry(sb, &this);
    163	default:
    164		return NULL;
    165	}
    166}
    167
    168static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
    169		int fh_len, int fh_type)
    170{
    171	struct gfs2_inum_host parent;
    172	__be32 *fh = (__force __be32 *)fid->raw;
    173
    174	switch (fh_type) {
    175	case GFS2_LARGE_FH_SIZE:
    176	case GFS2_OLD_FH_SIZE:
    177		if (fh_len < GFS2_LARGE_FH_SIZE)
    178			return NULL;
    179		parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
    180		parent.no_formal_ino |= be32_to_cpu(fh[5]);
    181		parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
    182		parent.no_addr |= be32_to_cpu(fh[7]);
    183		return gfs2_get_dentry(sb, &parent);
    184	default:
    185		return NULL;
    186	}
    187}
    188
    189const struct export_operations gfs2_export_ops = {
    190	.encode_fh = gfs2_encode_fh,
    191	.fh_to_dentry = gfs2_fh_to_dentry,
    192	.fh_to_parent = gfs2_fh_to_parent,
    193	.get_name = gfs2_get_name,
    194	.get_parent = gfs2_get_parent,
    195};
    196