[PATCH 6.6 045/102] smb: client: introduce reparse mount option

Greg Kroah-Hartman
2024-05-23T13:24:28Z

From: Paulo Alcantara <pc@manguebit.com>

[ Upstream commit eb90e8ecb2b54ac1af51e28596e0ef7ba351476d ]

Allow the user to create special files and symlinks by choosing
between WSL and NFS reparse points via 'reparse={nfs,wsl}' mount
options. If unset or 'reparse=default', the client will default to
creating them via NFS reparse points.

Creating WSL reparse points isn't supported yet, so simply return
error when attempting to mount with 'reparse=wsl' for now.

Signed-off-by: Paulo Alcantara <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/client/cifsglob.h | 6 ++++++
fs/smb/client/connect.c | 2 ++
fs/smb/client/fs_context.c | 35 +++++++++++++++++++++++++++++++++++
fs/smb/client/fs_context.h | 9 +++++++++
4 files changed, 52 insertions(+)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index fdadda4024f46..08540541046c1 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -153,6 +153,12 @@ enum securityEnum {
Kerberos, /* Kerberos via SPNEGO */
};

+enum cifs_reparse_type {
+ CIFS_REPARSE_TYPE_NFS,
+ CIFS_REPARSE_TYPE_WSL,
+ CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS,
+};
+
struct session_key {
unsigned int len;
char *response;
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index e28f011f11d6c..deba1cfd11801 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -2805,6 +2805,8 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
return 0;
if (old->ctx->closetimeo != new->ctx->closetimeo)
return 0;
+ if (old->ctx->reparse_type != new->ctx->reparse_type)
+ return 0;

return 1;
}
diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
index f119035a82725..535885fbdf51d 100644
--- a/fs/smb/client/fs_context.c
+++ b/fs/smb/client/fs_context.c
@@ -175,6 +175,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
fsparam_string("vers", Opt_vers),
fsparam_string("sec", Opt_sec),
fsparam_string("cache", Opt_cache),
+ fsparam_string("reparse", Opt_reparse),

/* Arguments that should be ignored */
fsparam_flag("guest", Opt_ignore),
@@ -297,6 +298,35 @@ cifs_parse_cache_flavor(struct fs_context *fc, char *value, struct smb3_fs_conte
return 0;
}

+static const match_table_t reparse_flavor_tokens = {
+ { Opt_reparse_default, "default" },
+ { Opt_reparse_nfs, "nfs" },
+ { Opt_reparse_wsl, "wsl" },
+ { Opt_reparse_err, NULL },
+};
+
+static int parse_reparse_flavor(struct fs_context *fc, char *value,
+ struct smb3_fs_context *ctx)
+{
+ substring_t args[MAX_OPT_ARGS];
+
+ switch (match_token(value, reparse_flavor_tokens, args)) {
+ case Opt_reparse_default:
+ ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;
+ break;
+ case Opt_reparse_nfs:
+ ctx->reparse_type = CIFS_REPARSE_TYPE_NFS;
+ break;
+ case Opt_reparse_wsl:
+ cifs_errorf(fc, "unsupported reparse= option: %s\n", value);
+ return 1;
+ default:
+ cifs_errorf(fc, "bad reparse= option: %s\n", value);
+ return 1;
+ }
+ return 0;
+}
+
#define DUP_CTX_STR(field) \
do { \
if (ctx->field) { \
@@ -1595,6 +1625,10 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
case Opt_rdma:
ctx->rdma = true;
break;
+ case Opt_reparse:
+ if (parse_reparse_flavor(fc, param->string, ctx))
+ goto cifs_parse_mount_err;
+ break;
}
/* case Opt_ignore: - is ignored as expected ... */

@@ -1683,6 +1717,7 @@ int smb3_init_fs_context(struct fs_context *fc)
ctx->backupgid_specified = false; /* no backup intent for a group */

ctx->retrans = 1;
+ ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT;

/*
* short int override_uid = -1;
diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
index 369a3fea1dfe0..e77ee81846b31 100644
--- a/fs/smb/client/fs_context.h
+++ b/fs/smb/client/fs_context.h
@@ -41,6 +41,13 @@ enum {
Opt_cache_err
};

+enum cifs_reparse_parm {
+ Opt_reparse_default,
+ Opt_reparse_nfs,
+ Opt_reparse_wsl,
+ Opt_reparse_err
+};
+
enum cifs_sec_param {
Opt_sec_krb5,
Opt_sec_krb5i,
@@ -149,6 +156,7 @@ enum cifs_param {
Opt_vers,
Opt_sec,
Opt_cache,
+ Opt_reparse,

/* Mount options to be ignored */
Opt_ignore,
@@ -275,6 +283,7 @@ struct smb3_fs_context {
char *leaf_fullpath;
struct cifs_ses *dfs_root_ses;
bool dfs_automount:1; /* set for dfs automount only */
+ enum cifs_reparse_type reparse_type;
};

extern const struct fs_parameter_spec smb3_fs_parameters[];
--
2.43.0