1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * fs/sharefs/main.c
4 *
5 * Copyright (c) 1998-2022 Erez Zadok
6 * Copyright (c) 2009 Shrikar Archak
7 * Copyright (c) 2003-2022 Stony Brook University
8 * Copyright (c) 2003-2022 The Research Foundation of SUNY
9 * Copyright (c) 2023 Huawei Device Co., Ltd.
10 */
11
12 #include <linux/module.h>
13 #include "sharefs.h"
14 #include "authentication.h"
15
16
17 struct sharefs_mount_priv {
18 const char *dev_name;
19 const char *raw_data;
20 };
21
22 /*
23 * There is no need to lock the sharefs_super_info's rwsem as there is no
24 * way anyone can have a reference to the superblock at this point in time.
25 */
sharefs_fill_super(struct super_block * sb,void * data,int silent)26 static int sharefs_fill_super(struct super_block *sb, void *data, int silent)
27 {
28
29 struct sharefs_mount_priv *priv = (struct sharefs_mount_priv *)data;
30 const char *dev_name = priv->dev_name;
31 const char *raw_data = priv->raw_data;
32
33 int err = 0;
34 struct super_block *lower_sb;
35 struct path lower_path;
36 struct inode *inode;
37
38 /* parse lower path */
39 err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
40 &lower_path);
41 if (err) {
42 printk(KERN_ERR "sharefs: error accessing "
43 "lower directory '%s'\n", dev_name);
44 goto out;
45 }
46
47 /* allocate superblock private data */
48 sb->s_fs_info = kzalloc(sizeof(struct sharefs_sb_info), GFP_KERNEL);
49 if (!SHAREFS_SB(sb)) {
50 printk(KERN_CRIT "sharefs: fill_super: out of memory\n");
51 err = -ENOMEM;
52 goto out_pput;
53 }
54
55 /* set the lower superblock field of upper superblock */
56 lower_sb = lower_path.dentry->d_sb;
57 atomic_inc(&lower_sb->s_active);
58 sharefs_set_lower_super(sb, lower_sb);
59
60 /* inherit maxbytes from lower file system */
61 sb->s_maxbytes = lower_sb->s_maxbytes;
62
63 /*
64 * Our c/m/atime granularity is 1 ns because we may stack on file
65 * systems whose granularity is as good.
66 */
67 sb->s_time_gran = 1;
68
69 sb->s_op = &sharefs_sops;
70
71 /* get a new inode and allocate our root dentry */
72 inode = sharefs_iget(sb, d_inode(lower_path.dentry));
73 if (IS_ERR(inode)) {
74 err = PTR_ERR(inode);
75 goto out_pput;
76 }
77 sharefs_root_inode_perm_init(inode);
78 sb->s_root = d_make_root(inode);
79 if (!sb->s_root) {
80 err = -ENOMEM;
81 goto out_pput;
82 }
83 d_set_d_op(sb->s_root, &sharefs_dops);
84
85 err = sharefs_parse_options(sb->s_fs_info, raw_data);
86 if (err)
87 goto out_pput;
88
89 /* link the upper and lower dentries */
90 sb->s_root->d_fsdata = NULL;
91 err = new_dentry_private_data(sb->s_root);
92 if (err)
93 goto out_pput;
94
95 /* if get here: cannot have error */
96
97 /* set the lower dentries for s_root */
98 sharefs_set_lower_path(sb->s_root, &lower_path);
99
100 /*
101 * No need to call interpose because we already have a positive
102 * dentry, which was instantiated by d_make_root. Just need to
103 * d_rehash it.
104 */
105 d_rehash(sb->s_root);
106 if (!silent)
107 printk(KERN_INFO
108 "sharefs: mounted on top of %s type %s\n",
109 dev_name, lower_sb->s_type->name);
110 goto out; /* all is well */
111
112 /*
113 * path_put is the only resource we need to free if an error occurred
114 * because returning an error from this function will cause
115 * generic_shutdown_super to be called, which will call
116 * sharefs_put_super, and that function will release any other
117 * resources we took.
118 */
119 out_pput:
120 path_put(&lower_path);
121 out:
122 return err;
123 }
124
sharefs_mount(struct file_system_type * fs_type,int flags,const char * dev_name,void * raw_data)125 struct dentry *sharefs_mount(struct file_system_type *fs_type, int flags,
126 const char *dev_name, void *raw_data)
127 {
128 struct sharefs_mount_priv priv = {
129 .dev_name = dev_name,
130 .raw_data = raw_data,
131 };
132
133 /* sharefs needs a valid dev_name to get the lower_sb's metadata */
134 if (!dev_name || !*dev_name)
135 return ERR_PTR(-EINVAL);
136
137 return mount_nodev(fs_type, flags, &priv,
138 sharefs_fill_super);
139 }
140
141 static struct file_system_type sharefs_fs_type = {
142 .owner = THIS_MODULE,
143 .name = SHAREFS_NAME,
144 .mount = sharefs_mount,
145 .kill_sb = generic_shutdown_super,
146 .fs_flags = 0,
147 };
148 MODULE_ALIAS_FS(SHAREFS_NAME);
149
init_sharefs_fs(void)150 static int __init init_sharefs_fs(void)
151 {
152 int err;
153
154 pr_info("Registering sharefs");
155
156 err = sharefs_init_inode_cache();
157 if (err)
158 goto out_err;
159 err = sharefs_init_dentry_cache();
160 if (err)
161 goto out_err;
162 err = register_filesystem(&sharefs_fs_type);
163 if (err) {
164 sharefs_err("share register failed!");
165 goto out_err;
166 }
167
168 err = sharefs_init_configfs();
169 if (err)
170 goto out_err;
171 return 0;
172 out_err:
173 sharefs_exit_configfs();
174 sharefs_destroy_inode_cache();
175 sharefs_destroy_dentry_cache();
176 sharefs_err("sharefs init failed!");
177 return err;
178 }
179
exit_sharefs_fs(void)180 static void __exit exit_sharefs_fs(void)
181 {
182 sharefs_destroy_inode_cache();
183 sharefs_destroy_dentry_cache();
184 unregister_filesystem(&sharefs_fs_type);
185 pr_info("Completed sharefs module unload\n");
186 }
187
188 MODULE_AUTHOR("Jingjing Mao");
189 MODULE_DESCRIPTION("Sharefs");
190 MODULE_LICENSE("GPL");
191
192 module_init(init_sharefs_fs);
193 module_exit(exit_sharefs_fs);
194