mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Pali Rohár" <pali@kernel.org>
To: Paulo Alcantara <pc@manguebit.org>, Namjae Jeon <linkinjeon@kernel.org>
Cc: linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 9/9] cifs: Add support for creating WSL symlinks in version 1 format
Date: Tue, 13 Oct 2026 10:48:27 +0200	[thread overview]
Message-ID: <20261013084827.ulqi2u2eebb4i3ay@pali> (raw)
In-Reply-To: <20260825230622.24617-10-pali@kernel.org>

On Wednesday 26 August 2026 01:06:22 Pali Rohár wrote:
> Add a new mount option -o symlink=wsl1 which cause that all newly created
> symlinks would be of WSL style in layout version 1 format. This type of
> symlinks is supported by all WSL versions.
> 
> Existing mount option -o symlink=wsl will be now an alias to -o
> symlink=wsl2 which creates symlinks in layout version 2 format.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>
> ---
>  fs/smb/client/cifsglob.h   |  9 +++--
>  fs/smb/client/fs_context.c | 11 ++++--
>  fs/smb/client/fs_context.h |  3 +-
>  fs/smb/client/link.c       |  3 +-
>  fs/smb/client/reparse.c    | 74 ++++++++++++++++++++++++++++++++------
>  5 files changed, 82 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
> index c5fdc0138165..66d4370f37dc 100644
> --- a/fs/smb/client/cifsglob.h
> +++ b/fs/smb/client/cifsglob.h
> @@ -190,7 +190,8 @@ enum cifs_symlink_type {
>  	CIFS_SYMLINK_TYPE_MFSYMLINKS,
>  	CIFS_SYMLINK_TYPE_SFU,
>  	CIFS_SYMLINK_TYPE_NFS,
> -	CIFS_SYMLINK_TYPE_WSL,
> +	CIFS_SYMLINK_TYPE_WSL1,
> +	CIFS_SYMLINK_TYPE_WSL2,
>  };
>  
>  static inline const char *cifs_symlink_type_str(enum cifs_symlink_type type)
> @@ -208,8 +209,10 @@ static inline const char *cifs_symlink_type_str(enum cifs_symlink_type type)
>  		return "sfu";
>  	case CIFS_SYMLINK_TYPE_NFS:
>  		return "nfs";
> -	case CIFS_SYMLINK_TYPE_WSL:
> -		return "wsl";
> +	case CIFS_SYMLINK_TYPE_WSL1:
> +		return "wsl1";
> +	case CIFS_SYMLINK_TYPE_WSL2:
> +		return "wsl2";
>  	default:
>  		return "unknown";
>  	}
> diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c
> index abc29500a664..3e8e4b43690a 100644
> --- a/fs/smb/client/fs_context.c
> +++ b/fs/smb/client/fs_context.c
> @@ -376,7 +376,9 @@ static const match_table_t symlink_flavor_tokens = {
>  	{ Opt_symlink_mfsymlinks,	"mfsymlinks" },
>  	{ Opt_symlink_sfu,		"sfu" },
>  	{ Opt_symlink_nfs,		"nfs" },
> -	{ Opt_symlink_wsl,		"wsl" },
> +	{ Opt_symlink_wsl1,		"wsl1" },
> +	{ Opt_symlink_wsl2,		"wsl2" },
> +	{ Opt_symlink_wsl2,		"wsl" }, /* wsl - alias for wsl2 */
>  	{ Opt_symlink_err,		NULL },
>  };
>  
> @@ -407,8 +409,11 @@ static int parse_symlink_flavor(struct fs_context *fc, char *value,
>  	case Opt_symlink_nfs:
>  		ctx->symlink_type = CIFS_SYMLINK_TYPE_NFS;
>  		break;
> -	case Opt_symlink_wsl:
> -		ctx->symlink_type = CIFS_SYMLINK_TYPE_WSL;
> +	case Opt_symlink_wsl1:
> +		ctx->symlink_type = CIFS_SYMLINK_TYPE_WSL1;
> +		break;
> +	case Opt_symlink_wsl2:
> +		ctx->symlink_type = CIFS_SYMLINK_TYPE_WSL2;
>  		break;
>  	default:
>  		cifs_errorf(fc, "bad symlink= option: %s\n", value);
> diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h
> index a80a5caff23c..56bbb20a30a3 100644
> --- a/fs/smb/client/fs_context.h
> +++ b/fs/smb/client/fs_context.h
> @@ -72,7 +72,8 @@ enum cifs_symlink_parm {
>  	Opt_symlink_mfsymlinks,
>  	Opt_symlink_sfu,
>  	Opt_symlink_nfs,
> -	Opt_symlink_wsl,
> +	Opt_symlink_wsl1,
> +	Opt_symlink_wsl2,
>  	Opt_symlink_err
>  };
>  
> diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
> index 8d5d6aca742a..fd7203aa0917 100644
> --- a/fs/smb/client/link.c
> +++ b/fs/smb/client/link.c
> @@ -604,7 +604,8 @@ cifs_symlink(struct mnt_idmap *idmap, struct inode *inode,
>  
>  	case CIFS_SYMLINK_TYPE_NATIVE:
>  	case CIFS_SYMLINK_TYPE_NFS:
> -	case CIFS_SYMLINK_TYPE_WSL:
> +	case CIFS_SYMLINK_TYPE_WSL1:
> +	case CIFS_SYMLINK_TYPE_WSL2:
>  		if (CIFS_REPARSE_SUPPORT(pTcon)) {
>  			rc = create_reparse_symlink(xid, inode, direntry, pTcon,
>  						    full_path, symname);
> diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
> index bed6f764c0bc..8db3e4917788 100644
> --- a/fs/smb/client/reparse.c
> +++ b/fs/smb/client/reparse.c
> @@ -22,7 +22,7 @@ static int mknod_nfs(unsigned int xid, struct inode *inode,
>  static int mknod_wsl(unsigned int xid, struct inode *inode,
>  		     struct dentry *dentry, struct cifs_tcon *tcon,
>  		     const char *full_path, umode_t mode, dev_t dev,
> -		     const char *symname);
> +		     const char *symname, int symver);
>  
>  static int create_native_symlink(const unsigned int xid, struct inode *inode,
>  				 struct dentry *dentry, struct cifs_tcon *tcon,
> @@ -43,8 +43,10 @@ int create_reparse_symlink(const unsigned int xid, struct inode *inode,
>  		return create_native_symlink(xid, inode, dentry, tcon, full_path, symname);
>  	case CIFS_SYMLINK_TYPE_NFS:
>  		return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
> -	case CIFS_SYMLINK_TYPE_WSL:
> -		return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname);
> +	case CIFS_SYMLINK_TYPE_WSL1:
> +		return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname, 1);
> +	case CIFS_SYMLINK_TYPE_WSL2:
> +		return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname, 2);
>  	default:
>  		return -EOPNOTSUPP;
>  	}
> @@ -554,6 +556,7 @@ static int mknod_nfs(unsigned int xid, struct inode *inode,
>  
>  static int wsl_set_reparse_buf(struct reparse_data_buffer **buf,
>  			       mode_t mode, const char *symname,
> +			       int symver,
>  			       struct cifs_sb_info *cifs_sb,
>  			       struct kvec *iov)
>  {
> @@ -589,15 +592,20 @@ static int wsl_set_reparse_buf(struct reparse_data_buffer **buf,
>  			kfree(symname_utf16);
>  			return -ENOMEM;
>  		}
> -		/* Version field must be set to 2 (MS-FSCC 2.1.2.7) */
> -		symlink_buf->Version = cpu_to_le32(2);
> -		/* Target for Version 2 is in UTF-8 but without trailing null-term byte */
> +		symlink_buf->Version = cpu_to_le32(symver);
> +		/* Target is in UTF-8 but without trailing null-term byte */
>  		symname_utf8_len = utf16s_to_utf8s((wchar_t *)symname_utf16, symname_utf16_len/2,
>  						   UTF16_LITTLE_ENDIAN,
>  						   symlink_buf->Target,
>  						   symname_utf8_maxlen);
>  		*buf = (struct reparse_data_buffer *)symlink_buf;
> -		buf_len = sizeof(struct reparse_wsl_symlink_data_buffer) + symname_utf8_len;
> +		buf_len = sizeof(struct reparse_wsl_symlink_data_buffer);
> +		/*
> +		 * Layout version 2 stores the symlink target in the reparse point buffer.
> +		 * Layout version 1 stores the symlink target in the data section of the file.
> +		 */
> +		if (symver == 2)
> +			buf_len += symname_utf8_len;
>  		kfree(symname_utf16);
>  		break;
>  	default:
> @@ -698,7 +706,7 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
>  static int mknod_wsl(unsigned int xid, struct inode *inode,
>  		     struct dentry *dentry, struct cifs_tcon *tcon,
>  		     const char *full_path, umode_t mode, dev_t dev,
> -		     const char *symname)
> +		     const char *symname, int symver)
>  {
>  	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
>  	struct cifs_open_info_data data;
> @@ -707,6 +715,12 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
>  	struct inode *new;
>  	unsigned int len;
>  	struct kvec reparse_iov, xattr_iov;
> +	struct cifs_open_parms oparms;
> +	struct cifs_io_parms io_parms;
> +	unsigned int bytes_written;
> +	struct kvec symv1_iov[2];
> +	struct cifs_fid fid;
> +	__u32 oplock;
>  	int rc;
>  
>  	/*
> @@ -716,7 +730,7 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
>  	if (!(le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_EXTENDED_ATTRIBUTES))
>  		return -EOPNOTSUPP;
>  
> -	rc = wsl_set_reparse_buf(&buf, mode, symname, cifs_sb, &reparse_iov);
> +	rc = wsl_set_reparse_buf(&buf, mode, symname, symver, cifs_sb, &reparse_iov);
>  	if (rc)
>  		return rc;
>  
> @@ -741,6 +755,46 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
>  				     &data, inode->i_sb,
>  				     xid, tcon, full_path, false,
>  				     &reparse_iov, &xattr_iov);
> +	if (!IS_ERR(new) && mode == S_IFLNK && symver == 1) {
> +		/*
> +		 * WSL symlink layout version 1 stores the symlink target
> +		 * location into the data section of the file.
> +		 * Store it now after the reparse point file was created.
> +		 * The target location was allocated into the buf but iov
> +		 * size filled in reparse_iov by wsl_set_reparse_buf() was
> +		 * set to smaller so the created reparse point does not
> +		 * contain it.
> +		 */
> +		oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
> +				     FILE_OPEN, CREATE_NOT_DIR | OPEN_REPARSE_POINT,
> +				     ACL_NO_MODE);
> +		oparms.fid = &fid;
> +		oplock = tcon->ses->server->oplocks ? REQ_OPLOCK : 0;
> +		rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, NULL);
> +		if (!rc) {
> +			symv1_iov[1].iov_base = ((struct reparse_wsl_symlink_data_buffer *)buf)->Target;
> +			symv1_iov[1].iov_len = strlen((const char *)symv1_iov[1].iov_base);
> +			io_parms = (struct cifs_io_parms) {
> +				.netfid = fid.netfid,
> +				.pid = current->tgid,
> +				.tcon = tcon,
> +				.offset = 0,
> +				.length = symv1_iov[1].iov_len,
> +			};
> +			rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
> +								&bytes_written,
> +								symv1_iov,
> +								ARRAY_SIZE(symv1_iov)-1);
> +			if (bytes_written != symv1_iov[1].iov_len)
> +				rc = -EIO;
> +			tcon->ses->server->ops->close(xid, tcon, &fid);
> +		}
> +		if (rc) {
> +			tcon->ses->server->ops->unlink(xid, tcon, full_path, cifs_sb, NULL);
> +			iput(new);
> +			new = ERR_PTR(rc);
> +		}
> +	}
>  	if (!IS_ERR(new))
>  		d_instantiate(dentry, new);
>  	else
> @@ -764,7 +818,7 @@ int mknod_reparse(unsigned int xid, struct inode *inode,
>  	case CIFS_REPARSE_TYPE_NFS:
>  		return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
>  	case CIFS_REPARSE_TYPE_WSL:
> -		return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL);
> +		return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL, 0);
>  	default:
>  		return -EOPNOTSUPP;
>  	}
> -- 
> 2.20.1
> 

