brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 6896fce Raw
403 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Super block/filesystem wide operations4 *5 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and 6 * Michael Callahan <callahan@maths.ox.ac.uk> 7 * 8 * Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>9 * Copyright (C) Carnegie Mellon University10 */11 12#include <linux/module.h>13#include <linux/kernel.h>14#include <linux/mm.h>15#include <linux/string.h>16#include <linux/stat.h>17#include <linux/errno.h>18#include <linux/unistd.h>19#include <linux/mutex.h>20#include <linux/spinlock.h>21#include <linux/file.h>22#include <linux/vfs.h>23#include <linux/slab.h>24#include <linux/pid_namespace.h>25#include <linux/uaccess.h>26#include <linux/fs.h>27#include <linux/fs_context.h>28#include <linux/fs_parser.h>29#include <linux/vmalloc.h>30 31#include <linux/coda.h>32#include "coda_psdev.h"33#include "coda_linux.h"34#include "coda_cache.h"35 36#include "coda_int.h"37 38/* VFS super_block ops */39static void coda_evict_inode(struct inode *);40static void coda_put_super(struct super_block *);41static int coda_statfs(struct dentry *dentry, struct kstatfs *buf);42 43static struct kmem_cache * coda_inode_cachep;44 45static struct inode *coda_alloc_inode(struct super_block *sb)46{47	struct coda_inode_info *ei;48	ei = alloc_inode_sb(sb, coda_inode_cachep, GFP_KERNEL);49	if (!ei)50		return NULL;51	memset(&ei->c_fid, 0, sizeof(struct CodaFid));52	ei->c_flags = 0;53	ei->c_uid = GLOBAL_ROOT_UID;54	ei->c_cached_perm = 0;55	spin_lock_init(&ei->c_lock);56	return &ei->vfs_inode;57}58 59static void coda_free_inode(struct inode *inode)60{61	kmem_cache_free(coda_inode_cachep, ITOC(inode));62}63 64static void init_once(void *foo)65{66	struct coda_inode_info *ei = (struct coda_inode_info *) foo;67 68	inode_init_once(&ei->vfs_inode);69}70 71int __init coda_init_inodecache(void)72{73	coda_inode_cachep = kmem_cache_create("coda_inode_cache",74				sizeof(struct coda_inode_info), 0,75				SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT,76				init_once);77	if (coda_inode_cachep == NULL)78		return -ENOMEM;79	return 0;80}81 82void coda_destroy_inodecache(void)83{84	/*85	 * Make sure all delayed rcu free inodes are flushed before we86	 * destroy cache.87	 */88	rcu_barrier();89	kmem_cache_destroy(coda_inode_cachep);90}91 92static int coda_reconfigure(struct fs_context *fc)93{94	sync_filesystem(fc->root->d_sb);95	fc->sb_flags |= SB_NOATIME;96	return 0;97}98 99/* exported operations */100static const struct super_operations coda_super_operations =101{102	.alloc_inode	= coda_alloc_inode,103	.free_inode	= coda_free_inode,104	.evict_inode	= coda_evict_inode,105	.put_super	= coda_put_super,106	.statfs		= coda_statfs,107};108 109struct coda_fs_context {110	int	idx;111};112 113enum {114	Opt_fd,115};116 117static const struct fs_parameter_spec coda_param_specs[] = {118	fsparam_fd	("fd",	Opt_fd),119	{}120};121 122static int coda_set_idx(struct fs_context *fc, struct file *file)123{124	struct coda_fs_context *ctx = fc->fs_private;125	struct inode *inode;126	int idx;127 128	inode = file_inode(file);129	if (!S_ISCHR(inode->i_mode) || imajor(inode) != CODA_PSDEV_MAJOR) {130		return invalf(fc, "coda: Not coda psdev");131	}132	idx = iminor(inode);133	if (idx < 0 || idx >= MAX_CODADEVS)134		return invalf(fc, "coda: Bad minor number");135	ctx->idx = idx;136	return 0;137}138 139static int coda_parse_fd(struct fs_context *fc, struct fs_parameter *param,140			 struct fs_parse_result *result)141{142	struct file *file;143	int err;144 145	if (param->type == fs_value_is_file) {146		file = param->file;147		param->file = NULL;148	} else {149		file = fget(result->uint_32);150	}151	if (!file)152		return -EBADF;153 154	err = coda_set_idx(fc, file);155	fput(file);156	return err;157}158 159static int coda_parse_param(struct fs_context *fc, struct fs_parameter *param)160{161	struct fs_parse_result result;162	int opt;163 164	opt = fs_parse(fc, coda_param_specs, param, &result);165	if (opt < 0)166		return opt;167 168	switch (opt) {169	case Opt_fd:170		return coda_parse_fd(fc, param, &result);171	}172 173	return 0;174}175 176/*177 * Parse coda's binary mount data form.  We ignore any errors and go with index178 * 0 if we get one for backward compatibility.179 */180static int coda_parse_monolithic(struct fs_context *fc, void *_data)181{182	struct file *file;183	struct coda_mount_data *data = _data;184 185	if (!data)186		return invalf(fc, "coda: Bad mount data");187 188	if (data->version != CODA_MOUNT_VERSION)189		return invalf(fc, "coda: Bad mount version");190 191	file = fget(data->fd);192	if (file) {193		coda_set_idx(fc, file);194		fput(file);195	}196	return 0;197}198 199static int coda_fill_super(struct super_block *sb, struct fs_context *fc)200{201	struct coda_fs_context *ctx = fc->fs_private;202	struct inode *root = NULL;203	struct venus_comm *vc;204	struct CodaFid fid;205	int error;206 207	infof(fc, "coda: device index: %i\n", ctx->idx);208 209	vc = &coda_comms[ctx->idx];210	mutex_lock(&vc->vc_mutex);211 212	if (!vc->vc_inuse) {213		errorf(fc, "coda: No pseudo device");214		error = -EINVAL;215		goto unlock_out;216	}217 218	if (vc->vc_sb) {219		errorf(fc, "coda: Device already mounted");220		error = -EBUSY;221		goto unlock_out;222	}223 224	vc->vc_sb = sb;225	mutex_unlock(&vc->vc_mutex);226 227	sb->s_fs_info = vc;228	sb->s_flags |= SB_NOATIME;229	sb->s_blocksize = 4096;	/* XXXXX  what do we put here?? */230	sb->s_blocksize_bits = 12;231	sb->s_magic = CODA_SUPER_MAGIC;232	sb->s_op = &coda_super_operations;233	sb->s_d_op = &coda_dentry_operations;234	sb->s_time_gran = 1;235	sb->s_time_min = S64_MIN;236	sb->s_time_max = S64_MAX;237 238	error = super_setup_bdi(sb);239	if (error)240		goto error;241 242	/* get root fid from Venus: this needs the root inode */243	error = venus_rootfid(sb, &fid);244	if ( error ) {245		pr_warn("%s: coda_get_rootfid failed with %d\n",246			__func__, error);247		goto error;248	}249	pr_info("%s: rootfid is %s\n", __func__, coda_f2s(&fid));250	251	/* make root inode */252        root = coda_cnode_make(&fid, sb);253        if (IS_ERR(root)) {254		error = PTR_ERR(root);255		pr_warn("Failure of coda_cnode_make for root: error %d\n",256			error);257		goto error;258	} 259 260	pr_info("%s: rootinode is %ld dev %s\n",261		__func__, root->i_ino, root->i_sb->s_id);262	sb->s_root = d_make_root(root);263	if (!sb->s_root) {264		error = -EINVAL;265		goto error;266	}267	return 0;268 269error:270	mutex_lock(&vc->vc_mutex);271	vc->vc_sb = NULL;272	sb->s_fs_info = NULL;273unlock_out:274	mutex_unlock(&vc->vc_mutex);275	return error;276}277 278static void coda_put_super(struct super_block *sb)279{280	struct venus_comm *vcp = coda_vcp(sb);281	mutex_lock(&vcp->vc_mutex);282	vcp->vc_sb = NULL;283	sb->s_fs_info = NULL;284	mutex_unlock(&vcp->vc_mutex);285	mutex_destroy(&vcp->vc_mutex);286 287	pr_info("Bye bye.\n");288}289 290static void coda_evict_inode(struct inode *inode)291{292	truncate_inode_pages_final(&inode->i_data);293	clear_inode(inode);294	coda_cache_clear_inode(inode);295}296 297int coda_getattr(struct mnt_idmap *idmap, const struct path *path,298		 struct kstat *stat, u32 request_mask, unsigned int flags)299{300	int err = coda_revalidate_inode(d_inode(path->dentry));301	if (!err)302		generic_fillattr(&nop_mnt_idmap, request_mask,303				 d_inode(path->dentry), stat);304	return err;305}306 307int coda_setattr(struct mnt_idmap *idmap, struct dentry *de,308		 struct iattr *iattr)309{310	struct inode *inode = d_inode(de);311	struct coda_vattr vattr;312	int error;313 314	memset(&vattr, 0, sizeof(vattr)); 315 316	inode_set_ctime_current(inode);317	coda_iattr_to_vattr(iattr, &vattr);318	vattr.va_type = C_VNON; /* cannot set type */319 320	/* Venus is responsible for truncating the container-file!!! */321	error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);322 323	if (!error) {324	        coda_vattr_to_iattr(inode, &vattr); 325		coda_cache_clear_inode(inode);326	}327	return error;328}329 330const struct inode_operations coda_file_inode_operations = {331	.permission	= coda_permission,332	.getattr	= coda_getattr,333	.setattr	= coda_setattr,334};335 336static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)337{338	int error;339	340	error = venus_statfs(dentry, buf);341 342	if (error) {343		/* fake something like AFS does */344		buf->f_blocks = 9000000;345		buf->f_bfree  = 9000000;346		buf->f_bavail = 9000000;347		buf->f_files  = 9000000;348		buf->f_ffree  = 9000000;349	}350 351	/* and fill in the rest */352	buf->f_type = CODA_SUPER_MAGIC;353	buf->f_bsize = 4096;354	buf->f_namelen = CODA_MAXNAMLEN;355 356	return 0; 357}358 359static int coda_get_tree(struct fs_context *fc)360{361	if (task_active_pid_ns(current) != &init_pid_ns)362		return -EINVAL;363 364	return get_tree_nodev(fc, coda_fill_super);365}366 367static void coda_free_fc(struct fs_context *fc)368{369	kfree(fc->fs_private);370}371 372static const struct fs_context_operations coda_context_ops = {373	.free		= coda_free_fc,374	.parse_param	= coda_parse_param,375	.parse_monolithic = coda_parse_monolithic,376	.get_tree	= coda_get_tree,377	.reconfigure	= coda_reconfigure,378};379 380static int coda_init_fs_context(struct fs_context *fc)381{382	struct coda_fs_context *ctx;383 384	ctx = kzalloc(sizeof(struct coda_fs_context), GFP_KERNEL);385	if (!ctx)386		return -ENOMEM;387 388	fc->fs_private = ctx;389	fc->ops = &coda_context_ops;390	return 0;391}392 393struct file_system_type coda_fs_type = {394	.owner		= THIS_MODULE,395	.name		= "coda",396	.init_fs_context = coda_init_fs_context,397	.parameters	= coda_param_specs,398	.kill_sb	= kill_anon_super,399	.fs_flags	= FS_BINARY_MOUNTDATA,400};401MODULE_ALIAS_FS("coda");402 403