at master 8.4 kB view raw
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 32static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; 33 34static 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 82static 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 141clunk_fid: 142 p9_fid_put(fid); 143 v9fs_session_close(v9ses); 144free_session: 145 kfree(v9ses); 146 return retval; 147 148release_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 166static 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 181static void 182v9fs_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 190static 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); 221done: 222 p9_fid_put(fid); 223 return res; 224} 225 226static 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 241static 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 252static 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 261static 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 272static 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 283static 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 301static 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 307static 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; 352error: 353 fc->need_free = 1; 354 return -ENOMEM; 355} 356 357struct 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}; 365MODULE_ALIAS_FS("9p");