Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag '9p-for-6.19-rc1' of https://github.com/martinetd/linux

Pull 9p updates from Dominique Martinet:

- fix a bug with O_APPEND in cached mode causing data to be written
multiple times on server

- use kvmalloc for trans_fd to avoid problems with large msize and
fragmented memory This should hopefully be used in more transports
when time allows

- convert to new mount API

- minor cleanups

* tag '9p-for-6.19-rc1' of https://github.com/martinetd/linux:
9p: fix new mount API cache option handling
9p: fix cache/debug options printing in v9fs_show_options
9p: convert to the new mount API
9p: create a v9fs_context structure to hold parsed options
net/9p: move structures and macros to header files
fs/fs_parse: add back fsparam_u32hex
fs/9p: delete unnnecessary condition
fs/9p: Don't open remote file with APPEND mode when writeback cache is used
net/9p: cleanup: change p9_trans_module->def to bool
9p: Use kvmalloc for message buffers on supported transports

+573 -698
+288 -254
fs/9p/v9fs.c
··· 13 13 #include <linux/fs.h> 14 14 #include <linux/sched.h> 15 15 #include <linux/cred.h> 16 - #include <linux/parser.h> 16 + #include <linux/fs_parser.h> 17 + #include <linux/fs_context.h> 17 18 #include <linux/slab.h> 18 19 #include <linux/seq_file.h> 19 20 #include <net/9p/9p.h> ··· 34 33 */ 35 34 36 35 enum { 36 + /* Mount-point source, we need to handle this explicitly because 37 + * the code below accepts unknown args and the vfs layer only handles 38 + * source if we rejected it as EINVAL */ 39 + Opt_source, 37 40 /* Options that take integer arguments */ 38 41 Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, 39 42 /* String options */ ··· 48 43 Opt_access, Opt_posixacl, 49 44 /* Lock timeout option */ 50 45 Opt_locktimeout, 51 - /* Error token */ 52 - Opt_err 46 + 47 + /* Client options */ 48 + Opt_msize, Opt_trans, Opt_legacy, Opt_version, 49 + 50 + /* fd transport options */ 51 + /* Options that take integer arguments */ 52 + Opt_rfdno, Opt_wfdno, 53 + /* Options that take no arguments */ 54 + 55 + /* rdma transport options */ 56 + /* Options that take integer arguments */ 57 + Opt_rq_depth, Opt_sq_depth, Opt_timeout, 58 + 59 + /* Options for both fd and rdma transports */ 60 + Opt_port, Opt_privport, 53 61 }; 54 62 55 - static const match_table_t tokens = { 56 - {Opt_debug, "debug=%x"}, 57 - {Opt_dfltuid, "dfltuid=%u"}, 58 - {Opt_dfltgid, "dfltgid=%u"}, 59 - {Opt_afid, "afid=%u"}, 60 - {Opt_uname, "uname=%s"}, 61 - {Opt_remotename, "aname=%s"}, 62 - {Opt_nodevmap, "nodevmap"}, 63 - {Opt_noxattr, "noxattr"}, 64 - {Opt_directio, "directio"}, 65 - {Opt_ignoreqv, "ignoreqv"}, 66 - {Opt_cache, "cache=%s"}, 67 - {Opt_cachetag, "cachetag=%s"}, 68 - {Opt_access, "access=%s"}, 69 - {Opt_posixacl, "posixacl"}, 70 - {Opt_locktimeout, "locktimeout=%u"}, 71 - {Opt_err, NULL} 63 + static const struct constant_table p9_versions[] = { 64 + { "9p2000", p9_proto_legacy }, 65 + { "9p2000.u", p9_proto_2000u }, 66 + { "9p2000.L", p9_proto_2000L }, 67 + {} 68 + }; 69 + 70 + /* 71 + * This structure contains all parameters used for the core code, 72 + * the client, and all the transports. 73 + */ 74 + const struct fs_parameter_spec v9fs_param_spec[] = { 75 + fsparam_string ("source", Opt_source), 76 + fsparam_u32hex ("debug", Opt_debug), 77 + fsparam_uid ("dfltuid", Opt_dfltuid), 78 + fsparam_gid ("dfltgid", Opt_dfltgid), 79 + fsparam_u32 ("afid", Opt_afid), 80 + fsparam_string ("uname", Opt_uname), 81 + fsparam_string ("aname", Opt_remotename), 82 + fsparam_flag ("nodevmap", Opt_nodevmap), 83 + fsparam_flag ("noxattr", Opt_noxattr), 84 + fsparam_flag ("directio", Opt_directio), 85 + fsparam_flag ("ignoreqv", Opt_ignoreqv), 86 + fsparam_string ("cache", Opt_cache), 87 + fsparam_string ("cachetag", Opt_cachetag), 88 + fsparam_string ("access", Opt_access), 89 + fsparam_flag ("posixacl", Opt_posixacl), 90 + fsparam_u32 ("locktimeout", Opt_locktimeout), 91 + 92 + /* client options */ 93 + fsparam_u32 ("msize", Opt_msize), 94 + fsparam_flag ("noextend", Opt_legacy), 95 + fsparam_string ("trans", Opt_trans), 96 + fsparam_enum ("version", Opt_version, p9_versions), 97 + 98 + /* fd transport options */ 99 + fsparam_u32 ("rfdno", Opt_rfdno), 100 + fsparam_u32 ("wfdno", Opt_wfdno), 101 + 102 + /* rdma transport options */ 103 + fsparam_u32 ("sq", Opt_sq_depth), 104 + fsparam_u32 ("rq", Opt_rq_depth), 105 + fsparam_u32 ("timeout", Opt_timeout), 106 + 107 + /* fd and rdma transprt options */ 108 + fsparam_u32 ("port", Opt_port), 109 + fsparam_flag ("privport", Opt_privport), 110 + {} 72 111 }; 73 112 74 113 /* Interpret mount options for cache mode */ ··· 150 101 struct v9fs_session_info *v9ses = root->d_sb->s_fs_info; 151 102 152 103 if (v9ses->debug) 153 - seq_printf(m, ",debug=%x", v9ses->debug); 104 + seq_printf(m, ",debug=%#x", v9ses->debug); 154 105 if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID)) 155 106 seq_printf(m, ",dfltuid=%u", 156 107 from_kuid_munged(&init_user_ns, v9ses->dfltuid)); ··· 166 117 if (v9ses->nodev) 167 118 seq_puts(m, ",nodevmap"); 168 119 if (v9ses->cache) 169 - seq_printf(m, ",cache=%x", v9ses->cache); 120 + seq_printf(m, ",cache=%#x", v9ses->cache); 170 121 #ifdef CONFIG_9P_FSCACHE 171 122 if (v9ses->cachetag && (v9ses->cache & CACHE_FSCACHE)) 172 123 seq_printf(m, ",cachetag=%s", v9ses->cachetag); ··· 202 153 } 203 154 204 155 /** 205 - * v9fs_parse_options - parse mount options into session structure 206 - * @v9ses: existing v9fs session information 207 - * @opts: The mount option string 156 + * v9fs_parse_param - parse a mount option into the filesystem context 157 + * @fc: the filesystem context 158 + * @param: the parameter to parse 208 159 * 209 160 * Return 0 upon success, -ERRNO upon failure. 210 161 */ 211 - 212 - static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) 162 + int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param) 213 163 { 214 - char *options, *tmp_options; 215 - substring_t args[MAX_OPT_ARGS]; 216 - char *p; 217 - int option = 0; 164 + struct v9fs_context *ctx = fc->fs_private; 165 + struct fs_parse_result result; 218 166 char *s; 219 - int ret = 0; 167 + int r; 168 + int opt; 169 + struct p9_client_opts *clnt = &ctx->client_opts; 170 + struct p9_fd_opts *fd_opts = &ctx->fd_opts; 171 + struct p9_rdma_opts *rdma_opts = &ctx->rdma_opts; 172 + struct p9_session_opts *session_opts = &ctx->session_opts; 220 173 221 - /* setup defaults */ 222 - v9ses->afid = ~0; 223 - v9ses->debug = 0; 224 - v9ses->cache = CACHE_NONE; 225 - #ifdef CONFIG_9P_FSCACHE 226 - v9ses->cachetag = NULL; 227 - #endif 228 - v9ses->session_lock_timeout = P9_LOCK_TIMEOUT; 174 + opt = fs_parse(fc, v9fs_param_spec, param, &result); 175 + if (opt < 0) { 176 + /* 177 + * We might like to report bad mount options here, but 178 + * traditionally 9p has ignored unknown mount options 179 + */ 180 + if (opt == -ENOPARAM) 181 + return 0; 229 182 230 - if (!opts) 231 - return 0; 232 - 233 - tmp_options = kstrdup(opts, GFP_KERNEL); 234 - if (!tmp_options) { 235 - ret = -ENOMEM; 236 - goto fail_option_alloc; 183 + return opt; 237 184 } 238 - options = tmp_options; 239 185 240 - while ((p = strsep(&options, ",")) != NULL) { 241 - int token, r; 242 - 243 - if (!*p) 244 - continue; 245 - 246 - token = match_token(p, tokens, args); 247 - switch (token) { 248 - case Opt_debug: 249 - r = match_int(&args[0], &option); 250 - if (r < 0) { 251 - p9_debug(P9_DEBUG_ERROR, 252 - "integer field, but no integer?\n"); 253 - ret = r; 254 - } else { 255 - v9ses->debug = option; 256 - #ifdef CONFIG_NET_9P_DEBUG 257 - p9_debug_level = option; 258 - #endif 259 - } 260 - break; 261 - 262 - case Opt_dfltuid: 263 - r = match_int(&args[0], &option); 264 - if (r < 0) { 265 - p9_debug(P9_DEBUG_ERROR, 266 - "integer field, but no integer?\n"); 267 - ret = r; 268 - continue; 269 - } 270 - v9ses->dfltuid = make_kuid(current_user_ns(), option); 271 - if (!uid_valid(v9ses->dfltuid)) { 272 - p9_debug(P9_DEBUG_ERROR, 273 - "uid field, but not a uid?\n"); 274 - ret = -EINVAL; 275 - } 276 - break; 277 - case Opt_dfltgid: 278 - r = match_int(&args[0], &option); 279 - if (r < 0) { 280 - p9_debug(P9_DEBUG_ERROR, 281 - "integer field, but no integer?\n"); 282 - ret = r; 283 - continue; 284 - } 285 - v9ses->dfltgid = make_kgid(current_user_ns(), option); 286 - if (!gid_valid(v9ses->dfltgid)) { 287 - p9_debug(P9_DEBUG_ERROR, 288 - "gid field, but not a gid?\n"); 289 - ret = -EINVAL; 290 - } 291 - break; 292 - case Opt_afid: 293 - r = match_int(&args[0], &option); 294 - if (r < 0) { 295 - p9_debug(P9_DEBUG_ERROR, 296 - "integer field, but no integer?\n"); 297 - ret = r; 298 - } else { 299 - v9ses->afid = option; 300 - } 301 - break; 302 - case Opt_uname: 303 - kfree(v9ses->uname); 304 - v9ses->uname = match_strdup(&args[0]); 305 - if (!v9ses->uname) { 306 - ret = -ENOMEM; 307 - goto free_and_return; 308 - } 309 - break; 310 - case Opt_remotename: 311 - kfree(v9ses->aname); 312 - v9ses->aname = match_strdup(&args[0]); 313 - if (!v9ses->aname) { 314 - ret = -ENOMEM; 315 - goto free_and_return; 316 - } 317 - break; 318 - case Opt_nodevmap: 319 - v9ses->nodev = 1; 320 - break; 321 - case Opt_noxattr: 322 - v9ses->flags |= V9FS_NO_XATTR; 323 - break; 324 - case Opt_directio: 325 - v9ses->flags |= V9FS_DIRECT_IO; 326 - break; 327 - case Opt_ignoreqv: 328 - v9ses->flags |= V9FS_IGNORE_QV; 329 - break; 330 - case Opt_cachetag: 331 - #ifdef CONFIG_9P_FSCACHE 332 - kfree(v9ses->cachetag); 333 - v9ses->cachetag = match_strdup(&args[0]); 334 - if (!v9ses->cachetag) { 335 - ret = -ENOMEM; 336 - goto free_and_return; 337 - } 338 - #endif 339 - break; 340 - case Opt_cache: 341 - s = match_strdup(&args[0]); 342 - if (!s) { 343 - ret = -ENOMEM; 344 - p9_debug(P9_DEBUG_ERROR, 345 - "problem allocating copy of cache arg\n"); 346 - goto free_and_return; 347 - } 348 - r = get_cache_mode(s); 349 - if (r < 0) 350 - ret = r; 351 - else 352 - v9ses->cache = r; 353 - 354 - kfree(s); 355 - break; 356 - 357 - case Opt_access: 358 - s = match_strdup(&args[0]); 359 - if (!s) { 360 - ret = -ENOMEM; 361 - p9_debug(P9_DEBUG_ERROR, 362 - "problem allocating copy of access arg\n"); 363 - goto free_and_return; 364 - } 365 - 366 - v9ses->flags &= ~V9FS_ACCESS_MASK; 367 - if (strcmp(s, "user") == 0) 368 - v9ses->flags |= V9FS_ACCESS_USER; 369 - else if (strcmp(s, "any") == 0) 370 - v9ses->flags |= V9FS_ACCESS_ANY; 371 - else if (strcmp(s, "client") == 0) { 372 - v9ses->flags |= V9FS_ACCESS_CLIENT; 373 - } else { 374 - uid_t uid; 375 - 376 - v9ses->flags |= V9FS_ACCESS_SINGLE; 377 - r = kstrtouint(s, 10, &uid); 378 - if (r) { 379 - ret = r; 380 - pr_info("Unknown access argument %s: %d\n", 381 - s, r); 382 - kfree(s); 383 - continue; 384 - } 385 - v9ses->uid = make_kuid(current_user_ns(), uid); 386 - if (!uid_valid(v9ses->uid)) { 387 - ret = -EINVAL; 388 - pr_info("Unknown uid %s\n", s); 389 - } 390 - } 391 - 392 - kfree(s); 393 - break; 394 - 395 - case Opt_posixacl: 396 - #ifdef CONFIG_9P_FS_POSIX_ACL 397 - v9ses->flags |= V9FS_POSIX_ACL; 398 - #else 399 - p9_debug(P9_DEBUG_ERROR, 400 - "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n"); 401 - #endif 402 - break; 403 - 404 - case Opt_locktimeout: 405 - r = match_int(&args[0], &option); 406 - if (r < 0) { 407 - p9_debug(P9_DEBUG_ERROR, 408 - "integer field, but no integer?\n"); 409 - ret = r; 410 - continue; 411 - } 412 - if (option < 1) { 413 - p9_debug(P9_DEBUG_ERROR, 414 - "locktimeout must be a greater than zero integer.\n"); 415 - ret = -EINVAL; 416 - continue; 417 - } 418 - v9ses->session_lock_timeout = (long)option * HZ; 419 - break; 420 - 421 - default: 422 - continue; 186 + switch (opt) { 187 + case Opt_source: 188 + if (fc->source) { 189 + pr_info("p9: multiple sources not supported\n"); 190 + return -EINVAL; 423 191 } 192 + fc->source = param->string; 193 + param->string = NULL; 194 + break; 195 + case Opt_debug: 196 + session_opts->debug = result.uint_32; 197 + #ifdef CONFIG_NET_9P_DEBUG 198 + p9_debug_level = result.uint_32; 199 + #endif 200 + break; 201 + 202 + case Opt_dfltuid: 203 + session_opts->dfltuid = result.uid; 204 + break; 205 + case Opt_dfltgid: 206 + session_opts->dfltgid = result.gid; 207 + break; 208 + case Opt_afid: 209 + session_opts->afid = result.uint_32; 210 + break; 211 + case Opt_uname: 212 + kfree(session_opts->uname); 213 + session_opts->uname = param->string; 214 + param->string = NULL; 215 + break; 216 + case Opt_remotename: 217 + kfree(session_opts->aname); 218 + session_opts->aname = param->string; 219 + param->string = NULL; 220 + break; 221 + case Opt_nodevmap: 222 + session_opts->nodev = 1; 223 + break; 224 + case Opt_noxattr: 225 + session_opts->flags |= V9FS_NO_XATTR; 226 + break; 227 + case Opt_directio: 228 + session_opts->flags |= V9FS_DIRECT_IO; 229 + break; 230 + case Opt_ignoreqv: 231 + session_opts->flags |= V9FS_IGNORE_QV; 232 + break; 233 + case Opt_cachetag: 234 + #ifdef CONFIG_9P_FSCACHE 235 + kfree(session_opts->cachetag); 236 + session_opts->cachetag = param->string; 237 + param->string = NULL; 238 + #endif 239 + break; 240 + case Opt_cache: 241 + r = get_cache_mode(param->string); 242 + if (r < 0) 243 + return r; 244 + session_opts->cache = r; 245 + break; 246 + case Opt_access: 247 + s = param->string; 248 + session_opts->flags &= ~V9FS_ACCESS_MASK; 249 + if (strcmp(s, "user") == 0) { 250 + session_opts->flags |= V9FS_ACCESS_USER; 251 + } else if (strcmp(s, "any") == 0) { 252 + session_opts->flags |= V9FS_ACCESS_ANY; 253 + } else if (strcmp(s, "client") == 0) { 254 + session_opts->flags |= V9FS_ACCESS_CLIENT; 255 + } else { 256 + uid_t uid; 257 + 258 + session_opts->flags |= V9FS_ACCESS_SINGLE; 259 + r = kstrtouint(s, 10, &uid); 260 + if (r) { 261 + pr_info("Unknown access argument %s: %d\n", 262 + param->string, r); 263 + return r; 264 + } 265 + session_opts->uid = make_kuid(current_user_ns(), uid); 266 + if (!uid_valid(session_opts->uid)) { 267 + pr_info("Unknown uid %s\n", s); 268 + return -EINVAL; 269 + } 270 + } 271 + break; 272 + 273 + case Opt_posixacl: 274 + #ifdef CONFIG_9P_FS_POSIX_ACL 275 + session_opts->flags |= V9FS_POSIX_ACL; 276 + #else 277 + p9_debug(P9_DEBUG_ERROR, 278 + "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n"); 279 + #endif 280 + break; 281 + 282 + case Opt_locktimeout: 283 + if (result.uint_32 < 1) { 284 + p9_debug(P9_DEBUG_ERROR, 285 + "locktimeout must be a greater than zero integer.\n"); 286 + return -EINVAL; 287 + } 288 + session_opts->session_lock_timeout = (long)result.uint_32 * HZ; 289 + break; 290 + 291 + /* Options for client */ 292 + case Opt_msize: 293 + if (result.uint_32 < 4096) { 294 + p9_debug(P9_DEBUG_ERROR, "msize should be at least 4k\n"); 295 + return -EINVAL; 296 + } 297 + if (result.uint_32 > INT_MAX) { 298 + p9_debug(P9_DEBUG_ERROR, "msize too big\n"); 299 + return -EINVAL; 300 + } 301 + clnt->msize = result.uint_32; 302 + break; 303 + case Opt_trans: 304 + v9fs_put_trans(clnt->trans_mod); 305 + clnt->trans_mod = v9fs_get_trans_by_name(param->string); 306 + if (!clnt->trans_mod) { 307 + pr_info("Could not find request transport: %s\n", 308 + param->string); 309 + return -EINVAL; 310 + } 311 + break; 312 + case Opt_legacy: 313 + clnt->proto_version = p9_proto_legacy; 314 + break; 315 + case Opt_version: 316 + clnt->proto_version = result.uint_32; 317 + p9_debug(P9_DEBUG_9P, "Protocol version: %s\n", param->string); 318 + break; 319 + /* Options for fd transport */ 320 + case Opt_rfdno: 321 + fd_opts->rfd = result.uint_32; 322 + break; 323 + case Opt_wfdno: 324 + fd_opts->wfd = result.uint_32; 325 + break; 326 + /* Options for rdma transport */ 327 + case Opt_sq_depth: 328 + rdma_opts->sq_depth = result.uint_32; 329 + break; 330 + case Opt_rq_depth: 331 + rdma_opts->rq_depth = result.uint_32; 332 + break; 333 + case Opt_timeout: 334 + rdma_opts->timeout = result.uint_32; 335 + break; 336 + /* Options for both fd and rdma transports */ 337 + case Opt_port: 338 + fd_opts->port = result.uint_32; 339 + rdma_opts->port = result.uint_32; 340 + break; 341 + case Opt_privport: 342 + fd_opts->privport = true; 343 + rdma_opts->port = true; 344 + break; 424 345 } 425 346 426 - free_and_return: 427 - kfree(tmp_options); 428 - fail_option_alloc: 429 - return ret; 347 + return 0; 348 + } 349 + 350 + static void v9fs_apply_options(struct v9fs_session_info *v9ses, 351 + struct fs_context *fc) 352 + { 353 + struct v9fs_context *ctx = fc->fs_private; 354 + 355 + v9ses->debug = ctx->session_opts.debug; 356 + v9ses->dfltuid = ctx->session_opts.dfltuid; 357 + v9ses->dfltgid = ctx->session_opts.dfltgid; 358 + v9ses->afid = ctx->session_opts.afid; 359 + v9ses->uname = ctx->session_opts.uname; 360 + ctx->session_opts.uname = NULL; 361 + v9ses->aname = ctx->session_opts.aname; 362 + ctx->session_opts.aname = NULL; 363 + v9ses->nodev = ctx->session_opts.nodev; 364 + /* 365 + * Note that we must |= flags here as session_init already 366 + * set basic flags. This adds in flags from parsed options. 367 + */ 368 + v9ses->flags |= ctx->session_opts.flags; 369 + #ifdef CONFIG_9P_FSCACHE 370 + v9ses->cachetag = ctx->session_opts.cachetag; 371 + ctx->session_opts.cachetag = NULL; 372 + #endif 373 + v9ses->cache = ctx->session_opts.cache; 374 + v9ses->uid = ctx->session_opts.uid; 375 + v9ses->session_lock_timeout = ctx->session_opts.session_lock_timeout; 430 376 } 431 377 432 378 /** 433 379 * v9fs_session_init - initialize session 434 380 * @v9ses: session information structure 435 - * @dev_name: device being mounted 436 - * @data: options 381 + * @fc: the filesystem mount context 437 382 * 438 383 */ 439 384 440 385 struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, 441 - const char *dev_name, char *data) 386 + struct fs_context *fc) 442 387 { 443 388 struct p9_fid *fid; 444 389 int rc = -ENOMEM; 445 390 446 - v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL); 447 - if (!v9ses->uname) 448 - goto err_names; 449 - 450 - v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL); 451 - if (!v9ses->aname) 452 - goto err_names; 453 391 init_rwsem(&v9ses->rename_sem); 454 392 455 - v9ses->uid = INVALID_UID; 456 - v9ses->dfltuid = V9FS_DEFUID; 457 - v9ses->dfltgid = V9FS_DEFGID; 458 - 459 - v9ses->clnt = p9_client_create(dev_name, data); 393 + v9ses->clnt = p9_client_create(fc); 460 394 if (IS_ERR(v9ses->clnt)) { 461 395 rc = PTR_ERR(v9ses->clnt); 462 396 p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n"); 463 397 goto err_names; 464 398 } 465 399 400 + /* 401 + * Initialize flags on the real v9ses. v9fs_apply_options below 402 + * will |= the additional flags from parsed options. 403 + */ 466 404 v9ses->flags = V9FS_ACCESS_USER; 467 405 468 406 if (p9_is_proto_dotl(v9ses->clnt)) { ··· 459 423 v9ses->flags |= V9FS_PROTO_2000U; 460 424 } 461 425 462 - rc = v9fs_parse_options(v9ses, data); 463 - if (rc < 0) 464 - goto err_clnt; 426 + v9fs_apply_options(v9ses, fc); 465 427 466 428 v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; 467 429 ··· 505 471 #ifdef CONFIG_9P_FSCACHE 506 472 /* register the session for caching */ 507 473 if (v9ses->cache & CACHE_FSCACHE) { 508 - rc = v9fs_cache_session_get_cookie(v9ses, dev_name); 474 + rc = v9fs_cache_session_get_cookie(v9ses, fc->source); 509 475 if (rc < 0) 510 476 goto err_clnt; 511 477 }
+6 -1
fs/9p/v9fs.h
··· 10 10 11 11 #include <linux/backing-dev.h> 12 12 #include <linux/netfs.h> 13 + #include <linux/fs_parser.h> 14 + #include <net/9p/client.h> 15 + #include <net/9p/transport.h> 13 16 14 17 /** 15 18 * enum p9_session_flags - option flags for each 9P session ··· 166 163 #endif 167 164 } 168 165 166 + extern const struct fs_parameter_spec v9fs_param_spec[]; 169 167 168 + extern int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param); 170 169 extern int v9fs_show_options(struct seq_file *m, struct dentry *root); 171 170 172 171 struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, 173 - const char *dev_name, char *data); 172 + struct fs_context *fc); 174 173 extern void v9fs_session_close(struct v9fs_session_info *v9ses); 175 174 extern void v9fs_session_cancel(struct v9fs_session_info *v9ses); 176 175 extern void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
-1
fs/9p/vfs_dentry.c
··· 109 109 p9_debug(P9_DEBUG_VFS, 110 110 "refresh inode: dentry = %pd (%p), got error %pe\n", 111 111 dentry, dentry, ERR_PTR(retval)); 112 - if (retval < 0) 113 112 return retval; 114 113 } 115 114 }
+8 -3
fs/9p/vfs_file.c
··· 43 43 struct v9fs_session_info *v9ses; 44 44 struct p9_fid *fid; 45 45 int omode; 46 + int o_append; 46 47 47 48 p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); 48 49 v9ses = v9fs_inode2v9ses(inode); 49 - if (v9fs_proto_dotl(v9ses)) 50 + if (v9fs_proto_dotl(v9ses)) { 50 51 omode = v9fs_open_to_dotl_flags(file->f_flags); 51 - else 52 + o_append = P9_DOTL_APPEND; 53 + } else { 52 54 omode = v9fs_uflags2omode(file->f_flags, 53 55 v9fs_proto_dotu(v9ses)); 56 + o_append = P9_OAPPEND; 57 + } 54 58 fid = file->private_data; 55 59 if (!fid) { 56 60 fid = v9fs_fid_clone(file_dentry(file)); ··· 62 58 return PTR_ERR(fid); 63 59 64 60 if ((v9ses->cache & CACHE_WRITEBACK) && (omode & P9_OWRITE)) { 65 - int writeback_omode = (omode & ~P9_OWRITE) | P9_ORDWR; 61 + int writeback_omode = (omode & ~(P9_OWRITE | o_append)) | P9_ORDWR; 66 62 67 63 p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, try opening O_RDWR\n"); 64 + 68 65 err = p9_client_open(fid, writeback_omode); 69 66 if (err < 0) { 70 67 p9_debug(P9_DEBUG_CACHE, "could not open O_RDWR, disabling caches\n");
+1 -2
fs/9p/vfs_inode.c
··· 786 786 p9_omode = v9fs_uflags2omode(flags, v9fs_proto_dotu(v9ses)); 787 787 788 788 if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) { 789 - p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR; 789 + p9_omode = (p9_omode & ~(P9_OWRITE | P9_OAPPEND)) | P9_ORDWR; 790 790 p9_debug(P9_DEBUG_CACHE, 791 791 "write-only file with writeback enabled, creating w/ O_RDWR\n"); 792 792 } ··· 1393 1393 .getattr = v9fs_vfs_getattr, 1394 1394 .setattr = v9fs_vfs_setattr, 1395 1395 }; 1396 -
+1 -1
fs/9p/vfs_inode_dotl.c
··· 282 282 } 283 283 284 284 if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) { 285 - p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR; 285 + p9_omode = (p9_omode & ~(P9_OWRITE | P9_DOTL_APPEND)) | P9_ORDWR; 286 286 p9_debug(P9_DEBUG_CACHE, 287 287 "write-only file with writeback enabled, creating w/ O_RDWR\n"); 288 288 }
+91 -39
fs/9p/vfs_super.c
··· 19 19 #include <linux/statfs.h> 20 20 #include <linux/magic.h> 21 21 #include <linux/fscache.h> 22 + #include <linux/fs_context.h> 22 23 #include <net/9p/9p.h> 23 24 #include <net/9p/client.h> 24 25 ··· 31 30 32 31 static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; 33 32 34 - /** 35 - * v9fs_set_super - set the superblock 36 - * @s: super block 37 - * @data: file system specific data 38 - * 39 - */ 40 - 41 - static int v9fs_set_super(struct super_block *s, void *data) 42 - { 43 - s->s_fs_info = data; 44 - return set_anon_super(s, data); 45 - } 46 - 47 - /** 48 - * v9fs_fill_super - populate superblock with info 49 - * @sb: superblock 50 - * @v9ses: session information 51 - * @flags: flags propagated from v9fs_mount() 52 - * 53 - */ 54 - 55 - static int 56 - v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, 57 - int flags) 33 + static int v9fs_fill_super(struct super_block *sb) 58 34 { 59 35 int ret; 36 + struct v9fs_session_info *v9ses = v9ses = sb->s_fs_info; 60 37 61 38 sb->s_maxbytes = MAX_LFS_FILESIZE; 62 39 sb->s_blocksize_bits = fls(v9ses->maxdata - 1); ··· 74 95 } 75 96 76 97 /** 77 - * v9fs_mount - mount a superblock 78 - * @fs_type: file system type 79 - * @flags: mount flags 80 - * @dev_name: device name that was mounted 81 - * @data: mount options 98 + * v9fs_get_tree - create the mountable root and superblock 99 + * @fc: the filesystem context 82 100 * 83 101 */ 84 102 85 - static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, 86 - const char *dev_name, void *data) 103 + static int v9fs_get_tree(struct fs_context *fc) 87 104 { 88 105 struct super_block *sb = NULL; 89 106 struct inode *inode = NULL; ··· 92 117 93 118 v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); 94 119 if (!v9ses) 95 - return ERR_PTR(-ENOMEM); 120 + return -ENOMEM; 96 121 97 - fid = v9fs_session_init(v9ses, dev_name, data); 122 + fid = v9fs_session_init(v9ses, fc); 98 123 if (IS_ERR(fid)) { 99 124 retval = PTR_ERR(fid); 100 125 goto free_session; 101 126 } 102 127 103 - sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses); 128 + fc->s_fs_info = v9ses; 129 + sb = sget_fc(fc, NULL, set_anon_super_fc); 104 130 if (IS_ERR(sb)) { 105 131 retval = PTR_ERR(sb); 106 132 goto clunk_fid; 107 133 } 108 - retval = v9fs_fill_super(sb, v9ses, flags); 134 + retval = v9fs_fill_super(sb); 109 135 if (retval) 110 136 goto release_sb; 111 137 ··· 135 159 v9fs_fid_add(root, &fid); 136 160 137 161 p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n"); 138 - return dget(sb->s_root); 162 + fc->root = dget(sb->s_root); 163 + return 0; 139 164 140 165 clunk_fid: 141 166 p9_fid_put(fid); 142 167 v9fs_session_close(v9ses); 143 168 free_session: 144 169 kfree(v9ses); 145 - return ERR_PTR(retval); 170 + return retval; 146 171 147 172 release_sb: 148 173 /* ··· 154 177 */ 155 178 p9_fid_put(fid); 156 179 deactivate_locked_super(sb); 157 - return ERR_PTR(retval); 180 + return retval; 158 181 } 159 182 160 183 /** ··· 280 303 .write_inode = v9fs_write_inode_dotl, 281 304 }; 282 305 306 + static void v9fs_free_fc(struct fs_context *fc) 307 + { 308 + struct v9fs_context *ctx = fc->fs_private; 309 + 310 + if (!ctx) 311 + return; 312 + 313 + /* These should be NULL by now but guard against leaks */ 314 + kfree(ctx->session_opts.uname); 315 + kfree(ctx->session_opts.aname); 316 + #ifdef CONFIG_9P_FSCACHE 317 + kfree(ctx->session_opts.cachetag); 318 + #endif 319 + if (ctx->client_opts.trans_mod) 320 + v9fs_put_trans(ctx->client_opts.trans_mod); 321 + kfree(ctx); 322 + } 323 + 324 + static const struct fs_context_operations v9fs_context_ops = { 325 + .parse_param = v9fs_parse_param, 326 + .get_tree = v9fs_get_tree, 327 + .free = v9fs_free_fc, 328 + }; 329 + 330 + static int v9fs_init_fs_context(struct fs_context *fc) 331 + { 332 + struct v9fs_context *ctx; 333 + 334 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 335 + if (!ctx) 336 + return -ENOMEM; 337 + 338 + /* initialize core options */ 339 + ctx->session_opts.afid = ~0; 340 + ctx->session_opts.cache = CACHE_NONE; 341 + ctx->session_opts.session_lock_timeout = P9_LOCK_TIMEOUT; 342 + ctx->session_opts.uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL); 343 + if (!ctx->session_opts.uname) 344 + goto error; 345 + 346 + ctx->session_opts.aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL); 347 + if (!ctx->session_opts.aname) 348 + goto error; 349 + 350 + ctx->session_opts.uid = INVALID_UID; 351 + ctx->session_opts.dfltuid = V9FS_DEFUID; 352 + ctx->session_opts.dfltgid = V9FS_DEFGID; 353 + 354 + /* initialize client options */ 355 + ctx->client_opts.proto_version = p9_proto_2000L; 356 + ctx->client_opts.msize = DEFAULT_MSIZE; 357 + 358 + /* initialize fd transport options */ 359 + ctx->fd_opts.port = P9_FD_PORT; 360 + ctx->fd_opts.rfd = ~0; 361 + ctx->fd_opts.wfd = ~0; 362 + ctx->fd_opts.privport = false; 363 + 364 + /* initialize rdma transport options */ 365 + ctx->rdma_opts.port = P9_RDMA_PORT; 366 + ctx->rdma_opts.sq_depth = P9_RDMA_SQ_DEPTH; 367 + ctx->rdma_opts.rq_depth = P9_RDMA_RQ_DEPTH; 368 + ctx->rdma_opts.timeout = P9_RDMA_TIMEOUT; 369 + ctx->rdma_opts.privport = false; 370 + 371 + fc->ops = &v9fs_context_ops; 372 + fc->fs_private = ctx; 373 + 374 + return 0; 375 + error: 376 + fc->need_free = 1; 377 + return -ENOMEM; 378 + } 379 + 283 380 struct file_system_type v9fs_fs_type = { 284 381 .name = "9p", 285 - .mount = v9fs_mount, 286 382 .kill_sb = v9fs_kill_super, 287 383 .owner = THIS_MODULE, 288 384 .fs_flags = FS_RENAME_DOES_D_MOVE, 385 + .init_fs_context = v9fs_init_fs_context, 386 + .parameters = v9fs_param_spec, 289 387 }; 290 388 MODULE_ALIAS_FS("9p");
+2
include/linux/fs_parser.h
··· 120 120 #define fsparam_u32(NAME, OPT) __fsparam(fs_param_is_u32, NAME, OPT, 0, NULL) 121 121 #define fsparam_u32oct(NAME, OPT) \ 122 122 __fsparam(fs_param_is_u32, NAME, OPT, 0, (void *)8) 123 + #define fsparam_u32hex(NAME, OPT) \ 124 + __fsparam(fs_param_is_u32, NAME, OPT, 0, (void *)16) 123 125 #define fsparam_s32(NAME, OPT) __fsparam(fs_param_is_s32, NAME, OPT, 0, NULL) 124 126 #define fsparam_u64(NAME, OPT) __fsparam(fs_param_is_u64, NAME, OPT, 0, NULL) 125 127 #define fsparam_enum(NAME, OPT, array) __fsparam(fs_param_is_enum, NAME, OPT, 0, array)
+97 -1
include/net/9p/client.h
··· 16 16 /* Number of requests per row */ 17 17 #define P9_ROW_MAXTAG 255 18 18 19 + /* DEFAULT MSIZE = 32 pages worth of payload + P9_HDRSZ + 20 + * room for write (16 extra) or read (11 extra) operands. 21 + */ 22 + 23 + #define DEFAULT_MSIZE ((128 * 1024) + P9_IOHDRSZ) 24 + 19 25 /** enum p9_proto_versions - 9P protocol versions 20 26 * @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u 21 27 * @p9_proto_2000u: 9P2000.u extension ··· 133 127 }; 134 128 135 129 /** 130 + * struct p9_fd_opts - holds client options during parsing 131 + * @msize: maximum data size negotiated by protocol 132 + * @prot-Oversion: 9P protocol version to use 133 + * @trans_mod: module API instantiated with this client 134 + * 135 + * These parsed options get transferred into client in 136 + * apply_client_options() 137 + */ 138 + struct p9_client_opts { 139 + unsigned int msize; 140 + unsigned char proto_version; 141 + struct p9_trans_module *trans_mod; 142 + }; 143 + 144 + /** 145 + * struct p9_fd_opts - per-transport options for fd transport 146 + * @rfd: file descriptor for reading (trans=fd) 147 + * @wfd: file descriptor for writing (trans=fd) 148 + * @port: port to connect to (trans=tcp) 149 + * @privport: port is privileged 150 + */ 151 + struct p9_fd_opts { 152 + int rfd; 153 + int wfd; 154 + u16 port; 155 + bool privport; 156 + }; 157 + 158 + /** 159 + * struct p9_rdma_opts - Collection of mount options for rdma transport 160 + * @port: port of connection 161 + * @privport: Whether a privileged port may be used 162 + * @sq_depth: The requested depth of the SQ. This really doesn't need 163 + * to be any deeper than the number of threads used in the client 164 + * @rq_depth: The depth of the RQ. Should be greater than or equal to SQ depth 165 + * @timeout: Time to wait in msecs for CM events 166 + */ 167 + struct p9_rdma_opts { 168 + short port; 169 + bool privport; 170 + int sq_depth; 171 + int rq_depth; 172 + long timeout; 173 + }; 174 + 175 + /** 176 + * struct p9_session_opts - holds parsed options for v9fs_session_info 177 + * @flags: session options of type &p9_session_flags 178 + * @nodev: set to 1 to disable device mapping 179 + * @debug: debug level 180 + * @afid: authentication handle 181 + * @cache: cache mode of type &p9_cache_bits 182 + * @cachetag: the tag of the cache associated with this session 183 + * @uname: string user name to mount hierarchy as 184 + * @aname: mount specifier for remote hierarchy 185 + * @dfltuid: default numeric userid to mount hierarchy as 186 + * @dfltgid: default numeric groupid to mount hierarchy as 187 + * @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarchy 188 + * @session_lock_timeout: retry interval for blocking locks 189 + * 190 + * This strucure holds options which are parsed and will be transferred 191 + * to the v9fs_session_info structure when mounted, and therefore largely 192 + * duplicates struct v9fs_session_info. 193 + */ 194 + struct p9_session_opts { 195 + unsigned int flags; 196 + unsigned char nodev; 197 + unsigned short debug; 198 + unsigned int afid; 199 + unsigned int cache; 200 + #ifdef CONFIG_9P_FSCACHE 201 + char *cachetag; 202 + #endif 203 + char *uname; 204 + char *aname; 205 + kuid_t dfltuid; 206 + kgid_t dfltgid; 207 + kuid_t uid; 208 + long session_lock_timeout; 209 + }; 210 + 211 + /* Used by mount API to store parsed mount options */ 212 + struct v9fs_context { 213 + struct p9_client_opts client_opts; 214 + struct p9_fd_opts fd_opts; 215 + struct p9_rdma_opts rdma_opts; 216 + struct p9_session_opts session_opts; 217 + }; 218 + 219 + /** 136 220 * struct p9_fid - file system entity handle 137 221 * @clnt: back pointer to instantiating &p9_client 138 222 * @fid: numeric identifier for this handle ··· 279 183 const char *name); 280 184 int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, 281 185 struct p9_fid *newdirfid, const char *new_name); 282 - struct p9_client *p9_client_create(const char *dev_name, char *options); 186 + struct p9_client *p9_client_create(struct fs_context *fc); 283 187 void p9_client_destroy(struct p9_client *clnt); 284 188 void p9_client_disconnect(struct p9_client *clnt); 285 189 void p9_client_begin_disconnect(struct p9_client *clnt);
+13 -2
include/net/9p/transport.h
··· 14 14 #define P9_DEF_MIN_RESVPORT (665U) 15 15 #define P9_DEF_MAX_RESVPORT (1023U) 16 16 17 + #define P9_FD_PORT 564 18 + 19 + #define P9_RDMA_PORT 5640 20 + #define P9_RDMA_SQ_DEPTH 32 21 + #define P9_RDMA_RQ_DEPTH 32 22 + #define P9_RDMA_TIMEOUT 30000 /* 30 seconds */ 23 + 17 24 /** 18 25 * struct p9_trans_module - transport module interface 19 26 * @list: used to maintain a list of currently available transports ··· 31 24 * we're less flexible when choosing the response message 32 25 * size in this case 33 26 * @def: set if this transport should be considered the default 27 + * @supports_vmalloc: set if this transport can work with vmalloc'd buffers 28 + * (non-physically contiguous memory). Transports requiring 29 + * DMA should leave this as false. 34 30 * @create: member function to create a new connection on this transport 35 31 * @close: member function to discard a connection on this transport 36 32 * @request: member function to issue a request to the transport ··· 53 43 char *name; /* name of transport */ 54 44 int maxsize; /* max message size of transport */ 55 45 bool pooled_rbuffers; 56 - int def; /* this transport should be default */ 46 + bool def; /* this transport should be default */ 47 + bool supports_vmalloc; /* can work with vmalloc'd buffers */ 57 48 struct module *owner; 58 49 int (*create)(struct p9_client *client, 59 - const char *devname, char *args); 50 + struct fs_context *fc); 60 51 void (*close)(struct p9_client *client); 61 52 int (*request)(struct p9_client *client, struct p9_req_t *req); 62 53 int (*cancel)(struct p9_client *client, struct p9_req_t *req);
+21 -144
net/9p/client.c
··· 20 20 #include <linux/uio.h> 21 21 #include <linux/netfs.h> 22 22 #include <net/9p/9p.h> 23 - #include <linux/parser.h> 24 23 #include <linux/seq_file.h> 24 + #include <linux/fs_context.h> 25 25 #include <net/9p/client.h> 26 26 #include <net/9p/transport.h> 27 27 #include "protocol.h" ··· 29 29 #define CREATE_TRACE_POINTS 30 30 #include <trace/events/9p.h> 31 31 32 - /* DEFAULT MSIZE = 32 pages worth of payload + P9_HDRSZ + 33 - * room for write (16 extra) or read (11 extra) operands. 34 - */ 35 - 36 - #define DEFAULT_MSIZE ((128 * 1024) + P9_IOHDRSZ) 37 - 38 32 /* Client Option Parsing (code inspired by NFS code) 39 33 * - a little lazy - parse all client options 40 34 */ 41 - 42 - enum { 43 - Opt_msize, 44 - Opt_trans, 45 - Opt_legacy, 46 - Opt_version, 47 - Opt_err, 48 - }; 49 - 50 - static const match_table_t tokens = { 51 - {Opt_msize, "msize=%u"}, 52 - {Opt_legacy, "noextend"}, 53 - {Opt_trans, "trans=%s"}, 54 - {Opt_version, "version=%s"}, 55 - {Opt_err, NULL}, 56 - }; 57 35 58 36 inline int p9_is_proto_dotl(struct p9_client *clnt) 59 37 { ··· 81 103 return err; 82 104 } 83 105 84 - /* Interpret mount option for protocol version */ 85 - static int get_protocol_version(char *s) 106 + static int apply_client_options(struct p9_client *clnt, struct fs_context *fc) 86 107 { 87 - int version = -EINVAL; 108 + struct v9fs_context *ctx = fc->fs_private; 88 109 89 - if (!strcmp(s, "9p2000")) { 90 - version = p9_proto_legacy; 91 - p9_debug(P9_DEBUG_9P, "Protocol version: Legacy\n"); 92 - } else if (!strcmp(s, "9p2000.u")) { 93 - version = p9_proto_2000u; 94 - p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.u\n"); 95 - } else if (!strcmp(s, "9p2000.L")) { 96 - version = p9_proto_2000L; 97 - p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.L\n"); 98 - } else { 99 - pr_info("Unknown protocol version %s\n", s); 100 - } 110 + clnt->msize = ctx->client_opts.msize; 111 + clnt->trans_mod = ctx->client_opts.trans_mod; 112 + ctx->client_opts.trans_mod = NULL; 113 + clnt->proto_version = ctx->client_opts.proto_version; 101 114 102 - return version; 103 - } 104 - 105 - /** 106 - * parse_opts - parse mount options into client structure 107 - * @opts: options string passed from mount 108 - * @clnt: existing v9fs client information 109 - * 110 - * Return 0 upon success, -ERRNO upon failure 111 - */ 112 - 113 - static int parse_opts(char *opts, struct p9_client *clnt) 114 - { 115 - char *options, *tmp_options; 116 - char *p; 117 - substring_t args[MAX_OPT_ARGS]; 118 - int option; 119 - char *s; 120 - int ret = 0; 121 - 122 - clnt->proto_version = p9_proto_2000L; 123 - clnt->msize = DEFAULT_MSIZE; 124 - 125 - if (!opts) 126 - return 0; 127 - 128 - tmp_options = kstrdup(opts, GFP_KERNEL); 129 - if (!tmp_options) 130 - return -ENOMEM; 131 - options = tmp_options; 132 - 133 - while ((p = strsep(&options, ",")) != NULL) { 134 - int token, r; 135 - 136 - if (!*p) 137 - continue; 138 - token = match_token(p, tokens, args); 139 - switch (token) { 140 - case Opt_msize: 141 - r = match_int(&args[0], &option); 142 - if (r < 0) { 143 - p9_debug(P9_DEBUG_ERROR, 144 - "integer field, but no integer?\n"); 145 - ret = r; 146 - continue; 147 - } 148 - if (option < 4096) { 149 - p9_debug(P9_DEBUG_ERROR, 150 - "msize should be at least 4k\n"); 151 - ret = -EINVAL; 152 - continue; 153 - } 154 - clnt->msize = option; 155 - break; 156 - case Opt_trans: 157 - s = match_strdup(&args[0]); 158 - if (!s) { 159 - ret = -ENOMEM; 160 - p9_debug(P9_DEBUG_ERROR, 161 - "problem allocating copy of trans arg\n"); 162 - goto free_and_return; 163 - } 164 - 165 - v9fs_put_trans(clnt->trans_mod); 166 - clnt->trans_mod = v9fs_get_trans_by_name(s); 167 - if (!clnt->trans_mod) { 168 - pr_info("Could not find request transport: %s\n", 169 - s); 170 - ret = -EINVAL; 171 - } 172 - kfree(s); 173 - break; 174 - case Opt_legacy: 175 - clnt->proto_version = p9_proto_legacy; 176 - break; 177 - case Opt_version: 178 - s = match_strdup(&args[0]); 179 - if (!s) { 180 - ret = -ENOMEM; 181 - p9_debug(P9_DEBUG_ERROR, 182 - "problem allocating copy of version arg\n"); 183 - goto free_and_return; 184 - } 185 - r = get_protocol_version(s); 186 - if (r < 0) 187 - ret = r; 188 - else 189 - clnt->proto_version = r; 190 - kfree(s); 191 - break; 192 - default: 193 - continue; 194 - } 195 - } 196 - 197 - free_and_return: 198 - if (ret) 199 - v9fs_put_trans(clnt->trans_mod); 200 - kfree(tmp_options); 201 - return ret; 115 + return 0; 202 116 } 203 117 204 118 static int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc, ··· 99 229 if (likely(c->fcall_cache) && alloc_msize == c->msize) { 100 230 fc->sdata = kmem_cache_alloc(c->fcall_cache, GFP_NOFS); 101 231 fc->cache = c->fcall_cache; 232 + if (!fc->sdata && c->trans_mod->supports_vmalloc) { 233 + fc->sdata = kvmalloc(alloc_msize, GFP_NOFS); 234 + fc->cache = NULL; 235 + } 102 236 } else { 103 - fc->sdata = kmalloc(alloc_msize, GFP_NOFS); 237 + if (c->trans_mod->supports_vmalloc) 238 + fc->sdata = kvmalloc(alloc_msize, GFP_NOFS); 239 + else 240 + fc->sdata = kmalloc(alloc_msize, GFP_NOFS); 104 241 fc->cache = NULL; 105 242 } 106 243 if (!fc->sdata) ··· 129 252 if (fc->cache) 130 253 kmem_cache_free(fc->cache, fc->sdata); 131 254 else 132 - kfree(fc->sdata); 255 + kvfree(fc->sdata); 133 256 } 134 257 EXPORT_SYMBOL(p9_fcall_fini); 135 258 ··· 851 974 return err; 852 975 } 853 976 854 - struct p9_client *p9_client_create(const char *dev_name, char *options) 977 + struct p9_client *p9_client_create(struct fs_context *fc) 855 978 { 856 979 int err; 857 980 static atomic_t seqno = ATOMIC_INIT(0); ··· 874 997 idr_init(&clnt->fids); 875 998 idr_init(&clnt->reqs); 876 999 877 - err = parse_opts(options, clnt); 878 - if (err < 0) 1000 + err = apply_client_options(clnt, fc); 1001 + if (err) 879 1002 goto free_client; 880 1003 881 1004 if (!clnt->trans_mod) ··· 891 1014 p9_debug(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n", 892 1015 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version); 893 1016 894 - err = clnt->trans_mod->create(clnt, dev_name, options); 1017 + err = clnt->trans_mod->create(clnt, fc); 895 1018 if (err) 896 1019 goto put_trans; 897 1020
+1 -1
net/9p/mod.c
··· 16 16 #include <linux/moduleparam.h> 17 17 #include <net/9p/9p.h> 18 18 #include <linux/fs.h> 19 - #include <linux/parser.h> 20 19 #include <net/9p/client.h> 21 20 #include <net/9p/transport.h> 22 21 #include <linux/list.h> ··· 170 171 if (m) 171 172 module_put(m->owner); 172 173 } 174 + EXPORT_SYMBOL(v9fs_put_trans); 173 175 174 176 /** 175 177 * init_p9 - Initialize module
+18 -118
net/9p/trans_fd.c
··· 22 22 #include <linux/uaccess.h> 23 23 #include <linux/inet.h> 24 24 #include <linux/file.h> 25 - #include <linux/parser.h> 25 + #include <linux/fs_context.h> 26 26 #include <linux/slab.h> 27 27 #include <linux/seq_file.h> 28 28 #include <net/9p/9p.h> ··· 31 31 32 32 #include <linux/syscalls.h> /* killme */ 33 33 34 - #define P9_PORT 564 35 34 #define MAX_SOCK_BUF (1024*1024) 36 35 #define MAXPOLLWADDR 2 37 36 38 37 static struct p9_trans_module p9_tcp_trans; 39 38 static struct p9_trans_module p9_fd_trans; 40 - 41 - /** 42 - * struct p9_fd_opts - per-transport options 43 - * @rfd: file descriptor for reading (trans=fd) 44 - * @wfd: file descriptor for writing (trans=fd) 45 - * @port: port to connect to (trans=tcp) 46 - * @privport: port is privileged 47 - */ 48 - 49 - struct p9_fd_opts { 50 - int rfd; 51 - int wfd; 52 - u16 port; 53 - bool privport; 54 - }; 55 - 56 - /* 57 - * Option Parsing (code inspired by NFS code) 58 - * - a little lazy - parse all fd-transport options 59 - */ 60 - 61 - enum { 62 - /* Options that take integer arguments */ 63 - Opt_port, Opt_rfdno, Opt_wfdno, Opt_err, 64 - /* Options that take no arguments */ 65 - Opt_privport, 66 - }; 67 - 68 - static const match_table_t tokens = { 69 - {Opt_port, "port=%u"}, 70 - {Opt_rfdno, "rfdno=%u"}, 71 - {Opt_wfdno, "wfdno=%u"}, 72 - {Opt_privport, "privport"}, 73 - {Opt_err, NULL}, 74 - }; 75 39 76 40 enum { 77 41 Rworksched = 1, /* read work scheduled or running */ ··· 706 742 static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt) 707 743 { 708 744 if (clnt->trans_mod == &p9_tcp_trans) { 709 - if (clnt->trans_opts.tcp.port != P9_PORT) 745 + if (clnt->trans_opts.tcp.port != P9_FD_PORT) 710 746 seq_printf(m, ",port=%u", clnt->trans_opts.tcp.port); 711 747 } else if (clnt->trans_mod == &p9_fd_trans) { 712 748 if (clnt->trans_opts.fd.rfd != ~0) ··· 714 750 if (clnt->trans_opts.fd.wfd != ~0) 715 751 seq_printf(m, ",wfd=%u", clnt->trans_opts.fd.wfd); 716 752 } 717 - return 0; 718 - } 719 - 720 - /** 721 - * parse_opts - parse mount options into p9_fd_opts structure 722 - * @params: options string passed from mount 723 - * @opts: fd transport-specific structure to parse options into 724 - * 725 - * Returns 0 upon success, -ERRNO upon failure 726 - */ 727 - 728 - static int parse_opts(char *params, struct p9_fd_opts *opts) 729 - { 730 - char *p; 731 - substring_t args[MAX_OPT_ARGS]; 732 - int option; 733 - char *options, *tmp_options; 734 - 735 - opts->port = P9_PORT; 736 - opts->rfd = ~0; 737 - opts->wfd = ~0; 738 - opts->privport = false; 739 - 740 - if (!params) 741 - return 0; 742 - 743 - tmp_options = kstrdup(params, GFP_KERNEL); 744 - if (!tmp_options) { 745 - p9_debug(P9_DEBUG_ERROR, 746 - "failed to allocate copy of option string\n"); 747 - return -ENOMEM; 748 - } 749 - options = tmp_options; 750 - 751 - while ((p = strsep(&options, ",")) != NULL) { 752 - int token; 753 - int r; 754 - if (!*p) 755 - continue; 756 - token = match_token(p, tokens, args); 757 - if ((token != Opt_err) && (token != Opt_privport)) { 758 - r = match_int(&args[0], &option); 759 - if (r < 0) { 760 - p9_debug(P9_DEBUG_ERROR, 761 - "integer field, but no integer?\n"); 762 - continue; 763 - } 764 - } 765 - switch (token) { 766 - case Opt_port: 767 - opts->port = option; 768 - break; 769 - case Opt_rfdno: 770 - opts->rfd = option; 771 - break; 772 - case Opt_wfdno: 773 - opts->wfd = option; 774 - break; 775 - case Opt_privport: 776 - opts->privport = true; 777 - break; 778 - default: 779 - continue; 780 - } 781 - } 782 - 783 - kfree(tmp_options); 784 753 return 0; 785 754 } 786 755 ··· 871 974 } 872 975 873 976 static int 874 - p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) 977 + p9_fd_create_tcp(struct p9_client *client, struct fs_context *fc) 875 978 { 979 + const char *addr = fc->source; 980 + struct v9fs_context *ctx = fc->fs_private; 876 981 int err; 877 982 char port_str[6]; 878 983 struct socket *csocket; 879 984 struct sockaddr_storage stor = { 0 }; 880 985 struct p9_fd_opts opts; 881 986 882 - err = parse_opts(args, &opts); 883 - if (err < 0) 884 - return err; 987 + /* opts are already parsed in context */ 988 + opts = ctx->fd_opts; 885 989 886 990 if (!addr) 887 991 return -EINVAL; ··· 929 1031 } 930 1032 931 1033 static int 932 - p9_fd_create_unix(struct p9_client *client, const char *addr, char *args) 1034 + p9_fd_create_unix(struct p9_client *client, struct fs_context *fc) 933 1035 { 1036 + const char *addr = fc->source; 934 1037 int err; 935 1038 struct socket *csocket; 936 1039 struct sockaddr_un sun_server; ··· 970 1071 } 971 1072 972 1073 static int 973 - p9_fd_create(struct p9_client *client, const char *addr, char *args) 1074 + p9_fd_create(struct p9_client *client, struct fs_context *fc) 974 1075 { 1076 + struct v9fs_context *ctx = fc->fs_private; 1077 + struct p9_fd_opts opts = ctx->fd_opts; 975 1078 int err; 976 - struct p9_fd_opts opts; 977 1079 978 - err = parse_opts(args, &opts); 979 - if (err < 0) 980 - return err; 981 1080 client->trans_opts.fd.rfd = opts.rfd; 982 1081 client->trans_opts.fd.wfd = opts.wfd; 983 1082 ··· 997 1100 .name = "tcp", 998 1101 .maxsize = MAX_SOCK_BUF, 999 1102 .pooled_rbuffers = false, 1000 - .def = 0, 1103 + .def = false, 1104 + .supports_vmalloc = true, 1001 1105 .create = p9_fd_create_tcp, 1002 1106 .close = p9_fd_close, 1003 1107 .request = p9_fd_request, ··· 1012 1114 static struct p9_trans_module p9_unix_trans = { 1013 1115 .name = "unix", 1014 1116 .maxsize = MAX_SOCK_BUF, 1015 - .def = 0, 1117 + .def = false, 1118 + .supports_vmalloc = true, 1016 1119 .create = p9_fd_create_unix, 1017 1120 .close = p9_fd_close, 1018 1121 .request = p9_fd_request, ··· 1027 1128 static struct p9_trans_module p9_fd_trans = { 1028 1129 .name = "fd", 1029 1130 .maxsize = MAX_SOCK_BUF, 1030 - .def = 0, 1131 + .def = false, 1132 + .supports_vmalloc = true, 1031 1133 .create = p9_fd_create, 1032 1134 .close = p9_fd_close, 1033 1135 .request = p9_fd_request,
+11 -123
net/9p/trans_rdma.c
··· 22 22 #include <linux/uaccess.h> 23 23 #include <linux/inet.h> 24 24 #include <linux/file.h> 25 - #include <linux/parser.h> 25 + #include <linux/fs_context.h> 26 26 #include <linux/semaphore.h> 27 27 #include <linux/slab.h> 28 28 #include <linux/seq_file.h> ··· 32 32 #include <rdma/ib_verbs.h> 33 33 #include <rdma/rdma_cm.h> 34 34 35 - #define P9_PORT 5640 36 - #define P9_RDMA_SQ_DEPTH 32 37 - #define P9_RDMA_RQ_DEPTH 32 38 35 #define P9_RDMA_SEND_SGE 4 39 36 #define P9_RDMA_RECV_SGE 4 40 37 #define P9_RDMA_IRD 0 41 38 #define P9_RDMA_ORD 0 42 - #define P9_RDMA_TIMEOUT 30000 /* 30 seconds */ 43 39 #define P9_RDMA_MAXSIZE (1024*1024) /* 1MB */ 44 40 45 41 /** ··· 106 110 }; 107 111 }; 108 112 109 - /** 110 - * struct p9_rdma_opts - Collection of mount options 111 - * @port: port of connection 112 - * @privport: Whether a privileged port may be used 113 - * @sq_depth: The requested depth of the SQ. This really doesn't need 114 - * to be any deeper than the number of threads used in the client 115 - * @rq_depth: The depth of the RQ. Should be greater than or equal to SQ depth 116 - * @timeout: Time to wait in msecs for CM events 117 - */ 118 - struct p9_rdma_opts { 119 - short port; 120 - bool privport; 121 - int sq_depth; 122 - int rq_depth; 123 - long timeout; 124 - }; 125 - 126 - /* 127 - * Option Parsing (code inspired by NFS code) 128 - */ 129 - enum { 130 - /* Options that take integer arguments */ 131 - Opt_port, Opt_rq_depth, Opt_sq_depth, Opt_timeout, 132 - /* Options that take no argument */ 133 - Opt_privport, 134 - Opt_err, 135 - }; 136 - 137 - static match_table_t tokens = { 138 - {Opt_port, "port=%u"}, 139 - {Opt_sq_depth, "sq=%u"}, 140 - {Opt_rq_depth, "rq=%u"}, 141 - {Opt_timeout, "timeout=%u"}, 142 - {Opt_privport, "privport"}, 143 - {Opt_err, NULL}, 144 - }; 145 - 146 113 static int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt) 147 114 { 148 115 struct p9_trans_rdma *rdma = clnt->trans; 149 116 150 - if (rdma->port != P9_PORT) 117 + if (rdma->port != P9_RDMA_PORT) 151 118 seq_printf(m, ",port=%u", rdma->port); 152 119 if (rdma->sq_depth != P9_RDMA_SQ_DEPTH) 153 120 seq_printf(m, ",sq=%u", rdma->sq_depth); ··· 120 161 seq_printf(m, ",timeout=%lu", rdma->timeout); 121 162 if (rdma->privport) 122 163 seq_puts(m, ",privport"); 123 - return 0; 124 - } 125 - 126 - /** 127 - * parse_opts - parse mount options into rdma options structure 128 - * @params: options string passed from mount 129 - * @opts: rdma transport-specific structure to parse options into 130 - * 131 - * Returns 0 upon success, -ERRNO upon failure 132 - */ 133 - static int parse_opts(char *params, struct p9_rdma_opts *opts) 134 - { 135 - char *p; 136 - substring_t args[MAX_OPT_ARGS]; 137 - int option; 138 - char *options, *tmp_options; 139 - 140 - opts->port = P9_PORT; 141 - opts->sq_depth = P9_RDMA_SQ_DEPTH; 142 - opts->rq_depth = P9_RDMA_RQ_DEPTH; 143 - opts->timeout = P9_RDMA_TIMEOUT; 144 - opts->privport = false; 145 - 146 - if (!params) 147 - return 0; 148 - 149 - tmp_options = kstrdup(params, GFP_KERNEL); 150 - if (!tmp_options) { 151 - p9_debug(P9_DEBUG_ERROR, 152 - "failed to allocate copy of option string\n"); 153 - return -ENOMEM; 154 - } 155 - options = tmp_options; 156 - 157 - while ((p = strsep(&options, ",")) != NULL) { 158 - int token; 159 - int r; 160 - if (!*p) 161 - continue; 162 - token = match_token(p, tokens, args); 163 - if ((token != Opt_err) && (token != Opt_privport)) { 164 - r = match_int(&args[0], &option); 165 - if (r < 0) { 166 - p9_debug(P9_DEBUG_ERROR, 167 - "integer field, but no integer?\n"); 168 - continue; 169 - } 170 - } 171 - switch (token) { 172 - case Opt_port: 173 - opts->port = option; 174 - break; 175 - case Opt_sq_depth: 176 - opts->sq_depth = option; 177 - break; 178 - case Opt_rq_depth: 179 - opts->rq_depth = option; 180 - break; 181 - case Opt_timeout: 182 - opts->timeout = option; 183 - break; 184 - case Opt_privport: 185 - opts->privport = true; 186 - break; 187 - default: 188 - continue; 189 - } 190 - } 191 - /* RQ must be at least as large as the SQ */ 192 - opts->rq_depth = max(opts->rq_depth, opts->sq_depth); 193 - kfree(tmp_options); 194 164 return 0; 195 165 } 196 166 ··· 516 628 /** 517 629 * rdma_create_trans - Transport method for creating a transport instance 518 630 * @client: client instance 519 - * @addr: IP address string 520 - * @args: Mount options string 631 + * @fc: The filesystem context 521 632 */ 522 633 static int 523 - rdma_create_trans(struct p9_client *client, const char *addr, char *args) 634 + rdma_create_trans(struct p9_client *client, struct fs_context *fc) 524 635 { 636 + const char *addr = fc->source; 637 + struct v9fs_context *ctx = fc->fs_private; 638 + struct p9_rdma_opts opts = ctx->rdma_opts; 525 639 int err; 526 - struct p9_rdma_opts opts; 527 640 struct p9_trans_rdma *rdma; 528 641 struct rdma_conn_param conn_param; 529 642 struct ib_qp_init_attr qp_attr; ··· 532 643 if (addr == NULL) 533 644 return -EINVAL; 534 645 535 - /* Parse the transport specific mount options */ 536 - err = parse_opts(args, &opts); 537 - if (err < 0) 538 - return err; 646 + /* options are already parsed, in the fs context */ 647 + opts = ctx->rdma_opts; 539 648 540 649 /* Create and initialize the RDMA transport structure */ 541 650 rdma = alloc_rdma(&opts); ··· 635 748 .name = "rdma", 636 749 .maxsize = P9_RDMA_MAXSIZE, 637 750 .pooled_rbuffers = true, 638 - .def = 0, 751 + .def = false, 752 + .supports_vmalloc = false, 639 753 .owner = THIS_MODULE, 640 754 .create = rdma_create_trans, 641 755 .close = rdma_close,
+4 -1
net/9p/trans_usbg.c
··· 27 27 #include <linux/cleanup.h> 28 28 #include <linux/kernel.h> 29 29 #include <linux/module.h> 30 + #include <linux/fs_context.h> 30 31 #include <linux/usb/composite.h> 31 32 #include <linux/usb/func_utils.h> 32 33 ··· 377 376 return ret; 378 377 } 379 378 380 - static int p9_usbg_create(struct p9_client *client, const char *devname, char *args) 379 + static int p9_usbg_create(struct p9_client *client, struct fs_context *fc) 381 380 { 381 + const char *devname = fc->source; 382 382 struct f_usb9pfs_dev *dev; 383 383 struct f_usb9pfs *usb9pfs; 384 384 int ret = -ENOENT; ··· 516 514 .close = p9_usbg_close, 517 515 .request = p9_usbg_request, 518 516 .cancel = p9_usbg_cancel, 517 + .supports_vmalloc = false, 519 518 .owner = THIS_MODULE, 520 519 }; 521 520
+6 -5
net/9p/trans_virtio.c
··· 26 26 #include <linux/highmem.h> 27 27 #include <linux/slab.h> 28 28 #include <net/9p/9p.h> 29 - #include <linux/parser.h> 29 + #include <linux/fs_context.h> 30 30 #include <net/9p/client.h> 31 31 #include <net/9p/transport.h> 32 32 #include <linux/scatterlist.h> ··· 679 679 /** 680 680 * p9_virtio_create - allocate a new virtio channel 681 681 * @client: client instance invoking this transport 682 - * @devname: string identifying the channel to connect to (unused) 683 - * @args: args passed from sys_mount() for per-transport options (unused) 682 + * @fc: the filesystem context 684 683 * 685 684 * This sets up a transport channel for 9p communication. Right now 686 685 * we only match the first available channel, but eventually we could look up ··· 690 691 */ 691 692 692 693 static int 693 - p9_virtio_create(struct p9_client *client, const char *devname, char *args) 694 + p9_virtio_create(struct p9_client *client, struct fs_context *fc) 694 695 { 696 + const char *devname = fc->source; 695 697 struct virtio_chan *chan; 696 698 int ret = -ENOENT; 697 699 int found = 0; ··· 802 802 */ 803 803 .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3), 804 804 .pooled_rbuffers = false, 805 - .def = 1, 805 + .def = true, 806 + .supports_vmalloc = false, 806 807 .owner = THIS_MODULE, 807 808 }; 808 809
+5 -2
net/9p/trans_xen.c
··· 15 15 16 16 #include <linux/module.h> 17 17 #include <linux/spinlock.h> 18 + #include <linux/fs_context.h> 18 19 #include <net/9p/9p.h> 19 20 #include <net/9p/client.h> 20 21 #include <net/9p/transport.h> ··· 67 66 return 1; 68 67 } 69 68 70 - static int p9_xen_create(struct p9_client *client, const char *addr, char *args) 69 + static int p9_xen_create(struct p9_client *client, struct fs_context *fc) 71 70 { 71 + const char *addr = fc->source; 72 72 struct xen_9pfs_front_priv *priv; 73 73 74 74 if (addr == NULL) ··· 259 257 .name = "xen", 260 258 .maxsize = 1 << (XEN_9PFS_RING_ORDER + XEN_PAGE_SHIFT - 2), 261 259 .pooled_rbuffers = false, 262 - .def = 1, 260 + .def = true, 261 + .supports_vmalloc = false, 263 262 .create = p9_xen_create, 264 263 .close = p9_xen_close, 265 264 .request = p9_xen_request,