10b1e987cSChristoph Hellwig // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Copyright (c) 2000-2001 Christoph Hellwig. 41cce1701SKrzysztof Błaszkowski * Copyright (c) 2016 Krzysztof Blaszkowski 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds /* 81da177e4SLinus Torvalds * Veritas filesystem driver - superblock related routines. 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds #include <linux/init.h> 111da177e4SLinus Torvalds #include <linux/module.h> 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds #include <linux/blkdev.h> 141da177e4SLinus Torvalds #include <linux/fs.h> 151da177e4SLinus Torvalds #include <linux/buffer_head.h> 161da177e4SLinus Torvalds #include <linux/kernel.h> 171da177e4SLinus Torvalds #include <linux/slab.h> 181da177e4SLinus Torvalds #include <linux/stat.h> 191da177e4SLinus Torvalds #include <linux/vfs.h> 20726c3342SDavid Howells #include <linux/mount.h> 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include "vxfs.h" 231da177e4SLinus Torvalds #include "vxfs_extern.h" 241da177e4SLinus Torvalds #include "vxfs_dir.h" 251da177e4SLinus Torvalds #include "vxfs_inode.h" 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds 281cce1701SKrzysztof Błaszkowski MODULE_AUTHOR("Christoph Hellwig, Krzysztof Blaszkowski"); 291da177e4SLinus Torvalds MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver"); 301da177e4SLinus Torvalds MODULE_LICENSE("Dual BSD/GPL"); 311da177e4SLinus Torvalds 322f137e31SChristoph Hellwig static struct kmem_cache *vxfs_inode_cachep; 332f137e31SChristoph Hellwig 341da177e4SLinus Torvalds /** 351da177e4SLinus Torvalds * vxfs_put_super - free superblock resources 361da177e4SLinus Torvalds * @sbp: VFS superblock. 371da177e4SLinus Torvalds * 381da177e4SLinus Torvalds * Description: 391da177e4SLinus Torvalds * vxfs_put_super frees all resources allocated for @sbp 401da177e4SLinus Torvalds * after the last instance of the filesystem is unmounted. 411da177e4SLinus Torvalds */ 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds static void 441da177e4SLinus Torvalds vxfs_put_super(struct super_block *sbp) 451da177e4SLinus Torvalds { 461da177e4SLinus Torvalds struct vxfs_sb_info *infp = VXFS_SBI(sbp); 471da177e4SLinus Torvalds 480e481d3cSKrzysztof Błaszkowski iput(infp->vsi_fship); 490e481d3cSKrzysztof Błaszkowski iput(infp->vsi_ilist); 500e481d3cSKrzysztof Błaszkowski iput(infp->vsi_stilist); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds brelse(infp->vsi_bp); 531da177e4SLinus Torvalds kfree(infp); 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /** 571da177e4SLinus Torvalds * vxfs_statfs - get filesystem information 58726c3342SDavid Howells * @dentry: VFS dentry to locate superblock 591da177e4SLinus Torvalds * @bufp: output buffer 601da177e4SLinus Torvalds * 611da177e4SLinus Torvalds * Description: 621da177e4SLinus Torvalds * vxfs_statfs fills the statfs buffer @bufp with information 63726c3342SDavid Howells * about the filesystem described by @dentry. 641da177e4SLinus Torvalds * 651da177e4SLinus Torvalds * Returns: 661da177e4SLinus Torvalds * Zero. 671da177e4SLinus Torvalds * 681da177e4SLinus Torvalds * Locking: 691da177e4SLinus Torvalds * No locks held. 701da177e4SLinus Torvalds * 711da177e4SLinus Torvalds * Notes: 721da177e4SLinus Torvalds * This is everything but complete... 731da177e4SLinus Torvalds */ 741da177e4SLinus Torvalds static int 75726c3342SDavid Howells vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp) 761da177e4SLinus Torvalds { 77726c3342SDavid Howells struct vxfs_sb_info *infp = VXFS_SBI(dentry->d_sb); 780d83f7fcSKrzysztof Błaszkowski struct vxfs_sb *raw_sb = infp->vsi_raw; 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds bufp->f_type = VXFS_SUPER_MAGIC; 81726c3342SDavid Howells bufp->f_bsize = dentry->d_sb->s_blocksize; 820d83f7fcSKrzysztof Błaszkowski bufp->f_blocks = fs32_to_cpu(infp, raw_sb->vs_dsize); 830d83f7fcSKrzysztof Błaszkowski bufp->f_bfree = fs32_to_cpu(infp, raw_sb->vs_free); 841da177e4SLinus Torvalds bufp->f_bavail = 0; 851da177e4SLinus Torvalds bufp->f_files = 0; 860d83f7fcSKrzysztof Błaszkowski bufp->f_ffree = fs32_to_cpu(infp, raw_sb->vs_ifree); 871da177e4SLinus Torvalds bufp->f_namelen = VXFS_NAMELEN; 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds return 0; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds static int vxfs_remount(struct super_block *sb, int *flags, char *data) 931da177e4SLinus Torvalds { 9402b9984dSTheodore Ts'o sync_filesystem(sb); 951751e8a6SLinus Torvalds *flags |= SB_RDONLY; 961da177e4SLinus Torvalds return 0; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 992f137e31SChristoph Hellwig static struct inode *vxfs_alloc_inode(struct super_block *sb) 1002f137e31SChristoph Hellwig { 1012f137e31SChristoph Hellwig struct vxfs_inode_info *vi; 1022f137e31SChristoph Hellwig 103fd60b288SMuchun Song vi = alloc_inode_sb(sb, vxfs_inode_cachep, GFP_KERNEL); 1042f137e31SChristoph Hellwig if (!vi) 1052f137e31SChristoph Hellwig return NULL; 106f2fe2fa1SKrzysztof Błaszkowski inode_init_once(&vi->vfs_inode); 1072f137e31SChristoph Hellwig return &vi->vfs_inode; 1082f137e31SChristoph Hellwig } 1092f137e31SChristoph Hellwig 1109f179271SAl Viro static void vxfs_free_inode(struct inode *inode) 1112f137e31SChristoph Hellwig { 1122f137e31SChristoph Hellwig kmem_cache_free(vxfs_inode_cachep, VXFS_INO(inode)); 1132f137e31SChristoph Hellwig } 1142f137e31SChristoph Hellwig 115f2bf2c70SChristoph Hellwig static const struct super_operations vxfs_super_ops = { 1162f137e31SChristoph Hellwig .alloc_inode = vxfs_alloc_inode, 1179f179271SAl Viro .free_inode = vxfs_free_inode, 118f2bf2c70SChristoph Hellwig .evict_inode = vxfs_evict_inode, 119f2bf2c70SChristoph Hellwig .put_super = vxfs_put_super, 120f2bf2c70SChristoph Hellwig .statfs = vxfs_statfs, 121f2bf2c70SChristoph Hellwig .remount_fs = vxfs_remount, 122f2bf2c70SChristoph Hellwig }; 1230d83f7fcSKrzysztof Błaszkowski 1240d83f7fcSKrzysztof Błaszkowski static int vxfs_try_sb_magic(struct super_block *sbp, int silent, 1250d83f7fcSKrzysztof Błaszkowski unsigned blk, __fs32 magic) 1260d83f7fcSKrzysztof Błaszkowski { 1270d83f7fcSKrzysztof Błaszkowski struct buffer_head *bp; 1280d83f7fcSKrzysztof Błaszkowski struct vxfs_sb *rsbp; 1290d83f7fcSKrzysztof Błaszkowski struct vxfs_sb_info *infp = VXFS_SBI(sbp); 1300d83f7fcSKrzysztof Błaszkowski int rc = -ENOMEM; 1310d83f7fcSKrzysztof Błaszkowski 1320d83f7fcSKrzysztof Błaszkowski bp = sb_bread(sbp, blk); 1330d83f7fcSKrzysztof Błaszkowski do { 1340d83f7fcSKrzysztof Błaszkowski if (!bp || !buffer_mapped(bp)) { 1350d83f7fcSKrzysztof Błaszkowski if (!silent) { 1360d83f7fcSKrzysztof Błaszkowski printk(KERN_WARNING 1370d83f7fcSKrzysztof Błaszkowski "vxfs: unable to read disk superblock at %u\n", 1380d83f7fcSKrzysztof Błaszkowski blk); 1390d83f7fcSKrzysztof Błaszkowski } 1400d83f7fcSKrzysztof Błaszkowski break; 1410d83f7fcSKrzysztof Błaszkowski } 1420d83f7fcSKrzysztof Błaszkowski 1430d83f7fcSKrzysztof Błaszkowski rc = -EINVAL; 1440d83f7fcSKrzysztof Błaszkowski rsbp = (struct vxfs_sb *)bp->b_data; 1450d83f7fcSKrzysztof Błaszkowski if (rsbp->vs_magic != magic) { 1460d83f7fcSKrzysztof Błaszkowski if (!silent) 1470d83f7fcSKrzysztof Błaszkowski printk(KERN_NOTICE 1480d83f7fcSKrzysztof Błaszkowski "vxfs: WRONG superblock magic %08x at %u\n", 1490d83f7fcSKrzysztof Błaszkowski rsbp->vs_magic, blk); 1500d83f7fcSKrzysztof Błaszkowski break; 1510d83f7fcSKrzysztof Błaszkowski } 1520d83f7fcSKrzysztof Błaszkowski 1530d83f7fcSKrzysztof Błaszkowski rc = 0; 1540d83f7fcSKrzysztof Błaszkowski infp->vsi_raw = rsbp; 1550d83f7fcSKrzysztof Błaszkowski infp->vsi_bp = bp; 1560d83f7fcSKrzysztof Błaszkowski } while (0); 1570d83f7fcSKrzysztof Błaszkowski 1580d83f7fcSKrzysztof Błaszkowski if (rc) { 1590d83f7fcSKrzysztof Błaszkowski infp->vsi_raw = NULL; 1600d83f7fcSKrzysztof Błaszkowski infp->vsi_bp = NULL; 1610d83f7fcSKrzysztof Błaszkowski brelse(bp); 1620d83f7fcSKrzysztof Błaszkowski } 1630d83f7fcSKrzysztof Błaszkowski 1640d83f7fcSKrzysztof Błaszkowski return rc; 1650d83f7fcSKrzysztof Błaszkowski } 1660d83f7fcSKrzysztof Błaszkowski 1671da177e4SLinus Torvalds /** 168*d3fcf834SRandy Dunlap * vxfs_fill_super - read superblock into memory and initialize filesystem 1691da177e4SLinus Torvalds * @sbp: VFS superblock (to fill) 1701da177e4SLinus Torvalds * @dp: fs private mount data 1711da177e4SLinus Torvalds * @silent: do not complain loudly when sth is wrong 1721da177e4SLinus Torvalds * 1731da177e4SLinus Torvalds * Description: 1741da177e4SLinus Torvalds * We are called on the first mount of a filesystem to read the 1751da177e4SLinus Torvalds * superblock into memory and do some basic setup. 1761da177e4SLinus Torvalds * 1771da177e4SLinus Torvalds * Returns: 1781da177e4SLinus Torvalds * The superblock on success, else %NULL. 1791da177e4SLinus Torvalds * 1801da177e4SLinus Torvalds * Locking: 181db719222SJan Blunck * We are under @sbp->s_lock. 1821da177e4SLinus Torvalds */ 1831da177e4SLinus Torvalds static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds struct vxfs_sb_info *infp; 1861da177e4SLinus Torvalds struct vxfs_sb *rsbp; 1871da177e4SLinus Torvalds u_long bsize; 1881da177e4SLinus Torvalds struct inode *root; 189d0b07948SDavid Howells int ret = -EINVAL; 1900d83f7fcSKrzysztof Błaszkowski u32 j; 1911da177e4SLinus Torvalds 1921751e8a6SLinus Torvalds sbp->s_flags |= SB_RDONLY; 1931da177e4SLinus Torvalds 194e915fc49SPekka Enberg infp = kzalloc(sizeof(*infp), GFP_KERNEL); 1951da177e4SLinus Torvalds if (!infp) { 1961da177e4SLinus Torvalds printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n"); 1971da177e4SLinus Torvalds return -ENOMEM; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds bsize = sb_min_blocksize(sbp, BLOCK_SIZE); 2011da177e4SLinus Torvalds if (!bsize) { 2021da177e4SLinus Torvalds printk(KERN_WARNING "vxfs: unable to set blocksize\n"); 2031da177e4SLinus Torvalds goto out; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 2062f137e31SChristoph Hellwig sbp->s_op = &vxfs_super_ops; 2070d83f7fcSKrzysztof Błaszkowski sbp->s_fs_info = infp; 20822b13969SDeepa Dinamani sbp->s_time_min = 0; 20922b13969SDeepa Dinamani sbp->s_time_max = U32_MAX; 2101da177e4SLinus Torvalds 2110d83f7fcSKrzysztof Błaszkowski if (!vxfs_try_sb_magic(sbp, silent, 1, 2120d83f7fcSKrzysztof Błaszkowski (__force __fs32)cpu_to_le32(VXFS_SUPER_MAGIC))) { 2130d83f7fcSKrzysztof Błaszkowski /* Unixware, x86 */ 2140d83f7fcSKrzysztof Błaszkowski infp->byte_order = VXFS_BO_LE; 2150d83f7fcSKrzysztof Błaszkowski } else if (!vxfs_try_sb_magic(sbp, silent, 8, 2160d83f7fcSKrzysztof Błaszkowski (__force __fs32)cpu_to_be32(VXFS_SUPER_MAGIC))) { 2170d83f7fcSKrzysztof Błaszkowski /* HP-UX, parisc */ 2180d83f7fcSKrzysztof Błaszkowski infp->byte_order = VXFS_BO_BE; 2190d83f7fcSKrzysztof Błaszkowski } else { 2201da177e4SLinus Torvalds if (!silent) 2210d83f7fcSKrzysztof Błaszkowski printk(KERN_NOTICE "vxfs: can't find superblock.\n"); 2221da177e4SLinus Torvalds goto out; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2250d83f7fcSKrzysztof Błaszkowski rsbp = infp->vsi_raw; 2260d83f7fcSKrzysztof Błaszkowski j = fs32_to_cpu(infp, rsbp->vs_version); 2270d83f7fcSKrzysztof Błaszkowski if ((j < 2 || j > 4) && !silent) { 2280d83f7fcSKrzysztof Błaszkowski printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", j); 2291da177e4SLinus Torvalds goto out; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds #ifdef DIAGNOSTIC 2330d83f7fcSKrzysztof Błaszkowski printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", j); 2340d83f7fcSKrzysztof Błaszkowski printk(KERN_DEBUG "vxfs: blocksize: %d\n", 2350d83f7fcSKrzysztof Błaszkowski fs32_to_cpu(infp, rsbp->vs_bsize)); 2361da177e4SLinus Torvalds #endif 2371da177e4SLinus Torvalds 2380d83f7fcSKrzysztof Błaszkowski sbp->s_magic = fs32_to_cpu(infp, rsbp->vs_magic); 2391da177e4SLinus Torvalds 2400d83f7fcSKrzysztof Błaszkowski infp->vsi_oltext = fs32_to_cpu(infp, rsbp->vs_oltext[0]); 2410d83f7fcSKrzysztof Błaszkowski infp->vsi_oltsize = fs32_to_cpu(infp, rsbp->vs_oltsize); 2421da177e4SLinus Torvalds 2430d83f7fcSKrzysztof Błaszkowski j = fs32_to_cpu(infp, rsbp->vs_bsize); 2440d83f7fcSKrzysztof Błaszkowski if (!sb_set_blocksize(sbp, j)) { 2451da177e4SLinus Torvalds printk(KERN_WARNING "vxfs: unable to set final block size\n"); 2461da177e4SLinus Torvalds goto out; 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds if (vxfs_read_olt(sbp, bsize)) { 2501da177e4SLinus Torvalds printk(KERN_WARNING "vxfs: unable to read olt\n"); 2511da177e4SLinus Torvalds goto out; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds if (vxfs_read_fshead(sbp)) { 2551da177e4SLinus Torvalds printk(KERN_WARNING "vxfs: unable to read fshead\n"); 2561da177e4SLinus Torvalds goto out; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 259d0b07948SDavid Howells root = vxfs_iget(sbp, VXFS_ROOT_INO); 260d0b07948SDavid Howells if (IS_ERR(root)) { 261d0b07948SDavid Howells ret = PTR_ERR(root); 262d0b07948SDavid Howells goto out; 263d0b07948SDavid Howells } 26448fde701SAl Viro sbp->s_root = d_make_root(root); 2651da177e4SLinus Torvalds if (!sbp->s_root) { 2661da177e4SLinus Torvalds printk(KERN_WARNING "vxfs: unable to get root dentry.\n"); 2671da177e4SLinus Torvalds goto out_free_ilist; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds return 0; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds out_free_ilist: 2730e481d3cSKrzysztof Błaszkowski iput(infp->vsi_fship); 2740e481d3cSKrzysztof Błaszkowski iput(infp->vsi_ilist); 2750e481d3cSKrzysztof Błaszkowski iput(infp->vsi_stilist); 2761da177e4SLinus Torvalds out: 2770d83f7fcSKrzysztof Błaszkowski brelse(infp->vsi_bp); 2781da177e4SLinus Torvalds kfree(infp); 279d0b07948SDavid Howells return ret; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds /* 2831da177e4SLinus Torvalds * The usual module blurb. 2841da177e4SLinus Torvalds */ 285152a0836SAl Viro static struct dentry *vxfs_mount(struct file_system_type *fs_type, 286152a0836SAl Viro int flags, const char *dev_name, void *data) 2871da177e4SLinus Torvalds { 288152a0836SAl Viro return mount_bdev(fs_type, flags, dev_name, data, vxfs_fill_super); 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds static struct file_system_type vxfs_fs_type = { 2921da177e4SLinus Torvalds .owner = THIS_MODULE, 2931da177e4SLinus Torvalds .name = "vxfs", 294152a0836SAl Viro .mount = vxfs_mount, 2951da177e4SLinus Torvalds .kill_sb = kill_block_super, 2961da177e4SLinus Torvalds .fs_flags = FS_REQUIRES_DEV, 2971da177e4SLinus Torvalds }; 2987f78e035SEric W. Biederman MODULE_ALIAS_FS("vxfs"); /* makes mount -t vxfs autoload the module */ 299fa7614ddSEric W. Biederman MODULE_ALIAS("vxfs"); 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds static int __init 3021da177e4SLinus Torvalds vxfs_init(void) 3031da177e4SLinus Torvalds { 304a4376e13SAlexey Dobriyan int rv; 305a4376e13SAlexey Dobriyan 306e9a0561bSDavid Windsor vxfs_inode_cachep = kmem_cache_create_usercopy("vxfs_inode", 3071da177e4SLinus Torvalds sizeof(struct vxfs_inode_info), 0, 308e9a0561bSDavid Windsor SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, 309e9a0561bSDavid Windsor offsetof(struct vxfs_inode_info, vii_immed.vi_immed), 310e9a0561bSDavid Windsor sizeof_field(struct vxfs_inode_info, 311e9a0561bSDavid Windsor vii_immed.vi_immed), 312e9a0561bSDavid Windsor NULL); 313a4376e13SAlexey Dobriyan if (!vxfs_inode_cachep) 3141da177e4SLinus Torvalds return -ENOMEM; 315a4376e13SAlexey Dobriyan rv = register_filesystem(&vxfs_fs_type); 316a4376e13SAlexey Dobriyan if (rv < 0) 317a4376e13SAlexey Dobriyan kmem_cache_destroy(vxfs_inode_cachep); 318a4376e13SAlexey Dobriyan return rv; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds static void __exit 3221da177e4SLinus Torvalds vxfs_cleanup(void) 3231da177e4SLinus Torvalds { 3241da177e4SLinus Torvalds unregister_filesystem(&vxfs_fs_type); 3258c0a8537SKirill A. Shutemov /* 3268c0a8537SKirill A. Shutemov * Make sure all delayed rcu free inodes are flushed before we 3278c0a8537SKirill A. Shutemov * destroy cache. 3288c0a8537SKirill A. Shutemov */ 3298c0a8537SKirill A. Shutemov rcu_barrier(); 3301da177e4SLinus Torvalds kmem_cache_destroy(vxfs_inode_cachep); 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds module_init(vxfs_init); 3341da177e4SLinus Torvalds module_exit(vxfs_cleanup); 335