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

dir.c (14682B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3/*
      4 * Directory operations for Coda filesystem
      5 * Original version: (C) 1996 P. Braam and M. Callahan
      6 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
      7 * 
      8 * Carnegie Mellon encourages users to contribute improvements to
      9 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
     10 */
     11
     12#include <linux/types.h>
     13#include <linux/kernel.h>
     14#include <linux/time.h>
     15#include <linux/fs.h>
     16#include <linux/slab.h>
     17#include <linux/file.h>
     18#include <linux/stat.h>
     19#include <linux/errno.h>
     20#include <linux/string.h>
     21#include <linux/spinlock.h>
     22#include <linux/namei.h>
     23#include <linux/uaccess.h>
     24
     25#include <linux/coda.h>
     26#include "coda_psdev.h"
     27#include "coda_linux.h"
     28#include "coda_cache.h"
     29
     30#include "coda_int.h"
     31
     32/* same as fs/bad_inode.c */
     33static int coda_return_EIO(void)
     34{
     35	return -EIO;
     36}
     37#define CODA_EIO_ERROR ((void *) (coda_return_EIO))
     38
     39/* inode operations for directories */
     40/* access routines: lookup, readlink, permission */
     41static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags)
     42{
     43	struct super_block *sb = dir->i_sb;
     44	const char *name = entry->d_name.name;
     45	size_t length = entry->d_name.len;
     46	struct inode *inode;
     47	int type = 0;
     48
     49	if (length > CODA_MAXNAMLEN) {
     50		pr_err("name too long: lookup, %s %zu\n",
     51		       coda_i2s(dir), length);
     52		return ERR_PTR(-ENAMETOOLONG);
     53	}
     54
     55	/* control object, create inode on the fly */
     56	if (is_root_inode(dir) && coda_iscontrol(name, length)) {
     57		inode = coda_cnode_makectl(sb);
     58		type = CODA_NOCACHE;
     59	} else {
     60		struct CodaFid fid = { { 0, } };
     61		int error = venus_lookup(sb, coda_i2f(dir), name, length,
     62				     &type, &fid);
     63		inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error);
     64	}
     65
     66	if (!IS_ERR(inode) && (type & CODA_NOCACHE))
     67		coda_flag_inode(inode, C_VATTR | C_PURGE);
     68
     69	if (inode == ERR_PTR(-ENOENT))
     70		inode = NULL;
     71
     72	return d_splice_alias(inode, entry);
     73}
     74
     75
     76int coda_permission(struct user_namespace *mnt_userns, struct inode *inode,
     77		    int mask)
     78{
     79	int error;
     80
     81	if (mask & MAY_NOT_BLOCK)
     82		return -ECHILD;
     83
     84	mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
     85 
     86	if (!mask)
     87		return 0;
     88
     89	if ((mask & MAY_EXEC) && !execute_ok(inode))
     90		return -EACCES;
     91
     92	if (coda_cache_check(inode, mask))
     93		return 0;
     94
     95	error = venus_access(inode->i_sb, coda_i2f(inode), mask);
     96    
     97	if (!error)
     98		coda_cache_enter(inode, mask);
     99
    100	return error;
    101}
    102
    103
    104static inline void coda_dir_update_mtime(struct inode *dir)
    105{
    106#ifdef REQUERY_VENUS_FOR_MTIME
    107	/* invalidate the directory cnode's attributes so we refetch the
    108	 * attributes from venus next time the inode is referenced */
    109	coda_flag_inode(dir, C_VATTR);
    110#else
    111	/* optimistically we can also act as if our nose bleeds. The
    112	 * granularity of the mtime is coarse anyways so we might actually be
    113	 * right most of the time. Note: we only do this for directories. */
    114	dir->i_mtime = dir->i_ctime = current_time(dir);
    115#endif
    116}
    117
    118/* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a
    119 * trick to fool GNU find's optimizations. If we can't be sure of the link
    120 * (because of volume mount points) we set i_nlink to 1 which forces find
    121 * to consider every child as a possible directory. We should also never
    122 * see an increment or decrement for deleted directories where i_nlink == 0 */
    123static inline void coda_dir_inc_nlink(struct inode *dir)
    124{
    125	if (dir->i_nlink >= 2)
    126		inc_nlink(dir);
    127}
    128
    129static inline void coda_dir_drop_nlink(struct inode *dir)
    130{
    131	if (dir->i_nlink > 2)
    132		drop_nlink(dir);
    133}
    134
    135/* creation routines: create, mknod, mkdir, link, symlink */
    136static int coda_create(struct user_namespace *mnt_userns, struct inode *dir,
    137		       struct dentry *de, umode_t mode, bool excl)
    138{
    139	int error;
    140	const char *name=de->d_name.name;
    141	int length=de->d_name.len;
    142	struct inode *inode;
    143	struct CodaFid newfid;
    144	struct coda_vattr attrs;
    145
    146	if (is_root_inode(dir) && coda_iscontrol(name, length))
    147		return -EPERM;
    148
    149	error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 
    150				0, mode, &newfid, &attrs);
    151	if (error)
    152		goto err_out;
    153
    154	inode = coda_iget(dir->i_sb, &newfid, &attrs);
    155	if (IS_ERR(inode)) {
    156		error = PTR_ERR(inode);
    157		goto err_out;
    158	}
    159
    160	/* invalidate the directory cnode's attributes */
    161	coda_dir_update_mtime(dir);
    162	d_instantiate(de, inode);
    163	return 0;
    164err_out:
    165	d_drop(de);
    166	return error;
    167}
    168
    169static int coda_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
    170		      struct dentry *de, umode_t mode)
    171{
    172	struct inode *inode;
    173	struct coda_vattr attrs;
    174	const char *name = de->d_name.name;
    175	int len = de->d_name.len;
    176	int error;
    177	struct CodaFid newfid;
    178
    179	if (is_root_inode(dir) && coda_iscontrol(name, len))
    180		return -EPERM;
    181
    182	attrs.va_mode = mode;
    183	error = venus_mkdir(dir->i_sb, coda_i2f(dir), 
    184			       name, len, &newfid, &attrs);
    185	if (error)
    186		goto err_out;
    187         
    188	inode = coda_iget(dir->i_sb, &newfid, &attrs);
    189	if (IS_ERR(inode)) {
    190		error = PTR_ERR(inode);
    191		goto err_out;
    192	}
    193
    194	/* invalidate the directory cnode's attributes */
    195	coda_dir_inc_nlink(dir);
    196	coda_dir_update_mtime(dir);
    197	d_instantiate(de, inode);
    198	return 0;
    199err_out:
    200	d_drop(de);
    201	return error;
    202}
    203
    204/* try to make de an entry in dir_inodde linked to source_de */ 
    205static int coda_link(struct dentry *source_de, struct inode *dir_inode, 
    206	  struct dentry *de)
    207{
    208	struct inode *inode = d_inode(source_de);
    209        const char * name = de->d_name.name;
    210	int len = de->d_name.len;
    211	int error;
    212
    213	if (is_root_inode(dir_inode) && coda_iscontrol(name, len))
    214		return -EPERM;
    215
    216	error = venus_link(dir_inode->i_sb, coda_i2f(inode),
    217			   coda_i2f(dir_inode), (const char *)name, len);
    218	if (error) {
    219		d_drop(de);
    220		return error;
    221	}
    222
    223	coda_dir_update_mtime(dir_inode);
    224	ihold(inode);
    225	d_instantiate(de, inode);
    226	inc_nlink(inode);
    227	return 0;
    228}
    229
    230
    231static int coda_symlink(struct user_namespace *mnt_userns,
    232			struct inode *dir_inode, struct dentry *de,
    233			const char *symname)
    234{
    235	const char *name = de->d_name.name;
    236	int len = de->d_name.len;
    237	int symlen;
    238	int error;
    239
    240	if (is_root_inode(dir_inode) && coda_iscontrol(name, len))
    241		return -EPERM;
    242
    243	symlen = strlen(symname);
    244	if (symlen > CODA_MAXPATHLEN)
    245		return -ENAMETOOLONG;
    246
    247	/*
    248	 * This entry is now negative. Since we do not create
    249	 * an inode for the entry we have to drop it.
    250	 */
    251	d_drop(de);
    252	error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,
    253			      symname, symlen);
    254
    255	/* mtime is no good anymore */
    256	if (!error)
    257		coda_dir_update_mtime(dir_inode);
    258
    259	return error;
    260}
    261
    262/* destruction routines: unlink, rmdir */
    263static int coda_unlink(struct inode *dir, struct dentry *de)
    264{
    265        int error;
    266	const char *name = de->d_name.name;
    267	int len = de->d_name.len;
    268
    269	error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
    270	if (error)
    271		return error;
    272
    273	coda_dir_update_mtime(dir);
    274	drop_nlink(d_inode(de));
    275	return 0;
    276}
    277
    278static int coda_rmdir(struct inode *dir, struct dentry *de)
    279{
    280	const char *name = de->d_name.name;
    281	int len = de->d_name.len;
    282	int error;
    283
    284	error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
    285	if (!error) {
    286		/* VFS may delete the child */
    287		if (d_really_is_positive(de))
    288			clear_nlink(d_inode(de));
    289
    290		/* fix the link count of the parent */
    291		coda_dir_drop_nlink(dir);
    292		coda_dir_update_mtime(dir);
    293	}
    294	return error;
    295}
    296
    297/* rename */
    298static int coda_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
    299		       struct dentry *old_dentry, struct inode *new_dir,
    300		       struct dentry *new_dentry, unsigned int flags)
    301{
    302	const char *old_name = old_dentry->d_name.name;
    303	const char *new_name = new_dentry->d_name.name;
    304	int old_length = old_dentry->d_name.len;
    305	int new_length = new_dentry->d_name.len;
    306	int error;
    307
    308	if (flags)
    309		return -EINVAL;
    310
    311	error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
    312			     coda_i2f(new_dir), old_length, new_length,
    313			     (const char *) old_name, (const char *)new_name);
    314	if (!error) {
    315		if (d_really_is_positive(new_dentry)) {
    316			if (d_is_dir(new_dentry)) {
    317				coda_dir_drop_nlink(old_dir);
    318				coda_dir_inc_nlink(new_dir);
    319			}
    320			coda_flag_inode(d_inode(new_dentry), C_VATTR);
    321		}
    322		coda_dir_update_mtime(old_dir);
    323		coda_dir_update_mtime(new_dir);
    324	}
    325	return error;
    326}
    327
    328static inline unsigned int CDT2DT(unsigned char cdt)
    329{
    330	unsigned int dt;
    331
    332	switch(cdt) {
    333	case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
    334	case CDT_FIFO:	  dt = DT_FIFO;    break;
    335	case CDT_CHR:	  dt = DT_CHR;     break;
    336	case CDT_DIR:	  dt = DT_DIR;     break;
    337	case CDT_BLK:	  dt = DT_BLK;     break;
    338	case CDT_REG:	  dt = DT_REG;     break;
    339	case CDT_LNK:	  dt = DT_LNK;     break;
    340	case CDT_SOCK:	  dt = DT_SOCK;    break;
    341	case CDT_WHT:	  dt = DT_WHT;     break;
    342	default:	  dt = DT_UNKNOWN; break;
    343	}
    344	return dt;
    345}
    346
    347/* support routines */
    348static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
    349{
    350	struct coda_file_info *cfi;
    351	struct coda_inode_info *cii;
    352	struct file *host_file;
    353	struct venus_dirent *vdir;
    354	unsigned long vdir_size = offsetof(struct venus_dirent, d_name);
    355	unsigned int type;
    356	struct qstr name;
    357	ino_t ino;
    358	int ret;
    359
    360	cfi = coda_ftoc(coda_file);
    361	host_file = cfi->cfi_container;
    362
    363	cii = ITOC(file_inode(coda_file));
    364
    365	vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
    366	if (!vdir) return -ENOMEM;
    367
    368	if (!dir_emit_dots(coda_file, ctx))
    369		goto out;
    370
    371	while (1) {
    372		loff_t pos = ctx->pos - 2;
    373
    374		/* read entries from the directory file */
    375		ret = kernel_read(host_file, vdir, sizeof(*vdir), &pos);
    376		if (ret < 0) {
    377			pr_err("%s: read dir %s failed %d\n",
    378			       __func__, coda_f2s(&cii->c_fid), ret);
    379			break;
    380		}
    381		if (ret == 0) break; /* end of directory file reached */
    382
    383		/* catch truncated reads */
    384		if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
    385			pr_err("%s: short read on %s\n",
    386			       __func__, coda_f2s(&cii->c_fid));
    387			ret = -EBADF;
    388			break;
    389		}
    390		/* validate whether the directory file actually makes sense */
    391		if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
    392			pr_err("%s: invalid dir %s\n",
    393			       __func__, coda_f2s(&cii->c_fid));
    394			ret = -EBADF;
    395			break;
    396		}
    397
    398		name.len = vdir->d_namlen;
    399		name.name = vdir->d_name;
    400
    401		/* Make sure we skip '.' and '..', we already got those */
    402		if (name.name[0] == '.' && (name.len == 1 ||
    403		    (name.name[1] == '.' && name.len == 2)))
    404			vdir->d_fileno = name.len = 0;
    405
    406		/* skip null entries */
    407		if (vdir->d_fileno && name.len) {
    408			ino = vdir->d_fileno;
    409			type = CDT2DT(vdir->d_type);
    410			if (!dir_emit(ctx, name.name, name.len, ino, type))
    411				break;
    412		}
    413		/* we'll always have progress because d_reclen is unsigned and
    414		 * we've already established it is non-zero. */
    415		ctx->pos += vdir->d_reclen;
    416	}
    417out:
    418	kfree(vdir);
    419	return 0;
    420}
    421
    422/* file operations for directories */
    423static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
    424{
    425	struct coda_file_info *cfi;
    426	struct file *host_file;
    427	int ret;
    428
    429	cfi = coda_ftoc(coda_file);
    430	host_file = cfi->cfi_container;
    431
    432	if (host_file->f_op->iterate || host_file->f_op->iterate_shared) {
    433		struct inode *host_inode = file_inode(host_file);
    434		ret = -ENOENT;
    435		if (!IS_DEADDIR(host_inode)) {
    436			if (host_file->f_op->iterate_shared) {
    437				inode_lock_shared(host_inode);
    438				ret = host_file->f_op->iterate_shared(host_file, ctx);
    439				file_accessed(host_file);
    440				inode_unlock_shared(host_inode);
    441			} else {
    442				inode_lock(host_inode);
    443				ret = host_file->f_op->iterate(host_file, ctx);
    444				file_accessed(host_file);
    445				inode_unlock(host_inode);
    446			}
    447		}
    448		return ret;
    449	}
    450	/* Venus: we must read Venus dirents from a file */
    451	return coda_venus_readdir(coda_file, ctx);
    452}
    453
    454/* called when a cache lookup succeeds */
    455static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
    456{
    457	struct inode *inode;
    458	struct coda_inode_info *cii;
    459
    460	if (flags & LOOKUP_RCU)
    461		return -ECHILD;
    462
    463	inode = d_inode(de);
    464	if (!inode || is_root_inode(inode))
    465		goto out;
    466	if (is_bad_inode(inode))
    467		goto bad;
    468
    469	cii = ITOC(d_inode(de));
    470	if (!(cii->c_flags & (C_PURGE | C_FLUSH)))
    471		goto out;
    472
    473	shrink_dcache_parent(de);
    474
    475	/* propagate for a flush */
    476	if (cii->c_flags & C_FLUSH) 
    477		coda_flag_inode_children(inode, C_FLUSH);
    478
    479	if (d_count(de) > 1)
    480		/* pretend it's valid, but don't change the flags */
    481		goto out;
    482
    483	/* clear the flags. */
    484	spin_lock(&cii->c_lock);
    485	cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
    486	spin_unlock(&cii->c_lock);
    487bad:
    488	return 0;
    489out:
    490	return 1;
    491}
    492
    493/*
    494 * This is the callback from dput() when d_count is going to 0.
    495 * We use this to unhash dentries with bad inodes.
    496 */
    497static int coda_dentry_delete(const struct dentry * dentry)
    498{
    499	struct inode *inode;
    500	struct coda_inode_info *cii;
    501
    502	if (d_really_is_negative(dentry)) 
    503		return 0;
    504
    505	inode = d_inode(dentry);
    506	if (!inode || is_bad_inode(inode))
    507		return 1;
    508
    509	cii = ITOC(inode);
    510	if (cii->c_flags & C_PURGE)
    511		return 1;
    512
    513	return 0;
    514}
    515
    516
    517
    518/*
    519 * This is called when we want to check if the inode has
    520 * changed on the server.  Coda makes this easy since the
    521 * cache manager Venus issues a downcall to the kernel when this 
    522 * happens 
    523 */
    524int coda_revalidate_inode(struct inode *inode)
    525{
    526	struct coda_vattr attr;
    527	int error;
    528	int old_mode;
    529	ino_t old_ino;
    530	struct coda_inode_info *cii = ITOC(inode);
    531
    532	if (!cii->c_flags)
    533		return 0;
    534
    535	if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
    536		error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
    537		if (error)
    538			return -EIO;
    539
    540		/* this inode may be lost if:
    541		   - it's ino changed 
    542		   - type changes must be permitted for repair and
    543		   missing mount points.
    544		*/
    545		old_mode = inode->i_mode;
    546		old_ino = inode->i_ino;
    547		coda_vattr_to_iattr(inode, &attr);
    548
    549		if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {
    550			pr_warn("inode %ld, fid %s changed type!\n",
    551				inode->i_ino, coda_f2s(&(cii->c_fid)));
    552		}
    553
    554		/* the following can happen when a local fid is replaced 
    555		   with a global one, here we lose and declare the inode bad */
    556		if (inode->i_ino != old_ino)
    557			return -EIO;
    558		
    559		coda_flag_inode_children(inode, C_FLUSH);
    560
    561		spin_lock(&cii->c_lock);
    562		cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
    563		spin_unlock(&cii->c_lock);
    564	}
    565	return 0;
    566}
    567
    568const struct dentry_operations coda_dentry_operations = {
    569	.d_revalidate	= coda_dentry_revalidate,
    570	.d_delete	= coda_dentry_delete,
    571};
    572
    573const struct inode_operations coda_dir_inode_operations = {
    574	.create		= coda_create,
    575	.lookup		= coda_lookup,
    576	.link		= coda_link,
    577	.unlink		= coda_unlink,
    578	.symlink	= coda_symlink,
    579	.mkdir		= coda_mkdir,
    580	.rmdir		= coda_rmdir,
    581	.mknod		= CODA_EIO_ERROR,
    582	.rename		= coda_rename,
    583	.permission	= coda_permission,
    584	.getattr	= coda_getattr,
    585	.setattr	= coda_setattr,
    586};
    587
    588const struct file_operations coda_dir_operations = {
    589	.llseek		= generic_file_llseek,
    590	.read		= generic_read_dir,
    591	.iterate	= coda_readdir,
    592	.open		= coda_open,
    593	.release	= coda_release,
    594	.fsync		= coda_fsync,
    595};