* Re: [PATCH] cifs: add mount option to encode xattr names as hexadecimal
2019-06-21 0:02 [PATCH] cifs: add mount option to encode xattr names as hexadecimal Ronnie Sahlberg
@ 2019-06-21 0:16 ` Steve French
2019-06-21 0:31 ` ronnie sahlberg
2019-07-16 5:35 ` Steve French
1 sibling, 1 reply; 4+ messages in thread
From: Steve French @ 2019-06-21 0:16 UTC (permalink / raw)
To: Ronnie Sahlberg; +Cc: linux-cifs
Do you remember which xfstests this fixes?
Also any ideas on whether we still need a fix for deleting an empty or
nonexistent xattr?
On Thu, Jun 20, 2019 at 7:03 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
>
> We store xattrs as Extended Attributes for SMB.
> Some servers treat the EA names as case-insensitive as well as converting them to all upper-case.
>
> This addresses that issue by adding a new mount option to convert all EA names to/from
> hexadecimal representation.
>
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
> fs/cifs/cifs_fs_sb.h | 1 +
> fs/cifs/cifsfs.c | 3 +++
> fs/cifs/cifsglob.h | 3 ++-
> fs/cifs/connect.c | 7 +++++++
> fs/cifs/smb2ops.c | 58 ++++++++++++++++++++++++++++++++++++++++------------
> 5 files changed, 58 insertions(+), 14 deletions(-)
>
> diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
> index ed49222abecb..11fb5f4d2b0e 100644
> --- a/fs/cifs/cifs_fs_sb.h
> +++ b/fs/cifs/cifs_fs_sb.h
> @@ -52,6 +52,7 @@
> #define CIFS_MOUNT_UID_FROM_ACL 0x2000000 /* try to get UID via special SID */
> #define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */
> #define CIFS_MOUNT_NO_DFS 0x8000000 /* disable DFS resolving */
> +#define CIFS_MOUNT_ENCODED_XATTR 0x10000000 /* encode the xattr names */
>
> struct cifs_sb_info {
> struct rb_root tlink_tree;
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index d06edebf3a73..c3c837ee3c4e 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -471,6 +471,9 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
> else
> seq_puts(s, ",noforcegid");
>
> + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_ENCODED_XATTR)
> + seq_puts(s, ",endodedxattr");
> +
> cifs_show_address(s, tcon->ses->server);
>
> if (!tcon->unix_ext)
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 4777b3c4a92c..b479207f7f74 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -585,6 +585,7 @@ struct smb_vol {
> bool resilient:1; /* noresilient not required since not fored for CA */
> bool domainauto:1;
> bool rdma:1;
> + bool encoded_xattr:1;
> unsigned int bsize;
> unsigned int rsize;
> unsigned int wsize;
> @@ -617,7 +618,7 @@ struct smb_vol {
> CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \
> CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
> CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID | \
> - CIFS_MOUNT_NO_DFS)
> + CIFS_MOUNT_NO_DFS|CIFS_MOUNT_ENCODED_XATTR)
>
> /**
> * Generic VFS superblock mount flags (s_flags) to consider when
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 51f272377ae1..f955b28a9b38 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -97,6 +97,7 @@ enum {
> Opt_persistent, Opt_nopersistent,
> Opt_resilient, Opt_noresilient,
> Opt_domainauto, Opt_rdma,
> + Opt_encodedxattr,
>
> /* Mount options which take numeric value */
> Opt_backupuid, Opt_backupgid, Opt_uid,
> @@ -194,6 +195,7 @@ static const match_table_t cifs_mount_option_tokens = {
> { Opt_noresilient, "noresilienthandles"},
> { Opt_domainauto, "domainauto"},
> { Opt_rdma, "rdma"},
> + { Opt_encodedxattr, "encodedxattr" },
>
> { Opt_backupuid, "backupuid=%s" },
> { Opt_backupgid, "backupgid=%s" },
> @@ -1911,6 +1913,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
> case Opt_rdma:
> vol->rdma = true;
> break;
> + case Opt_encodedxattr:
> + vol->encoded_xattr = 1;
> + break;
>
> /* Numeric Values */
> case Opt_backupuid:
> @@ -3986,6 +3991,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
> cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
> if (pvolume_info->override_gid)
> cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
> + if (pvolume_info->encoded_xattr)
> + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_ENCODED_XATTR;
> if (pvolume_info->dynperm)
> cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
> if (pvolume_info->fsc)
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 376577cc4159..e2684a6627bb 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -891,7 +891,8 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
> static ssize_t
> move_smb2_ea_to_cifs(char *dst, size_t dst_size,
> struct smb2_file_full_ea_info *src, size_t src_size,
> - const unsigned char *ea_name)
> + const unsigned char *ea_name,
> + struct cifs_sb_info *cifs_sb)
> {
> int rc = 0;
> unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
> @@ -905,6 +906,18 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size,
> value = &src->ea_data[src->ea_name_length + 1];
> value_len = (size_t)le16_to_cpu(src->ea_value_length);
>
> + if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR) {
> + if (name_len & 0x01) {
> + rc = -EINVAL;
> + goto out;
> + }
> + name_len = name_len / 2;
> + if (hex2bin(name, name, name_len)) {
> + rc = -EINVAL;
> + goto out;
> + }
> + }
> +
> if (name_len == 0)
> break;
>
> @@ -1018,7 +1031,8 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
> info = (struct smb2_file_full_ea_info *)(
> le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
> rc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
> - le32_to_cpu(rsp->OutputBufferLength), ea_name);
> + le32_to_cpu(rsp->OutputBufferLength),
> + ea_name, cifs_sb);
>
> qeas_exit:
> kfree(utf16_path);
> @@ -1029,13 +1043,14 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
>
> static int
> smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> - const char *path, const char *ea_name, const void *ea_value,
> + const char *path, const char *name, const void *ea_value,
> const __u16 ea_value_len, const struct nls_table *nls_codepage,
> struct cifs_sb_info *cifs_sb)
> {
> struct cifs_ses *ses = tcon->ses;
> __le16 *utf16_path = NULL;
> - int ea_name_len = strlen(ea_name);
> + char *ea_name = (char *)name;
> + int ea_name_len = strlen(name);
> int flags = 0;
> int len;
> struct smb_rqst rqst[3];
> @@ -1050,21 +1065,36 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> void *data[1];
> struct smb2_file_full_ea_info *ea = NULL;
> struct kvec close_iov[1];
> - int rc;
> + int i, rc;
> +
> + memset(rqst, 0, sizeof(rqst));
> + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
> + memset(rsp_iov, 0, sizeof(rsp_iov));
>
> if (smb3_encryption_required(tcon))
> flags |= CIFS_TRANSFORM_REQ;
>
> - if (ea_name_len > 255)
> - return -EINVAL;
> + /* Do we need to encode the name in hex ? */
> + if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR) {
> + ea_name = kzalloc(ea_name_len * 2 + 1, GFP_KERNEL);
> + if (ea_name == NULL) {
> + rc = -ENOMEM;
> + goto sea_exit;
> + }
> + bin2hex(ea_name, name, ea_name_len);
> + ea_name_len = 2 * ea_name_len;
> + }
>
> - utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
> - if (!utf16_path)
> - return -ENOMEM;
> + if (ea_name_len > 255) {
> + rc = -EINVAL;
> + goto sea_exit;
> + }
>
> - memset(rqst, 0, sizeof(rqst));
> - resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
> - memset(rsp_iov, 0, sizeof(rsp_iov));
> + utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
> + if (!utf16_path) {
> + rc = -ENOMEM;
> + goto sea_exit;
> + }
>
> if (ses->server->ops->query_all_EAs) {
> if (!ea_value) {
> @@ -1137,6 +1167,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> resp_buftype, rsp_iov);
>
> sea_exit:
> + if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR)
> + kfree(ea_name);
> kfree(ea);
> kfree(utf16_path);
> SMB2_open_free(&rqst[0]);
> --
> 2.13.6
>
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] cifs: add mount option to encode xattr names as hexadecimal
2019-06-21 0:02 [PATCH] cifs: add mount option to encode xattr names as hexadecimal Ronnie Sahlberg
2019-06-21 0:16 ` Steve French
@ 2019-07-16 5:35 ` Steve French
1 sibling, 0 replies; 4+ messages in thread
From: Steve French @ 2019-07-16 5:35 UTC (permalink / raw)
To: Ronnie Sahlberg; +Cc: linux-cifs
[-- Attachment #1: Type: text/plain, Size: 9161 bytes --]
Updated patch to fix minor compile warning and to rebase it on current for-next
On Thu, Jun 20, 2019 at 7:03 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
>
> We store xattrs as Extended Attributes for SMB.
> Some servers treat the EA names as case-insensitive as well as converting them to all upper-case.
>
> This addresses that issue by adding a new mount option to convert all EA names to/from
> hexadecimal representation.
>
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
> fs/cifs/cifs_fs_sb.h | 1 +
> fs/cifs/cifsfs.c | 3 +++
> fs/cifs/cifsglob.h | 3 ++-
> fs/cifs/connect.c | 7 +++++++
> fs/cifs/smb2ops.c | 58 ++++++++++++++++++++++++++++++++++++++++------------
> 5 files changed, 58 insertions(+), 14 deletions(-)
>
> diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
> index ed49222abecb..11fb5f4d2b0e 100644
> --- a/fs/cifs/cifs_fs_sb.h
> +++ b/fs/cifs/cifs_fs_sb.h
> @@ -52,6 +52,7 @@
> #define CIFS_MOUNT_UID_FROM_ACL 0x2000000 /* try to get UID via special SID */
> #define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */
> #define CIFS_MOUNT_NO_DFS 0x8000000 /* disable DFS resolving */
> +#define CIFS_MOUNT_ENCODED_XATTR 0x10000000 /* encode the xattr names */
>
> struct cifs_sb_info {
> struct rb_root tlink_tree;
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index d06edebf3a73..c3c837ee3c4e 100644
> --- a/fs/cifs/cifsfs.c
> +++ b/fs/cifs/cifsfs.c
> @@ -471,6 +471,9 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
> else
> seq_puts(s, ",noforcegid");
>
> + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_ENCODED_XATTR)
> + seq_puts(s, ",endodedxattr");
> +
> cifs_show_address(s, tcon->ses->server);
>
> if (!tcon->unix_ext)
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 4777b3c4a92c..b479207f7f74 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -585,6 +585,7 @@ struct smb_vol {
> bool resilient:1; /* noresilient not required since not fored for CA */
> bool domainauto:1;
> bool rdma:1;
> + bool encoded_xattr:1;
> unsigned int bsize;
> unsigned int rsize;
> unsigned int wsize;
> @@ -617,7 +618,7 @@ struct smb_vol {
> CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \
> CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
> CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID | \
> - CIFS_MOUNT_NO_DFS)
> + CIFS_MOUNT_NO_DFS|CIFS_MOUNT_ENCODED_XATTR)
>
> /**
> * Generic VFS superblock mount flags (s_flags) to consider when
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 51f272377ae1..f955b28a9b38 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -97,6 +97,7 @@ enum {
> Opt_persistent, Opt_nopersistent,
> Opt_resilient, Opt_noresilient,
> Opt_domainauto, Opt_rdma,
> + Opt_encodedxattr,
>
> /* Mount options which take numeric value */
> Opt_backupuid, Opt_backupgid, Opt_uid,
> @@ -194,6 +195,7 @@ static const match_table_t cifs_mount_option_tokens = {
> { Opt_noresilient, "noresilienthandles"},
> { Opt_domainauto, "domainauto"},
> { Opt_rdma, "rdma"},
> + { Opt_encodedxattr, "encodedxattr" },
>
> { Opt_backupuid, "backupuid=%s" },
> { Opt_backupgid, "backupgid=%s" },
> @@ -1911,6 +1913,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
> case Opt_rdma:
> vol->rdma = true;
> break;
> + case Opt_encodedxattr:
> + vol->encoded_xattr = 1;
> + break;
>
> /* Numeric Values */
> case Opt_backupuid:
> @@ -3986,6 +3991,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
> cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
> if (pvolume_info->override_gid)
> cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
> + if (pvolume_info->encoded_xattr)
> + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_ENCODED_XATTR;
> if (pvolume_info->dynperm)
> cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
> if (pvolume_info->fsc)
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 376577cc4159..e2684a6627bb 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -891,7 +891,8 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
> static ssize_t
> move_smb2_ea_to_cifs(char *dst, size_t dst_size,
> struct smb2_file_full_ea_info *src, size_t src_size,
> - const unsigned char *ea_name)
> + const unsigned char *ea_name,
> + struct cifs_sb_info *cifs_sb)
> {
> int rc = 0;
> unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
> @@ -905,6 +906,18 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size,
> value = &src->ea_data[src->ea_name_length + 1];
> value_len = (size_t)le16_to_cpu(src->ea_value_length);
>
> + if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR) {
> + if (name_len & 0x01) {
> + rc = -EINVAL;
> + goto out;
> + }
> + name_len = name_len / 2;
> + if (hex2bin(name, name, name_len)) {
> + rc = -EINVAL;
> + goto out;
> + }
> + }
> +
> if (name_len == 0)
> break;
>
> @@ -1018,7 +1031,8 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
> info = (struct smb2_file_full_ea_info *)(
> le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
> rc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
> - le32_to_cpu(rsp->OutputBufferLength), ea_name);
> + le32_to_cpu(rsp->OutputBufferLength),
> + ea_name, cifs_sb);
>
> qeas_exit:
> kfree(utf16_path);
> @@ -1029,13 +1043,14 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
>
> static int
> smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> - const char *path, const char *ea_name, const void *ea_value,
> + const char *path, const char *name, const void *ea_value,
> const __u16 ea_value_len, const struct nls_table *nls_codepage,
> struct cifs_sb_info *cifs_sb)
> {
> struct cifs_ses *ses = tcon->ses;
> __le16 *utf16_path = NULL;
> - int ea_name_len = strlen(ea_name);
> + char *ea_name = (char *)name;
> + int ea_name_len = strlen(name);
> int flags = 0;
> int len;
> struct smb_rqst rqst[3];
> @@ -1050,21 +1065,36 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> void *data[1];
> struct smb2_file_full_ea_info *ea = NULL;
> struct kvec close_iov[1];
> - int rc;
> + int i, rc;
> +
> + memset(rqst, 0, sizeof(rqst));
> + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
> + memset(rsp_iov, 0, sizeof(rsp_iov));
>
> if (smb3_encryption_required(tcon))
> flags |= CIFS_TRANSFORM_REQ;
>
> - if (ea_name_len > 255)
> - return -EINVAL;
> + /* Do we need to encode the name in hex ? */
> + if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR) {
> + ea_name = kzalloc(ea_name_len * 2 + 1, GFP_KERNEL);
> + if (ea_name == NULL) {
> + rc = -ENOMEM;
> + goto sea_exit;
> + }
> + bin2hex(ea_name, name, ea_name_len);
> + ea_name_len = 2 * ea_name_len;
> + }
>
> - utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
> - if (!utf16_path)
> - return -ENOMEM;
> + if (ea_name_len > 255) {
> + rc = -EINVAL;
> + goto sea_exit;
> + }
>
> - memset(rqst, 0, sizeof(rqst));
> - resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
> - memset(rsp_iov, 0, sizeof(rsp_iov));
> + utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
> + if (!utf16_path) {
> + rc = -ENOMEM;
> + goto sea_exit;
> + }
>
> if (ses->server->ops->query_all_EAs) {
> if (!ea_value) {
> @@ -1137,6 +1167,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> resp_buftype, rsp_iov);
>
> sea_exit:
> + if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR)
> + kfree(ea_name);
> kfree(ea);
> kfree(utf16_path);
> SMB2_open_free(&rqst[0]);
> --
> 2.13.6
>
--
Thanks,
Steve
[-- Attachment #2: 0005-smb3-add-mount-option-to-encode-xattr-names-as-hexad.patch --]
[-- Type: text/x-patch, Size: 7491 bytes --]
From 8ee52a8ad1dabc3e4802cfb064a0025c2cd0eec6 Mon Sep 17 00:00:00 2001
From: Ronnie Sahlberg <lsahlber@redhat.com>
Date: Tue, 16 Jul 2019 00:25:16 -0500
Subject: [PATCH 5/5] smb3: add mount option to encode xattr names as
hexadecimal
We store xattrs as Extended Attributes for SMB.
Some servers treat the EA names as case-insensitive as well
as converting them to all upper-case.
This addresses that issue by adding a new mount option to convert
all EA names to/from hexadecimal representation.
Fixes xfstest generic/533 to Windows servers
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
---
fs/cifs/cifs_fs_sb.h | 1 +
fs/cifs/cifsfs.c | 3 +++
fs/cifs/cifsglob.h | 4 +++-
fs/cifs/connect.c | 8 ++++++-
fs/cifs/smb2ops.c | 56 ++++++++++++++++++++++++++++++++++----------
5 files changed, 58 insertions(+), 14 deletions(-)
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index b326d2ca3765..90e2192daeff 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -53,6 +53,7 @@
#define CIFS_MOUNT_NO_HANDLE_CACHE 0x4000000 /* disable caching dir handles */
#define CIFS_MOUNT_NO_DFS 0x8000000 /* disable DFS resolving */
#define CIFS_MOUNT_MODE_FROM_SID 0x10000000 /* retrieve mode from special ACE */
+#define CIFS_MOUNT_ENCODED_XATTR 0x20000000 /* encode the xattr names */
struct cifs_sb_info {
struct rb_root tlink_tree;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 0ee63ac4ef72..320c7a6fd318 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -471,6 +471,9 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
else
seq_puts(s, ",noforcegid");
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_ENCODED_XATTR)
+ seq_puts(s, ",endodedxattr");
+
cifs_show_address(s, tcon->ses->server);
if (!tcon->unix_ext)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index fe610e7e3670..8c7ea733947b 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -586,6 +586,7 @@ struct smb_vol {
bool resilient:1; /* noresilient not required since not fored for CA */
bool domainauto:1;
bool rdma:1;
+ bool encoded_xattr:1;
unsigned int bsize;
unsigned int rsize;
unsigned int wsize;
@@ -620,7 +621,8 @@ struct smb_vol {
CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID | \
CIFS_MOUNT_UID_FROM_ACL | CIFS_MOUNT_NO_HANDLE_CACHE | \
- CIFS_MOUNT_NO_DFS | CIFS_MOUNT_MODE_FROM_SID)
+ CIFS_MOUNT_NO_DFS | CIFS_MOUNT_MODE_FROM_SID | \
+ CIFS_MOUNT_ENCODED_XATTR)
/**
* Generic VFS superblock mount flags (s_flags) to consider when
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 6331c4f93b59..35dfc412370b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -97,7 +97,7 @@ enum {
Opt_persistent, Opt_nopersistent,
Opt_resilient, Opt_noresilient,
Opt_domainauto, Opt_rdma, Opt_modesid,
- Opt_compress,
+ Opt_compress, Opt_encodedxattr,
/* Mount options which take numeric value */
Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -196,6 +196,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_noresilient, "noresilienthandles"},
{ Opt_domainauto, "domainauto"},
{ Opt_rdma, "rdma"},
+ { Opt_encodedxattr, "encodedxattr" },
{ Opt_backupuid, "backupuid=%s" },
{ Opt_backupgid, "backupgid=%s" },
@@ -1922,6 +1923,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
cifs_dbg(VFS,
"SMB3 compression support is experimental\n");
break;
+ case Opt_encodedxattr:
+ vol->encoded_xattr = 1;
+ break;
/* Numeric Values */
case Opt_backupuid:
@@ -4004,6 +4008,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
if (pvolume_info->override_gid)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+ if (pvolume_info->encoded_xattr)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_ENCODED_XATTR;
if (pvolume_info->dynperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
if (pvolume_info->fsc)
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0cdc4e47ca87..6cb4def11ebe 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -878,7 +878,8 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
static ssize_t
move_smb2_ea_to_cifs(char *dst, size_t dst_size,
struct smb2_file_full_ea_info *src, size_t src_size,
- const unsigned char *ea_name)
+ const unsigned char *ea_name,
+ struct cifs_sb_info *cifs_sb)
{
int rc = 0;
unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
@@ -892,6 +893,18 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size,
value = &src->ea_data[src->ea_name_length + 1];
value_len = (size_t)le16_to_cpu(src->ea_value_length);
+ if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR) {
+ if (name_len & 0x01) {
+ rc = -EINVAL;
+ goto out;
+ }
+ name_len = name_len / 2;
+ if (hex2bin(name, name, name_len)) {
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+
if (name_len == 0)
break;
@@ -1005,7 +1018,8 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
info = (struct smb2_file_full_ea_info *)(
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
rc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
- le32_to_cpu(rsp->OutputBufferLength), ea_name);
+ le32_to_cpu(rsp->OutputBufferLength),
+ ea_name, cifs_sb);
qeas_exit:
kfree(utf16_path);
@@ -1016,13 +1030,14 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
static int
smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
- const char *path, const char *ea_name, const void *ea_value,
+ const char *path, const char *name, const void *ea_value,
const __u16 ea_value_len, const struct nls_table *nls_codepage,
struct cifs_sb_info *cifs_sb)
{
struct cifs_ses *ses = tcon->ses;
__le16 *utf16_path = NULL;
- int ea_name_len = strlen(ea_name);
+ char *ea_name = (char *)name;
+ int ea_name_len = strlen(name);
int flags = 0;
int len;
struct smb_rqst rqst[3];
@@ -1039,19 +1054,34 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
struct kvec close_iov[1];
int rc;
+ memset(rqst, 0, sizeof(rqst));
+ resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
+ memset(rsp_iov, 0, sizeof(rsp_iov));
+
if (smb3_encryption_required(tcon))
flags |= CIFS_TRANSFORM_REQ;
- if (ea_name_len > 255)
- return -EINVAL;
+ /* Do we need to encode the name in hex ? */
+ if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR) {
+ ea_name = kzalloc(ea_name_len * 2 + 1, GFP_KERNEL);
+ if (ea_name == NULL) {
+ rc = -ENOMEM;
+ goto sea_exit;
+ }
+ bin2hex(ea_name, name, ea_name_len);
+ ea_name_len = 2 * ea_name_len;
+ }
- utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
- if (!utf16_path)
- return -ENOMEM;
+ if (ea_name_len > 255) {
+ rc = -EINVAL;
+ goto sea_exit;
+ }
- memset(rqst, 0, sizeof(rqst));
- resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
- memset(rsp_iov, 0, sizeof(rsp_iov));
+ utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+ if (!utf16_path) {
+ rc = -ENOMEM;
+ goto sea_exit;
+ }
if (ses->server->ops->query_all_EAs) {
if (!ea_value) {
@@ -1124,6 +1154,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
resp_buftype, rsp_iov);
sea_exit:
+ if (cifs_sb->mnt_cifs_flags | CIFS_MOUNT_ENCODED_XATTR)
+ kfree(ea_name);
kfree(ea);
kfree(utf16_path);
SMB2_open_free(&rqst[0]);
--
2.20.1
^ permalink raw reply related [flat|nested] 4+ messages in thread