xref: /kernel/linux/linux-6.6/fs/epfs/super.c (revision 62306a36)
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