Skip to content

Commit 8dc5b3a

Browse files
committed
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+
2 parents 2500e28 + 76e7527 commit 8dc5b3a

File tree

9 files changed

+274
-5
lines changed

9 files changed

+274
-5
lines changed

fs/cifs/cifsglob.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ struct smb_version_operations {
421421
size_t, struct cifs_sb_info *);
422422
int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
423423
const char *, const void *, const __u16,
424-
const struct nls_table *, int);
424+
const struct nls_table *, struct cifs_sb_info *);
425425
struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
426426
const char *, u32 *);
427427
struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,

fs/cifs/cifsproto.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,8 @@ extern ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
484484
extern int CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
485485
const char *fileName, const char *ea_name,
486486
const void *ea_value, const __u16 ea_value_len,
487-
const struct nls_table *nls_codepage, int remap_special_chars);
487+
const struct nls_table *nls_codepage,
488+
struct cifs_sb_info *cifs_sb);
488489
extern int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon,
489490
__u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen);
490491
extern int CIFSSMBSetCIFSACL(const unsigned int, struct cifs_tcon *, __u16,

fs/cifs/cifssmb.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,18 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
178178
* reconnect the same SMB session
179179
*/
180180
mutex_lock(&ses->session_mutex);
181+
182+
/*
183+
* Recheck after acquire mutex. If another thread is negotiating
184+
* and the server never sends an answer the socket will be closed
185+
* and tcpStatus set to reconnect.
186+
*/
187+
if (server->tcpStatus == CifsNeedReconnect) {
188+
rc = -EHOSTDOWN;
189+
mutex_unlock(&ses->session_mutex);
190+
goto out;
191+
}
192+
181193
rc = cifs_negotiate_protocol(0, ses);
182194
if (rc == 0 && ses->need_reconnect)
183195
rc = cifs_setup_session(0, ses, nls_codepage);
@@ -6264,7 +6276,7 @@ int
62646276
CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
62656277
const char *fileName, const char *ea_name, const void *ea_value,
62666278
const __u16 ea_value_len, const struct nls_table *nls_codepage,
6267-
int remap)
6279+
struct cifs_sb_info *cifs_sb)
62686280
{
62696281
struct smb_com_transaction2_spi_req *pSMB = NULL;
62706282
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -6273,6 +6285,7 @@ CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
62736285
int rc = 0;
62746286
int bytes_returned = 0;
62756287
__u16 params, param_offset, byte_count, offset, count;
6288+
int remap = cifs_remap(cifs_sb);
62766289

62776290
cifs_dbg(FYI, "In SetEA\n");
62786291
SetEARetry:

fs/cifs/connect.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,8 @@ server_unresponsive(struct TCP_Server_Info *server)
509509
* 65s kernel_recvmsg times out, and we see that we haven't gotten
510510
* a response in >60s.
511511
*/
512-
if (server->tcpStatus == CifsGood &&
512+
if ((server->tcpStatus == CifsGood ||
513+
server->tcpStatus == CifsNeedNegotiate) &&
513514
time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
514515
cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
515516
server->hostname, (2 * server->echo_interval) / HZ);

fs/cifs/smb2ops.c

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,194 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
426426
return rc;
427427
}
428428

429+
static ssize_t
430+
move_smb2_ea_to_cifs(char *dst, size_t dst_size,
431+
struct smb2_file_full_ea_info *src, size_t src_size,
432+
const unsigned char *ea_name)
433+
{
434+
int rc = 0;
435+
unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
436+
char *name, *value;
437+
size_t name_len, value_len, user_name_len;
438+
439+
while (src_size > 0) {
440+
name = &src->ea_data[0];
441+
name_len = (size_t)src->ea_name_length;
442+
value = &src->ea_data[src->ea_name_length + 1];
443+
value_len = (size_t)le16_to_cpu(src->ea_value_length);
444+
445+
if (name_len == 0) {
446+
break;
447+
}
448+
449+
if (src_size < 8 + name_len + 1 + value_len) {
450+
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
451+
rc = -EIO;
452+
goto out;
453+
}
454+
455+
if (ea_name) {
456+
if (ea_name_len == name_len &&
457+
memcmp(ea_name, name, name_len) == 0) {
458+
rc = value_len;
459+
if (dst_size == 0)
460+
goto out;
461+
if (dst_size < value_len) {
462+
rc = -ERANGE;
463+
goto out;
464+
}
465+
memcpy(dst, value, value_len);
466+
goto out;
467+
}
468+
} else {
469+
/* 'user.' plus a terminating null */
470+
user_name_len = 5 + 1 + name_len;
471+
472+
rc += user_name_len;
473+
474+
if (dst_size >= user_name_len) {
475+
dst_size -= user_name_len;
476+
memcpy(dst, "user.", 5);
477+
dst += 5;
478+
memcpy(dst, src->ea_data, name_len);
479+
dst += name_len;
480+
*dst = 0;
481+
++dst;
482+
} else if (dst_size == 0) {
483+
/* skip copy - calc size only */
484+
} else {
485+
/* stop before overrun buffer */
486+
rc = -ERANGE;
487+
break;
488+
}
489+
}
490+
491+
if (!src->next_entry_offset)
492+
break;
493+
494+
if (src_size < le32_to_cpu(src->next_entry_offset)) {
495+
/* stop before overrun buffer */
496+
rc = -ERANGE;
497+
break;
498+
}
499+
src_size -= le32_to_cpu(src->next_entry_offset);
500+
src = (void *)((char *)src +
501+
le32_to_cpu(src->next_entry_offset));
502+
}
503+
504+
/* didn't find the named attribute */
505+
if (ea_name)
506+
rc = -ENODATA;
507+
508+
out:
509+
return (ssize_t)rc;
510+
}
511+
512+
static ssize_t
513+
smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
514+
const unsigned char *path, const unsigned char *ea_name,
515+
char *ea_data, size_t buf_size,
516+
struct cifs_sb_info *cifs_sb)
517+
{
518+
int rc;
519+
__le16 *utf16_path;
520+
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
521+
struct cifs_open_parms oparms;
522+
struct cifs_fid fid;
523+
struct smb2_file_full_ea_info *smb2_data;
524+
525+
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
526+
if (!utf16_path)
527+
return -ENOMEM;
528+
529+
oparms.tcon = tcon;
530+
oparms.desired_access = FILE_READ_EA;
531+
oparms.disposition = FILE_OPEN;
532+
oparms.create_options = 0;
533+
oparms.fid = &fid;
534+
oparms.reconnect = false;
535+
536+
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
537+
kfree(utf16_path);
538+
if (rc) {
539+
cifs_dbg(FYI, "open failed rc=%d\n", rc);
540+
return rc;
541+
}
542+
543+
smb2_data = kzalloc(SMB2_MAX_EA_BUF, GFP_KERNEL);
544+
if (smb2_data == NULL) {
545+
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
546+
return -ENOMEM;
547+
}
548+
549+
rc = SMB2_query_eas(xid, tcon, fid.persistent_fid, fid.volatile_fid,
550+
smb2_data);
551+
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
552+
553+
if (!rc)
554+
rc = move_smb2_ea_to_cifs(ea_data, buf_size, smb2_data,
555+
SMB2_MAX_EA_BUF, ea_name);
556+
557+
kfree(smb2_data);
558+
return rc;
559+
}
560+
561+
562+
static int
563+
smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
564+
const char *path, const char *ea_name, const void *ea_value,
565+
const __u16 ea_value_len, const struct nls_table *nls_codepage,
566+
struct cifs_sb_info *cifs_sb)
567+
{
568+
int rc;
569+
__le16 *utf16_path;
570+
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
571+
struct cifs_open_parms oparms;
572+
struct cifs_fid fid;
573+
struct smb2_file_full_ea_info *ea;
574+
int ea_name_len = strlen(ea_name);
575+
int len;
576+
577+
if (ea_name_len > 255)
578+
return -EINVAL;
579+
580+
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
581+
if (!utf16_path)
582+
return -ENOMEM;
583+
584+
oparms.tcon = tcon;
585+
oparms.desired_access = FILE_WRITE_EA;
586+
oparms.disposition = FILE_OPEN;
587+
oparms.create_options = 0;
588+
oparms.fid = &fid;
589+
oparms.reconnect = false;
590+
591+
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
592+
kfree(utf16_path);
593+
if (rc) {
594+
cifs_dbg(FYI, "open failed rc=%d\n", rc);
595+
return rc;
596+
}
597+
598+
len = sizeof(ea) + ea_name_len + ea_value_len + 1;
599+
ea = kzalloc(len, GFP_KERNEL);
600+
if (ea == NULL) {
601+
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
602+
return -ENOMEM;
603+
}
604+
605+
ea->ea_name_length = ea_name_len;
606+
ea->ea_value_length = cpu_to_le16(ea_value_len);
607+
memcpy(ea->ea_data, ea_name, ea_name_len + 1);
608+
memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len);
609+
610+
rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea,
611+
len);
612+
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
613+
614+
return rc;
615+
}
616+
429617
static bool
430618
smb2_can_echo(struct TCP_Server_Info *server)
431619
{
@@ -2572,6 +2760,10 @@ struct smb_version_operations smb20_operations = {
25722760
.dir_needs_close = smb2_dir_needs_close,
25732761
.get_dfs_refer = smb2_get_dfs_refer,
25742762
.select_sectype = smb2_select_sectype,
2763+
#ifdef CONFIG_CIFS_XATTR
2764+
.query_all_EAs = smb2_query_eas,
2765+
.set_EA = smb2_set_ea,
2766+
#endif /* CIFS_XATTR */
25752767
#ifdef CONFIG_CIFS_ACL
25762768
.get_acl = get_smb2_acl,
25772769
.get_acl_by_fid = get_smb2_acl_by_fid,
@@ -2662,6 +2854,10 @@ struct smb_version_operations smb21_operations = {
26622854
.enum_snapshots = smb3_enum_snapshots,
26632855
.get_dfs_refer = smb2_get_dfs_refer,
26642856
.select_sectype = smb2_select_sectype,
2857+
#ifdef CONFIG_CIFS_XATTR
2858+
.query_all_EAs = smb2_query_eas,
2859+
.set_EA = smb2_set_ea,
2860+
#endif /* CIFS_XATTR */
26652861
#ifdef CONFIG_CIFS_ACL
26662862
.get_acl = get_smb2_acl,
26672863
.get_acl_by_fid = get_smb2_acl_by_fid,
@@ -2762,6 +2958,10 @@ struct smb_version_operations smb30_operations = {
27622958
.receive_transform = smb3_receive_transform,
27632959
.get_dfs_refer = smb2_get_dfs_refer,
27642960
.select_sectype = smb2_select_sectype,
2961+
#ifdef CONFIG_CIFS_XATTR
2962+
.query_all_EAs = smb2_query_eas,
2963+
.set_EA = smb2_set_ea,
2964+
#endif /* CIFS_XATTR */
27652965
#ifdef CONFIG_CIFS_ACL
27662966
.get_acl = get_smb2_acl,
27672967
.get_acl_by_fid = get_smb2_acl_by_fid,
@@ -2863,6 +3063,10 @@ struct smb_version_operations smb311_operations = {
28633063
.receive_transform = smb3_receive_transform,
28643064
.get_dfs_refer = smb2_get_dfs_refer,
28653065
.select_sectype = smb2_select_sectype,
3066+
#ifdef CONFIG_CIFS_XATTR
3067+
.query_all_EAs = smb2_query_eas,
3068+
.set_EA = smb2_set_ea,
3069+
#endif /* CIFS_XATTR */
28663070
};
28673071
#endif /* CIFS_SMB311 */
28683072

fs/cifs/smb2pdu.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,18 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
238238
* the same SMB session
239239
*/
240240
mutex_lock(&tcon->ses->session_mutex);
241+
242+
/*
243+
* Recheck after acquire mutex. If another thread is negotiating
244+
* and the server never sends an answer the socket will be closed
245+
* and tcpStatus set to reconnect.
246+
*/
247+
if (server->tcpStatus == CifsNeedReconnect) {
248+
rc = -EHOSTDOWN;
249+
mutex_unlock(&tcon->ses->session_mutex);
250+
goto out;
251+
}
252+
241253
rc = cifs_negotiate_protocol(0, tcon->ses);
242254
if (!rc && tcon->ses->need_reconnect)
243255
rc = cifs_setup_session(0, tcon->ses, nls_codepage);
@@ -2145,6 +2157,18 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
21452157
return rc;
21462158
}
21472159

2160+
int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
2161+
u64 persistent_fid, u64 volatile_fid,
2162+
struct smb2_file_full_ea_info *data)
2163+
{
2164+
return query_info(xid, tcon, persistent_fid, volatile_fid,
2165+
FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
2166+
SMB2_MAX_EA_BUF,
2167+
sizeof(struct smb2_file_full_ea_info),
2168+
(void **)&data,
2169+
NULL);
2170+
}
2171+
21482172
int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
21492173
u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data)
21502174
{
@@ -3184,6 +3208,16 @@ SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
31843208
1, (void **)&pnntsd, &pacllen);
31853209
}
31863210

