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
epfs_alloc_inode(struct super_block * sb)17 static 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
epfs_free_inode(struct inode * inode)29 static 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)
i_callback(struct rcu_head * head)38 static 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
epfs_destroy_inode(struct inode * inode)47 static 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
epfs_evict_inode(struct inode * inode)61 static 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
epfs_statfs(struct dentry * dentry,struct kstatfs * buf)74 static int epfs_statfs(struct dentry *dentry, struct kstatfs *buf)
75 {
76 buf->f_type = EPFS_SUPER_MAGIC;
77 return 0;
78 }
79 struct 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
epfs_fill_super(struct super_block * s,void * data,int silent)89 static 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
epfs_mount(struct file_system_type * fs_type,int flags,const char * dev_name,void * raw_data)111 struct 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
epfs_kill_sb(struct super_block * sb)117 void epfs_kill_sb(struct super_block *sb)
118 {
119 kill_anon_super(sb);
120 }
121
122 struct 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