xref: /kernel/linux/linux-6.6/fs/sharefs/main.c (revision 62306a36)
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
17struct 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 */
26static 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	 */
119out_pput:
120	path_put(&lower_path);
121out:
122	return err;
123}
124
125struct 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
141static 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
149static int __init init_sharefs_fs(void)
150{
151	int err;
152
153	pr_info("Registering sharefs");
154
155	err = sharefs_init_inode_cache();
156	if (err)
157		goto out_err;
158	err = sharefs_init_dentry_cache();
159	if (err)
160		goto out_err;
161	err = register_filesystem(&sharefs_fs_type);
162	if (err) {
163		sharefs_err("share register failed!");
164		goto out_err;
165	}
166
167	err = sharefs_init_configfs();
168	if (err)
169		goto out_err;
170	return 0;
171out_err:
172	sharefs_exit_configfs();
173	sharefs_destroy_inode_cache();
174	sharefs_destroy_dentry_cache();
175	sharefs_err("sharefs init failed!");
176	return err;
177}
178
179static void __exit exit_sharefs_fs(void)
180{
181	sharefs_destroy_inode_cache();
182	sharefs_destroy_dentry_cache();
183	unregister_filesystem(&sharefs_fs_type);
184	sharefs_exit_configfs();
185	pr_info("Completed sharefs module unload\n");
186}
187
188module_init(init_sharefs_fs);
189module_exit(exit_sharefs_fs);
190
191MODULE_LICENSE("GPL V2");
192MODULE_DESCRIPTION("Share File System");
193MODULE_ALIAS_FS("sharefs");