18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Super block/filesystem wide operations 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and 68c2ecf20Sopenharmony_ci * Michael Callahan <callahan@maths.ox.ac.uk> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Rewritten for Linux 2.1. Peter Braam <braam@cs.cmu.edu> 98c2ecf20Sopenharmony_ci * Copyright (C) Carnegie Mellon University 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/stat.h> 178c2ecf20Sopenharmony_ci#include <linux/errno.h> 188c2ecf20Sopenharmony_ci#include <linux/unistd.h> 198c2ecf20Sopenharmony_ci#include <linux/mutex.h> 208c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 218c2ecf20Sopenharmony_ci#include <linux/file.h> 228c2ecf20Sopenharmony_ci#include <linux/vfs.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/pid_namespace.h> 258c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 268c2ecf20Sopenharmony_ci#include <linux/fs.h> 278c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/coda.h> 308c2ecf20Sopenharmony_ci#include "coda_psdev.h" 318c2ecf20Sopenharmony_ci#include "coda_linux.h" 328c2ecf20Sopenharmony_ci#include "coda_cache.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "coda_int.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* VFS super_block ops */ 378c2ecf20Sopenharmony_cistatic void coda_evict_inode(struct inode *); 388c2ecf20Sopenharmony_cistatic void coda_put_super(struct super_block *); 398c2ecf20Sopenharmony_cistatic int coda_statfs(struct dentry *dentry, struct kstatfs *buf); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic struct kmem_cache * coda_inode_cachep; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct inode *coda_alloc_inode(struct super_block *sb) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct coda_inode_info *ei; 468c2ecf20Sopenharmony_ci ei = kmem_cache_alloc(coda_inode_cachep, GFP_KERNEL); 478c2ecf20Sopenharmony_ci if (!ei) 488c2ecf20Sopenharmony_ci return NULL; 498c2ecf20Sopenharmony_ci memset(&ei->c_fid, 0, sizeof(struct CodaFid)); 508c2ecf20Sopenharmony_ci ei->c_flags = 0; 518c2ecf20Sopenharmony_ci ei->c_uid = GLOBAL_ROOT_UID; 528c2ecf20Sopenharmony_ci ei->c_cached_perm = 0; 538c2ecf20Sopenharmony_ci spin_lock_init(&ei->c_lock); 548c2ecf20Sopenharmony_ci return &ei->vfs_inode; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void coda_free_inode(struct inode *inode) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci kmem_cache_free(coda_inode_cachep, ITOC(inode)); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void init_once(void *foo) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct coda_inode_info *ei = (struct coda_inode_info *) foo; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci inode_init_once(&ei->vfs_inode); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciint __init coda_init_inodecache(void) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci coda_inode_cachep = kmem_cache_create("coda_inode_cache", 728c2ecf20Sopenharmony_ci sizeof(struct coda_inode_info), 0, 738c2ecf20Sopenharmony_ci SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD| 748c2ecf20Sopenharmony_ci SLAB_ACCOUNT, init_once); 758c2ecf20Sopenharmony_ci if (coda_inode_cachep == NULL) 768c2ecf20Sopenharmony_ci return -ENOMEM; 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_civoid coda_destroy_inodecache(void) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 848c2ecf20Sopenharmony_ci * destroy cache. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci rcu_barrier(); 878c2ecf20Sopenharmony_ci kmem_cache_destroy(coda_inode_cachep); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int coda_remount(struct super_block *sb, int *flags, char *data) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci sync_filesystem(sb); 938c2ecf20Sopenharmony_ci *flags |= SB_NOATIME; 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* exported operations */ 988c2ecf20Sopenharmony_cistatic const struct super_operations coda_super_operations = 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci .alloc_inode = coda_alloc_inode, 1018c2ecf20Sopenharmony_ci .free_inode = coda_free_inode, 1028c2ecf20Sopenharmony_ci .evict_inode = coda_evict_inode, 1038c2ecf20Sopenharmony_ci .put_super = coda_put_super, 1048c2ecf20Sopenharmony_ci .statfs = coda_statfs, 1058c2ecf20Sopenharmony_ci .remount_fs = coda_remount, 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int get_device_index(struct coda_mount_data *data) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct fd f; 1118c2ecf20Sopenharmony_ci struct inode *inode; 1128c2ecf20Sopenharmony_ci int idx; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (data == NULL) { 1158c2ecf20Sopenharmony_ci pr_warn("%s: Bad mount data\n", __func__); 1168c2ecf20Sopenharmony_ci return -1; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (data->version != CODA_MOUNT_VERSION) { 1208c2ecf20Sopenharmony_ci pr_warn("%s: Bad mount version\n", __func__); 1218c2ecf20Sopenharmony_ci return -1; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci f = fdget(data->fd); 1258c2ecf20Sopenharmony_ci if (!f.file) 1268c2ecf20Sopenharmony_ci goto Ebadf; 1278c2ecf20Sopenharmony_ci inode = file_inode(f.file); 1288c2ecf20Sopenharmony_ci if (!S_ISCHR(inode->i_mode) || imajor(inode) != CODA_PSDEV_MAJOR) { 1298c2ecf20Sopenharmony_ci fdput(f); 1308c2ecf20Sopenharmony_ci goto Ebadf; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci idx = iminor(inode); 1348c2ecf20Sopenharmony_ci fdput(f); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (idx < 0 || idx >= MAX_CODADEVS) { 1378c2ecf20Sopenharmony_ci pr_warn("%s: Bad minor number\n", __func__); 1388c2ecf20Sopenharmony_ci return -1; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return idx; 1428c2ecf20Sopenharmony_ciEbadf: 1438c2ecf20Sopenharmony_ci pr_warn("%s: Bad file\n", __func__); 1448c2ecf20Sopenharmony_ci return -1; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int coda_fill_super(struct super_block *sb, void *data, int silent) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct inode *root = NULL; 1508c2ecf20Sopenharmony_ci struct venus_comm *vc; 1518c2ecf20Sopenharmony_ci struct CodaFid fid; 1528c2ecf20Sopenharmony_ci int error; 1538c2ecf20Sopenharmony_ci int idx; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (task_active_pid_ns(current) != &init_pid_ns) 1568c2ecf20Sopenharmony_ci return -EINVAL; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci idx = get_device_index((struct coda_mount_data *) data); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Ignore errors in data, for backward compatibility */ 1618c2ecf20Sopenharmony_ci if(idx == -1) 1628c2ecf20Sopenharmony_ci idx = 0; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci pr_info("%s: device index: %i\n", __func__, idx); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci vc = &coda_comms[idx]; 1678c2ecf20Sopenharmony_ci mutex_lock(&vc->vc_mutex); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (!vc->vc_inuse) { 1708c2ecf20Sopenharmony_ci pr_warn("%s: No pseudo device\n", __func__); 1718c2ecf20Sopenharmony_ci error = -EINVAL; 1728c2ecf20Sopenharmony_ci goto unlock_out; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (vc->vc_sb) { 1768c2ecf20Sopenharmony_ci pr_warn("%s: Device already mounted\n", __func__); 1778c2ecf20Sopenharmony_ci error = -EBUSY; 1788c2ecf20Sopenharmony_ci goto unlock_out; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci vc->vc_sb = sb; 1828c2ecf20Sopenharmony_ci mutex_unlock(&vc->vc_mutex); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci sb->s_fs_info = vc; 1858c2ecf20Sopenharmony_ci sb->s_flags |= SB_NOATIME; 1868c2ecf20Sopenharmony_ci sb->s_blocksize = 4096; /* XXXXX what do we put here?? */ 1878c2ecf20Sopenharmony_ci sb->s_blocksize_bits = 12; 1888c2ecf20Sopenharmony_ci sb->s_magic = CODA_SUPER_MAGIC; 1898c2ecf20Sopenharmony_ci sb->s_op = &coda_super_operations; 1908c2ecf20Sopenharmony_ci sb->s_d_op = &coda_dentry_operations; 1918c2ecf20Sopenharmony_ci sb->s_time_gran = 1; 1928c2ecf20Sopenharmony_ci sb->s_time_min = S64_MIN; 1938c2ecf20Sopenharmony_ci sb->s_time_max = S64_MAX; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci error = super_setup_bdi(sb); 1968c2ecf20Sopenharmony_ci if (error) 1978c2ecf20Sopenharmony_ci goto error; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* get root fid from Venus: this needs the root inode */ 2008c2ecf20Sopenharmony_ci error = venus_rootfid(sb, &fid); 2018c2ecf20Sopenharmony_ci if ( error ) { 2028c2ecf20Sopenharmony_ci pr_warn("%s: coda_get_rootfid failed with %d\n", 2038c2ecf20Sopenharmony_ci __func__, error); 2048c2ecf20Sopenharmony_ci goto error; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci pr_info("%s: rootfid is %s\n", __func__, coda_f2s(&fid)); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* make root inode */ 2098c2ecf20Sopenharmony_ci root = coda_cnode_make(&fid, sb); 2108c2ecf20Sopenharmony_ci if (IS_ERR(root)) { 2118c2ecf20Sopenharmony_ci error = PTR_ERR(root); 2128c2ecf20Sopenharmony_ci pr_warn("Failure of coda_cnode_make for root: error %d\n", 2138c2ecf20Sopenharmony_ci error); 2148c2ecf20Sopenharmony_ci goto error; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci pr_info("%s: rootinode is %ld dev %s\n", 2188c2ecf20Sopenharmony_ci __func__, root->i_ino, root->i_sb->s_id); 2198c2ecf20Sopenharmony_ci sb->s_root = d_make_root(root); 2208c2ecf20Sopenharmony_ci if (!sb->s_root) { 2218c2ecf20Sopenharmony_ci error = -EINVAL; 2228c2ecf20Sopenharmony_ci goto error; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cierror: 2278c2ecf20Sopenharmony_ci mutex_lock(&vc->vc_mutex); 2288c2ecf20Sopenharmony_ci vc->vc_sb = NULL; 2298c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 2308c2ecf20Sopenharmony_ciunlock_out: 2318c2ecf20Sopenharmony_ci mutex_unlock(&vc->vc_mutex); 2328c2ecf20Sopenharmony_ci return error; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic void coda_put_super(struct super_block *sb) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct venus_comm *vcp = coda_vcp(sb); 2388c2ecf20Sopenharmony_ci mutex_lock(&vcp->vc_mutex); 2398c2ecf20Sopenharmony_ci vcp->vc_sb = NULL; 2408c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 2418c2ecf20Sopenharmony_ci mutex_unlock(&vcp->vc_mutex); 2428c2ecf20Sopenharmony_ci mutex_destroy(&vcp->vc_mutex); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci pr_info("Bye bye.\n"); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void coda_evict_inode(struct inode *inode) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 2508c2ecf20Sopenharmony_ci clear_inode(inode); 2518c2ecf20Sopenharmony_ci coda_cache_clear_inode(inode); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciint coda_getattr(const struct path *path, struct kstat *stat, 2558c2ecf20Sopenharmony_ci u32 request_mask, unsigned int flags) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci int err = coda_revalidate_inode(d_inode(path->dentry)); 2588c2ecf20Sopenharmony_ci if (!err) 2598c2ecf20Sopenharmony_ci generic_fillattr(d_inode(path->dentry), stat); 2608c2ecf20Sopenharmony_ci return err; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ciint coda_setattr(struct dentry *de, struct iattr *iattr) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct inode *inode = d_inode(de); 2668c2ecf20Sopenharmony_ci struct coda_vattr vattr; 2678c2ecf20Sopenharmony_ci int error; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci memset(&vattr, 0, sizeof(vattr)); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 2728c2ecf20Sopenharmony_ci coda_iattr_to_vattr(iattr, &vattr); 2738c2ecf20Sopenharmony_ci vattr.va_type = C_VNON; /* cannot set type */ 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Venus is responsible for truncating the container-file!!! */ 2768c2ecf20Sopenharmony_ci error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!error) { 2798c2ecf20Sopenharmony_ci coda_vattr_to_iattr(inode, &vattr); 2808c2ecf20Sopenharmony_ci coda_cache_clear_inode(inode); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci return error; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ciconst struct inode_operations coda_file_inode_operations = { 2868c2ecf20Sopenharmony_ci .permission = coda_permission, 2878c2ecf20Sopenharmony_ci .getattr = coda_getattr, 2888c2ecf20Sopenharmony_ci .setattr = coda_setattr, 2898c2ecf20Sopenharmony_ci}; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int coda_statfs(struct dentry *dentry, struct kstatfs *buf) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int error; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci error = venus_statfs(dentry, buf); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (error) { 2988c2ecf20Sopenharmony_ci /* fake something like AFS does */ 2998c2ecf20Sopenharmony_ci buf->f_blocks = 9000000; 3008c2ecf20Sopenharmony_ci buf->f_bfree = 9000000; 3018c2ecf20Sopenharmony_ci buf->f_bavail = 9000000; 3028c2ecf20Sopenharmony_ci buf->f_files = 9000000; 3038c2ecf20Sopenharmony_ci buf->f_ffree = 9000000; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* and fill in the rest */ 3078c2ecf20Sopenharmony_ci buf->f_type = CODA_SUPER_MAGIC; 3088c2ecf20Sopenharmony_ci buf->f_bsize = 4096; 3098c2ecf20Sopenharmony_ci buf->f_namelen = CODA_MAXNAMLEN; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/* init_coda: used by filesystems.c to register coda */ 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic struct dentry *coda_mount(struct file_system_type *fs_type, 3178c2ecf20Sopenharmony_ci int flags, const char *dev_name, void *data) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci return mount_nodev(fs_type, flags, data, coda_fill_super); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistruct file_system_type coda_fs_type = { 3238c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3248c2ecf20Sopenharmony_ci .name = "coda", 3258c2ecf20Sopenharmony_ci .mount = coda_mount, 3268c2ecf20Sopenharmony_ci .kill_sb = kill_anon_super, 3278c2ecf20Sopenharmony_ci .fs_flags = FS_BINARY_MOUNTDATA, 3288c2ecf20Sopenharmony_ci}; 3298c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("coda"); 3308c2ecf20Sopenharmony_ci 331