3211+
int
3212+
SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
3213+
u64 persistent_fid, u64 volatile_fid,
3214+
struct smb2_file_full_ea_info *buf, int len)
3215+
{
3216+
return send_set_info(xid, tcon, persistent_fid, volatile_fid,
3217+
current->tgid, FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE,
3218+
0, 1, (void **)&buf, &len);
3219+
}
3220+
31873221
int
31883222
SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
31893223
const u64 persistent_fid, const u64 volatile_fid,

fs/cifs/smb2pdu.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,16 @@ struct smb2_file_link_info { /* encoding of request for level 11 */
11781178
char FileName[0]; /* Name to be assigned to new link */
11791179
} __packed; /* level 11 Set */
11801180

1181+
#define SMB2_MAX_EA_BUF 2048
1182+
1183+
struct smb2_file_full_ea_info { /* encoding of response for level 15 */
1184+
__le32 next_entry_offset;
1185+
__u8 flags;
1186+
__u8 ea_name_length;
1187+
__le16 ea_value_length;
1188+
char ea_data[0]; /* \0 terminated name plus value */
1189+
} __packed; /* level 15 Set */
1190+
11811191
/*
11821192
* This level 18, although with struct with same name is different from cifs
11831193
* level 0x107. Level 0x107 has an extra u64 between AccessFlags and

fs/cifs/smb2proto.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
132132
u64 persistent_file_id, u64 volatile_file_id);
133133
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
134134
u64 persistent_file_id, u64 volatile_file_id);
135+
extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
136+
u64 persistent_file_id, u64 volatile_file_id,
137+
struct smb2_file_full_ea_info *data);
135138
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
136139
u64 persistent_file_id, u64 volatile_file_id,
137140
struct smb2_file_all_info *data);
@@ -169,6 +172,9 @@ extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
169172
extern int SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
170173
u64 persistent_fid, u64 volatile_fid,
171174
struct cifs_ntsd *pnntsd, int pacllen, int aclflag);
175+
extern int SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
176+
u64 persistent_fid, u64 volatile_fid,
177+
struct smb2_file_full_ea_info *buf, int len);
172178
extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
173179
u64 persistent_fid, u64 volatile_fid);
174180
extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,

0 commit comments

Comments
 (0)