mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
enable xattr support for smb3 and also a bugfix
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQGcBAABAgAGBQJZsb0OAAoJEIosvXAHck9RgOYL/0AAqRPEt1mvZTIm51LXxSYy 4Iyyz8AEHFp4ZW5jctblm49/4mh3rJ4O7Ig50de00y+XkoJIzACgf1lazaTTCcNQ lspHnfqCgR1DvF+A7OxbfS4CkF43SXFnL3GcoiW5zpV8QndM3DWLVIj1AHpEtEOX sa3mSdFVhdEP6ka5Q98vam4N6jRnvz1gapLQKHpRTuVAGYZAw44+8HJKxN5btTIP F+9X4zCyNjDDsuKoxAkVZmo/k7cxbKQBRjq9fNLHPR/GPEy06I+j2AqTnd7Gc/o+ 2hw0X4eF8N7HbEujnvEcqPLCqwNVtPNdlOelICNmNSo4OYhrhb3u93hEv7oFuVLH /PlGrzRYi6TEf1aBiftfA9aNVNzCHtnqRIZiC9+LhCiI77H9ef4/Fl7i6xsoKcAi XA0RyslWNbhlQBWMXeQN7k2lyZIx4+Kq7xnnW1FBPLIuLMCrZAS0/IAcakKf3Mud zDzOKI7ZRWEIEaSsM/I/QFfagkMuKTSea6XovkogUw== =+DYj -----END PGP SIGNATURE----- Merge tag '4.14-smb3-xattr-enable' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs update from Steve French: "Enable xattr support for smb3 and also a bugfix" * tag '4.14-smb3-xattr-enable' of git://git.samba.org/sfrench/cifs-2.6: cifs: Check for timeout on Negotiate stage cifs: Add support for writing attributes on SMB2+ cifs: Add support for reading attributes on SMB2+
This commit is contained in:
commit
8dc5b3a6cb
@ -421,7 +421,7 @@ struct smb_version_operations {
|
||||
size_t, struct cifs_sb_info *);
|
||||
int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
|
||||
const char *, const void *, const __u16,
|
||||
const struct nls_table *, int);
|
||||
const struct nls_table *, struct cifs_sb_info *);
|
||||
struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
|
||||
const char *, u32 *);
|
||||
struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,
|
||||
|
@ -484,7 +484,8 @@ extern ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
extern int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *fileName, const char *ea_name,
|
||||
const void *ea_value, const __u16 ea_value_len,
|
||||
const struct nls_table *nls_codepage, int remap_special_chars);
|
||||
const struct nls_table *nls_codepage,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
extern int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
|
||||
extern int CIFSSMBSetCIFSACL(const unsigned int, struct cifs_tcon *, __u16,
|
||||
|
@ -178,6 +178,18 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||
* reconnect the same SMB session
|
||||
*/
|
||||
mutex_lock(&ses->session_mutex);
|
||||
|
||||
/*
|
||||
* Recheck after acquire mutex. If another thread is negotiating
|
||||
* and the server never sends an answer the socket will be closed
|
||||
* and tcpStatus set to reconnect.
|
||||
*/
|
||||
if (server->tcpStatus == CifsNeedReconnect) {
|
||||
rc = -EHOSTDOWN;
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = cifs_negotiate_protocol(0, ses);
|
||||
if (rc == 0 && ses->need_reconnect)
|
||||
rc = cifs_setup_session(0, ses, nls_codepage);
|
||||
@ -6264,7 +6276,7 @@ int
|
||||
CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *fileName, const char *ea_name, const void *ea_value,
|
||||
const __u16 ea_value_len, const struct nls_table *nls_codepage,
|
||||
int remap)
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
struct smb_com_transaction2_spi_req *pSMB = NULL;
|
||||
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
|
||||
@ -6273,6 +6285,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
int rc = 0;
|
||||
int bytes_returned = 0;
|
||||
__u16 params, param_offset, byte_count, offset, count;
|
||||
int remap = cifs_remap(cifs_sb);
|
||||
|
||||
cifs_dbg(FYI, "In SetEA\n");
|
||||
SetEARetry:
|
||||
|
@ -509,7 +509,8 @@ server_unresponsive(struct TCP_Server_Info *server)
|
||||
* 65s kernel_recvmsg times out, and we see that we haven't gotten
|
||||
* a response in >60s.
|
||||
*/
|
||||
if (server->tcpStatus == CifsGood &&
|
||||
if ((server->tcpStatus == CifsGood ||
|
||||
server->tcpStatus == CifsNeedNegotiate) &&
|
||||
time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
|
||||
cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
|
||||
server->hostname, (2 * server->echo_interval) / HZ);
|
||||
|
@ -426,6 +426,194 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
return rc;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
|
||||
char *name, *value;
|
||||
size_t name_len, value_len, user_name_len;
|
||||
|
||||
while (src_size > 0) {
|
||||
name = &src->ea_data[0];
|
||||
name_len = (size_t)src->ea_name_length;
|
||||
value = &src->ea_data[src->ea_name_length + 1];
|
||||
value_len = (size_t)le16_to_cpu(src->ea_value_length);
|
||||
|
||||
if (name_len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (src_size < 8 + name_len + 1 + value_len) {
|
||||
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ea_name) {
|
||||
if (ea_name_len == name_len &&
|
||||
memcmp(ea_name, name, name_len) == 0) {
|
||||
rc = value_len;
|
||||
if (dst_size == 0)
|
||||
goto out;
|
||||
if (dst_size < value_len) {
|
||||
rc = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
memcpy(dst, value, value_len);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* 'user.' plus a terminating null */
|
||||
user_name_len = 5 + 1 + name_len;
|
||||
|
||||
rc += user_name_len;
|
||||
|
||||
if (dst_size >= user_name_len) {
|
||||
dst_size -= user_name_len;
|
||||
memcpy(dst, "user.", 5);
|
||||
dst += 5;
|
||||
memcpy(dst, src->ea_data, name_len);
|
||||
dst += name_len;
|
||||
*dst = 0;
|
||||
++dst;
|
||||
} else if (dst_size == 0) {
|
||||
/* skip copy - calc size only */
|
||||
} else {
|
||||
/* stop before overrun buffer */
|
||||
rc = -ERANGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!src->next_entry_offset)
|
||||
break;
|
||||
|
||||
if (src_size < le32_to_cpu(src->next_entry_offset)) {
|
||||
/* stop before overrun buffer */
|
||||
rc = -ERANGE;
|
||||
break;
|
||||
}
|
||||
src_size -= le32_to_cpu(src->next_entry_offset);
|
||||
src = (void *)((char *)src +
|
||||
le32_to_cpu(src->next_entry_offset));
|
||||
}
|
||||
|
||||
/* didn't find the named attribute */
|
||||
if (ea_name)
|
||||
rc = -ENODATA;
|
||||
|
||||
out:
|
||||
return (ssize_t)rc;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const unsigned char *path, const unsigned char *ea_name,
|
||||
char *ea_data, size_t buf_size,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int rc;
|
||||
__le16 *utf16_path;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
struct smb2_file_full_ea_info *smb2_data;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_EA;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
oparms.create_options = 0;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
|
||||
kfree(utf16_path);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "open failed rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
smb2_data = kzalloc(SMB2_MAX_EA_BUF, GFP_KERNEL);
|
||||
if (smb2_data == NULL) {
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc = SMB2_query_eas(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
||||
smb2_data);
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
|
||||
if (!rc)
|
||||
rc = move_smb2_ea_to_cifs(ea_data, buf_size, smb2_data,
|
||||
SMB2_MAX_EA_BUF, ea_name);
|
||||
|
||||
kfree(smb2_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
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 __u16 ea_value_len, const struct nls_table *nls_codepage,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int rc;
|
||||
__le16 *utf16_path;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
struct smb2_file_full_ea_info *ea;
|
||||
int ea_name_len = strlen(ea_name);
|
||||
int len;
|
||||
|
||||
if (ea_name_len > 255)
|
||||
return -EINVAL;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_WRITE_EA;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
oparms.create_options = 0;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
|
||||
kfree(utf16_path);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "open failed rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
len = sizeof(ea) + ea_name_len + ea_value_len + 1;
|
||||
ea = kzalloc(len, GFP_KERNEL);
|
||||
if (ea == NULL) {
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ea->ea_name_length = ea_name_len;
|
||||
ea->ea_value_length = cpu_to_le16(ea_value_len);
|
||||
memcpy(ea->ea_data, ea_name, ea_name_len + 1);
|
||||
memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len);
|
||||
|
||||
rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea,
|
||||
len);
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool
|
||||
smb2_can_echo(struct TCP_Server_Info *server)
|
||||
{
|
||||
@ -2572,6 +2760,10 @@ struct smb_version_operations smb20_operations = {
|
||||
.dir_needs_close = smb2_dir_needs_close,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
.select_sectype = smb2_select_sectype,
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
.query_all_EAs = smb2_query_eas,
|
||||
.set_EA = smb2_set_ea,
|
||||
#endif /* CIFS_XATTR */
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
.get_acl = get_smb2_acl,
|
||||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
@ -2662,6 +2854,10 @@ struct smb_version_operations smb21_operations = {
|
||||
.enum_snapshots = smb3_enum_snapshots,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
.select_sectype = smb2_select_sectype,
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
.query_all_EAs = smb2_query_eas,
|
||||
.set_EA = smb2_set_ea,
|
||||
#endif /* CIFS_XATTR */
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
.get_acl = get_smb2_acl,
|
||||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
@ -2762,6 +2958,10 @@ struct smb_version_operations smb30_operations = {
|
||||
.receive_transform = smb3_receive_transform,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
.select_sectype = smb2_select_sectype,
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
.query_all_EAs = smb2_query_eas,
|
||||
.set_EA = smb2_set_ea,
|
||||
#endif /* CIFS_XATTR */
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
.get_acl = get_smb2_acl,
|
||||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
@ -2863,6 +3063,10 @@ struct smb_version_operations smb311_operations = {
|
||||
.receive_transform = smb3_receive_transform,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
.select_sectype = smb2_select_sectype,
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
.query_all_EAs = smb2_query_eas,
|
||||
.set_EA = smb2_set_ea,
|
||||
#endif /* CIFS_XATTR */
|
||||
};
|
||||
#endif /* CIFS_SMB311 */
|
||||
|
||||
|
@ -238,6 +238,18 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||
* the same SMB session
|
||||
*/
|
||||
mutex_lock(&tcon->ses->session_mutex);
|
||||
|
||||
/*
|
||||
* Recheck after acquire mutex. If another thread is negotiating
|
||||
* and the server never sends an answer the socket will be closed
|
||||
* and tcpStatus set to reconnect.
|
||||
*/
|
||||
if (server->tcpStatus == CifsNeedReconnect) {
|
||||
rc = -EHOSTDOWN;
|
||||
mutex_unlock(&tcon->ses->session_mutex);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = cifs_negotiate_protocol(0, tcon->ses);
|
||||
if (!rc && tcon->ses->need_reconnect)
|
||||
rc = cifs_setup_session(0, tcon->ses, nls_codepage);
|
||||
@ -2145,6 +2157,18 @@ qinf_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
struct smb2_file_full_ea_info *data)
|
||||
{
|
||||
return query_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
|
||||
SMB2_MAX_EA_BUF,
|
||||
sizeof(struct smb2_file_full_ea_info),
|
||||
(void **)&data,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data)
|
||||
{
|
||||
@ -3184,6 +3208,16 @@ SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
1, (void **)&pnntsd, &pacllen);
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
struct smb2_file_full_ea_info *buf, int len)
|
||||
{
|
||||
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
current->tgid, FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE,
|
||||
0, 1, (void **)&buf, &len);
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const u64 persistent_fid, const u64 volatile_fid,
|
||||
|
@ -1178,6 +1178,16 @@ struct smb2_file_link_info { /* encoding of request for level 11 */
|
||||
char FileName[0]; /* Name to be assigned to new link */
|
||||
} __packed; /* level 11 Set */
|
||||
|
||||
#define SMB2_MAX_EA_BUF 2048
|
||||
|
||||
struct smb2_file_full_ea_info { /* encoding of response for level 15 */
|
||||
__le32 next_entry_offset;
|
||||
__u8 flags;
|
||||
__u8 ea_name_length;
|
||||
__le16 ea_value_length;
|
||||
char ea_data[0]; /* \0 terminated name plus value */
|
||||
} __packed; /* level 15 Set */
|
||||
|
||||
/*
|
||||
* This level 18, although with struct with same name is different from cifs
|
||||
* level 0x107. Level 0x107 has an extra u64 between AccessFlags and
|
||||
|
@ -132,6 +132,9 @@ extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id);
|
||||
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id);
|
||||
extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
struct smb2_file_full_ea_info *data);
|
||||
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
struct smb2_file_all_info *data);
|
||||
@ -169,6 +172,9 @@ extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
extern int SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
struct cifs_ntsd *pnntsd, int pacllen, int aclflag);
|
||||
extern int SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
struct smb2_file_full_ea_info *buf, int len);
|
||||
extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid);
|
||||
extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
@ -84,7 +84,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
|
||||
if (pTcon->ses->server->ops->set_EA)
|
||||
rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
|
||||
full_path, name, value, (__u16)size,
|
||||
cifs_sb->local_nls, cifs_remap(cifs_sb));
|
||||
cifs_sb->local_nls, cifs_sb);
|
||||
break;
|
||||
|
||||
case XATTR_CIFS_ACL: {
|
||||
|
Loading…
Reference in New Issue
Block a user