162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Copyright (C) 2020, Microsoft Corporation.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *   Author(s): Steve French <stfrench@microsoft.com>
662306a36Sopenharmony_ci *              David Howells <dhowells@redhat.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/nsproxy.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/magic.h>
1462306a36Sopenharmony_ci#include <linux/security.h>
1562306a36Sopenharmony_ci#include <net/net_namespace.h>
1662306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL
1762306a36Sopenharmony_ci#include "dfs_cache.h"
1862306a36Sopenharmony_ci#endif
1962306a36Sopenharmony_ci*/
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/ctype.h>
2262306a36Sopenharmony_ci#include <linux/fs_context.h>
2362306a36Sopenharmony_ci#include <linux/fs_parser.h>
2462306a36Sopenharmony_ci#include <linux/fs.h>
2562306a36Sopenharmony_ci#include <linux/mount.h>
2662306a36Sopenharmony_ci#include <linux/parser.h>
2762306a36Sopenharmony_ci#include <linux/utsname.h>
2862306a36Sopenharmony_ci#include "cifsfs.h"
2962306a36Sopenharmony_ci#include "cifspdu.h"
3062306a36Sopenharmony_ci#include "cifsglob.h"
3162306a36Sopenharmony_ci#include "cifsproto.h"
3262306a36Sopenharmony_ci#include "cifs_unicode.h"
3362306a36Sopenharmony_ci#include "cifs_debug.h"
3462306a36Sopenharmony_ci#include "cifs_fs_sb.h"
3562306a36Sopenharmony_ci#include "ntlmssp.h"
3662306a36Sopenharmony_ci#include "nterr.h"
3762306a36Sopenharmony_ci#include "rfc1002pdu.h"
3862306a36Sopenharmony_ci#include "fs_context.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic DEFINE_MUTEX(cifs_mount_mutex);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic const match_table_t cifs_smb_version_tokens = {
4362306a36Sopenharmony_ci	{ Smb_1, SMB1_VERSION_STRING },
4462306a36Sopenharmony_ci	{ Smb_20, SMB20_VERSION_STRING},
4562306a36Sopenharmony_ci	{ Smb_21, SMB21_VERSION_STRING },
4662306a36Sopenharmony_ci	{ Smb_30, SMB30_VERSION_STRING },
4762306a36Sopenharmony_ci	{ Smb_302, SMB302_VERSION_STRING },
4862306a36Sopenharmony_ci	{ Smb_302, ALT_SMB302_VERSION_STRING },
4962306a36Sopenharmony_ci	{ Smb_311, SMB311_VERSION_STRING },
5062306a36Sopenharmony_ci	{ Smb_311, ALT_SMB311_VERSION_STRING },
5162306a36Sopenharmony_ci	{ Smb_3any, SMB3ANY_VERSION_STRING },
5262306a36Sopenharmony_ci	{ Smb_default, SMBDEFAULT_VERSION_STRING },
5362306a36Sopenharmony_ci	{ Smb_version_err, NULL }
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic const match_table_t cifs_secflavor_tokens = {
5762306a36Sopenharmony_ci	{ Opt_sec_krb5, "krb5" },
5862306a36Sopenharmony_ci	{ Opt_sec_krb5i, "krb5i" },
5962306a36Sopenharmony_ci	{ Opt_sec_krb5p, "krb5p" },
6062306a36Sopenharmony_ci	{ Opt_sec_ntlmsspi, "ntlmsspi" },
6162306a36Sopenharmony_ci	{ Opt_sec_ntlmssp, "ntlmssp" },
6262306a36Sopenharmony_ci	{ Opt_sec_ntlmv2, "nontlm" },
6362306a36Sopenharmony_ci	{ Opt_sec_ntlmv2, "ntlmv2" },
6462306a36Sopenharmony_ci	{ Opt_sec_ntlmv2i, "ntlmv2i" },
6562306a36Sopenharmony_ci	{ Opt_sec_none, "none" },
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	{ Opt_sec_err, NULL }
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciconst struct fs_parameter_spec smb3_fs_parameters[] = {
7162306a36Sopenharmony_ci	/* Mount options that take no arguments */
7262306a36Sopenharmony_ci	fsparam_flag_no("user_xattr", Opt_user_xattr),
7362306a36Sopenharmony_ci	fsparam_flag_no("forceuid", Opt_forceuid),
7462306a36Sopenharmony_ci	fsparam_flag_no("multichannel", Opt_multichannel),
7562306a36Sopenharmony_ci	fsparam_flag_no("forcegid", Opt_forcegid),
7662306a36Sopenharmony_ci	fsparam_flag("noblocksend", Opt_noblocksend),
7762306a36Sopenharmony_ci	fsparam_flag("noautotune", Opt_noautotune),
7862306a36Sopenharmony_ci	fsparam_flag("nolease", Opt_nolease),
7962306a36Sopenharmony_ci	fsparam_flag_no("hard", Opt_hard),
8062306a36Sopenharmony_ci	fsparam_flag_no("soft", Opt_soft),
8162306a36Sopenharmony_ci	fsparam_flag_no("perm", Opt_perm),
8262306a36Sopenharmony_ci	fsparam_flag("nodelete", Opt_nodelete),
8362306a36Sopenharmony_ci	fsparam_flag_no("mapposix", Opt_mapposix),
8462306a36Sopenharmony_ci	fsparam_flag("mapchars", Opt_mapchars),
8562306a36Sopenharmony_ci	fsparam_flag("nomapchars", Opt_nomapchars),
8662306a36Sopenharmony_ci	fsparam_flag_no("sfu", Opt_sfu),
8762306a36Sopenharmony_ci	fsparam_flag("nodfs", Opt_nodfs),
8862306a36Sopenharmony_ci	fsparam_flag_no("posixpaths", Opt_posixpaths),
8962306a36Sopenharmony_ci	fsparam_flag_no("unix", Opt_unix),
9062306a36Sopenharmony_ci	fsparam_flag_no("linux", Opt_unix),
9162306a36Sopenharmony_ci	fsparam_flag_no("posix", Opt_unix),
9262306a36Sopenharmony_ci	fsparam_flag("nocase", Opt_nocase),
9362306a36Sopenharmony_ci	fsparam_flag("ignorecase", Opt_nocase),
9462306a36Sopenharmony_ci	fsparam_flag_no("brl", Opt_brl),
9562306a36Sopenharmony_ci	fsparam_flag_no("handlecache", Opt_handlecache),
9662306a36Sopenharmony_ci	fsparam_flag("forcemandatorylock", Opt_forcemandatorylock),
9762306a36Sopenharmony_ci	fsparam_flag("forcemand", Opt_forcemandatorylock),
9862306a36Sopenharmony_ci	fsparam_flag("setuidfromacl", Opt_setuidfromacl),
9962306a36Sopenharmony_ci	fsparam_flag("idsfromsid", Opt_setuidfromacl),
10062306a36Sopenharmony_ci	fsparam_flag_no("setuids", Opt_setuids),
10162306a36Sopenharmony_ci	fsparam_flag_no("dynperm", Opt_dynperm),
10262306a36Sopenharmony_ci	fsparam_flag_no("intr", Opt_intr),
10362306a36Sopenharmony_ci	fsparam_flag_no("strictsync", Opt_strictsync),
10462306a36Sopenharmony_ci	fsparam_flag_no("serverino", Opt_serverino),
10562306a36Sopenharmony_ci	fsparam_flag("rwpidforward", Opt_rwpidforward),
10662306a36Sopenharmony_ci	fsparam_flag("cifsacl", Opt_cifsacl),
10762306a36Sopenharmony_ci	fsparam_flag_no("acl", Opt_acl),
10862306a36Sopenharmony_ci	fsparam_flag("locallease", Opt_locallease),
10962306a36Sopenharmony_ci	fsparam_flag("sign", Opt_sign),
11062306a36Sopenharmony_ci	fsparam_flag("ignore_signature", Opt_ignore_signature),
11162306a36Sopenharmony_ci	fsparam_flag("signloosely", Opt_ignore_signature),
11262306a36Sopenharmony_ci	fsparam_flag("seal", Opt_seal),
11362306a36Sopenharmony_ci	fsparam_flag("noac", Opt_noac),
11462306a36Sopenharmony_ci	fsparam_flag("fsc", Opt_fsc),
11562306a36Sopenharmony_ci	fsparam_flag("mfsymlinks", Opt_mfsymlinks),
11662306a36Sopenharmony_ci	fsparam_flag("multiuser", Opt_multiuser),
11762306a36Sopenharmony_ci	fsparam_flag("sloppy", Opt_sloppy),
11862306a36Sopenharmony_ci	fsparam_flag("nosharesock", Opt_nosharesock),
11962306a36Sopenharmony_ci	fsparam_flag_no("persistenthandles", Opt_persistent),
12062306a36Sopenharmony_ci	fsparam_flag_no("resilienthandles", Opt_resilient),
12162306a36Sopenharmony_ci	fsparam_flag_no("tcpnodelay", Opt_tcp_nodelay),
12262306a36Sopenharmony_ci	fsparam_flag("nosparse", Opt_nosparse),
12362306a36Sopenharmony_ci	fsparam_flag("domainauto", Opt_domainauto),
12462306a36Sopenharmony_ci	fsparam_flag("rdma", Opt_rdma),
12562306a36Sopenharmony_ci	fsparam_flag("modesid", Opt_modesid),
12662306a36Sopenharmony_ci	fsparam_flag("modefromsid", Opt_modesid),
12762306a36Sopenharmony_ci	fsparam_flag("rootfs", Opt_rootfs),
12862306a36Sopenharmony_ci	fsparam_flag("compress", Opt_compress),
12962306a36Sopenharmony_ci	fsparam_flag("witness", Opt_witness),
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* Mount options which take numeric value */
13262306a36Sopenharmony_ci	fsparam_u32("backupuid", Opt_backupuid),
13362306a36Sopenharmony_ci	fsparam_u32("backupgid", Opt_backupgid),
13462306a36Sopenharmony_ci	fsparam_u32("uid", Opt_uid),
13562306a36Sopenharmony_ci	fsparam_u32("cruid", Opt_cruid),
13662306a36Sopenharmony_ci	fsparam_u32("gid", Opt_gid),
13762306a36Sopenharmony_ci	fsparam_u32("file_mode", Opt_file_mode),
13862306a36Sopenharmony_ci	fsparam_u32("dirmode", Opt_dirmode),
13962306a36Sopenharmony_ci	fsparam_u32("dir_mode", Opt_dirmode),
14062306a36Sopenharmony_ci	fsparam_u32("port", Opt_port),
14162306a36Sopenharmony_ci	fsparam_u32("min_enc_offload", Opt_min_enc_offload),
14262306a36Sopenharmony_ci	fsparam_u32("esize", Opt_min_enc_offload),
14362306a36Sopenharmony_ci	fsparam_u32("bsize", Opt_blocksize),
14462306a36Sopenharmony_ci	fsparam_u32("rasize", Opt_rasize),
14562306a36Sopenharmony_ci	fsparam_u32("rsize", Opt_rsize),
14662306a36Sopenharmony_ci	fsparam_u32("wsize", Opt_wsize),
14762306a36Sopenharmony_ci	fsparam_u32("actimeo", Opt_actimeo),
14862306a36Sopenharmony_ci	fsparam_u32("acdirmax", Opt_acdirmax),
14962306a36Sopenharmony_ci	fsparam_u32("acregmax", Opt_acregmax),
15062306a36Sopenharmony_ci	fsparam_u32("closetimeo", Opt_closetimeo),
15162306a36Sopenharmony_ci	fsparam_u32("echo_interval", Opt_echo_interval),
15262306a36Sopenharmony_ci	fsparam_u32("max_credits", Opt_max_credits),
15362306a36Sopenharmony_ci	fsparam_u32("max_cached_dirs", Opt_max_cached_dirs),
15462306a36Sopenharmony_ci	fsparam_u32("handletimeout", Opt_handletimeout),
15562306a36Sopenharmony_ci	fsparam_u64("snapshot", Opt_snapshot),
15662306a36Sopenharmony_ci	fsparam_u32("max_channels", Opt_max_channels),
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* Mount options which take string value */
15962306a36Sopenharmony_ci	fsparam_string("source", Opt_source),
16062306a36Sopenharmony_ci	fsparam_string("user", Opt_user),
16162306a36Sopenharmony_ci	fsparam_string("username", Opt_user),
16262306a36Sopenharmony_ci	fsparam_string("pass", Opt_pass),
16362306a36Sopenharmony_ci	fsparam_string("password", Opt_pass),
16462306a36Sopenharmony_ci	fsparam_string("ip", Opt_ip),
16562306a36Sopenharmony_ci	fsparam_string("addr", Opt_ip),
16662306a36Sopenharmony_ci	fsparam_string("domain", Opt_domain),
16762306a36Sopenharmony_ci	fsparam_string("dom", Opt_domain),
16862306a36Sopenharmony_ci	fsparam_string("srcaddr", Opt_srcaddr),
16962306a36Sopenharmony_ci	fsparam_string("iocharset", Opt_iocharset),
17062306a36Sopenharmony_ci	fsparam_string("netbiosname", Opt_netbiosname),
17162306a36Sopenharmony_ci	fsparam_string("servern", Opt_servern),
17262306a36Sopenharmony_ci	fsparam_string("ver", Opt_ver),
17362306a36Sopenharmony_ci	fsparam_string("vers", Opt_vers),
17462306a36Sopenharmony_ci	fsparam_string("sec", Opt_sec),
17562306a36Sopenharmony_ci	fsparam_string("cache", Opt_cache),
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* Arguments that should be ignored */
17862306a36Sopenharmony_ci	fsparam_flag("guest", Opt_ignore),
17962306a36Sopenharmony_ci	fsparam_flag("noatime", Opt_ignore),
18062306a36Sopenharmony_ci	fsparam_flag("relatime", Opt_ignore),
18162306a36Sopenharmony_ci	fsparam_flag("_netdev", Opt_ignore),
18262306a36Sopenharmony_ci	fsparam_flag_no("suid", Opt_ignore),
18362306a36Sopenharmony_ci	fsparam_flag_no("exec", Opt_ignore),
18462306a36Sopenharmony_ci	fsparam_flag_no("dev", Opt_ignore),
18562306a36Sopenharmony_ci	fsparam_flag_no("mand", Opt_ignore),
18662306a36Sopenharmony_ci	fsparam_flag_no("auto", Opt_ignore),
18762306a36Sopenharmony_ci	fsparam_string("cred", Opt_ignore),
18862306a36Sopenharmony_ci	fsparam_string("credentials", Opt_ignore),
18962306a36Sopenharmony_ci	/*
19062306a36Sopenharmony_ci	 * UNC and prefixpath is now extracted from Opt_source
19162306a36Sopenharmony_ci	 * in the new mount API so we can just ignore them going forward.
19262306a36Sopenharmony_ci	 */
19362306a36Sopenharmony_ci	fsparam_string("unc", Opt_ignore),
19462306a36Sopenharmony_ci	fsparam_string("prefixpath", Opt_ignore),
19562306a36Sopenharmony_ci	{}
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int
19962306a36Sopenharmony_cicifs_parse_security_flavors(struct fs_context *fc, char *value, struct smb3_fs_context *ctx)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	substring_t args[MAX_OPT_ARGS];
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/*
20562306a36Sopenharmony_ci	 * With mount options, the last one should win. Reset any existing
20662306a36Sopenharmony_ci	 * settings back to default.
20762306a36Sopenharmony_ci	 */
20862306a36Sopenharmony_ci	ctx->sectype = Unspecified;
20962306a36Sopenharmony_ci	ctx->sign = false;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	switch (match_token(value, cifs_secflavor_tokens, args)) {
21262306a36Sopenharmony_ci	case Opt_sec_krb5p:
21362306a36Sopenharmony_ci		cifs_errorf(fc, "sec=krb5p is not supported. Use sec=krb5,seal instead\n");
21462306a36Sopenharmony_ci		return 1;
21562306a36Sopenharmony_ci	case Opt_sec_krb5i:
21662306a36Sopenharmony_ci		ctx->sign = true;
21762306a36Sopenharmony_ci		fallthrough;
21862306a36Sopenharmony_ci	case Opt_sec_krb5:
21962306a36Sopenharmony_ci		ctx->sectype = Kerberos;
22062306a36Sopenharmony_ci		break;
22162306a36Sopenharmony_ci	case Opt_sec_ntlmsspi:
22262306a36Sopenharmony_ci		ctx->sign = true;
22362306a36Sopenharmony_ci		fallthrough;
22462306a36Sopenharmony_ci	case Opt_sec_ntlmssp:
22562306a36Sopenharmony_ci		ctx->sectype = RawNTLMSSP;
22662306a36Sopenharmony_ci		break;
22762306a36Sopenharmony_ci	case Opt_sec_ntlmv2i:
22862306a36Sopenharmony_ci		ctx->sign = true;
22962306a36Sopenharmony_ci		fallthrough;
23062306a36Sopenharmony_ci	case Opt_sec_ntlmv2:
23162306a36Sopenharmony_ci		ctx->sectype = NTLMv2;
23262306a36Sopenharmony_ci		break;
23362306a36Sopenharmony_ci	case Opt_sec_none:
23462306a36Sopenharmony_ci		ctx->nullauth = 1;
23562306a36Sopenharmony_ci		kfree(ctx->username);
23662306a36Sopenharmony_ci		ctx->username = NULL;
23762306a36Sopenharmony_ci		break;
23862306a36Sopenharmony_ci	default:
23962306a36Sopenharmony_ci		cifs_errorf(fc, "bad security option: %s\n", value);
24062306a36Sopenharmony_ci		return 1;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return 0;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic const match_table_t cifs_cacheflavor_tokens = {
24762306a36Sopenharmony_ci	{ Opt_cache_loose, "loose" },
24862306a36Sopenharmony_ci	{ Opt_cache_strict, "strict" },
24962306a36Sopenharmony_ci	{ Opt_cache_none, "none" },
25062306a36Sopenharmony_ci	{ Opt_cache_ro, "ro" },
25162306a36Sopenharmony_ci	{ Opt_cache_rw, "singleclient" },
25262306a36Sopenharmony_ci	{ Opt_cache_err, NULL }
25362306a36Sopenharmony_ci};
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic int
25662306a36Sopenharmony_cicifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_context *ctx)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	substring_t args[MAX_OPT_ARGS];
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	switch (match_token(value, cifs_cacheflavor_tokens, args)) {
26162306a36Sopenharmony_ci	case Opt_cache_loose:
26262306a36Sopenharmony_ci		ctx->direct_io = false;
26362306a36Sopenharmony_ci		ctx->strict_io = false;
26462306a36Sopenharmony_ci		ctx->cache_ro = false;
26562306a36Sopenharmony_ci		ctx->cache_rw = false;
26662306a36Sopenharmony_ci		break;
26762306a36Sopenharmony_ci	case Opt_cache_strict:
26862306a36Sopenharmony_ci		ctx->direct_io = false;
26962306a36Sopenharmony_ci		ctx->strict_io = true;
27062306a36Sopenharmony_ci		ctx->cache_ro = false;
27162306a36Sopenharmony_ci		ctx->cache_rw = false;
27262306a36Sopenharmony_ci		break;
27362306a36Sopenharmony_ci	case Opt_cache_none:
27462306a36Sopenharmony_ci		ctx->direct_io = true;
27562306a36Sopenharmony_ci		ctx->strict_io = false;
27662306a36Sopenharmony_ci		ctx->cache_ro = false;
27762306a36Sopenharmony_ci		ctx->cache_rw = false;
27862306a36Sopenharmony_ci		break;
27962306a36Sopenharmony_ci	case Opt_cache_ro:
28062306a36Sopenharmony_ci		ctx->direct_io = false;
28162306a36Sopenharmony_ci		ctx->strict_io = false;
28262306a36Sopenharmony_ci		ctx->cache_ro = true;
28362306a36Sopenharmony_ci		ctx->cache_rw = false;
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	case Opt_cache_rw:
28662306a36Sopenharmony_ci		ctx->direct_io = false;
28762306a36Sopenharmony_ci		ctx->strict_io = false;
28862306a36Sopenharmony_ci		ctx->cache_ro = false;
28962306a36Sopenharmony_ci		ctx->cache_rw = true;
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	default:
29262306a36Sopenharmony_ci		cifs_errorf(fc, "bad cache= option: %s\n", value);
29362306a36Sopenharmony_ci		return 1;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci	return 0;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci#define DUP_CTX_STR(field)						\
29962306a36Sopenharmony_cido {									\
30062306a36Sopenharmony_ci	if (ctx->field) {						\
30162306a36Sopenharmony_ci		new_ctx->field = kstrdup(ctx->field, GFP_ATOMIC);	\
30262306a36Sopenharmony_ci		if (new_ctx->field == NULL) {				\
30362306a36Sopenharmony_ci			smb3_cleanup_fs_context_contents(new_ctx);	\
30462306a36Sopenharmony_ci			return -ENOMEM;					\
30562306a36Sopenharmony_ci		}							\
30662306a36Sopenharmony_ci	}								\
30762306a36Sopenharmony_ci} while (0)
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciint
31062306a36Sopenharmony_cismb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	memcpy(new_ctx, ctx, sizeof(*ctx));
31362306a36Sopenharmony_ci	new_ctx->prepath = NULL;
31462306a36Sopenharmony_ci	new_ctx->nodename = NULL;
31562306a36Sopenharmony_ci	new_ctx->username = NULL;
31662306a36Sopenharmony_ci	new_ctx->password = NULL;
31762306a36Sopenharmony_ci	new_ctx->server_hostname = NULL;
31862306a36Sopenharmony_ci	new_ctx->domainname = NULL;
31962306a36Sopenharmony_ci	new_ctx->UNC = NULL;
32062306a36Sopenharmony_ci	new_ctx->source = NULL;
32162306a36Sopenharmony_ci	new_ctx->iocharset = NULL;
32262306a36Sopenharmony_ci	new_ctx->leaf_fullpath = NULL;
32362306a36Sopenharmony_ci	/*
32462306a36Sopenharmony_ci	 * Make sure to stay in sync with smb3_cleanup_fs_context_contents()
32562306a36Sopenharmony_ci	 */
32662306a36Sopenharmony_ci	DUP_CTX_STR(prepath);
32762306a36Sopenharmony_ci	DUP_CTX_STR(username);
32862306a36Sopenharmony_ci	DUP_CTX_STR(password);
32962306a36Sopenharmony_ci	DUP_CTX_STR(server_hostname);
33062306a36Sopenharmony_ci	DUP_CTX_STR(UNC);
33162306a36Sopenharmony_ci	DUP_CTX_STR(source);
33262306a36Sopenharmony_ci	DUP_CTX_STR(domainname);
33362306a36Sopenharmony_ci	DUP_CTX_STR(nodename);
33462306a36Sopenharmony_ci	DUP_CTX_STR(iocharset);
33562306a36Sopenharmony_ci	DUP_CTX_STR(leaf_fullpath);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return 0;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int
34162306a36Sopenharmony_cicifs_parse_smb_version(struct fs_context *fc, char *value, struct smb3_fs_context *ctx, bool is_smb3)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	substring_t args[MAX_OPT_ARGS];
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	switch (match_token(value, cifs_smb_version_tokens, args)) {
34662306a36Sopenharmony_ci#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
34762306a36Sopenharmony_ci	case Smb_1:
34862306a36Sopenharmony_ci		if (disable_legacy_dialects) {
34962306a36Sopenharmony_ci			cifs_errorf(fc, "mount with legacy dialect disabled\n");
35062306a36Sopenharmony_ci			return 1;
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci		if (is_smb3) {
35362306a36Sopenharmony_ci			cifs_errorf(fc, "vers=1.0 (cifs) not permitted when mounting with smb3\n");
35462306a36Sopenharmony_ci			return 1;
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci		cifs_errorf(fc, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n");
35762306a36Sopenharmony_ci		ctx->ops = &smb1_operations;
35862306a36Sopenharmony_ci		ctx->vals = &smb1_values;
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci	case Smb_20:
36162306a36Sopenharmony_ci		if (disable_legacy_dialects) {
36262306a36Sopenharmony_ci			cifs_errorf(fc, "mount with legacy dialect disabled\n");
36362306a36Sopenharmony_ci			return 1;
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci		if (is_smb3) {
36662306a36Sopenharmony_ci			cifs_errorf(fc, "vers=2.0 not permitted when mounting with smb3\n");
36762306a36Sopenharmony_ci			return 1;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci		ctx->ops = &smb20_operations;
37062306a36Sopenharmony_ci		ctx->vals = &smb20_values;
37162306a36Sopenharmony_ci		break;
37262306a36Sopenharmony_ci#else
37362306a36Sopenharmony_ci	case Smb_1:
37462306a36Sopenharmony_ci		cifs_errorf(fc, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n");
37562306a36Sopenharmony_ci		return 1;
37662306a36Sopenharmony_ci	case Smb_20:
37762306a36Sopenharmony_ci		cifs_errorf(fc, "vers=2.0 mount not permitted when legacy dialects disabled\n");
37862306a36Sopenharmony_ci		return 1;
37962306a36Sopenharmony_ci#endif /* CIFS_ALLOW_INSECURE_LEGACY */
38062306a36Sopenharmony_ci	case Smb_21:
38162306a36Sopenharmony_ci		ctx->ops = &smb21_operations;
38262306a36Sopenharmony_ci		ctx->vals = &smb21_values;
38362306a36Sopenharmony_ci		break;
38462306a36Sopenharmony_ci	case Smb_30:
38562306a36Sopenharmony_ci		ctx->ops = &smb30_operations;
38662306a36Sopenharmony_ci		ctx->vals = &smb30_values;
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci	case Smb_302:
38962306a36Sopenharmony_ci		ctx->ops = &smb30_operations; /* currently identical with 3.0 */
39062306a36Sopenharmony_ci		ctx->vals = &smb302_values;
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	case Smb_311:
39362306a36Sopenharmony_ci		ctx->ops = &smb311_operations;
39462306a36Sopenharmony_ci		ctx->vals = &smb311_values;
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci	case Smb_3any:
39762306a36Sopenharmony_ci		ctx->ops = &smb30_operations; /* currently identical with 3.0 */
39862306a36Sopenharmony_ci		ctx->vals = &smb3any_values;
39962306a36Sopenharmony_ci		break;
40062306a36Sopenharmony_ci	case Smb_default:
40162306a36Sopenharmony_ci		ctx->ops = &smb30_operations;
40262306a36Sopenharmony_ci		ctx->vals = &smbdefault_values;
40362306a36Sopenharmony_ci		break;
40462306a36Sopenharmony_ci	default:
40562306a36Sopenharmony_ci		cifs_errorf(fc, "Unknown vers= option specified: %s\n", value);
40662306a36Sopenharmony_ci		return 1;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci	return 0;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ciint smb3_parse_opt(const char *options, const char *key, char **val)
41262306a36Sopenharmony_ci{
41362306a36Sopenharmony_ci	int rc = -ENOENT;
41462306a36Sopenharmony_ci	char *opts, *orig, *p;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	orig = opts = kstrdup(options, GFP_KERNEL);
41762306a36Sopenharmony_ci	if (!opts)
41862306a36Sopenharmony_ci		return -ENOMEM;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	while ((p = strsep(&opts, ","))) {
42162306a36Sopenharmony_ci		char *nval;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		if (!*p)
42462306a36Sopenharmony_ci			continue;
42562306a36Sopenharmony_ci		if (strncasecmp(p, key, strlen(key)))
42662306a36Sopenharmony_ci			continue;
42762306a36Sopenharmony_ci		nval = strchr(p, '=');
42862306a36Sopenharmony_ci		if (nval) {
42962306a36Sopenharmony_ci			if (nval == p)
43062306a36Sopenharmony_ci				continue;
43162306a36Sopenharmony_ci			*nval++ = 0;
43262306a36Sopenharmony_ci			*val = kstrdup(nval, GFP_KERNEL);
43362306a36Sopenharmony_ci			rc = !*val ? -ENOMEM : 0;
43462306a36Sopenharmony_ci			goto out;
43562306a36Sopenharmony_ci		}
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ciout:
43862306a36Sopenharmony_ci	kfree(orig);
43962306a36Sopenharmony_ci	return rc;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci/*
44362306a36Sopenharmony_ci * Remove duplicate path delimiters. Windows is supposed to do that
44462306a36Sopenharmony_ci * but there are some bugs that prevent rename from working if there are
44562306a36Sopenharmony_ci * multiple delimiters.
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * Return a sanitized duplicate of @path or NULL for empty prefix paths.
44862306a36Sopenharmony_ci * Otherwise, return ERR_PTR.
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * @gfp indicates the GFP_* flags for kstrdup.
45162306a36Sopenharmony_ci * The caller is responsible for freeing the original.
45262306a36Sopenharmony_ci */
45362306a36Sopenharmony_ci#define IS_DELIM(c) ((c) == '/' || (c) == '\\')
45462306a36Sopenharmony_cichar *cifs_sanitize_prepath(char *prepath, gfp_t gfp)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	char *cursor1 = prepath, *cursor2 = prepath;
45762306a36Sopenharmony_ci	char *s;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/* skip all prepended delimiters */
46062306a36Sopenharmony_ci	while (IS_DELIM(*cursor1))
46162306a36Sopenharmony_ci		cursor1++;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* copy the first letter */
46462306a36Sopenharmony_ci	*cursor2 = *cursor1;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* copy the remainder... */
46762306a36Sopenharmony_ci	while (*(cursor1++)) {
46862306a36Sopenharmony_ci		/* ... skipping all duplicated delimiters */
46962306a36Sopenharmony_ci		if (IS_DELIM(*cursor1) && IS_DELIM(*cursor2))
47062306a36Sopenharmony_ci			continue;
47162306a36Sopenharmony_ci		*(++cursor2) = *cursor1;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/* if the last character is a delimiter, skip it */
47562306a36Sopenharmony_ci	if (IS_DELIM(*(cursor2 - 1)))
47662306a36Sopenharmony_ci		cursor2--;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	*cursor2 = '\0';
47962306a36Sopenharmony_ci	if (!*prepath)
48062306a36Sopenharmony_ci		return NULL;
48162306a36Sopenharmony_ci	s = kstrdup(prepath, gfp);
48262306a36Sopenharmony_ci	if (!s)
48362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
48462306a36Sopenharmony_ci	return s;
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/*
48862306a36Sopenharmony_ci * Return full path based on the values of @ctx->{UNC,prepath}.
48962306a36Sopenharmony_ci *
49062306a36Sopenharmony_ci * It is assumed that both values were already parsed by smb3_parse_devname().
49162306a36Sopenharmony_ci */
49262306a36Sopenharmony_cichar *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dirsep)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	size_t ulen, plen;
49562306a36Sopenharmony_ci	char *s;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	ulen = strlen(ctx->UNC);
49862306a36Sopenharmony_ci	plen = ctx->prepath ? strlen(ctx->prepath) + 1 : 0;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	s = kmalloc(ulen + plen + 1, GFP_KERNEL);
50162306a36Sopenharmony_ci	if (!s)
50262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
50362306a36Sopenharmony_ci	memcpy(s, ctx->UNC, ulen);
50462306a36Sopenharmony_ci	if (plen) {
50562306a36Sopenharmony_ci		s[ulen] = dirsep;
50662306a36Sopenharmony_ci		memcpy(s + ulen + 1, ctx->prepath, plen);
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci	s[ulen + plen] = '\0';
50962306a36Sopenharmony_ci	convert_delimiter(s, dirsep);
51062306a36Sopenharmony_ci	return s;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci/*
51462306a36Sopenharmony_ci * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath
51562306a36Sopenharmony_ci * fields with the result. Returns 0 on success and an error otherwise
51662306a36Sopenharmony_ci * (e.g. ENOMEM or EINVAL)
51762306a36Sopenharmony_ci */
51862306a36Sopenharmony_ciint
51962306a36Sopenharmony_cismb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	char *pos;
52262306a36Sopenharmony_ci	const char *delims = "/\\";
52362306a36Sopenharmony_ci	size_t len;
52462306a36Sopenharmony_ci	int rc;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (unlikely(!devname || !*devname)) {
52762306a36Sopenharmony_ci		cifs_dbg(VFS, "Device name not specified\n");
52862306a36Sopenharmony_ci		return -EINVAL;
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* make sure we have a valid UNC double delimiter prefix */
53262306a36Sopenharmony_ci	len = strspn(devname, delims);
53362306a36Sopenharmony_ci	if (len != 2)
53462306a36Sopenharmony_ci		return -EINVAL;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* find delimiter between host and sharename */
53762306a36Sopenharmony_ci	pos = strpbrk(devname + 2, delims);
53862306a36Sopenharmony_ci	if (!pos)
53962306a36Sopenharmony_ci		return -EINVAL;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	/* record the server hostname */
54262306a36Sopenharmony_ci	kfree(ctx->server_hostname);
54362306a36Sopenharmony_ci	ctx->server_hostname = kstrndup(devname + 2, pos - devname - 2, GFP_KERNEL);
54462306a36Sopenharmony_ci	if (!ctx->server_hostname)
54562306a36Sopenharmony_ci		return -ENOMEM;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* skip past delimiter */
54862306a36Sopenharmony_ci	++pos;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	/* now go until next delimiter or end of string */
55162306a36Sopenharmony_ci	len = strcspn(pos, delims);
55262306a36Sopenharmony_ci	if (!len)
55362306a36Sopenharmony_ci		return -EINVAL;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/* move "pos" up to delimiter or NULL */
55662306a36Sopenharmony_ci	pos += len;
55762306a36Sopenharmony_ci	kfree(ctx->UNC);
55862306a36Sopenharmony_ci	ctx->UNC = kstrndup(devname, pos - devname, GFP_KERNEL);
55962306a36Sopenharmony_ci	if (!ctx->UNC)
56062306a36Sopenharmony_ci		return -ENOMEM;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	convert_delimiter(ctx->UNC, '\\');
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	/* skip any delimiter */
56562306a36Sopenharmony_ci	if (*pos == '/' || *pos == '\\')
56662306a36Sopenharmony_ci		pos++;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	kfree(ctx->prepath);
56962306a36Sopenharmony_ci	ctx->prepath = NULL;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/* If pos is NULL then no prepath */
57262306a36Sopenharmony_ci	if (!*pos)
57362306a36Sopenharmony_ci		return 0;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	ctx->prepath = cifs_sanitize_prepath(pos, GFP_KERNEL);
57662306a36Sopenharmony_ci	if (IS_ERR(ctx->prepath)) {
57762306a36Sopenharmony_ci		rc = PTR_ERR(ctx->prepath);
57862306a36Sopenharmony_ci		ctx->prepath = NULL;
57962306a36Sopenharmony_ci		return rc;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	return 0;
58362306a36Sopenharmony_ci}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic void smb3_fs_context_free(struct fs_context *fc);
58662306a36Sopenharmony_cistatic int smb3_fs_context_parse_param(struct fs_context *fc,
58762306a36Sopenharmony_ci				       struct fs_parameter *param);
58862306a36Sopenharmony_cistatic int smb3_fs_context_parse_monolithic(struct fs_context *fc,
58962306a36Sopenharmony_ci					    void *data);
59062306a36Sopenharmony_cistatic int smb3_get_tree(struct fs_context *fc);
59162306a36Sopenharmony_cistatic int smb3_reconfigure(struct fs_context *fc);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic const struct fs_context_operations smb3_fs_context_ops = {
59462306a36Sopenharmony_ci	.free			= smb3_fs_context_free,
59562306a36Sopenharmony_ci	.parse_param		= smb3_fs_context_parse_param,
59662306a36Sopenharmony_ci	.parse_monolithic	= smb3_fs_context_parse_monolithic,
59762306a36Sopenharmony_ci	.get_tree		= smb3_get_tree,
59862306a36Sopenharmony_ci	.reconfigure		= smb3_reconfigure,
59962306a36Sopenharmony_ci};
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci/*
60262306a36Sopenharmony_ci * Parse a monolithic block of data from sys_mount().
60362306a36Sopenharmony_ci * smb3_fs_context_parse_monolithic - Parse key[=val][,key[=val]]* mount data
60462306a36Sopenharmony_ci * @ctx: The superblock configuration to fill in.
60562306a36Sopenharmony_ci * @data: The data to parse
60662306a36Sopenharmony_ci *
60762306a36Sopenharmony_ci * Parse a blob of data that's in key[=val][,key[=val]]* form.  This can be
60862306a36Sopenharmony_ci * called from the ->monolithic_mount_data() fs_context operation.
60962306a36Sopenharmony_ci *
61062306a36Sopenharmony_ci * Returns 0 on success or the error returned by the ->parse_option() fs_context
61162306a36Sopenharmony_ci * operation on failure.
61262306a36Sopenharmony_ci */
61362306a36Sopenharmony_cistatic int smb3_fs_context_parse_monolithic(struct fs_context *fc,
61462306a36Sopenharmony_ci					   void *data)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	char *options = data, *key;
61762306a36Sopenharmony_ci	int ret = 0;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (!options)
62062306a36Sopenharmony_ci		return 0;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	ret = security_sb_eat_lsm_opts(options, &fc->security);
62362306a36Sopenharmony_ci	if (ret)
62462306a36Sopenharmony_ci		return ret;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* BB Need to add support for sep= here TBD */
62762306a36Sopenharmony_ci	while ((key = strsep(&options, ",")) != NULL) {
62862306a36Sopenharmony_ci		size_t len;
62962306a36Sopenharmony_ci		char *value;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci		if (*key == 0)
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		/* Check if following character is the deliminator If yes,
63562306a36Sopenharmony_ci		 * we have encountered a double deliminator reset the NULL
63662306a36Sopenharmony_ci		 * character to the deliminator
63762306a36Sopenharmony_ci		 */
63862306a36Sopenharmony_ci		while (options && options[0] == ',') {
63962306a36Sopenharmony_ci			len = strlen(key);
64062306a36Sopenharmony_ci			strcpy(key + len, options);
64162306a36Sopenharmony_ci			options = strchr(options, ',');
64262306a36Sopenharmony_ci			if (options)
64362306a36Sopenharmony_ci				*options++ = 0;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		len = 0;
64862306a36Sopenharmony_ci		value = strchr(key, '=');
64962306a36Sopenharmony_ci		if (value) {
65062306a36Sopenharmony_ci			if (value == key)
65162306a36Sopenharmony_ci				continue;
65262306a36Sopenharmony_ci			*value++ = 0;
65362306a36Sopenharmony_ci			len = strlen(value);
65462306a36Sopenharmony_ci		}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci		ret = vfs_parse_fs_string(fc, key, value, len);
65762306a36Sopenharmony_ci		if (ret < 0)
65862306a36Sopenharmony_ci			break;
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	return ret;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/*
66562306a36Sopenharmony_ci * Validate the preparsed information in the config.
66662306a36Sopenharmony_ci */
66762306a36Sopenharmony_cistatic int smb3_fs_context_validate(struct fs_context *fc)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct smb3_fs_context *ctx = smb3_fc2context(fc);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (ctx->rdma && ctx->vals->protocol_id < SMB30_PROT_ID) {
67262306a36Sopenharmony_ci		cifs_errorf(fc, "SMB Direct requires Version >=3.0\n");
67362306a36Sopenharmony_ci		return -EOPNOTSUPP;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci#ifndef CONFIG_KEYS
67762306a36Sopenharmony_ci	/* Muliuser mounts require CONFIG_KEYS support */
67862306a36Sopenharmony_ci	if (ctx->multiuser) {
67962306a36Sopenharmony_ci		cifs_errorf(fc, "Multiuser mounts require kernels with CONFIG_KEYS enabled\n");
68062306a36Sopenharmony_ci		return -1;
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci#endif
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (ctx->got_version == false)
68562306a36Sopenharmony_ci		pr_warn_once("No dialect specified on mount. Default has changed to a more secure dialect, SMB2.1 or later (e.g. SMB3.1.1), from CIFS (SMB1). To use the less secure SMB1 dialect to access old servers which do not support SMB3.1.1 (or even SMB3 or SMB2.1) specify vers=1.0 on mount.\n");
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	if (!ctx->UNC) {
68962306a36Sopenharmony_ci		cifs_errorf(fc, "CIFS mount error: No usable UNC path provided in device string!\n");
69062306a36Sopenharmony_ci		return -1;
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	/* make sure UNC has a share name */
69462306a36Sopenharmony_ci	if (strlen(ctx->UNC) < 3 || !strchr(ctx->UNC + 3, '\\')) {
69562306a36Sopenharmony_ci		cifs_errorf(fc, "Malformed UNC. Unable to find share name.\n");
69662306a36Sopenharmony_ci		return -ENOENT;
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	if (!ctx->got_ip) {
70062306a36Sopenharmony_ci		int len;
70162306a36Sopenharmony_ci		const char *slash;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		/* No ip= option specified? Try to get it from UNC */
70462306a36Sopenharmony_ci		/* Use the address part of the UNC. */
70562306a36Sopenharmony_ci		slash = strchr(&ctx->UNC[2], '\\');
70662306a36Sopenharmony_ci		len = slash - &ctx->UNC[2];
70762306a36Sopenharmony_ci		if (!cifs_convert_address((struct sockaddr *)&ctx->dstaddr,
70862306a36Sopenharmony_ci					  &ctx->UNC[2], len)) {
70962306a36Sopenharmony_ci			pr_err("Unable to determine destination address\n");
71062306a36Sopenharmony_ci			return -EHOSTUNREACH;
71162306a36Sopenharmony_ci		}
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	/* set the port that we got earlier */
71562306a36Sopenharmony_ci	cifs_set_port((struct sockaddr *)&ctx->dstaddr, ctx->port);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	if (ctx->override_uid && !ctx->uid_specified) {
71862306a36Sopenharmony_ci		ctx->override_uid = 0;
71962306a36Sopenharmony_ci		pr_notice("ignoring forceuid mount option specified with no uid= option\n");
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	if (ctx->override_gid && !ctx->gid_specified) {
72362306a36Sopenharmony_ci		ctx->override_gid = 0;
72462306a36Sopenharmony_ci		pr_notice("ignoring forcegid mount option specified with no gid= option\n");
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	return 0;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic int smb3_get_tree_common(struct fs_context *fc)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct smb3_fs_context *ctx = smb3_fc2context(fc);
73362306a36Sopenharmony_ci	struct dentry *root;
73462306a36Sopenharmony_ci	int rc = 0;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	root = cifs_smb3_do_mount(fc->fs_type, 0, ctx);
73762306a36Sopenharmony_ci	if (IS_ERR(root))
73862306a36Sopenharmony_ci		return PTR_ERR(root);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	fc->root = root;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return rc;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci/*
74662306a36Sopenharmony_ci * Create an SMB3 superblock from the parameters passed.
74762306a36Sopenharmony_ci */
74862306a36Sopenharmony_cistatic int smb3_get_tree(struct fs_context *fc)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	int err = smb3_fs_context_validate(fc);
75162306a36Sopenharmony_ci	int ret;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	if (err)
75462306a36Sopenharmony_ci		return err;
75562306a36Sopenharmony_ci	mutex_lock(&cifs_mount_mutex);
75662306a36Sopenharmony_ci	ret = smb3_get_tree_common(fc);
75762306a36Sopenharmony_ci	mutex_unlock(&cifs_mount_mutex);
75862306a36Sopenharmony_ci	return ret;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic void smb3_fs_context_free(struct fs_context *fc)
76262306a36Sopenharmony_ci{
76362306a36Sopenharmony_ci	struct smb3_fs_context *ctx = smb3_fc2context(fc);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	smb3_cleanup_fs_context(ctx);
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci/*
76962306a36Sopenharmony_ci * Compare the old and new proposed context during reconfigure
77062306a36Sopenharmony_ci * and check if the changes are compatible.
77162306a36Sopenharmony_ci */
77262306a36Sopenharmony_cistatic int smb3_verify_reconfigure_ctx(struct fs_context *fc,
77362306a36Sopenharmony_ci				       struct smb3_fs_context *new_ctx,
77462306a36Sopenharmony_ci				       struct smb3_fs_context *old_ctx, bool need_recon)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	if (new_ctx->posix_paths != old_ctx->posix_paths) {
77762306a36Sopenharmony_ci		cifs_errorf(fc, "can not change posixpaths during remount\n");
77862306a36Sopenharmony_ci		return -EINVAL;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci	if (new_ctx->sectype != old_ctx->sectype) {
78162306a36Sopenharmony_ci		cifs_errorf(fc, "can not change sec during remount\n");
78262306a36Sopenharmony_ci		return -EINVAL;
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci	if (new_ctx->multiuser != old_ctx->multiuser) {
78562306a36Sopenharmony_ci		cifs_errorf(fc, "can not change multiuser during remount\n");
78662306a36Sopenharmony_ci		return -EINVAL;
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci	if (new_ctx->UNC &&
78962306a36Sopenharmony_ci	    (!old_ctx->UNC || strcmp(new_ctx->UNC, old_ctx->UNC))) {
79062306a36Sopenharmony_ci		cifs_errorf(fc, "can not change UNC during remount\n");
79162306a36Sopenharmony_ci		return -EINVAL;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci	if (new_ctx->username &&
79462306a36Sopenharmony_ci	    (!old_ctx->username || strcmp(new_ctx->username, old_ctx->username))) {
79562306a36Sopenharmony_ci		cifs_errorf(fc, "can not change username during remount\n");
79662306a36Sopenharmony_ci		return -EINVAL;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci	if (new_ctx->password &&
79962306a36Sopenharmony_ci	    (!old_ctx->password || strcmp(new_ctx->password, old_ctx->password))) {
80062306a36Sopenharmony_ci		if (need_recon == false) {
80162306a36Sopenharmony_ci			cifs_errorf(fc,
80262306a36Sopenharmony_ci				    "can not change password of active session during remount\n");
80362306a36Sopenharmony_ci			return -EINVAL;
80462306a36Sopenharmony_ci		} else if (old_ctx->sectype == Kerberos) {
80562306a36Sopenharmony_ci			cifs_errorf(fc,
80662306a36Sopenharmony_ci				    "can not change password for Kerberos via remount\n");
80762306a36Sopenharmony_ci			return -EINVAL;
80862306a36Sopenharmony_ci		}
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci	if (new_ctx->domainname &&
81162306a36Sopenharmony_ci	    (!old_ctx->domainname || strcmp(new_ctx->domainname, old_ctx->domainname))) {
81262306a36Sopenharmony_ci		cifs_errorf(fc, "can not change domainname during remount\n");
81362306a36Sopenharmony_ci		return -EINVAL;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci	if (strcmp(new_ctx->workstation_name, old_ctx->workstation_name)) {
81662306a36Sopenharmony_ci		cifs_errorf(fc, "can not change workstation_name during remount\n");
81762306a36Sopenharmony_ci		return -EINVAL;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci	if (new_ctx->nodename &&
82062306a36Sopenharmony_ci	    (!old_ctx->nodename || strcmp(new_ctx->nodename, old_ctx->nodename))) {
82162306a36Sopenharmony_ci		cifs_errorf(fc, "can not change nodename during remount\n");
82262306a36Sopenharmony_ci		return -EINVAL;
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci	if (new_ctx->iocharset &&
82562306a36Sopenharmony_ci	    (!old_ctx->iocharset || strcmp(new_ctx->iocharset, old_ctx->iocharset))) {
82662306a36Sopenharmony_ci		cifs_errorf(fc, "can not change iocharset during remount\n");
82762306a36Sopenharmony_ci		return -EINVAL;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return 0;
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci#define STEAL_STRING(cifs_sb, ctx, field)				\
83462306a36Sopenharmony_cido {									\
83562306a36Sopenharmony_ci	kfree(ctx->field);						\
83662306a36Sopenharmony_ci	ctx->field = cifs_sb->ctx->field;				\
83762306a36Sopenharmony_ci	cifs_sb->ctx->field = NULL;					\
83862306a36Sopenharmony_ci} while (0)
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci#define STEAL_STRING_SENSITIVE(cifs_sb, ctx, field)			\
84162306a36Sopenharmony_cido {									\
84262306a36Sopenharmony_ci	kfree_sensitive(ctx->field);					\
84362306a36Sopenharmony_ci	ctx->field = cifs_sb->ctx->field;				\
84462306a36Sopenharmony_ci	cifs_sb->ctx->field = NULL;					\
84562306a36Sopenharmony_ci} while (0)
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic int smb3_reconfigure(struct fs_context *fc)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	struct smb3_fs_context *ctx = smb3_fc2context(fc);
85062306a36Sopenharmony_ci	struct dentry *root = fc->root;
85162306a36Sopenharmony_ci	struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
85262306a36Sopenharmony_ci	struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses;
85362306a36Sopenharmony_ci	bool need_recon = false;
85462306a36Sopenharmony_ci	int rc;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (ses->expired_pwd)
85762306a36Sopenharmony_ci		need_recon = true;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	rc = smb3_verify_reconfigure_ctx(fc, ctx, cifs_sb->ctx, need_recon);
86062306a36Sopenharmony_ci	if (rc)
86162306a36Sopenharmony_ci		return rc;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/*
86462306a36Sopenharmony_ci	 * We can not change UNC/username/password/domainname/
86562306a36Sopenharmony_ci	 * workstation_name/nodename/iocharset
86662306a36Sopenharmony_ci	 * during reconnect so ignore what we have in the new context and
86762306a36Sopenharmony_ci	 * just use what we already have in cifs_sb->ctx.
86862306a36Sopenharmony_ci	 */
86962306a36Sopenharmony_ci	STEAL_STRING(cifs_sb, ctx, UNC);
87062306a36Sopenharmony_ci	STEAL_STRING(cifs_sb, ctx, source);
87162306a36Sopenharmony_ci	STEAL_STRING(cifs_sb, ctx, username);
87262306a36Sopenharmony_ci	if (need_recon == false)
87362306a36Sopenharmony_ci		STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
87462306a36Sopenharmony_ci	else  {
87562306a36Sopenharmony_ci		kfree_sensitive(ses->password);
87662306a36Sopenharmony_ci		ses->password = kstrdup(ctx->password, GFP_KERNEL);
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci	STEAL_STRING(cifs_sb, ctx, domainname);
87962306a36Sopenharmony_ci	STEAL_STRING(cifs_sb, ctx, nodename);
88062306a36Sopenharmony_ci	STEAL_STRING(cifs_sb, ctx, iocharset);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	/* if rsize or wsize not passed in on remount, use previous values */
88362306a36Sopenharmony_ci	if (ctx->rsize == 0)
88462306a36Sopenharmony_ci		ctx->rsize = cifs_sb->ctx->rsize;
88562306a36Sopenharmony_ci	if (ctx->wsize == 0)
88662306a36Sopenharmony_ci		ctx->wsize = cifs_sb->ctx->wsize;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	smb3_cleanup_fs_context_contents(cifs_sb->ctx);
89062306a36Sopenharmony_ci	rc = smb3_fs_context_dup(cifs_sb->ctx, ctx);
89162306a36Sopenharmony_ci	smb3_update_mnt_flags(cifs_sb);
89262306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DFS_UPCALL
89362306a36Sopenharmony_ci	if (!rc)
89462306a36Sopenharmony_ci		rc = dfs_cache_remount_fs(cifs_sb);
89562306a36Sopenharmony_ci#endif
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	return rc;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int smb3_fs_context_parse_param(struct fs_context *fc,
90162306a36Sopenharmony_ci				      struct fs_parameter *param)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	struct fs_parse_result result;
90462306a36Sopenharmony_ci	struct smb3_fs_context *ctx = smb3_fc2context(fc);
90562306a36Sopenharmony_ci	int i, opt;
90662306a36Sopenharmony_ci	bool is_smb3 = !strcmp(fc->fs_type->name, "smb3");
90762306a36Sopenharmony_ci	bool skip_parsing = false;
90862306a36Sopenharmony_ci	kuid_t uid;
90962306a36Sopenharmony_ci	kgid_t gid;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	cifs_dbg(FYI, "CIFS: parsing cifs mount option '%s'\n", param->key);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/*
91462306a36Sopenharmony_ci	 * fs_parse can not handle string options with an empty value so
91562306a36Sopenharmony_ci	 * we will need special handling of them.
91662306a36Sopenharmony_ci	 */
91762306a36Sopenharmony_ci	if (param->type == fs_value_is_string && param->string[0] == 0) {
91862306a36Sopenharmony_ci		if (!strcmp("pass", param->key) || !strcmp("password", param->key)) {
91962306a36Sopenharmony_ci			skip_parsing = true;
92062306a36Sopenharmony_ci			opt = Opt_pass;
92162306a36Sopenharmony_ci		} else if (!strcmp("user", param->key) || !strcmp("username", param->key)) {
92262306a36Sopenharmony_ci			skip_parsing = true;
92362306a36Sopenharmony_ci			opt = Opt_user;
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	if (!skip_parsing) {
92862306a36Sopenharmony_ci		opt = fs_parse(fc, smb3_fs_parameters, param, &result);
92962306a36Sopenharmony_ci		if (opt < 0)
93062306a36Sopenharmony_ci			return ctx->sloppy ? 1 : opt;
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	switch (opt) {
93462306a36Sopenharmony_ci	case Opt_compress:
93562306a36Sopenharmony_ci		ctx->compression = UNKNOWN_TYPE;
93662306a36Sopenharmony_ci		cifs_dbg(VFS,
93762306a36Sopenharmony_ci			"SMB3 compression support is experimental\n");
93862306a36Sopenharmony_ci		break;
93962306a36Sopenharmony_ci	case Opt_nodfs:
94062306a36Sopenharmony_ci		ctx->nodfs = 1;
94162306a36Sopenharmony_ci		break;
94262306a36Sopenharmony_ci	case Opt_hard:
94362306a36Sopenharmony_ci		if (result.negated) {
94462306a36Sopenharmony_ci			if (ctx->retry == 1)
94562306a36Sopenharmony_ci				cifs_dbg(VFS, "conflicting hard vs. soft mount options\n");
94662306a36Sopenharmony_ci			ctx->retry = 0;
94762306a36Sopenharmony_ci		} else
94862306a36Sopenharmony_ci			ctx->retry = 1;
94962306a36Sopenharmony_ci		break;
95062306a36Sopenharmony_ci	case Opt_soft:
95162306a36Sopenharmony_ci		if (result.negated)
95262306a36Sopenharmony_ci			ctx->retry = 1;
95362306a36Sopenharmony_ci		else {
95462306a36Sopenharmony_ci			if (ctx->retry == 1)
95562306a36Sopenharmony_ci				cifs_dbg(VFS, "conflicting hard vs soft mount options\n");
95662306a36Sopenharmony_ci			ctx->retry = 0;
95762306a36Sopenharmony_ci		}
95862306a36Sopenharmony_ci		break;
95962306a36Sopenharmony_ci	case Opt_mapposix:
96062306a36Sopenharmony_ci		if (result.negated)
96162306a36Sopenharmony_ci			ctx->remap = false;
96262306a36Sopenharmony_ci		else {
96362306a36Sopenharmony_ci			ctx->remap = true;
96462306a36Sopenharmony_ci			ctx->sfu_remap = false; /* disable SFU mapping */
96562306a36Sopenharmony_ci		}
96662306a36Sopenharmony_ci		break;
96762306a36Sopenharmony_ci	case Opt_mapchars:
96862306a36Sopenharmony_ci		if (result.negated)
96962306a36Sopenharmony_ci			ctx->sfu_remap = false;
97062306a36Sopenharmony_ci		else {
97162306a36Sopenharmony_ci			ctx->sfu_remap = true;
97262306a36Sopenharmony_ci			ctx->remap = false; /* disable SFM (mapposix) mapping */
97362306a36Sopenharmony_ci		}
97462306a36Sopenharmony_ci		break;
97562306a36Sopenharmony_ci	case Opt_user_xattr:
97662306a36Sopenharmony_ci		if (result.negated)
97762306a36Sopenharmony_ci			ctx->no_xattr = 1;
97862306a36Sopenharmony_ci		else
97962306a36Sopenharmony_ci			ctx->no_xattr = 0;
98062306a36Sopenharmony_ci		break;
98162306a36Sopenharmony_ci	case Opt_forceuid:
98262306a36Sopenharmony_ci		if (result.negated)
98362306a36Sopenharmony_ci			ctx->override_uid = 0;
98462306a36Sopenharmony_ci		else
98562306a36Sopenharmony_ci			ctx->override_uid = 1;
98662306a36Sopenharmony_ci		break;
98762306a36Sopenharmony_ci	case Opt_forcegid:
98862306a36Sopenharmony_ci		if (result.negated)
98962306a36Sopenharmony_ci			ctx->override_gid = 0;
99062306a36Sopenharmony_ci		else
99162306a36Sopenharmony_ci			ctx->override_gid = 1;
99262306a36Sopenharmony_ci		break;
99362306a36Sopenharmony_ci	case Opt_perm:
99462306a36Sopenharmony_ci		if (result.negated)
99562306a36Sopenharmony_ci			ctx->noperm = 1;
99662306a36Sopenharmony_ci		else
99762306a36Sopenharmony_ci			ctx->noperm = 0;
99862306a36Sopenharmony_ci		break;
99962306a36Sopenharmony_ci	case Opt_dynperm:
100062306a36Sopenharmony_ci		if (result.negated)
100162306a36Sopenharmony_ci			ctx->dynperm = 0;
100262306a36Sopenharmony_ci		else
100362306a36Sopenharmony_ci			ctx->dynperm = 1;
100462306a36Sopenharmony_ci		break;
100562306a36Sopenharmony_ci	case Opt_sfu:
100662306a36Sopenharmony_ci		if (result.negated)
100762306a36Sopenharmony_ci			ctx->sfu_emul = 0;
100862306a36Sopenharmony_ci		else
100962306a36Sopenharmony_ci			ctx->sfu_emul = 1;
101062306a36Sopenharmony_ci		break;
101162306a36Sopenharmony_ci	case Opt_noblocksend:
101262306a36Sopenharmony_ci		ctx->noblocksnd = 1;
101362306a36Sopenharmony_ci		break;
101462306a36Sopenharmony_ci	case Opt_noautotune:
101562306a36Sopenharmony_ci		ctx->noautotune = 1;
101662306a36Sopenharmony_ci		break;
101762306a36Sopenharmony_ci	case Opt_nolease:
101862306a36Sopenharmony_ci		ctx->no_lease = 1;
101962306a36Sopenharmony_ci		break;
102062306a36Sopenharmony_ci	case Opt_nosparse:
102162306a36Sopenharmony_ci		ctx->no_sparse = 1;
102262306a36Sopenharmony_ci		break;
102362306a36Sopenharmony_ci	case Opt_nodelete:
102462306a36Sopenharmony_ci		ctx->nodelete = 1;
102562306a36Sopenharmony_ci		break;
102662306a36Sopenharmony_ci	case Opt_multichannel:
102762306a36Sopenharmony_ci		if (result.negated) {
102862306a36Sopenharmony_ci			ctx->multichannel = false;
102962306a36Sopenharmony_ci			ctx->max_channels = 1;
103062306a36Sopenharmony_ci		} else {
103162306a36Sopenharmony_ci			ctx->multichannel = true;
103262306a36Sopenharmony_ci			/* if number of channels not specified, default to 2 */
103362306a36Sopenharmony_ci			if (ctx->max_channels < 2)
103462306a36Sopenharmony_ci				ctx->max_channels = 2;
103562306a36Sopenharmony_ci		}
103662306a36Sopenharmony_ci		break;
103762306a36Sopenharmony_ci	case Opt_uid:
103862306a36Sopenharmony_ci		uid = make_kuid(current_user_ns(), result.uint_32);
103962306a36Sopenharmony_ci		if (!uid_valid(uid))
104062306a36Sopenharmony_ci			goto cifs_parse_mount_err;
104162306a36Sopenharmony_ci		ctx->linux_uid = uid;
104262306a36Sopenharmony_ci		ctx->uid_specified = true;
104362306a36Sopenharmony_ci		break;
104462306a36Sopenharmony_ci	case Opt_cruid:
104562306a36Sopenharmony_ci		uid = make_kuid(current_user_ns(), result.uint_32);
104662306a36Sopenharmony_ci		if (!uid_valid(uid))
104762306a36Sopenharmony_ci			goto cifs_parse_mount_err;
104862306a36Sopenharmony_ci		ctx->cred_uid = uid;
104962306a36Sopenharmony_ci		ctx->cruid_specified = true;
105062306a36Sopenharmony_ci		break;
105162306a36Sopenharmony_ci	case Opt_backupuid:
105262306a36Sopenharmony_ci		uid = make_kuid(current_user_ns(), result.uint_32);
105362306a36Sopenharmony_ci		if (!uid_valid(uid))
105462306a36Sopenharmony_ci			goto cifs_parse_mount_err;
105562306a36Sopenharmony_ci		ctx->backupuid = uid;
105662306a36Sopenharmony_ci		ctx->backupuid_specified = true;
105762306a36Sopenharmony_ci		break;
105862306a36Sopenharmony_ci	case Opt_backupgid:
105962306a36Sopenharmony_ci		gid = make_kgid(current_user_ns(), result.uint_32);
106062306a36Sopenharmony_ci		if (!gid_valid(gid))
106162306a36Sopenharmony_ci			goto cifs_parse_mount_err;
106262306a36Sopenharmony_ci		ctx->backupgid = gid;
106362306a36Sopenharmony_ci		ctx->backupgid_specified = true;
106462306a36Sopenharmony_ci		break;
106562306a36Sopenharmony_ci	case Opt_gid:
106662306a36Sopenharmony_ci		gid = make_kgid(current_user_ns(), result.uint_32);
106762306a36Sopenharmony_ci		if (!gid_valid(gid))
106862306a36Sopenharmony_ci			goto cifs_parse_mount_err;
106962306a36Sopenharmony_ci		ctx->linux_gid = gid;
107062306a36Sopenharmony_ci		ctx->gid_specified = true;
107162306a36Sopenharmony_ci		break;
107262306a36Sopenharmony_ci	case Opt_port:
107362306a36Sopenharmony_ci		ctx->port = result.uint_32;
107462306a36Sopenharmony_ci		break;
107562306a36Sopenharmony_ci	case Opt_file_mode:
107662306a36Sopenharmony_ci		ctx->file_mode = result.uint_32;
107762306a36Sopenharmony_ci		break;
107862306a36Sopenharmony_ci	case Opt_dirmode:
107962306a36Sopenharmony_ci		ctx->dir_mode = result.uint_32;
108062306a36Sopenharmony_ci		break;
108162306a36Sopenharmony_ci	case Opt_min_enc_offload:
108262306a36Sopenharmony_ci		ctx->min_offload = result.uint_32;
108362306a36Sopenharmony_ci		break;
108462306a36Sopenharmony_ci	case Opt_blocksize:
108562306a36Sopenharmony_ci		/*
108662306a36Sopenharmony_ci		 * inode blocksize realistically should never need to be
108762306a36Sopenharmony_ci		 * less than 16K or greater than 16M and default is 1MB.
108862306a36Sopenharmony_ci		 * Note that small inode block sizes (e.g. 64K) can lead
108962306a36Sopenharmony_ci		 * to very poor performance of common tools like cp and scp
109062306a36Sopenharmony_ci		 */
109162306a36Sopenharmony_ci		if ((result.uint_32 < CIFS_MAX_MSGSIZE) ||
109262306a36Sopenharmony_ci		   (result.uint_32 > (4 * SMB3_DEFAULT_IOSIZE))) {
109362306a36Sopenharmony_ci			cifs_errorf(fc, "%s: Invalid blocksize\n",
109462306a36Sopenharmony_ci				__func__);
109562306a36Sopenharmony_ci			goto cifs_parse_mount_err;
109662306a36Sopenharmony_ci		}
109762306a36Sopenharmony_ci		ctx->bsize = result.uint_32;
109862306a36Sopenharmony_ci		ctx->got_bsize = true;
109962306a36Sopenharmony_ci		break;
110062306a36Sopenharmony_ci	case Opt_rasize:
110162306a36Sopenharmony_ci		/*
110262306a36Sopenharmony_ci		 * readahead size realistically should never need to be
110362306a36Sopenharmony_ci		 * less than 1M (CIFS_DEFAULT_IOSIZE) or greater than 32M
110462306a36Sopenharmony_ci		 * (perhaps an exception should be considered in the
110562306a36Sopenharmony_ci		 * for the case of a large number of channels
110662306a36Sopenharmony_ci		 * when multichannel is negotiated) since that would lead
110762306a36Sopenharmony_ci		 * to plenty of parallel I/O in flight to the server.
110862306a36Sopenharmony_ci		 * Note that smaller read ahead sizes would
110962306a36Sopenharmony_ci		 * hurt performance of common tools like cp and scp
111062306a36Sopenharmony_ci		 * which often trigger sequential i/o with read ahead
111162306a36Sopenharmony_ci		 */
111262306a36Sopenharmony_ci		if ((result.uint_32 > (8 * SMB3_DEFAULT_IOSIZE)) ||
111362306a36Sopenharmony_ci		    (result.uint_32 < CIFS_DEFAULT_IOSIZE)) {
111462306a36Sopenharmony_ci			cifs_errorf(fc, "%s: Invalid rasize %d vs. %d\n",
111562306a36Sopenharmony_ci				__func__, result.uint_32, SMB3_DEFAULT_IOSIZE);
111662306a36Sopenharmony_ci			goto cifs_parse_mount_err;
111762306a36Sopenharmony_ci		}
111862306a36Sopenharmony_ci		ctx->rasize = result.uint_32;
111962306a36Sopenharmony_ci		break;
112062306a36Sopenharmony_ci	case Opt_rsize:
112162306a36Sopenharmony_ci		ctx->rsize = result.uint_32;
112262306a36Sopenharmony_ci		ctx->got_rsize = true;
112362306a36Sopenharmony_ci		break;
112462306a36Sopenharmony_ci	case Opt_wsize:
112562306a36Sopenharmony_ci		ctx->wsize = result.uint_32;
112662306a36Sopenharmony_ci		ctx->got_wsize = true;
112762306a36Sopenharmony_ci		if (ctx->wsize % PAGE_SIZE != 0) {
112862306a36Sopenharmony_ci			ctx->wsize = round_down(ctx->wsize, PAGE_SIZE);
112962306a36Sopenharmony_ci			if (ctx->wsize == 0) {
113062306a36Sopenharmony_ci				ctx->wsize = PAGE_SIZE;
113162306a36Sopenharmony_ci				cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE);
113262306a36Sopenharmony_ci			} else {
113362306a36Sopenharmony_ci				cifs_dbg(VFS,
113462306a36Sopenharmony_ci					 "wsize rounded down to %d to multiple of PAGE_SIZE %ld\n",
113562306a36Sopenharmony_ci					 ctx->wsize, PAGE_SIZE);
113662306a36Sopenharmony_ci			}
113762306a36Sopenharmony_ci		}
113862306a36Sopenharmony_ci		break;
113962306a36Sopenharmony_ci	case Opt_acregmax:
114062306a36Sopenharmony_ci		ctx->acregmax = HZ * result.uint_32;
114162306a36Sopenharmony_ci		if (ctx->acregmax > CIFS_MAX_ACTIMEO) {
114262306a36Sopenharmony_ci			cifs_errorf(fc, "acregmax too large\n");
114362306a36Sopenharmony_ci			goto cifs_parse_mount_err;
114462306a36Sopenharmony_ci		}
114562306a36Sopenharmony_ci		break;
114662306a36Sopenharmony_ci	case Opt_acdirmax:
114762306a36Sopenharmony_ci		ctx->acdirmax = HZ * result.uint_32;
114862306a36Sopenharmony_ci		if (ctx->acdirmax > CIFS_MAX_ACTIMEO) {
114962306a36Sopenharmony_ci			cifs_errorf(fc, "acdirmax too large\n");
115062306a36Sopenharmony_ci			goto cifs_parse_mount_err;
115162306a36Sopenharmony_ci		}
115262306a36Sopenharmony_ci		break;
115362306a36Sopenharmony_ci	case Opt_actimeo:
115462306a36Sopenharmony_ci		if (HZ * result.uint_32 > CIFS_MAX_ACTIMEO) {
115562306a36Sopenharmony_ci			cifs_errorf(fc, "timeout too large\n");
115662306a36Sopenharmony_ci			goto cifs_parse_mount_err;
115762306a36Sopenharmony_ci		}
115862306a36Sopenharmony_ci		if ((ctx->acdirmax != CIFS_DEF_ACTIMEO) ||
115962306a36Sopenharmony_ci		    (ctx->acregmax != CIFS_DEF_ACTIMEO)) {
116062306a36Sopenharmony_ci			cifs_errorf(fc, "actimeo ignored since acregmax or acdirmax specified\n");
116162306a36Sopenharmony_ci			break;
116262306a36Sopenharmony_ci		}
116362306a36Sopenharmony_ci		ctx->acdirmax = ctx->acregmax = HZ * result.uint_32;
116462306a36Sopenharmony_ci		break;
116562306a36Sopenharmony_ci	case Opt_closetimeo:
116662306a36Sopenharmony_ci		ctx->closetimeo = HZ * result.uint_32;
116762306a36Sopenharmony_ci		if (ctx->closetimeo > SMB3_MAX_DCLOSETIMEO) {
116862306a36Sopenharmony_ci			cifs_errorf(fc, "closetimeo too large\n");
116962306a36Sopenharmony_ci			goto cifs_parse_mount_err;
117062306a36Sopenharmony_ci		}
117162306a36Sopenharmony_ci		break;
117262306a36Sopenharmony_ci	case Opt_echo_interval:
117362306a36Sopenharmony_ci		ctx->echo_interval = result.uint_32;
117462306a36Sopenharmony_ci		break;
117562306a36Sopenharmony_ci	case Opt_snapshot:
117662306a36Sopenharmony_ci		ctx->snapshot_time = result.uint_64;
117762306a36Sopenharmony_ci		break;
117862306a36Sopenharmony_ci	case Opt_max_credits:
117962306a36Sopenharmony_ci		if (result.uint_32 < 20 || result.uint_32 > 60000) {
118062306a36Sopenharmony_ci			cifs_errorf(fc, "%s: Invalid max_credits value\n",
118162306a36Sopenharmony_ci				 __func__);
118262306a36Sopenharmony_ci			goto cifs_parse_mount_err;
118362306a36Sopenharmony_ci		}
118462306a36Sopenharmony_ci		ctx->max_credits = result.uint_32;
118562306a36Sopenharmony_ci		break;
118662306a36Sopenharmony_ci	case Opt_max_channels:
118762306a36Sopenharmony_ci		if (result.uint_32 < 1 || result.uint_32 > CIFS_MAX_CHANNELS) {
118862306a36Sopenharmony_ci			cifs_errorf(fc, "%s: Invalid max_channels value, needs to be 1-%d\n",
118962306a36Sopenharmony_ci				 __func__, CIFS_MAX_CHANNELS);
119062306a36Sopenharmony_ci			goto cifs_parse_mount_err;
119162306a36Sopenharmony_ci		}
119262306a36Sopenharmony_ci		ctx->max_channels = result.uint_32;
119362306a36Sopenharmony_ci		/* If more than one channel requested ... they want multichan */
119462306a36Sopenharmony_ci		if (result.uint_32 > 1)
119562306a36Sopenharmony_ci			ctx->multichannel = true;
119662306a36Sopenharmony_ci		break;
119762306a36Sopenharmony_ci	case Opt_max_cached_dirs:
119862306a36Sopenharmony_ci		if (result.uint_32 < 1) {
119962306a36Sopenharmony_ci			cifs_errorf(fc, "%s: Invalid max_cached_dirs, needs to be 1 or more\n",
120062306a36Sopenharmony_ci				    __func__);
120162306a36Sopenharmony_ci			goto cifs_parse_mount_err;
120262306a36Sopenharmony_ci		}
120362306a36Sopenharmony_ci		ctx->max_cached_dirs = result.uint_32;
120462306a36Sopenharmony_ci		break;
120562306a36Sopenharmony_ci	case Opt_handletimeout:
120662306a36Sopenharmony_ci		ctx->handle_timeout = result.uint_32;
120762306a36Sopenharmony_ci		if (ctx->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) {
120862306a36Sopenharmony_ci			cifs_errorf(fc, "Invalid handle cache timeout, longer than 16 minutes\n");
120962306a36Sopenharmony_ci			goto cifs_parse_mount_err;
121062306a36Sopenharmony_ci		}
121162306a36Sopenharmony_ci		break;
121262306a36Sopenharmony_ci	case Opt_source:
121362306a36Sopenharmony_ci		kfree(ctx->UNC);
121462306a36Sopenharmony_ci		ctx->UNC = NULL;
121562306a36Sopenharmony_ci		switch (smb3_parse_devname(param->string, ctx)) {
121662306a36Sopenharmony_ci		case 0:
121762306a36Sopenharmony_ci			break;
121862306a36Sopenharmony_ci		case -ENOMEM:
121962306a36Sopenharmony_ci			cifs_errorf(fc, "Unable to allocate memory for devname\n");
122062306a36Sopenharmony_ci			goto cifs_parse_mount_err;
122162306a36Sopenharmony_ci		case -EINVAL:
122262306a36Sopenharmony_ci			cifs_errorf(fc, "Malformed UNC in devname\n");
122362306a36Sopenharmony_ci			goto cifs_parse_mount_err;
122462306a36Sopenharmony_ci		default:
122562306a36Sopenharmony_ci			cifs_errorf(fc, "Unknown error parsing devname\n");
122662306a36Sopenharmony_ci			goto cifs_parse_mount_err;
122762306a36Sopenharmony_ci		}
122862306a36Sopenharmony_ci		ctx->source = smb3_fs_context_fullpath(ctx, '/');
122962306a36Sopenharmony_ci		if (IS_ERR(ctx->source)) {
123062306a36Sopenharmony_ci			ctx->source = NULL;
123162306a36Sopenharmony_ci			cifs_errorf(fc, "OOM when copying UNC string\n");
123262306a36Sopenharmony_ci			goto cifs_parse_mount_err;
123362306a36Sopenharmony_ci		}
123462306a36Sopenharmony_ci		fc->source = kstrdup(ctx->source, GFP_KERNEL);
123562306a36Sopenharmony_ci		if (fc->source == NULL) {
123662306a36Sopenharmony_ci			cifs_errorf(fc, "OOM when copying UNC string\n");
123762306a36Sopenharmony_ci			goto cifs_parse_mount_err;
123862306a36Sopenharmony_ci		}
123962306a36Sopenharmony_ci		break;
124062306a36Sopenharmony_ci	case Opt_user:
124162306a36Sopenharmony_ci		kfree(ctx->username);
124262306a36Sopenharmony_ci		ctx->username = NULL;
124362306a36Sopenharmony_ci		if (ctx->nullauth)
124462306a36Sopenharmony_ci			break;
124562306a36Sopenharmony_ci		if (strlen(param->string) == 0) {
124662306a36Sopenharmony_ci			/* null user, ie. anonymous authentication */
124762306a36Sopenharmony_ci			ctx->nullauth = 1;
124862306a36Sopenharmony_ci			break;
124962306a36Sopenharmony_ci		}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci		if (strnlen(param->string, CIFS_MAX_USERNAME_LEN) >
125262306a36Sopenharmony_ci		    CIFS_MAX_USERNAME_LEN) {
125362306a36Sopenharmony_ci			pr_warn("username too long\n");
125462306a36Sopenharmony_ci			goto cifs_parse_mount_err;
125562306a36Sopenharmony_ci		}
125662306a36Sopenharmony_ci		ctx->username = kstrdup(param->string, GFP_KERNEL);
125762306a36Sopenharmony_ci		if (ctx->username == NULL) {
125862306a36Sopenharmony_ci			cifs_errorf(fc, "OOM when copying username string\n");
125962306a36Sopenharmony_ci			goto cifs_parse_mount_err;
126062306a36Sopenharmony_ci		}
126162306a36Sopenharmony_ci		break;
126262306a36Sopenharmony_ci	case Opt_pass:
126362306a36Sopenharmony_ci		kfree_sensitive(ctx->password);
126462306a36Sopenharmony_ci		ctx->password = NULL;
126562306a36Sopenharmony_ci		if (strlen(param->string) == 0)
126662306a36Sopenharmony_ci			break;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci		ctx->password = kstrdup(param->string, GFP_KERNEL);
126962306a36Sopenharmony_ci		if (ctx->password == NULL) {
127062306a36Sopenharmony_ci			cifs_errorf(fc, "OOM when copying password string\n");
127162306a36Sopenharmony_ci			goto cifs_parse_mount_err;
127262306a36Sopenharmony_ci		}
127362306a36Sopenharmony_ci		break;
127462306a36Sopenharmony_ci	case Opt_ip:
127562306a36Sopenharmony_ci		if (strlen(param->string) == 0) {
127662306a36Sopenharmony_ci			ctx->got_ip = false;
127762306a36Sopenharmony_ci			break;
127862306a36Sopenharmony_ci		}
127962306a36Sopenharmony_ci		if (!cifs_convert_address((struct sockaddr *)&ctx->dstaddr,
128062306a36Sopenharmony_ci					  param->string,
128162306a36Sopenharmony_ci					  strlen(param->string))) {
128262306a36Sopenharmony_ci			pr_err("bad ip= option (%s)\n", param->string);
128362306a36Sopenharmony_ci			goto cifs_parse_mount_err;
128462306a36Sopenharmony_ci		}
128562306a36Sopenharmony_ci		ctx->got_ip = true;
128662306a36Sopenharmony_ci		break;
128762306a36Sopenharmony_ci	case Opt_domain:
128862306a36Sopenharmony_ci		if (strnlen(param->string, CIFS_MAX_DOMAINNAME_LEN)
128962306a36Sopenharmony_ci				== CIFS_MAX_DOMAINNAME_LEN) {
129062306a36Sopenharmony_ci			pr_warn("domain name too long\n");
129162306a36Sopenharmony_ci			goto cifs_parse_mount_err;
129262306a36Sopenharmony_ci		}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci		kfree(ctx->domainname);
129562306a36Sopenharmony_ci		ctx->domainname = kstrdup(param->string, GFP_KERNEL);
129662306a36Sopenharmony_ci		if (ctx->domainname == NULL) {
129762306a36Sopenharmony_ci			cifs_errorf(fc, "OOM when copying domainname string\n");
129862306a36Sopenharmony_ci			goto cifs_parse_mount_err;
129962306a36Sopenharmony_ci		}
130062306a36Sopenharmony_ci		cifs_dbg(FYI, "Domain name set\n");
130162306a36Sopenharmony_ci		break;
130262306a36Sopenharmony_ci	case Opt_srcaddr:
130362306a36Sopenharmony_ci		if (!cifs_convert_address(
130462306a36Sopenharmony_ci				(struct sockaddr *)&ctx->srcaddr,
130562306a36Sopenharmony_ci				param->string, strlen(param->string))) {
130662306a36Sopenharmony_ci			pr_warn("Could not parse srcaddr: %s\n",
130762306a36Sopenharmony_ci				param->string);
130862306a36Sopenharmony_ci			goto cifs_parse_mount_err;
130962306a36Sopenharmony_ci		}
131062306a36Sopenharmony_ci		break;
131162306a36Sopenharmony_ci	case Opt_iocharset:
131262306a36Sopenharmony_ci		if (strnlen(param->string, 1024) >= 65) {
131362306a36Sopenharmony_ci			pr_warn("iocharset name too long\n");
131462306a36Sopenharmony_ci			goto cifs_parse_mount_err;
131562306a36Sopenharmony_ci		}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci		if (strncasecmp(param->string, "default", 7) != 0) {
131862306a36Sopenharmony_ci			kfree(ctx->iocharset);
131962306a36Sopenharmony_ci			ctx->iocharset = kstrdup(param->string, GFP_KERNEL);
132062306a36Sopenharmony_ci			if (ctx->iocharset == NULL) {
132162306a36Sopenharmony_ci				cifs_errorf(fc, "OOM when copying iocharset string\n");
132262306a36Sopenharmony_ci				goto cifs_parse_mount_err;
132362306a36Sopenharmony_ci			}
132462306a36Sopenharmony_ci		}
132562306a36Sopenharmony_ci		/* if iocharset not set then load_nls_default
132662306a36Sopenharmony_ci		 * is used by caller
132762306a36Sopenharmony_ci		 */
132862306a36Sopenharmony_ci		cifs_dbg(FYI, "iocharset set to %s\n", ctx->iocharset);
132962306a36Sopenharmony_ci		break;
133062306a36Sopenharmony_ci	case Opt_netbiosname:
133162306a36Sopenharmony_ci		memset(ctx->source_rfc1001_name, 0x20,
133262306a36Sopenharmony_ci			RFC1001_NAME_LEN);
133362306a36Sopenharmony_ci		/*
133462306a36Sopenharmony_ci		 * FIXME: are there cases in which a comma can
133562306a36Sopenharmony_ci		 * be valid in workstation netbios name (and
133662306a36Sopenharmony_ci		 * need special handling)?
133762306a36Sopenharmony_ci		 */
133862306a36Sopenharmony_ci		for (i = 0; i < RFC1001_NAME_LEN; i++) {
133962306a36Sopenharmony_ci			/* don't ucase netbiosname for user */
134062306a36Sopenharmony_ci			if (param->string[i] == 0)
134162306a36Sopenharmony_ci				break;
134262306a36Sopenharmony_ci			ctx->source_rfc1001_name[i] = param->string[i];
134362306a36Sopenharmony_ci		}
134462306a36Sopenharmony_ci		/* The string has 16th byte zero still from
134562306a36Sopenharmony_ci		 * set at top of the function
134662306a36Sopenharmony_ci		 */
134762306a36Sopenharmony_ci		if (i == RFC1001_NAME_LEN && param->string[i] != 0)
134862306a36Sopenharmony_ci			pr_warn("netbiosname longer than 15 truncated\n");
134962306a36Sopenharmony_ci		break;
135062306a36Sopenharmony_ci	case Opt_servern:
135162306a36Sopenharmony_ci		/* last byte, type, is 0x20 for servr type */
135262306a36Sopenharmony_ci		memset(ctx->target_rfc1001_name, 0x20,
135362306a36Sopenharmony_ci			RFC1001_NAME_LEN_WITH_NULL);
135462306a36Sopenharmony_ci		/*
135562306a36Sopenharmony_ci		 * BB are there cases in which a comma can be valid in this
135662306a36Sopenharmony_ci		 * workstation netbios name (and need special handling)?
135762306a36Sopenharmony_ci		 */
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		/* user or mount helper must uppercase the netbios name */
136062306a36Sopenharmony_ci		for (i = 0; i < 15; i++) {
136162306a36Sopenharmony_ci			if (param->string[i] == 0)
136262306a36Sopenharmony_ci				break;
136362306a36Sopenharmony_ci			ctx->target_rfc1001_name[i] = param->string[i];
136462306a36Sopenharmony_ci		}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci		/* The string has 16th byte zero still from set at top of function */
136762306a36Sopenharmony_ci		if (i == RFC1001_NAME_LEN && param->string[i] != 0)
136862306a36Sopenharmony_ci			pr_warn("server netbiosname longer than 15 truncated\n");
136962306a36Sopenharmony_ci		break;
137062306a36Sopenharmony_ci	case Opt_ver:
137162306a36Sopenharmony_ci		/* version of mount userspace tools, not dialect */
137262306a36Sopenharmony_ci		/* If interface changes in mount.cifs bump to new ver */
137362306a36Sopenharmony_ci		if (strncasecmp(param->string, "1", 1) == 0) {
137462306a36Sopenharmony_ci			if (strlen(param->string) > 1) {
137562306a36Sopenharmony_ci				pr_warn("Bad mount helper ver=%s. Did you want SMB1 (CIFS) dialect and mean to type vers=1.0 instead?\n",
137662306a36Sopenharmony_ci					param->string);
137762306a36Sopenharmony_ci				goto cifs_parse_mount_err;
137862306a36Sopenharmony_ci			}
137962306a36Sopenharmony_ci			/* This is the default */
138062306a36Sopenharmony_ci			break;
138162306a36Sopenharmony_ci		}
138262306a36Sopenharmony_ci		/* For all other value, error */
138362306a36Sopenharmony_ci		pr_warn("Invalid mount helper version specified\n");
138462306a36Sopenharmony_ci		goto cifs_parse_mount_err;
138562306a36Sopenharmony_ci	case Opt_vers:
138662306a36Sopenharmony_ci		/* protocol version (dialect) */
138762306a36Sopenharmony_ci		if (cifs_parse_smb_version(fc, param->string, ctx, is_smb3) != 0)
138862306a36Sopenharmony_ci			goto cifs_parse_mount_err;
138962306a36Sopenharmony_ci		ctx->got_version = true;
139062306a36Sopenharmony_ci		break;
139162306a36Sopenharmony_ci	case Opt_sec:
139262306a36Sopenharmony_ci		if (cifs_parse_security_flavors(fc, param->string, ctx) != 0)
139362306a36Sopenharmony_ci			goto cifs_parse_mount_err;
139462306a36Sopenharmony_ci		break;
139562306a36Sopenharmony_ci	case Opt_cache:
139662306a36Sopenharmony_ci		if (cifs_parse_cache_flavor(fc, param->string, ctx) != 0)
139762306a36Sopenharmony_ci			goto cifs_parse_mount_err;
139862306a36Sopenharmony_ci		break;
139962306a36Sopenharmony_ci	case Opt_witness:
140062306a36Sopenharmony_ci#ifndef CONFIG_CIFS_SWN_UPCALL
140162306a36Sopenharmony_ci		cifs_errorf(fc, "Witness support needs CONFIG_CIFS_SWN_UPCALL config option\n");
140262306a36Sopenharmony_ci			goto cifs_parse_mount_err;
140362306a36Sopenharmony_ci#endif
140462306a36Sopenharmony_ci		ctx->witness = true;
140562306a36Sopenharmony_ci		pr_warn_once("Witness protocol support is experimental\n");
140662306a36Sopenharmony_ci		break;
140762306a36Sopenharmony_ci	case Opt_rootfs:
140862306a36Sopenharmony_ci#ifndef CONFIG_CIFS_ROOT
140962306a36Sopenharmony_ci		cifs_dbg(VFS, "rootfs support requires CONFIG_CIFS_ROOT config option\n");
141062306a36Sopenharmony_ci		goto cifs_parse_mount_err;
141162306a36Sopenharmony_ci#endif
141262306a36Sopenharmony_ci		ctx->rootfs = true;
141362306a36Sopenharmony_ci		break;
141462306a36Sopenharmony_ci	case Opt_posixpaths:
141562306a36Sopenharmony_ci		if (result.negated)
141662306a36Sopenharmony_ci			ctx->posix_paths = 0;
141762306a36Sopenharmony_ci		else
141862306a36Sopenharmony_ci			ctx->posix_paths = 1;
141962306a36Sopenharmony_ci		break;
142062306a36Sopenharmony_ci	case Opt_unix:
142162306a36Sopenharmony_ci		if (result.negated) {
142262306a36Sopenharmony_ci			if (ctx->linux_ext == 1)
142362306a36Sopenharmony_ci				pr_warn_once("conflicting posix mount options specified\n");
142462306a36Sopenharmony_ci			ctx->linux_ext = 0;
142562306a36Sopenharmony_ci			ctx->no_linux_ext = 1;
142662306a36Sopenharmony_ci		} else {
142762306a36Sopenharmony_ci			if (ctx->no_linux_ext == 1)
142862306a36Sopenharmony_ci				pr_warn_once("conflicting posix mount options specified\n");
142962306a36Sopenharmony_ci			ctx->linux_ext = 1;
143062306a36Sopenharmony_ci			ctx->no_linux_ext = 0;
143162306a36Sopenharmony_ci		}
143262306a36Sopenharmony_ci		break;
143362306a36Sopenharmony_ci	case Opt_nocase:
143462306a36Sopenharmony_ci		ctx->nocase = 1;
143562306a36Sopenharmony_ci		break;
143662306a36Sopenharmony_ci	case Opt_brl:
143762306a36Sopenharmony_ci		if (result.negated) {
143862306a36Sopenharmony_ci			/*
143962306a36Sopenharmony_ci			 * turn off mandatory locking in mode
144062306a36Sopenharmony_ci			 * if remote locking is turned off since the
144162306a36Sopenharmony_ci			 * local vfs will do advisory
144262306a36Sopenharmony_ci			 */
144362306a36Sopenharmony_ci			if (ctx->file_mode ==
144462306a36Sopenharmony_ci				(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
144562306a36Sopenharmony_ci				ctx->file_mode = S_IALLUGO;
144662306a36Sopenharmony_ci			ctx->nobrl =  1;
144762306a36Sopenharmony_ci		} else
144862306a36Sopenharmony_ci			ctx->nobrl =  0;
144962306a36Sopenharmony_ci		break;
145062306a36Sopenharmony_ci	case Opt_handlecache:
145162306a36Sopenharmony_ci		if (result.negated)
145262306a36Sopenharmony_ci			ctx->nohandlecache = 1;
145362306a36Sopenharmony_ci		else
145462306a36Sopenharmony_ci			ctx->nohandlecache = 0;
145562306a36Sopenharmony_ci		break;
145662306a36Sopenharmony_ci	case Opt_forcemandatorylock:
145762306a36Sopenharmony_ci		ctx->mand_lock = 1;
145862306a36Sopenharmony_ci		break;
145962306a36Sopenharmony_ci	case Opt_setuids:
146062306a36Sopenharmony_ci		ctx->setuids = result.negated;
146162306a36Sopenharmony_ci		break;
146262306a36Sopenharmony_ci	case Opt_intr:
146362306a36Sopenharmony_ci		ctx->intr = !result.negated;
146462306a36Sopenharmony_ci		break;
146562306a36Sopenharmony_ci	case Opt_setuidfromacl:
146662306a36Sopenharmony_ci		ctx->setuidfromacl = 1;
146762306a36Sopenharmony_ci		break;
146862306a36Sopenharmony_ci	case Opt_strictsync:
146962306a36Sopenharmony_ci		ctx->nostrictsync = result.negated;
147062306a36Sopenharmony_ci		break;
147162306a36Sopenharmony_ci	case Opt_serverino:
147262306a36Sopenharmony_ci		ctx->server_ino = !result.negated;
147362306a36Sopenharmony_ci		break;
147462306a36Sopenharmony_ci	case Opt_rwpidforward:
147562306a36Sopenharmony_ci		ctx->rwpidforward = 1;
147662306a36Sopenharmony_ci		break;
147762306a36Sopenharmony_ci	case Opt_modesid:
147862306a36Sopenharmony_ci		ctx->mode_ace = 1;
147962306a36Sopenharmony_ci		break;
148062306a36Sopenharmony_ci	case Opt_cifsacl:
148162306a36Sopenharmony_ci		ctx->cifs_acl = !result.negated;
148262306a36Sopenharmony_ci		break;
148362306a36Sopenharmony_ci	case Opt_acl:
148462306a36Sopenharmony_ci		ctx->no_psx_acl = result.negated;
148562306a36Sopenharmony_ci		break;
148662306a36Sopenharmony_ci	case Opt_locallease:
148762306a36Sopenharmony_ci		ctx->local_lease = 1;
148862306a36Sopenharmony_ci		break;
148962306a36Sopenharmony_ci	case Opt_sign:
149062306a36Sopenharmony_ci		ctx->sign = true;
149162306a36Sopenharmony_ci		break;
149262306a36Sopenharmony_ci	case Opt_ignore_signature:
149362306a36Sopenharmony_ci		ctx->sign = true;
149462306a36Sopenharmony_ci		ctx->ignore_signature = true;
149562306a36Sopenharmony_ci		break;
149662306a36Sopenharmony_ci	case Opt_seal:
149762306a36Sopenharmony_ci		/* we do not do the following in secFlags because seal
149862306a36Sopenharmony_ci		 * is a per tree connection (mount) not a per socket
149962306a36Sopenharmony_ci		 * or per-smb connection option in the protocol
150062306a36Sopenharmony_ci		 * vol->secFlg |= CIFSSEC_MUST_SEAL;
150162306a36Sopenharmony_ci		 */
150262306a36Sopenharmony_ci		ctx->seal = 1;
150362306a36Sopenharmony_ci		break;
150462306a36Sopenharmony_ci	case Opt_noac:
150562306a36Sopenharmony_ci		pr_warn("Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
150662306a36Sopenharmony_ci		break;
150762306a36Sopenharmony_ci	case Opt_fsc:
150862306a36Sopenharmony_ci#ifndef CONFIG_CIFS_FSCACHE
150962306a36Sopenharmony_ci		cifs_errorf(fc, "FS-Cache support needs CONFIG_CIFS_FSCACHE kernel config option set\n");
151062306a36Sopenharmony_ci		goto cifs_parse_mount_err;
151162306a36Sopenharmony_ci#endif
151262306a36Sopenharmony_ci		ctx->fsc = true;
151362306a36Sopenharmony_ci		break;
151462306a36Sopenharmony_ci	case Opt_mfsymlinks:
151562306a36Sopenharmony_ci		ctx->mfsymlinks = true;
151662306a36Sopenharmony_ci		break;
151762306a36Sopenharmony_ci	case Opt_multiuser:
151862306a36Sopenharmony_ci		ctx->multiuser = true;
151962306a36Sopenharmony_ci		break;
152062306a36Sopenharmony_ci	case Opt_sloppy:
152162306a36Sopenharmony_ci		ctx->sloppy = true;
152262306a36Sopenharmony_ci		break;
152362306a36Sopenharmony_ci	case Opt_nosharesock:
152462306a36Sopenharmony_ci		ctx->nosharesock = true;
152562306a36Sopenharmony_ci		break;
152662306a36Sopenharmony_ci	case Opt_persistent:
152762306a36Sopenharmony_ci		if (result.negated) {
152862306a36Sopenharmony_ci			ctx->nopersistent = true;
152962306a36Sopenharmony_ci			if (ctx->persistent) {
153062306a36Sopenharmony_ci				cifs_errorf(fc, "persistenthandles mount options conflict\n");
153162306a36Sopenharmony_ci				goto cifs_parse_mount_err;
153262306a36Sopenharmony_ci			}
153362306a36Sopenharmony_ci		} else {
153462306a36Sopenharmony_ci			ctx->persistent = true;
153562306a36Sopenharmony_ci			if ((ctx->nopersistent) || (ctx->resilient)) {
153662306a36Sopenharmony_ci				cifs_errorf(fc, "persistenthandles mount options conflict\n");
153762306a36Sopenharmony_ci				goto cifs_parse_mount_err;
153862306a36Sopenharmony_ci			}
153962306a36Sopenharmony_ci		}
154062306a36Sopenharmony_ci		break;
154162306a36Sopenharmony_ci	case Opt_resilient:
154262306a36Sopenharmony_ci		if (result.negated) {
154362306a36Sopenharmony_ci			ctx->resilient = false; /* already the default */
154462306a36Sopenharmony_ci		} else {
154562306a36Sopenharmony_ci			ctx->resilient = true;
154662306a36Sopenharmony_ci			if (ctx->persistent) {
154762306a36Sopenharmony_ci				cifs_errorf(fc, "persistenthandles mount options conflict\n");
154862306a36Sopenharmony_ci				goto cifs_parse_mount_err;
154962306a36Sopenharmony_ci			}
155062306a36Sopenharmony_ci		}
155162306a36Sopenharmony_ci		break;
155262306a36Sopenharmony_ci	case Opt_tcp_nodelay:
155362306a36Sopenharmony_ci		/* tcp nodelay should not usually be needed since we CORK/UNCORK the socket */
155462306a36Sopenharmony_ci		if (result.negated)
155562306a36Sopenharmony_ci			ctx->sockopt_tcp_nodelay = false;
155662306a36Sopenharmony_ci		else
155762306a36Sopenharmony_ci			ctx->sockopt_tcp_nodelay = true;
155862306a36Sopenharmony_ci		break;
155962306a36Sopenharmony_ci	case Opt_domainauto:
156062306a36Sopenharmony_ci		ctx->domainauto = true;
156162306a36Sopenharmony_ci		break;
156262306a36Sopenharmony_ci	case Opt_rdma:
156362306a36Sopenharmony_ci		ctx->rdma = true;
156462306a36Sopenharmony_ci		break;
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci	/* case Opt_ignore: - is ignored as expected ... */
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	return 0;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci cifs_parse_mount_err:
157162306a36Sopenharmony_ci	kfree_sensitive(ctx->password);
157262306a36Sopenharmony_ci	ctx->password = NULL;
157362306a36Sopenharmony_ci	return -EINVAL;
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ciint smb3_init_fs_context(struct fs_context *fc)
157762306a36Sopenharmony_ci{
157862306a36Sopenharmony_ci	struct smb3_fs_context *ctx;
157962306a36Sopenharmony_ci	char *nodename = utsname()->nodename;
158062306a36Sopenharmony_ci	int i;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
158362306a36Sopenharmony_ci	if (unlikely(!ctx))
158462306a36Sopenharmony_ci		return -ENOMEM;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	strscpy(ctx->workstation_name, nodename, sizeof(ctx->workstation_name));
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	/*
158962306a36Sopenharmony_ci	 * does not have to be perfect mapping since field is
159062306a36Sopenharmony_ci	 * informational, only used for servers that do not support
159162306a36Sopenharmony_ci	 * port 445 and it can be overridden at mount time
159262306a36Sopenharmony_ci	 */
159362306a36Sopenharmony_ci	memset(ctx->source_rfc1001_name, 0x20, RFC1001_NAME_LEN);
159462306a36Sopenharmony_ci	for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++)
159562306a36Sopenharmony_ci		ctx->source_rfc1001_name[i] = toupper(nodename[i]);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	ctx->source_rfc1001_name[RFC1001_NAME_LEN] = 0;
159862306a36Sopenharmony_ci	/*
159962306a36Sopenharmony_ci	 * null target name indicates to use *SMBSERVR default called name
160062306a36Sopenharmony_ci	 *  if we end up sending RFC1001 session initialize
160162306a36Sopenharmony_ci	 */
160262306a36Sopenharmony_ci	ctx->target_rfc1001_name[0] = 0;
160362306a36Sopenharmony_ci	ctx->cred_uid = current_uid();
160462306a36Sopenharmony_ci	ctx->linux_uid = current_uid();
160562306a36Sopenharmony_ci	ctx->linux_gid = current_gid();
160662306a36Sopenharmony_ci	/* By default 4MB read ahead size, 1MB block size */
160762306a36Sopenharmony_ci	ctx->bsize = CIFS_DEFAULT_IOSIZE; /* can improve cp performance significantly */
160862306a36Sopenharmony_ci	ctx->rasize = 0; /* 0 = use default (ie negotiated rsize) for read ahead pages */
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	/*
161162306a36Sopenharmony_ci	 * default to SFM style remapping of seven reserved characters
161262306a36Sopenharmony_ci	 * unless user overrides it or we negotiate CIFS POSIX where
161362306a36Sopenharmony_ci	 * it is unnecessary.  Can not simultaneously use more than one mapping
161462306a36Sopenharmony_ci	 * since then readdir could list files that open could not open
161562306a36Sopenharmony_ci	 */
161662306a36Sopenharmony_ci	ctx->remap = true;
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	/* default to only allowing write access to owner of the mount */
161962306a36Sopenharmony_ci	ctx->dir_mode = ctx->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	/* ctx->retry default is 0 (i.e. "soft" limited retry not hard retry) */
162262306a36Sopenharmony_ci	/* default is always to request posix paths. */
162362306a36Sopenharmony_ci	ctx->posix_paths = 1;
162462306a36Sopenharmony_ci	/* default to using server inode numbers where available */
162562306a36Sopenharmony_ci	ctx->server_ino = 1;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	/* default is to use strict cifs caching semantics */
162862306a36Sopenharmony_ci	ctx->strict_io = true;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	ctx->acregmax = CIFS_DEF_ACTIMEO;
163162306a36Sopenharmony_ci	ctx->acdirmax = CIFS_DEF_ACTIMEO;
163262306a36Sopenharmony_ci	ctx->closetimeo = SMB3_DEF_DCLOSETIMEO;
163362306a36Sopenharmony_ci	ctx->max_cached_dirs = MAX_CACHED_FIDS;
163462306a36Sopenharmony_ci	/* Most clients set timeout to 0, allows server to use its default */
163562306a36Sopenharmony_ci	ctx->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	/* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */
163862306a36Sopenharmony_ci	ctx->ops = &smb30_operations;
163962306a36Sopenharmony_ci	ctx->vals = &smbdefault_values;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	ctx->echo_interval = SMB_ECHO_INTERVAL_DEFAULT;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	/* default to no multichannel (single server connection) */
164462306a36Sopenharmony_ci	ctx->multichannel = false;
164562306a36Sopenharmony_ci	ctx->max_channels = 1;
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	ctx->backupuid_specified = false; /* no backup intent for a user */
164862306a36Sopenharmony_ci	ctx->backupgid_specified = false; /* no backup intent for a group */
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci/*
165162306a36Sopenharmony_ci *	short int override_uid = -1;
165262306a36Sopenharmony_ci *	short int override_gid = -1;
165362306a36Sopenharmony_ci *	char *nodename = strdup(utsname()->nodename);
165462306a36Sopenharmony_ci *	struct sockaddr *dstaddr = (struct sockaddr *)&vol->dstaddr;
165562306a36Sopenharmony_ci */
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	fc->fs_private = ctx;
165862306a36Sopenharmony_ci	fc->ops = &smb3_fs_context_ops;
165962306a36Sopenharmony_ci	return 0;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_civoid
166362306a36Sopenharmony_cismb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	if (ctx == NULL)
166662306a36Sopenharmony_ci		return;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	/*
166962306a36Sopenharmony_ci	 * Make sure this stays in sync with smb3_fs_context_dup()
167062306a36Sopenharmony_ci	 */
167162306a36Sopenharmony_ci	kfree(ctx->username);
167262306a36Sopenharmony_ci	ctx->username = NULL;
167362306a36Sopenharmony_ci	kfree_sensitive(ctx->password);
167462306a36Sopenharmony_ci	ctx->password = NULL;
167562306a36Sopenharmony_ci	kfree(ctx->server_hostname);
167662306a36Sopenharmony_ci	ctx->server_hostname = NULL;
167762306a36Sopenharmony_ci	kfree(ctx->UNC);
167862306a36Sopenharmony_ci	ctx->UNC = NULL;
167962306a36Sopenharmony_ci	kfree(ctx->source);
168062306a36Sopenharmony_ci	ctx->source = NULL;
168162306a36Sopenharmony_ci	kfree(ctx->domainname);
168262306a36Sopenharmony_ci	ctx->domainname = NULL;
168362306a36Sopenharmony_ci	kfree(ctx->nodename);
168462306a36Sopenharmony_ci	ctx->nodename = NULL;
168562306a36Sopenharmony_ci	kfree(ctx->iocharset);
168662306a36Sopenharmony_ci	ctx->iocharset = NULL;
168762306a36Sopenharmony_ci	kfree(ctx->prepath);
168862306a36Sopenharmony_ci	ctx->prepath = NULL;
168962306a36Sopenharmony_ci	kfree(ctx->leaf_fullpath);
169062306a36Sopenharmony_ci	ctx->leaf_fullpath = NULL;
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_civoid
169462306a36Sopenharmony_cismb3_cleanup_fs_context(struct smb3_fs_context *ctx)
169562306a36Sopenharmony_ci{
169662306a36Sopenharmony_ci	if (!ctx)
169762306a36Sopenharmony_ci		return;
169862306a36Sopenharmony_ci	smb3_cleanup_fs_context_contents(ctx);
169962306a36Sopenharmony_ci	kfree(ctx);
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_civoid smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb)
170362306a36Sopenharmony_ci{
170462306a36Sopenharmony_ci	struct smb3_fs_context *ctx = cifs_sb->ctx;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	if (ctx->nodfs)
170762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_DFS;
170862306a36Sopenharmony_ci	else
170962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_DFS;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	if (ctx->noperm)
171262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
171362306a36Sopenharmony_ci	else
171462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_PERM;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	if (ctx->setuids)
171762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
171862306a36Sopenharmony_ci	else
171962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SET_UID;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	if (ctx->setuidfromacl)
172262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UID_FROM_ACL;
172362306a36Sopenharmony_ci	else
172462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UID_FROM_ACL;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	if (ctx->server_ino)
172762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
172862306a36Sopenharmony_ci	else
172962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	if (ctx->remap)
173262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
173362306a36Sopenharmony_ci	else
173462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SFM_CHR;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	if (ctx->sfu_remap)
173762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
173862306a36Sopenharmony_ci	else
173962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MAP_SPECIAL_CHR;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	if (ctx->no_xattr)
174262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
174362306a36Sopenharmony_ci	else
174462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_XATTR;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	if (ctx->sfu_emul)
174762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
174862306a36Sopenharmony_ci	else
174962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_UNX_EMUL;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	if (ctx->nobrl)
175262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
175362306a36Sopenharmony_ci	else
175462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_BRL;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	if (ctx->nohandlecache)
175762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_HANDLE_CACHE;
175862306a36Sopenharmony_ci	else
175962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NO_HANDLE_CACHE;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	if (ctx->nostrictsync)
176262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC;
176362306a36Sopenharmony_ci	else
176462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOSSYNC;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	if (ctx->mand_lock)
176762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
176862306a36Sopenharmony_ci	else
176962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_NOPOSIXBRL;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	if (ctx->rwpidforward)
177262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
177362306a36Sopenharmony_ci	else
177462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_RWPIDFORWARD;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	if (ctx->mode_ace)
177762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MODE_FROM_SID;
177862306a36Sopenharmony_ci	else
177962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MODE_FROM_SID;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	if (ctx->cifs_acl)
178262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
178362306a36Sopenharmony_ci	else
178462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_ACL;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	if (ctx->backupuid_specified)
178762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID;
178862306a36Sopenharmony_ci	else
178962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPUID;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	if (ctx->backupgid_specified)
179262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID;
179362306a36Sopenharmony_ci	else
179462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_CIFS_BACKUPGID;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	if (ctx->override_uid)
179762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
179862306a36Sopenharmony_ci	else
179962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_UID;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	if (ctx->override_gid)
180262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
180362306a36Sopenharmony_ci	else
180462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_OVERR_GID;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	if (ctx->dynperm)
180762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
180862306a36Sopenharmony_ci	else
180962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DYNPERM;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	if (ctx->fsc)
181262306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
181362306a36Sopenharmony_ci	else
181462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_FSCACHE;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	if (ctx->multiuser)
181762306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
181862306a36Sopenharmony_ci					    CIFS_MOUNT_NO_PERM);
181962306a36Sopenharmony_ci	else
182062306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MULTIUSER;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	if (ctx->strict_io)
182462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO;
182562306a36Sopenharmony_ci	else
182662306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_STRICT_IO;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	if (ctx->direct_io)
182962306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
183062306a36Sopenharmony_ci	else
183162306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_DIRECT_IO;
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	if (ctx->mfsymlinks)
183462306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
183562306a36Sopenharmony_ci	else
183662306a36Sopenharmony_ci		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_MF_SYMLINKS;
183762306a36Sopenharmony_ci	if (ctx->mfsymlinks) {
183862306a36Sopenharmony_ci		if (ctx->sfu_emul) {
183962306a36Sopenharmony_ci			/*
184062306a36Sopenharmony_ci			 * Our SFU ("Services for Unix" emulation does not allow
184162306a36Sopenharmony_ci			 * creating symlinks but does allow reading existing SFU
184262306a36Sopenharmony_ci			 * symlinks (it does allow both creating and reading SFU
184362306a36Sopenharmony_ci			 * style mknod and FIFOs though). When "mfsymlinks" and
184462306a36Sopenharmony_ci			 * "sfu" are both enabled at the same time, it allows
184562306a36Sopenharmony_ci			 * reading both types of symlinks, but will only create
184662306a36Sopenharmony_ci			 * them with mfsymlinks format. This allows better
184762306a36Sopenharmony_ci			 * Apple compatibility (probably better for Samba too)
184862306a36Sopenharmony_ci			 * while still recognizing old Windows style symlinks.
184962306a36Sopenharmony_ci			 */
185062306a36Sopenharmony_ci			cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
185162306a36Sopenharmony_ci		}
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci	cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SHUTDOWN;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	return;
185662306a36Sopenharmony_ci}
1857