brintos

brintos / linux-shallow public Read only

0
0
Text · 14.1 KiB · 4e552ba Raw
590 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Directory operations for Coda filesystem5 * Original version: (C) 1996 P. Braam and M. Callahan6 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University7 * 8 * Carnegie Mellon encourages users to contribute improvements to9 * 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 mnt_idmap *idmap, 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_MTIME107	/* invalidate the directory cnode's attributes so we refetch the108	 * attributes from venus next time the inode is referenced */109	coda_flag_inode(dir, C_VATTR);110#else111	/* optimistically we can also act as if our nose bleeds. The112	 * granularity of the mtime is coarse anyways so we might actually be113	 * right most of the time. Note: we only do this for directories. */114	inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));115#endif116}117 118/* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a119 * trick to fool GNU find's optimizations. If we can't be sure of the link120 * (because of volume mount points) we set i_nlink to 1 which forces find121 * to consider every child as a possible directory. We should also never122 * 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 mnt_idmap *idmap, 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 mnt_idmap *idmap, 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 mnt_idmap *idmap,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 create249	 * 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 mnt_idmap *idmap, 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 and414		 * 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_shared) {433		struct inode *host_inode = file_inode(host_file);434		ret = -ENOENT;435		if (!IS_DEADDIR(host_inode)) {436			inode_lock_shared(host_inode);437			ret = host_file->f_op->iterate_shared(host_file, ctx);438			file_accessed(host_file);439			inode_unlock_shared(host_inode);440		}441		return ret;442	}443	/* Venus: we must read Venus dirents from a file */444	return coda_venus_readdir(coda_file, ctx);445}446 447/* called when a cache lookup succeeds */448static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)449{450	struct inode *inode;451	struct coda_inode_info *cii;452 453	if (flags & LOOKUP_RCU)454		return -ECHILD;455 456	inode = d_inode(de);457	if (!inode || is_root_inode(inode))458		goto out;459	if (is_bad_inode(inode))460		goto bad;461 462	cii = ITOC(d_inode(de));463	if (!(cii->c_flags & (C_PURGE | C_FLUSH)))464		goto out;465 466	shrink_dcache_parent(de);467 468	/* propagate for a flush */469	if (cii->c_flags & C_FLUSH) 470		coda_flag_inode_children(inode, C_FLUSH);471 472	if (d_count(de) > 1)473		/* pretend it's valid, but don't change the flags */474		goto out;475 476	/* clear the flags. */477	spin_lock(&cii->c_lock);478	cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);479	spin_unlock(&cii->c_lock);480bad:481	return 0;482out:483	return 1;484}485 486/*487 * This is the callback from dput() when d_count is going to 0.488 * We use this to unhash dentries with bad inodes.489 */490static int coda_dentry_delete(const struct dentry * dentry)491{492	struct inode *inode;493	struct coda_inode_info *cii;494 495	if (d_really_is_negative(dentry)) 496		return 0;497 498	inode = d_inode(dentry);499	if (!inode || is_bad_inode(inode))500		return 1;501 502	cii = ITOC(inode);503	if (cii->c_flags & C_PURGE)504		return 1;505 506	return 0;507}508 509 510 511/*512 * This is called when we want to check if the inode has513 * changed on the server.  Coda makes this easy since the514 * cache manager Venus issues a downcall to the kernel when this 515 * happens 516 */517int coda_revalidate_inode(struct inode *inode)518{519	struct coda_vattr attr;520	int error;521	int old_mode;522	ino_t old_ino;523	struct coda_inode_info *cii = ITOC(inode);524 525	if (!cii->c_flags)526		return 0;527 528	if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {529		error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);530		if (error)531			return -EIO;532 533		/* this inode may be lost if:534		   - it's ino changed 535		   - type changes must be permitted for repair and536		   missing mount points.537		*/538		old_mode = inode->i_mode;539		old_ino = inode->i_ino;540		coda_vattr_to_iattr(inode, &attr);541 542		if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {543			pr_warn("inode %ld, fid %s changed type!\n",544				inode->i_ino, coda_f2s(&(cii->c_fid)));545		}546 547		/* the following can happen when a local fid is replaced 548		   with a global one, here we lose and declare the inode bad */549		if (inode->i_ino != old_ino)550			return -EIO;551		552		coda_flag_inode_children(inode, C_FLUSH);553 554		spin_lock(&cii->c_lock);555		cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);556		spin_unlock(&cii->c_lock);557	}558	return 0;559}560 561const struct dentry_operations coda_dentry_operations = {562	.d_revalidate	= coda_dentry_revalidate,563	.d_delete	= coda_dentry_delete,564};565 566const struct inode_operations coda_dir_inode_operations = {567	.create		= coda_create,568	.lookup		= coda_lookup,569	.link		= coda_link,570	.unlink		= coda_unlink,571	.symlink	= coda_symlink,572	.mkdir		= coda_mkdir,573	.rmdir		= coda_rmdir,574	.mknod		= CODA_EIO_ERROR,575	.rename		= coda_rename,576	.permission	= coda_permission,577	.getattr	= coda_getattr,578	.setattr	= coda_setattr,579};580 581WRAP_DIR_ITER(coda_readdir) // FIXME!582const struct file_operations coda_dir_operations = {583	.llseek		= generic_file_llseek,584	.read		= generic_read_dir,585	.iterate_shared	= shared_coda_readdir,586	.open		= coda_open,587	.release	= coda_release,588	.fsync		= coda_fsync,589};590