xref: /kernel/linux/linux-5.10/fs/sharefs/super.c (revision 8c2ecf20)
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 1998-2022 Erez Zadok
4 * Copyright (c) 2009	   Shrikar Archak
5 * Copyright (c) 2003-2022 Stony Brook University
6 * Copyright (c) 2003-2022 The Research Foundation of SUNY
7 */
8#include <linux/backing-dev-defs.h>
9#include <linux/ratelimit.h>
10#include <linux/slab.h>
11#include <linux/parser.h>
12#include "sharefs.h"
13
14enum {
15	OPT_USER_ID,
16	OPT_OVERRIDE,
17	OPT_OVERRIDE_SUPPORT_DELETE,
18    	OPT_ERR,
19};
20
21static match_table_t sharefs_tokens = {
22	{ OPT_USER_ID, "user_id=%s" },
23	{ OPT_OVERRIDE, "override" },
24	{ OPT_OVERRIDE_SUPPORT_DELETE, "override_support_delete" },
25    	{ OPT_ERR, NULL }
26};
27
28int sharefs_parse_options(struct sharefs_sb_info *sbi, const char *data)
29{
30	char *p = NULL;
31	char *name = NULL;
32	char *options = NULL;
33	char *options_src = NULL;
34	substring_t args[MAX_OPT_ARGS];
35	unsigned int user_id = 0;
36	int err = 0;
37
38	options = kstrdup(data, GFP_KERNEL);
39	if (data && !options) {
40		err = -ENOMEM;
41		goto out;
42	}
43	options_src = options;
44
45	while ((p = strsep(&options_src, ",")) != NULL) {
46		int token;
47
48		if (!*p)
49			continue;
50		args[0].to = args[0].from = NULL;
51		token = match_token(p, sharefs_tokens, args);
52
53		switch (token) {
54		case OPT_USER_ID:
55			name = match_strdup(&args[0]);
56			if (name) {
57				err = kstrtouint(name, 10, &user_id);
58				kfree(name);
59				name = NULL;
60				if (err)
61					goto out;
62				sbi->user_id = user_id;
63			}
64			break;
65		case OPT_OVERRIDE:
66			sbi->override = true;
67			break;
68		case OPT_OVERRIDE_SUPPORT_DELETE:
69			sbi->override_support_delete = true;
70			break;
71		default:
72			err = -EINVAL;
73			goto out;
74		}
75	}
76out:
77	kfree(options);
78
79	return err;
80}
81
82/*
83 * The inode cache is used with alloc_inode for both our inode info and the
84 * vfs inode.
85 */
86static struct kmem_cache *sharefs_inode_cachep;
87
88/* final actions when unmounting a file system */
89static void sharefs_put_super(struct super_block *sb)
90{
91	struct sharefs_sb_info *spd;
92	struct super_block *s;
93
94	spd = SHAREFS_SB(sb);
95	if (!spd)
96		return;
97
98	/* decrement lower super references */
99	s = sharefs_lower_super(sb);
100	sharefs_set_lower_super(sb, NULL);
101	atomic_dec(&s->s_active);
102
103	kfree(spd);
104	sb->s_fs_info = NULL;
105}
106
107static int sharefs_statfs(struct dentry *dentry, struct kstatfs *buf)
108{
109	int err;
110	struct path lower_path;
111
112	sharefs_get_lower_path(dentry, &lower_path);
113	err = vfs_statfs(&lower_path, buf);
114	sharefs_put_lower_path(dentry, &lower_path);
115
116	/* set return buf to our f/s to avoid confusing user-level utils */
117	buf->f_type = SHAREFS_SUPER_MAGIC;
118
119	return err;
120}
121
122/*
123 * Called by iput() when the inode reference count reached zero
124 * and the inode is not hashed anywhere.  Used to clear anything
125 * that needs to be, before the inode is completely destroyed and put
126 * on the inode free list.
127 */
128static void sharefs_evict_inode(struct inode *inode)
129{
130	struct inode *lower_inode;
131
132	truncate_inode_pages(&inode->i_data, 0);
133	clear_inode(inode);
134	/*
135	 * Decrement a reference to a lower_inode, which was incremented
136	 * by our read_inode when it was created initially.
137	 */
138	lower_inode = sharefs_lower_inode(inode);
139	sharefs_set_lower_inode(inode, NULL);
140	iput(lower_inode);
141}
142
143void __sharefs_log(const char *level, const bool ratelimited,
144		 const char *function, const char *fmt, ...)
145{
146	struct va_format vaf;
147	va_list args;
148
149	va_start(args, fmt);
150	vaf.fmt = fmt;
151	vaf.va = &args;
152	if (ratelimited)
153		printk_ratelimited("%s sharefs: %s() %pV\n", level,
154				   function, &vaf);
155	else
156		printk("%s sharefs: %s() %pV\n", level, function, &vaf);
157	va_end(args);
158}
159
160static struct inode *sharefs_alloc_inode(struct super_block *sb)
161{
162	struct sharefs_inode_info *i;
163
164	i = kmem_cache_alloc(sharefs_inode_cachep, GFP_KERNEL);
165	if (!i)
166		return NULL;
167
168	/* memset everything up to the inode to 0 */
169	memset(i, 0, offsetof(struct sharefs_inode_info, vfs_inode));
170
171	atomic64_set(&i->vfs_inode.i_version, 1);
172	return &i->vfs_inode;
173}
174
175static void sharefs_destroy_inode(struct inode *inode)
176{
177	kmem_cache_free(sharefs_inode_cachep, SHAREFS_I(inode));
178}
179
180/* sharefs inode cache constructor */
181static void init_once(void *obj)
182{
183	struct sharefs_inode_info *i = obj;
184
185	inode_init_once(&i->vfs_inode);
186}
187
188int sharefs_init_inode_cache(void)
189{
190	int err = 0;
191
192	sharefs_inode_cachep =
193		kmem_cache_create("sharefs_inode_cache",
194				  sizeof(struct sharefs_inode_info), 0,
195				  SLAB_RECLAIM_ACCOUNT, init_once);
196	if (!sharefs_inode_cachep)
197		err = -ENOMEM;
198	return err;
199}
200
201/* sharefs inode cache destructor */
202void sharefs_destroy_inode_cache(void)
203{
204	if (sharefs_inode_cachep)
205		kmem_cache_destroy(sharefs_inode_cachep);
206}
207
208const struct super_operations sharefs_sops = {
209	.put_super	= sharefs_put_super,
210	.statfs		= sharefs_statfs,
211	.evict_inode	= sharefs_evict_inode,
212	.alloc_inode	= sharefs_alloc_inode,
213	.destroy_inode	= sharefs_destroy_inode,
214};
215