If SMB server does not support EAs then for SMB2_OP_QUERY_WSL_EA request it returns STATUS_EAS_NOT_SUPPORTED. Function smb2_compound_op() translates STATUS_EAS_NOT_SUPPORTED to -EOPNOTSUPP which cause failure during calling lstat() syscall from userspace on any reparse point, including Native SMB symlink (which does not use any EAs). If SMB server does not support to attach both EAs and Reparse Point to path at the same time then same error STATUS_EAS_NOT_SUPPORTED is returned. This is the case for Windows 8 / Windows Server 2012. It is known limitation of NTFS driver in those older Windows versions. Since commit ea41367b2a60 ("smb: client: introduce SMB2_OP_QUERY_WSL_EA") Linux SMB client always ask for EAs on detected reparse point paths due to support of WSL EAs. But this commit broke reparse point support for all older Windows SMB servers which do not have support for WSL and WSL EAs. Avoid this problem by retrying the request without SMB2_OP_QUERY_WSL_EA when it fails on -EOPNOTSUPP error. This should fix broken support for all special files (symlink, fifo, socket, block and char) for SMB server which do not support EAs at all and for SMB server which do not allow to attach both EAs and Reparse Point at the same time. Fixes: ea41367b2a60 ("smb: client: introduce SMB2_OP_QUERY_WSL_EA") Cc: stable@xxxxxxxxxxxxxxx Signed-off-by: Pali Rohár <pali@xxxxxxxxxx> --- fs/smb/client/smb2inode.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index e8bb3f8b53f1..58276434e47b 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -875,6 +875,7 @@ int smb2_query_path_info(const unsigned int xid, bool islink; int i, num_cmds = 0; int rc, rc2; + bool skip_wsl_ea; data->adjust_tz = false; data->reparse_point = false; @@ -943,7 +944,13 @@ int smb2_query_path_info(const unsigned int xid, if (rc || !data->reparse_point) goto out; - if (!tcon->posix_extensions) + skip_wsl_ea = false; +retry_cmd: + /* + * Skip SMB2_OP_QUERY_WSL_EA if using POSIX extensions or + * retrying request with explicitly skipping for WSL EAs. + */ + if (!tcon->posix_extensions && !skip_wsl_ea) cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; /* * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create @@ -961,6 +968,35 @@ int smb2_query_path_info(const unsigned int xid, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms, in_iov, cmds, num_cmds, cfile, NULL, NULL, NULL); + if (rc == -EOPNOTSUPP && !tcon->posix_extensions && !skip_wsl_ea) { + /* + * Older Windows versions do not allow to set both EAs + * and Reparse Point as the same time. This is known + * limitation of older NTFS driver and it was fixed in + * Windows 10. Trying to query EAs on file which has + * Reparse Point set ends with STATUS_EAS_NOT_SUPPORTED + * error, even when server filesystem supports EAs. + * This error is translated to errno -EOPNOTSUPP. + * So in this case retry the request again without EAs. + */ + skip_wsl_ea = true; + num_cmds = 1; + goto retry_cmd; + } + if (rc == 0 && skip_wsl_ea && + (data->reparse.tag == IO_REPARSE_TAG_LX_CHR || + data->reparse.tag == IO_REPARSE_TAG_LX_BLK)) { + /* + * WSL CHR and BLK reparse points store major and minor + * device numbers in EAs (instead of reparse point buffer, + * like it is for WSL symlink or NFS reparse point types). + * Therefore with skipped EAs it is not possible to finish + * query of these files. So change error back to the + * original -EOPNOTSUPP. + */ + rc = -EOPNOTSUPP; + } + if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) { bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY; rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb); -- 2.20.1