xref: /openbmc/linux/fs/coda/inode.c (revision 0d72b928)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Super block/filesystem wide operations
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
61da177e4SLinus Torvalds  * Michael Callahan <callahan@maths.ox.ac.uk>
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>
91da177e4SLinus Torvalds  * Copyright (C) Carnegie Mellon University
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/kernel.h>
141da177e4SLinus Torvalds #include <linux/mm.h>
151da177e4SLinus Torvalds #include <linux/string.h>
161da177e4SLinus Torvalds #include <linux/stat.h>
171da177e4SLinus Torvalds #include <linux/errno.h>
181da177e4SLinus Torvalds #include <linux/unistd.h>
19da47c19eSYoshihisa Abe #include <linux/mutex.h>
20b5ce1d83SYoshihisa Abe #include <linux/spinlock.h>
211da177e4SLinus Torvalds #include <linux/file.h>
221da177e4SLinus Torvalds #include <linux/vfs.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
249fd973e0SEric W. Biederman #include <linux/pid_namespace.h>
25834b46c3SFabian Frederick #include <linux/uaccess.h>
261da177e4SLinus Torvalds #include <linux/fs.h>
271da177e4SLinus Torvalds #include <linux/vmalloc.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include <linux/coda.h>
308fc8b9dfSDavid Howells #include "coda_psdev.h"
3131a203dfSAl Viro #include "coda_linux.h"
3231a203dfSAl Viro #include "coda_cache.h"
331da177e4SLinus Torvalds 
34c98d8cfbSAdrian Bunk #include "coda_int.h"
35c98d8cfbSAdrian Bunk 
361da177e4SLinus Torvalds /* VFS super_block ops */
37b57922d9SAl Viro static void coda_evict_inode(struct inode *);
381da177e4SLinus Torvalds static void coda_put_super(struct super_block *);
39726c3342SDavid Howells static int coda_statfs(struct dentry *dentry, struct kstatfs *buf);
401da177e4SLinus Torvalds 
41e18b890bSChristoph Lameter static struct kmem_cache * coda_inode_cachep;
421da177e4SLinus Torvalds 
coda_alloc_inode(struct super_block * sb)431da177e4SLinus Torvalds static struct inode *coda_alloc_inode(struct super_block *sb)
441da177e4SLinus Torvalds {
451da177e4SLinus Torvalds 	struct coda_inode_info *ei;
46fd60b288SMuchun Song 	ei = alloc_inode_sb(sb, coda_inode_cachep, GFP_KERNEL);
471da177e4SLinus Torvalds 	if (!ei)
481da177e4SLinus Torvalds 		return NULL;
491da177e4SLinus Torvalds 	memset(&ei->c_fid, 0, sizeof(struct CodaFid));
501da177e4SLinus Torvalds 	ei->c_flags = 0;
5117499e33SEric W. Biederman 	ei->c_uid = GLOBAL_ROOT_UID;
521da177e4SLinus Torvalds 	ei->c_cached_perm = 0;
53b5ce1d83SYoshihisa Abe 	spin_lock_init(&ei->c_lock);
541da177e4SLinus Torvalds 	return &ei->vfs_inode;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
coda_free_inode(struct inode * inode)57d984892bSAl Viro static void coda_free_inode(struct inode *inode)
58fa0d7e3dSNick Piggin {
59fa0d7e3dSNick Piggin 	kmem_cache_free(coda_inode_cachep, ITOC(inode));
60fa0d7e3dSNick Piggin }
61fa0d7e3dSNick Piggin 
init_once(void * foo)6251cc5068SAlexey Dobriyan static void init_once(void *foo)
631da177e4SLinus Torvalds {
641da177e4SLinus Torvalds 	struct coda_inode_info *ei = (struct coda_inode_info *) foo;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	inode_init_once(&ei->vfs_inode);
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
coda_init_inodecache(void)695f356fd4SFabian Frederick int __init coda_init_inodecache(void)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds 	coda_inode_cachep = kmem_cache_create("coda_inode_cache",
725d097056SVladimir Davydov 				sizeof(struct coda_inode_info), 0,
735d097056SVladimir Davydov 				SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
745d097056SVladimir Davydov 				SLAB_ACCOUNT, init_once);
751da177e4SLinus Torvalds 	if (coda_inode_cachep == NULL)
761da177e4SLinus Torvalds 		return -ENOMEM;
771da177e4SLinus Torvalds 	return 0;
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds 
coda_destroy_inodecache(void)801da177e4SLinus Torvalds void coda_destroy_inodecache(void)
811da177e4SLinus Torvalds {
828c0a8537SKirill A. Shutemov 	/*
838c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
848c0a8537SKirill A. Shutemov 	 * destroy cache.
858c0a8537SKirill A. Shutemov 	 */
868c0a8537SKirill A. Shutemov 	rcu_barrier();
871a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(coda_inode_cachep);
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds 
coda_remount(struct super_block * sb,int * flags,char * data)901da177e4SLinus Torvalds static int coda_remount(struct super_block *sb, int *flags, char *data)
911da177e4SLinus Torvalds {
9202b9984dSTheodore Ts'o 	sync_filesystem(sb);
931751e8a6SLinus Torvalds 	*flags |= SB_NOATIME;
941da177e4SLinus Torvalds 	return 0;
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds /* exported operations */
98ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations coda_super_operations =
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds 	.alloc_inode	= coda_alloc_inode,
101d984892bSAl Viro 	.free_inode	= coda_free_inode,
102b57922d9SAl Viro 	.evict_inode	= coda_evict_inode,
1031da177e4SLinus Torvalds 	.put_super	= coda_put_super,
1041da177e4SLinus Torvalds 	.statfs		= coda_statfs,
1051da177e4SLinus Torvalds 	.remount_fs	= coda_remount,
1061da177e4SLinus Torvalds };
1071da177e4SLinus Torvalds 
get_device_index(struct coda_mount_data * data)1081da177e4SLinus Torvalds static int get_device_index(struct coda_mount_data *data)
1091da177e4SLinus Torvalds {
1102903ff01SAl Viro 	struct fd f;
1111da177e4SLinus Torvalds 	struct inode *inode;
1122903ff01SAl Viro 	int idx;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	if (data == NULL) {
1156d6bd94fSFabian Frederick 		pr_warn("%s: Bad mount data\n", __func__);
1161da177e4SLinus Torvalds 		return -1;
1171da177e4SLinus Torvalds 	}
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 	if (data->version != CODA_MOUNT_VERSION) {
1206d6bd94fSFabian Frederick 		pr_warn("%s: Bad mount version\n", __func__);
1211da177e4SLinus Torvalds 		return -1;
1221da177e4SLinus Torvalds 	}
1231da177e4SLinus Torvalds 
1242903ff01SAl Viro 	f = fdget(data->fd);
1252903ff01SAl Viro 	if (!f.file)
12678f7d75eSAl Viro 		goto Ebadf;
127496ad9aaSAl Viro 	inode = file_inode(f.file);
12878f7d75eSAl Viro 	if (!S_ISCHR(inode->i_mode) || imajor(inode) != CODA_PSDEV_MAJOR) {
1292903ff01SAl Viro 		fdput(f);
13078f7d75eSAl Viro 		goto Ebadf;
1311da177e4SLinus Torvalds 	}
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds 	idx = iminor(inode);
1342903ff01SAl Viro 	fdput(f);
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds 	if (idx < 0 || idx >= MAX_CODADEVS) {
1376d6bd94fSFabian Frederick 		pr_warn("%s: Bad minor number\n", __func__);
1381da177e4SLinus Torvalds 		return -1;
1391da177e4SLinus Torvalds 	}
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	return idx;
14278f7d75eSAl Viro Ebadf:
1436d6bd94fSFabian Frederick 	pr_warn("%s: Bad file\n", __func__);
14478f7d75eSAl Viro 	return -1;
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds 
coda_fill_super(struct super_block * sb,void * data,int silent)1471da177e4SLinus Torvalds static int coda_fill_super(struct super_block *sb, void *data, int silent)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds 	struct inode *root = NULL;
150da47c19eSYoshihisa Abe 	struct venus_comm *vc;
1511da177e4SLinus Torvalds 	struct CodaFid fid;
1521da177e4SLinus Torvalds 	int error;
1531da177e4SLinus Torvalds 	int idx;
1541da177e4SLinus Torvalds 
1559fd973e0SEric W. Biederman 	if (task_active_pid_ns(current) != &init_pid_ns)
1569fd973e0SEric W. Biederman 		return -EINVAL;
1579fd973e0SEric W. Biederman 
1581da177e4SLinus Torvalds 	idx = get_device_index((struct coda_mount_data *) data);
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	/* Ignore errors in data, for backward compatibility */
1611da177e4SLinus Torvalds 	if(idx == -1)
1621da177e4SLinus Torvalds 		idx = 0;
1631da177e4SLinus Torvalds 
1646d6bd94fSFabian Frederick 	pr_info("%s: device index: %i\n", __func__,  idx);
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	vc = &coda_comms[idx];
167da47c19eSYoshihisa Abe 	mutex_lock(&vc->vc_mutex);
168f7cc02b8SYoshihisa Abe 
1691da177e4SLinus Torvalds 	if (!vc->vc_inuse) {
1706d6bd94fSFabian Frederick 		pr_warn("%s: No pseudo device\n", __func__);
171f7cc02b8SYoshihisa Abe 		error = -EINVAL;
172f7cc02b8SYoshihisa Abe 		goto unlock_out;
1731da177e4SLinus Torvalds 	}
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	if (vc->vc_sb) {
1766d6bd94fSFabian Frederick 		pr_warn("%s: Device already mounted\n", __func__);
177f7cc02b8SYoshihisa Abe 		error = -EBUSY;
178f7cc02b8SYoshihisa Abe 		goto unlock_out;
1791da177e4SLinus Torvalds 	}
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 	vc->vc_sb = sb;
182da47c19eSYoshihisa Abe 	mutex_unlock(&vc->vc_mutex);
1831da177e4SLinus Torvalds 
184a1b0aa87SJan Harkes 	sb->s_fs_info = vc;
1851751e8a6SLinus Torvalds 	sb->s_flags |= SB_NOATIME;
186fac1f0e3SJan Harkes 	sb->s_blocksize = 4096;	/* XXXXX  what do we put here?? */
187fac1f0e3SJan Harkes 	sb->s_blocksize_bits = 12;
1881da177e4SLinus Torvalds 	sb->s_magic = CODA_SUPER_MAGIC;
1891da177e4SLinus Torvalds 	sb->s_op = &coda_super_operations;
1909501e4c4SAl Viro 	sb->s_d_op = &coda_dentry_operations;
19122b13969SDeepa Dinamani 	sb->s_time_gran = 1;
19222b13969SDeepa Dinamani 	sb->s_time_min = S64_MIN;
19322b13969SDeepa Dinamani 	sb->s_time_max = S64_MAX;
194a5695a79SJan Kara 
195a5695a79SJan Kara 	error = super_setup_bdi(sb);
196a5695a79SJan Kara 	if (error)
197a5695a79SJan Kara 		goto error;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	/* get root fid from Venus: this needs the root inode */
2001da177e4SLinus Torvalds 	error = venus_rootfid(sb, &fid);
2011da177e4SLinus Torvalds 	if ( error ) {
2026d6bd94fSFabian Frederick 		pr_warn("%s: coda_get_rootfid failed with %d\n",
2036d6bd94fSFabian Frederick 			__func__, error);
2041da177e4SLinus Torvalds 		goto error;
2051da177e4SLinus Torvalds 	}
2066d6bd94fSFabian Frederick 	pr_info("%s: rootfid is %s\n", __func__, coda_f2s(&fid));
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 	/* make root inode */
209f4947fbcSAl Viro         root = coda_cnode_make(&fid, sb);
210f4947fbcSAl Viro         if (IS_ERR(root)) {
211f4947fbcSAl Viro 		error = PTR_ERR(root);
212d9b4b319SFabian Frederick 		pr_warn("Failure of coda_cnode_make for root: error %d\n",
213d9b4b319SFabian Frederick 			error);
2141da177e4SLinus Torvalds 		goto error;
2151da177e4SLinus Torvalds 	}
2161da177e4SLinus Torvalds 
2176d6bd94fSFabian Frederick 	pr_info("%s: rootinode is %ld dev %s\n",
2186d6bd94fSFabian Frederick 		__func__, root->i_ino, root->i_sb->s_id);
21948fde701SAl Viro 	sb->s_root = d_make_root(root);
220f7cc02b8SYoshihisa Abe 	if (!sb->s_root) {
221f7cc02b8SYoshihisa Abe 		error = -EINVAL;
2221da177e4SLinus Torvalds 		goto error;
223f7cc02b8SYoshihisa Abe 	}
2241da177e4SLinus Torvalds 	return 0;
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds error:
227da47c19eSYoshihisa Abe 	mutex_lock(&vc->vc_mutex);
228f7cc02b8SYoshihisa Abe 	vc->vc_sb = NULL;
229f7cc02b8SYoshihisa Abe 	sb->s_fs_info = NULL;
230f7cc02b8SYoshihisa Abe unlock_out:
231da47c19eSYoshihisa Abe 	mutex_unlock(&vc->vc_mutex);
232f7cc02b8SYoshihisa Abe 	return error;
2331da177e4SLinus Torvalds }
2341da177e4SLinus Torvalds 
coda_put_super(struct super_block * sb)2351da177e4SLinus Torvalds static void coda_put_super(struct super_block *sb)
2361da177e4SLinus Torvalds {
237da47c19eSYoshihisa Abe 	struct venus_comm *vcp = coda_vcp(sb);
238da47c19eSYoshihisa Abe 	mutex_lock(&vcp->vc_mutex);
239da47c19eSYoshihisa Abe 	vcp->vc_sb = NULL;
240a1b0aa87SJan Harkes 	sb->s_fs_info = NULL;
241da47c19eSYoshihisa Abe 	mutex_unlock(&vcp->vc_mutex);
24279a0d65eSFabian Frederick 	mutex_destroy(&vcp->vc_mutex);
2431da177e4SLinus Torvalds 
244f38cfb25SFabian Frederick 	pr_info("Bye bye.\n");
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds 
coda_evict_inode(struct inode * inode)247b57922d9SAl Viro static void coda_evict_inode(struct inode *inode)
2481da177e4SLinus Torvalds {
24991b0abe3SJohannes Weiner 	truncate_inode_pages_final(&inode->i_data);
250dbd5768fSJan Kara 	clear_inode(inode);
2511da177e4SLinus Torvalds 	coda_cache_clear_inode(inode);
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
coda_getattr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int flags)254b74d24f7SChristian Brauner int coda_getattr(struct mnt_idmap *idmap, const struct path *path,
255549c7297SChristian Brauner 		 struct kstat *stat, u32 request_mask, unsigned int flags)
2561da177e4SLinus Torvalds {
257a528d35eSDavid Howells 	int err = coda_revalidate_inode(d_inode(path->dentry));
2581da177e4SLinus Torvalds 	if (!err)
259*0d72b928SJeff Layton 		generic_fillattr(&nop_mnt_idmap, request_mask,
260*0d72b928SJeff Layton 				 d_inode(path->dentry), stat);
2611da177e4SLinus Torvalds 	return err;
2621da177e4SLinus Torvalds }
2631da177e4SLinus Torvalds 
coda_setattr(struct mnt_idmap * idmap,struct dentry * de,struct iattr * iattr)264c1632a0fSChristian Brauner int coda_setattr(struct mnt_idmap *idmap, struct dentry *de,
265549c7297SChristian Brauner 		 struct iattr *iattr)
2661da177e4SLinus Torvalds {
2672b0143b5SDavid Howells 	struct inode *inode = d_inode(de);
2681da177e4SLinus Torvalds 	struct coda_vattr vattr;
2691da177e4SLinus Torvalds 	int error;
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	memset(&vattr, 0, sizeof(vattr));
2721da177e4SLinus Torvalds 
273ea9b53d4SJeff Layton 	inode_set_ctime_current(inode);
2741da177e4SLinus Torvalds 	coda_iattr_to_vattr(iattr, &vattr);
2751da177e4SLinus Torvalds 	vattr.va_type = C_VNON; /* cannot set type */
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	/* Venus is responsible for truncating the container-file!!! */
2781da177e4SLinus Torvalds 	error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds 	if (!error) {
2811da177e4SLinus Torvalds 	        coda_vattr_to_iattr(inode, &vattr);
2821da177e4SLinus Torvalds 		coda_cache_clear_inode(inode);
2831da177e4SLinus Torvalds 	}
2841da177e4SLinus Torvalds 	return error;
2851da177e4SLinus Torvalds }
2861da177e4SLinus Torvalds 
287754661f1SArjan van de Ven const struct inode_operations coda_file_inode_operations = {
2881da177e4SLinus Torvalds 	.permission	= coda_permission,
2891da177e4SLinus Torvalds 	.getattr	= coda_getattr,
2901da177e4SLinus Torvalds 	.setattr	= coda_setattr,
2911da177e4SLinus Torvalds };
2921da177e4SLinus Torvalds 
coda_statfs(struct dentry * dentry,struct kstatfs * buf)293726c3342SDavid Howells static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
2941da177e4SLinus Torvalds {
2951da177e4SLinus Torvalds 	int error;
2961da177e4SLinus Torvalds 
297726c3342SDavid Howells 	error = venus_statfs(dentry, buf);
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 	if (error) {
3001da177e4SLinus Torvalds 		/* fake something like AFS does */
3011da177e4SLinus Torvalds 		buf->f_blocks = 9000000;
3021da177e4SLinus Torvalds 		buf->f_bfree  = 9000000;
3031da177e4SLinus Torvalds 		buf->f_bavail = 9000000;
3041da177e4SLinus Torvalds 		buf->f_files  = 9000000;
3051da177e4SLinus Torvalds 		buf->f_ffree  = 9000000;
3061da177e4SLinus Torvalds 	}
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	/* and fill in the rest */
3091da177e4SLinus Torvalds 	buf->f_type = CODA_SUPER_MAGIC;
310fac1f0e3SJan Harkes 	buf->f_bsize = 4096;
3111da177e4SLinus Torvalds 	buf->f_namelen = CODA_MAXNAMLEN;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 	return 0;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds /* init_coda: used by filesystems.c to register coda */
3171da177e4SLinus Torvalds 
coda_mount(struct file_system_type * fs_type,int flags,const char * dev_name,void * data)3183c26ff6eSAl Viro static struct dentry *coda_mount(struct file_system_type *fs_type,
3193c26ff6eSAl Viro 	int flags, const char *dev_name, void *data)
3201da177e4SLinus Torvalds {
3213c26ff6eSAl Viro 	return mount_nodev(fs_type, flags, data, coda_fill_super);
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds struct file_system_type coda_fs_type = {
3251da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
3261da177e4SLinus Torvalds 	.name		= "coda",
3273c26ff6eSAl Viro 	.mount		= coda_mount,
3281da177e4SLinus Torvalds 	.kill_sb	= kill_anon_super,
3291da177e4SLinus Torvalds 	.fs_flags	= FS_BINARY_MOUNTDATA,
3301da177e4SLinus Torvalds };
3317f78e035SEric W. Biederman MODULE_ALIAS_FS("coda");
3321da177e4SLinus Torvalds 
333