For visibility, this is fixup for sashiko review:

diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index c3e125669e9b..679ba469b77e 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -775,7 +775,6 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
 			symv1_iov[1].iov_base = ((struct reparse_wsl_symlink_data_buffer *)buf)->Target;
 			symv1_iov[1].iov_len = strlen((const char *)symv1_iov[1].iov_base);
 			io_parms = (struct cifs_io_parms) {
-				.netfid = fid.netfid,
 				.pid = current->tgid,
 				.tcon = tcon,
 				.offset = 0,
@@ -785,7 +784,7 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
 								&bytes_written,
 								symv1_iov,
 								ARRAY_SIZE(symv1_iov)-1);
-			if (bytes_written != symv1_iov[1].iov_len)
+			if (!rc && bytes_written != symv1_iov[1].iov_len)
 				rc = -EIO;
 			tcon->ses->server->ops->close(xid, tcon, &fid);
 		}

  reply	other threads:[~2026-10-13  8:48 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-06 18:48 [PATCH RESEND 00/11] cifs: Various changes Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 01/11] cifs: Fix and improve cifs_is_path_accessible() function Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 02/11] cifs: Remove code for querying FILE_INFO_STANDARD via CIFSSMBQPathInfo() Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 03/11] cifs: Remove CIFSSMBSetPathInfoFB() fallback function Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 04/11] cifs: Remove cifs_backup_query_path_info() and replace it by cifs_query_path_info() Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 05/11] cifs: Fix validation of EAs for WSL reparse points Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 06/11] cifs: Validate presence of EA $LXMOD " Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 07/11] cifs: Check if server supports EAs before trying to set it for WSL Pali Rohár
