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

nfsfh.h (9730B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2/*
      3 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
      4 *
      5 * This file describes the layout of the file handles as passed
      6 * over the wire.
      7 */
      8#ifndef _LINUX_NFSD_NFSFH_H
      9#define _LINUX_NFSD_NFSFH_H
     10
     11#include <linux/crc32.h>
     12#include <linux/sunrpc/svc.h>
     13#include <linux/iversion.h>
     14#include <linux/exportfs.h>
     15#include <linux/nfs4.h>
     16
     17/*
     18 * The file handle starts with a sequence of four-byte words.
     19 * The first word contains a version number (1) and three descriptor bytes
     20 * that tell how the remaining 3 variable length fields should be handled.
     21 * These three bytes are auth_type, fsid_type and fileid_type.
     22 *
     23 * All four-byte values are in host-byte-order.
     24 *
     25 * The auth_type field is deprecated and must be set to 0.
     26 *
     27 * The fsid_type identifies how the filesystem (or export point) is
     28 *    encoded.
     29 *  Current values:
     30 *     0  - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number
     31 *        NOTE: we cannot use the kdev_t device id value, because kdev_t.h
     32 *              says we mustn't.  We must break it up and reassemble.
     33 *     1  - 4 byte user specified identifier
     34 *     2  - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED
     35 *     3  - 4 byte device id, encoded for user-space, 4 byte inode number
     36 *     4  - 4 byte inode number and 4 byte uuid
     37 *     5  - 8 byte uuid
     38 *     6  - 16 byte uuid
     39 *     7  - 8 byte inode number and 16 byte uuid
     40 *
     41 * The fileid_type identifies how the file within the filesystem is encoded.
     42 *   The values for this field are filesystem specific, exccept that
     43 *   filesystems must not use the values '0' or '0xff'. 'See enum fid_type'
     44 *   in include/linux/exportfs.h for currently registered values.
     45 */
     46
     47struct knfsd_fh {
     48	unsigned int	fh_size;	/*
     49					 * Points to the current size while
     50					 * building a new file handle.
     51					 */
     52	union {
     53		char			fh_raw[NFS4_FHSIZE];
     54		struct {
     55			u8		fh_version;	/* == 1 */
     56			u8		fh_auth_type;	/* deprecated */
     57			u8		fh_fsid_type;
     58			u8		fh_fileid_type;
     59			u32		fh_fsid[]; /* flexible-array member */
     60		};
     61	};
     62};
     63
     64static inline __u32 ino_t_to_u32(ino_t ino)
     65{
     66	return (__u32) ino;
     67}
     68
     69static inline ino_t u32_to_ino_t(__u32 uino)
     70{
     71	return (ino_t) uino;
     72}
     73
     74/*
     75 * This is the internal representation of an NFS handle used in knfsd.
     76 * pre_mtime/post_version will be used to support wcc_attr's in NFSv3.
     77 */
     78typedef struct svc_fh {
     79	struct knfsd_fh		fh_handle;	/* FH data */
     80	int			fh_maxsize;	/* max size for fh_handle */
     81	struct dentry *		fh_dentry;	/* validated dentry */
     82	struct svc_export *	fh_export;	/* export pointer */
     83
     84	bool			fh_locked;	/* inode locked by us */
     85	bool			fh_want_write;	/* remount protection taken */
     86	bool			fh_no_wcc;	/* no wcc data needed */
     87	bool			fh_no_atomic_attr;
     88						/*
     89						 * wcc data is not atomic with
     90						 * operation
     91						 */
     92	int			fh_flags;	/* FH flags */
     93	bool			fh_post_saved;	/* post-op attrs saved */
     94	bool			fh_pre_saved;	/* pre-op attrs saved */
     95
     96	/* Pre-op attributes saved during fh_lock */
     97	__u64			fh_pre_size;	/* size before operation */
     98	struct timespec64	fh_pre_mtime;	/* mtime before oper */
     99	struct timespec64	fh_pre_ctime;	/* ctime before oper */
    100	/*
    101	 * pre-op nfsv4 change attr: note must check IS_I_VERSION(inode)
    102	 *  to find out if it is valid.
    103	 */
    104	u64			fh_pre_change;
    105
    106	/* Post-op attributes saved in fh_unlock */
    107	struct kstat		fh_post_attr;	/* full attrs after operation */
    108	u64			fh_post_change; /* nfsv4 change; see above */
    109} svc_fh;
    110#define NFSD4_FH_FOREIGN (1<<0)
    111#define SET_FH_FLAG(c, f) ((c)->fh_flags |= (f))
    112#define HAS_FH_FLAG(c, f) ((c)->fh_flags & (f))
    113
    114enum nfsd_fsid {
    115	FSID_DEV = 0,
    116	FSID_NUM,
    117	FSID_MAJOR_MINOR,
    118	FSID_ENCODE_DEV,
    119	FSID_UUID4_INUM,
    120	FSID_UUID8,
    121	FSID_UUID16,
    122	FSID_UUID16_INUM,
    123};
    124
    125enum fsid_source {
    126	FSIDSOURCE_DEV,
    127	FSIDSOURCE_FSID,
    128	FSIDSOURCE_UUID,
    129};
    130extern enum fsid_source fsid_source(const struct svc_fh *fhp);
    131
    132
    133/*
    134 * This might look a little large to "inline" but in all calls except
    135 * one, 'vers' is constant so moste of the function disappears.
    136 *
    137 * In some cases the values are considered to be host endian and in
    138 * others, net endian. fsidv is always considered to be u32 as the
    139 * callers don't know which it will be. So we must use __force to keep
    140 * sparse from complaining. Since these values are opaque to the
    141 * client, that shouldn't be a problem.
    142 */
    143static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
    144			   u32 fsid, unsigned char *uuid)
    145{
    146	u32 *up;
    147	switch(vers) {
    148	case FSID_DEV:
    149		fsidv[0] = (__force __u32)htonl((MAJOR(dev)<<16) |
    150				 MINOR(dev));
    151		fsidv[1] = ino_t_to_u32(ino);
    152		break;
    153	case FSID_NUM:
    154		fsidv[0] = fsid;
    155		break;
    156	case FSID_MAJOR_MINOR:
    157		fsidv[0] = (__force __u32)htonl(MAJOR(dev));
    158		fsidv[1] = (__force __u32)htonl(MINOR(dev));
    159		fsidv[2] = ino_t_to_u32(ino);
    160		break;
    161
    162	case FSID_ENCODE_DEV:
    163		fsidv[0] = new_encode_dev(dev);
    164		fsidv[1] = ino_t_to_u32(ino);
    165		break;
    166
    167	case FSID_UUID4_INUM:
    168		/* 4 byte fsid and inode number */
    169		up = (u32*)uuid;
    170		fsidv[0] = ino_t_to_u32(ino);
    171		fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3];
    172		break;
    173
    174	case FSID_UUID8:
    175		/* 8 byte fsid  */
    176		up = (u32*)uuid;
    177		fsidv[0] = up[0] ^ up[2];
    178		fsidv[1] = up[1] ^ up[3];
    179		break;
    180
    181	case FSID_UUID16:
    182		/* 16 byte fsid - NFSv3+ only */
    183		memcpy(fsidv, uuid, 16);
    184		break;
    185
    186	case FSID_UUID16_INUM:
    187		/* 8 byte inode and 16 byte fsid */
    188		*(u64*)fsidv = (u64)ino;
    189		memcpy(fsidv+2, uuid, 16);
    190		break;
    191	default: BUG();
    192	}
    193}
    194
    195static inline int key_len(int type)
    196{
    197	switch(type) {
    198	case FSID_DEV:		return 8;
    199	case FSID_NUM: 		return 4;
    200	case FSID_MAJOR_MINOR:	return 12;
    201	case FSID_ENCODE_DEV:	return 8;
    202	case FSID_UUID4_INUM:	return 8;
    203	case FSID_UUID8:	return 8;
    204	case FSID_UUID16:	return 16;
    205	case FSID_UUID16_INUM:	return 24;
    206	default: return 0;
    207	}
    208}
    209
    210/*
    211 * Shorthand for dprintk()'s
    212 */
    213extern char * SVCFH_fmt(struct svc_fh *fhp);
    214
    215/*
    216 * Function prototypes
    217 */
    218__be32	fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int);
    219__be32	fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
    220__be32	fh_update(struct svc_fh *);
    221void	fh_put(struct svc_fh *);
    222
    223static __inline__ struct svc_fh *
    224fh_copy(struct svc_fh *dst, struct svc_fh *src)
    225{
    226	WARN_ON(src->fh_dentry || src->fh_locked);
    227			
    228	*dst = *src;
    229	return dst;
    230}
    231
    232static inline void
    233fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src)
    234{
    235	dst->fh_size = src->fh_size;
    236	memcpy(&dst->fh_raw, &src->fh_raw, src->fh_size);
    237}
    238
    239static __inline__ struct svc_fh *
    240fh_init(struct svc_fh *fhp, int maxsize)
    241{
    242	memset(fhp, 0, sizeof(*fhp));
    243	fhp->fh_maxsize = maxsize;
    244	return fhp;
    245}
    246
    247static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
    248{
    249	if (fh1->fh_size != fh2->fh_size)
    250		return false;
    251	if (memcmp(fh1->fh_raw, fh2->fh_raw, fh1->fh_size) != 0)
    252		return false;
    253	return true;
    254}
    255
    256static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
    257{
    258	if (fh1->fh_fsid_type != fh2->fh_fsid_type)
    259		return false;
    260	if (memcmp(fh1->fh_fsid, fh2->fh_fsid, key_len(fh1->fh_fsid_type)) != 0)
    261		return false;
    262	return true;
    263}
    264
    265#ifdef CONFIG_CRC32
    266/**
    267 * knfsd_fh_hash - calculate the crc32 hash for the filehandle
    268 * @fh - pointer to filehandle
    269 *
    270 * returns a crc32 hash for the filehandle that is compatible with
    271 * the one displayed by "wireshark".
    272 */
    273static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)
    274{
    275	return ~crc32_le(0xFFFFFFFF, fh->fh_raw, fh->fh_size);
    276}
    277#else
    278static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)
    279{
    280	return 0;
    281}
    282#endif
    283
    284/**
    285 * fh_clear_pre_post_attrs - Reset pre/post attributes
    286 * @fhp: file handle to be updated
    287 *
    288 */
    289static inline void fh_clear_pre_post_attrs(struct svc_fh *fhp)
    290{
    291	fhp->fh_post_saved = false;
    292	fhp->fh_pre_saved = false;
    293}
    294
    295/*
    296 * We could use i_version alone as the change attribute.  However,
    297 * i_version can go backwards after a reboot.  On its own that doesn't
    298 * necessarily cause a problem, but if i_version goes backwards and then
    299 * is incremented again it could reuse a value that was previously used
    300 * before boot, and a client who queried the two values might
    301 * incorrectly assume nothing changed.
    302 *
    303 * By using both ctime and the i_version counter we guarantee that as
    304 * long as time doesn't go backwards we never reuse an old value.
    305 */
    306static inline u64 nfsd4_change_attribute(struct kstat *stat,
    307					 struct inode *inode)
    308{
    309	if (inode->i_sb->s_export_op->fetch_iversion)
    310		return inode->i_sb->s_export_op->fetch_iversion(inode);
    311	else if (IS_I_VERSION(inode)) {
    312		u64 chattr;
    313
    314		chattr =  stat->ctime.tv_sec;
    315		chattr <<= 30;
    316		chattr += stat->ctime.tv_nsec;
    317		chattr += inode_query_iversion(inode);
    318		return chattr;
    319	} else
    320		return time_to_chattr(&stat->ctime);
    321}
    322
    323extern void fh_fill_pre_attrs(struct svc_fh *fhp);
    324extern void fh_fill_post_attrs(struct svc_fh *fhp);
    325
    326
    327/*
    328 * Lock a file handle/inode
    329 * NOTE: both fh_lock and fh_unlock are done "by hand" in
    330 * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once
    331 * so, any changes here should be reflected there.
    332 */
    333
    334static inline void
    335fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
    336{
    337	struct dentry	*dentry = fhp->fh_dentry;
    338	struct inode	*inode;
    339
    340	BUG_ON(!dentry);
    341
    342	if (fhp->fh_locked) {
    343		printk(KERN_WARNING "fh_lock: %pd2 already locked!\n",
    344			dentry);
    345		return;
    346	}
    347
    348	inode = d_inode(dentry);
    349	inode_lock_nested(inode, subclass);
    350	fh_fill_pre_attrs(fhp);
    351	fhp->fh_locked = true;
    352}
    353
    354static inline void
    355fh_lock(struct svc_fh *fhp)
    356{
    357	fh_lock_nested(fhp, I_MUTEX_NORMAL);
    358}
    359
    360/*
    361 * Unlock a file handle/inode
    362 */
    363static inline void
    364fh_unlock(struct svc_fh *fhp)
    365{
    366	if (fhp->fh_locked) {
    367		fh_fill_post_attrs(fhp);
    368		inode_unlock(d_inode(fhp->fh_dentry));
    369		fhp->fh_locked = false;
    370	}
    371}
    372
    373#endif /* _LINUX_NFSD_NFSFH_H */