1// SPDX-License-Identifier: GPL-2.0 2/* 3 * fs/epfs/super.c 4 * 5 * Copyright (c) 2022 Huawei Technologies Co., Ltd. 6 * Author: weilongping@huawei.com 7 * Create: 2022-06-10 8 */ 9#include <linux/file.h> 10#include <linux/fs.h> 11#include <linux/slab.h> 12#include <linux/statfs.h> 13#include <linux/version.h> 14 15#include "internal.h" 16 17static struct inode *epfs_alloc_inode(struct super_block *sb) 18{ 19 struct epfs_inode_info *info = 20 kmem_cache_zalloc(epfs_inode_cachep, GFP_KERNEL); 21 if (IS_ENABLED(CONFIG_EPFS_DEBUG)) 22 epfs_debug("inode info: %p", info); 23 inode_init_once(&info->vfs_inode); 24 mutex_init(&info->lock); 25 return &info->vfs_inode; 26} 27 28// Free epfs_inode_info 29static void epfs_free_inode(struct inode *inode) 30{ 31 if (IS_ENABLED(CONFIG_EPFS_DEBUG)) 32 epfs_debug("free_inode: %p", inode); 33 kmem_cache_free(epfs_inode_cachep, 34 epfs_inode_to_private(inode)); 35} 36 37#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) 38static void i_callback(struct rcu_head *head) 39{ 40 struct inode *inode = container_of(head, struct inode, i_rcu); 41 42 epfs_free_inode(inode); 43} 44#endif 45 46// Destroy epfs_range 47static void epfs_destroy_inode(struct inode *inode) 48{ 49 struct epfs_inode_info *info = epfs_inode_to_private(inode); 50 51 mutex_lock(&info->lock); 52 kfree(info->range); 53 info->range = NULL; 54 mutex_unlock(&info->lock); 55#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) 56 call_rcu(&inode->i_rcu, i_callback); 57#endif 58} 59 60// Clear vfs_inode 61static void epfs_evict_inode(struct inode *inode) 62{ 63 struct epfs_inode_info *info = epfs_inode_to_private(inode); 64 65 clear_inode(inode); 66 mutex_lock(&info->lock); 67 if (info->origin_file) { 68 fput(info->origin_file); 69 info->origin_file = NULL; 70 } 71 mutex_unlock(&info->lock); 72} 73 74static int epfs_statfs(struct dentry *dentry, struct kstatfs *buf) 75{ 76 buf->f_type = EPFS_SUPER_MAGIC; 77 return 0; 78} 79struct super_operations epfs_sops = { 80 .alloc_inode = epfs_alloc_inode, 81 .destroy_inode = epfs_destroy_inode, 82#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) 83 .free_inode = epfs_free_inode, 84#endif 85 .evict_inode = epfs_evict_inode, 86 .statfs = epfs_statfs, 87}; 88 89static int epfs_fill_super(struct super_block *s, void *data, int silent) 90{ 91 struct inode *inode; 92 93 s->s_op = &epfs_sops; 94 s->s_d_op = &epfs_dops; 95 s->s_magic = EPFS_SUPER_MAGIC; 96 inode = epfs_iget(s, true /* dir */); 97 if (!inode) { 98 epfs_err("Failed to get root inode!"); 99 return -ENOMEM; 100 } 101 102 s->s_root = d_make_root(inode); 103 if (!s->s_root) { 104 epfs_err("Failed to make root inode"); 105 return -ENOMEM; 106 } 107 108 return 0; 109} 110 111struct dentry *epfs_mount(struct file_system_type *fs_type, int flags, 112 const char *dev_name, void *raw_data) 113{ 114 return mount_nodev(fs_type, flags, raw_data, epfs_fill_super); 115} 116 117void epfs_kill_sb(struct super_block *sb) 118{ 119 kill_anon_super(sb); 120} 121 122struct file_system_type epfs_fs_type = { 123 .owner = THIS_MODULE, 124 .name = "epfs", 125 .mount = epfs_mount, 126 .kill_sb = epfs_kill_sb, 127}; 128