2026-07-06 22:33   ` Steve French
2026-07-06 22:42     ` Pali Rohár
     [not found]       ` <CAH2r5mvDGM7i8EsdPkW681a_AnXOAsHkg38eJqegO7g2gV8qAw@mail.gmail.com>
2026-07-06 22:58         ` Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 08/11] cifs: Extend ->set_EA() callback to allow operate on reparse point Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 09/11] cifs: Create native Window socket file compatible also with WSL subsystem Pali Rohár
2026-08-09 12:09   ` Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 10/11] cifs: Add support for parsing WSL symlinks in version 1 format Pali Rohár
2026-07-06 20:50   ` Pali Rohár
2026-07-06 21:02   ` Pali Rohár
2026-08-09 12:09   ` [PATCH v2] " Pali Rohár
2026-07-06 18:48 ` [PATCH RESEND 11/11] cifs: Add support for creating " Pali Rohár
2026-08-09 12:13   ` [PATCH v2] " Pali Rohár
2026-08-21 21:47 ` [PATCH RESEND 00/11] cifs: Various changes Pali Rohár
2026-08-22 13:28   ` Namjae Jeon
2026-08-22 13:31     ` Pali Rohár
2026-08-24 22:45       ` Paulo Alcantara
2026-08-25 20:26         ` Pali Rohár
2026-08-25 23:06   ` [PATCH 0/9] " Pali Rohár
2026-08-25 23:06     ` [PATCH 1/9] cifs: Remove code for querying FILE_INFO_STANDARD via CIFSSMBQPathInfo() Pali Rohár
2026-08-25 23:06     ` [PATCH 2/9] cifs: Remove cifs_backup_query_path_info() and replace it by cifs_query_path_info() Pali Rohár
2026-08-25 23:06     ` [PATCH 3/9] cifs: Fix validation of EAs for WSL reparse points Pali Rohár
2026-08-25 23:06     ` [PATCH 4/9] cifs: Validate presence of EA $LXMOD " Pali Rohár
2026-08-25 23:06     ` [PATCH 5/9] cifs: Check if server supports EAs before trying to set it for WSL Pali Rohár
2026-08-25 23:06     ` [PATCH 6/9] cifs: Extend ->set_EA() callback to allow operate on reparse point Pali Rohár
2026-08-25 23:06     ` [PATCH 7/9] cifs: Create native Window socket file compatible also with WSL subsystem Pali Rohár
2026-08-25 23:06     ` [PATCH 8/9] cifs: Add support for parsing WSL symlinks in version 1 format Pali Rohár
2026-10-13  8:47       ` Pali Rohár
2026-08-25 23:06     ` [PATCH 9/9] cifs: Add support for creating " Pali Rohár
2026-10-13  8:48       ` Pali Rohár [this message]
2026-10-12 14:10     ` [PATCH 0/9] Various changes Pali Rohár
2026-10-13  5:25       ` Namjae Jeon
2026-10-13  6:55         ` Pali Rohár
2026-10-13  7:56           ` Namjae Jeon
2026-10-13  8:11             ` Pali Rohár
2026-10-13  8:20               ` Namjae Jeon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261013084827.ulqi2u2eebb4i3ay@pali \
    --to=pali@kernel.org \
    --cc=linkinjeon@kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pc@manguebit.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®