xref: /linux/fs/9p/vfs_super.c (revision bbbf7f32843b5788786cd8d91e9430823c2777c9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *
4  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
5  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
6  */
7 
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/errno.h>
11 #include <linux/fs.h>
12 #include <linux/file.h>
13 #include <linux/stat.h>
14 #include <linux/string.h>
15 #include <linux/pagemap.h>
16 #include <linux/mount.h>
17 #include <linux/sched.h>
18 #include <linux/slab.h>
19 #include <linux/statfs.h>
20 #include <linux/magic.h>
21 #include <linux/fscache.h>
22 #include <linux/fs_context.h>
23 #include <net/9p/9p.h>
24 #include <net/9p/client.h>
25 
26 #include "v9fs.h"
27 #include "v9fs_vfs.h"
28 #include "fid.h"
29 #include "xattr.h"
30 #include "acl.h"
31 
32 static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
33 
v9fs_fill_super(struct super_block * sb)34 static int v9fs_fill_super(struct super_block *sb)
35 {
36 	int ret;
37 	struct v9fs_session_info *v9ses = v9ses = sb->s_fs_info;
38 
39 	sb->s_maxbytes = MAX_LFS_FILESIZE;
40 	sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
41 	sb->s_blocksize = 1 << sb->s_blocksize_bits;
42 	sb->s_magic = V9FS_MAGIC;
43 	if (v9fs_proto_dotl(v9ses)) {
44 		sb->s_op = &v9fs_super_ops_dotl;
45 		if (!(v9ses->flags & V9FS_NO_XATTR))
46 			sb->s_xattr = v9fs_xattr_handlers;
47 	} else {
48 		sb->s_op = &v9fs_super_ops;
49 		sb->s_time_max = U32_MAX;
50 	}
51 
52 	sb->s_time_min = 0;
53 
54 	ret = super_setup_bdi(sb);
55 	if (ret)
56 		return ret;
57 
58 	if (!v9ses->cache) {
59 		sb->s_bdi->ra_pages = 0;
60 		sb->s_bdi->io_pages = 0;
61 	} else {
62 		sb->s_bdi->ra_pages = v9ses->maxdata >> PAGE_SHIFT;
63 		sb->s_bdi->io_pages = v9ses->maxdata >> PAGE_SHIFT;
64 	}
65 
66 	sb->s_flags |= SB_ACTIVE;
67 
68 #ifdef CONFIG_9P_FS_POSIX_ACL
69 	if ((v9ses->flags & V9FS_ACL_MASK) == V9FS_POSIX_ACL)
70 		sb->s_flags |= SB_POSIXACL;
71 #endif
72 
73 	return 0;
74 }
75 
76 /**
77  * v9fs_get_tree - create the mountable root and superblock
78  * @fc: the filesystem context
79  *
80  */
81 
v9fs_get_tree(struct fs_context * fc)82 static int v9fs_get_tree(struct fs_context *fc)
83 {
84 	struct super_block *sb = NULL;
85 	struct inode *inode = NULL;
86 	struct dentry *root = NULL;
87 	struct v9fs_session_info *v9ses = NULL;
88 	struct p9_fid *fid;
89 	int retval = 0;
90 
91 	p9_debug(P9_DEBUG_VFS, "\n");
92 
93 	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
94 	if (!v9ses)
95 		return -ENOMEM;
96 
97 	fid = v9fs_session_init(v9ses, fc);
98 	if (IS_ERR(fid)) {
99 		retval = PTR_ERR(fid);
100 		goto free_session;
101 	}
102 
103 	fc->s_fs_info = v9ses;
104 	sb = sget_fc(fc, NULL, set_anon_super_fc);
105 	if (IS_ERR(sb)) {
106 		retval = PTR_ERR(sb);
107 		goto clunk_fid;
108 	}
109 	retval = v9fs_fill_super(sb);
110 	if (retval)
111 		goto release_sb;
112 
113 	if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {
114 		set_default_d_op(sb, &v9fs_cached_dentry_operations);
115 	} else {
116 		set_default_d_op(sb, &v9fs_dentry_operations);
117 		sb->s_d_flags |= DCACHE_DONTCACHE;
118 	}
119 
120 	inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb);
121 	if (IS_ERR(inode)) {
122 		retval = PTR_ERR(inode);
123 		goto release_sb;
124 	}
125 
126 	root = d_make_root(inode);
127 	if (!root) {
128 		retval = -ENOMEM;
129 		goto release_sb;
130 	}
131 	sb->s_root = root;
132 	retval = v9fs_get_acl(inode, fid);
133 	if (retval)
134 		goto release_sb;
135 	v9fs_fid_add(root, &fid);
136 
137 	p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n");
138 	fc->root = dget(sb->s_root);
139 	return 0;
140 
141 clunk_fid:
142 	p9_fid_put(fid);
143 	v9fs_session_close(v9ses);
144 free_session:
145 	kfree(v9ses);
146 	return retval;
147 
148 release_sb:
149 	/*
150 	 * we will do the session_close and root dentry release
151 	 * in the below call. But we need to clunk fid, because we haven't
152 	 * attached the fid to dentry so it won't get clunked
153 	 * automatically.
154 	 */
155 	p9_fid_put(fid);
156 	deactivate_locked_super(sb);
157 	return retval;
158 }
159 
160 /**
161  * v9fs_kill_super - Kill Superblock
162  * @s: superblock
163  *
164  */
165 
v9fs_kill_super(struct super_block * s)166 static void v9fs_kill_super(struct super_block *s)
167 {
168 	struct v9fs_session_info *v9ses = s->s_fs_info;
169 
170 	p9_debug(P9_DEBUG_VFS, " %p\n", s);
171 
172 	kill_anon_super(s);
173 
174 	v9fs_session_cancel(v9ses);
175 	v9fs_session_close(v9ses);
176 	kfree(v9ses);
177 	s->s_fs_info = NULL;
178 	p9_debug(P9_DEBUG_VFS, "exiting kill_super\n");
179 }
180 
181 static void
v9fs_umount_begin(struct super_block * sb)182 v9fs_umount_begin(struct super_block *sb)
183 {
184 	struct v9fs_session_info *v9ses;
185 
186 	v9ses = sb->s_fs_info;
187 	v9fs_session_begin_cancel(v9ses);
188 }
189 
v9fs_statfs(struct dentry * dentry,struct kstatfs * buf)190 static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
191 {
192 	struct v9fs_session_info *v9ses;
193 	struct p9_fid *fid;
194 	struct p9_rstatfs rs;
195 	int res;
196 
197 	fid = v9fs_fid_lookup(dentry);
198 	if (IS_ERR(fid)) {
199 		res = PTR_ERR(fid);
200 		goto done;
201 	}
202 
203 	v9ses = v9fs_dentry2v9ses(dentry);
204 	if (v9fs_proto_dotl(v9ses)) {
205 		res = p9_client_statfs(fid, &rs);
206 		if (res == 0) {
207 			buf->f_type = rs.type;
208 			buf->f_bsize = rs.bsize;
209 			buf->f_blocks = rs.blocks;
210 			buf->f_bfree = rs.bfree;
211 			buf->f_bavail = rs.bavail;
212 			buf->f_files = rs.files;
213 			buf->f_ffree = rs.ffree;
214 			buf->f_fsid = u64_to_fsid(rs.fsid);
215 			buf->f_namelen = rs.namelen;
216 		}
217 		if (res != -ENOSYS)
218 			goto done;
219 	}
220 	res = simple_statfs(dentry, buf);
221 done:
222 	p9_fid_put(fid);
223 	return res;
224 }
225 
v9fs_drop_inode(struct inode * inode)226 static int v9fs_drop_inode(struct inode *inode)
227 {
228 	struct v9fs_session_info *v9ses;
229 
230 	v9ses = v9fs_inode2v9ses(inode);
231 	if (v9ses->cache & (CACHE_META|CACHE_LOOSE))
232 		return inode_generic_drop(inode);
233 	/*
234 	 * in case of non cached mode always drop the
235 	 * inode because we want the inode attribute
236 	 * to always match that on the server.
237 	 */
238 	return 1;
239 }
240 
v9fs_write_inode(struct inode * inode,struct writeback_control * wbc)241 static int v9fs_write_inode(struct inode *inode,
242 			    struct writeback_control *wbc)
243 {
244 	/*
245 	 * send an fsync request to server irrespective of
246 	 * wbc->sync_mode.
247 	 */
248 	p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
249 	return netfs_unpin_writeback(inode, wbc);
250 }
251 
v9fs_write_inode_dotl(struct inode * inode,struct writeback_control * wbc)252 static int v9fs_write_inode_dotl(struct inode *inode,
253 				 struct writeback_control *wbc)
254 {
255 
256 	p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);
257 
258 	return netfs_unpin_writeback(inode, wbc);
259 }
260 
261 static const struct super_operations v9fs_super_ops = {
262 	.alloc_inode = v9fs_alloc_inode,
263 	.free_inode = v9fs_free_inode,
264 	.statfs = simple_statfs,
265 	.drop_inode = v9fs_drop_inode,
266 	.evict_inode = v9fs_evict_inode,
267 	.show_options = v9fs_show_options,
268 	.umount_begin = v9fs_umount_begin,
269 	.write_inode = v9fs_write_inode,
270 };
271 
272 static const struct super_operations v9fs_super_ops_dotl = {
273 	.alloc_inode = v9fs_alloc_inode,
274 	.free_inode = v9fs_free_inode,
275 	.statfs = v9fs_statfs,
276 	.drop_inode = v9fs_drop_inode,
277 	.evict_inode = v9fs_evict_inode,
278 	.show_options = v9fs_show_options,
279 	.umount_begin = v9fs_umount_begin,
280 	.write_inode = v9fs_write_inode_dotl,
281 };
282 
v9fs_free_fc(struct fs_context * fc)283 static void v9fs_free_fc(struct fs_context *fc)
284 {
285 	struct v9fs_context *ctx = fc->fs_private;
286 
287 	if (!ctx)
288 		return;
289 
290 	/* These should be NULL by now but guard against leaks */
291 	kfree(ctx->session_opts.uname);
292 	kfree(ctx->session_opts.aname);
293 #ifdef CONFIG_9P_FSCACHE
294 	kfree(ctx->session_opts.cachetag);
295 #endif
296 	if (ctx->client_opts.trans_mod)
297 		v9fs_put_trans(ctx->client_opts.trans_mod);
298 	kfree(ctx);
299 }
300 
301 static const struct fs_context_operations v9fs_context_ops = {
302 	.parse_param	= v9fs_parse_param,
303 	.get_tree	= v9fs_get_tree,
304 	.free		= v9fs_free_fc,
305 };
306 
v9fs_init_fs_context(struct fs_context * fc)307 static int v9fs_init_fs_context(struct fs_context *fc)
308 {
309 	struct v9fs_context	*ctx;
310 
311 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
312 	if (!ctx)
313 		return -ENOMEM;
314 
315 	/* initialize core options */
316 	ctx->session_opts.afid = ~0;
317 	ctx->session_opts.cache = CACHE_NONE;
318 	ctx->session_opts.session_lock_timeout = P9_LOCK_TIMEOUT;
319 	ctx->session_opts.uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
320 	if (!ctx->session_opts.uname)
321 		goto error;
322 
323 	ctx->session_opts.aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
324 	if (!ctx->session_opts.aname)
325 		goto error;
326 
327 	ctx->session_opts.uid = INVALID_UID;
328 	ctx->session_opts.dfltuid = V9FS_DEFUID;
329 	ctx->session_opts.dfltgid = V9FS_DEFGID;
330 
331 	/* initialize client options */
332 	ctx->client_opts.proto_version = p9_proto_2000L;
333 	ctx->client_opts.msize = DEFAULT_MSIZE;
334 
335 	/* initialize fd transport options */
336 	ctx->fd_opts.port = P9_FD_PORT;
337 	ctx->fd_opts.rfd = ~0;
338 	ctx->fd_opts.wfd = ~0;
339 	ctx->fd_opts.privport = false;
340 
341 	/* initialize rdma transport options */
342 	ctx->rdma_opts.port = P9_RDMA_PORT;
343 	ctx->rdma_opts.sq_depth = P9_RDMA_SQ_DEPTH;
344 	ctx->rdma_opts.rq_depth = P9_RDMA_RQ_DEPTH;
345 	ctx->rdma_opts.timeout = P9_RDMA_TIMEOUT;
346 	ctx->rdma_opts.privport = false;
347 
348 	fc->ops = &v9fs_context_ops;
349 	fc->fs_private = ctx;
350 
351 	return 0;
352 error:
353 	fc->need_free = 1;
354 	return -ENOMEM;
355 }
356 
357 struct file_system_type v9fs_fs_type = {
358 	.name = "9p",
359 	.kill_sb = v9fs_kill_super,
360 	.owner = THIS_MODULE,
361 	.fs_flags = FS_RENAME_DOES_D_MOVE,
362 	.init_fs_context = v9fs_init_fs_context,
363 	.parameters = v9fs_param_spec,
364 };
365 MODULE_ALIAS_FS("9p");
366