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