Skip to content

Commit 153322f

Browse files
author
Steve French
committed
smb3: Fix enumerating snapshots to Azure
Some servers (see MS-SMB2 protocol specification section 3.3.5.15.1) expect that the FSCTL enumerate snapshots is done twice, with the first query having EXACTLY the minimum size response buffer requested (16 bytes) which refreshes the snapshot list (otherwise that and subsequent queries get an empty list returned). So had to add code to set the maximum response size differently for the first snapshot query (which gets the size needed for the second query which contains the actual list of snapshots). Signed-off-by: Steve French <[email protected]> Reviewed-by: Ronnie Sahlberg <[email protected]> Reviewed-by: Pavel Shilovsky <[email protected]> CC: Stable <[email protected]> # 4.19+
1 parent 2f94a31 commit 153322f

File tree

4 files changed

+58
-28
lines changed

4 files changed

+58
-28
lines changed

fs/cifs/smb2file.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
7474
fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY,
7575
true /* is_fsctl */,
7676
(char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
77-
NULL, NULL /* no return info */);
77+
CIFSMaxBufSize, NULL, NULL /* no return info */);
7878
if (rc == -EOPNOTSUPP) {
7979
cifs_dbg(VFS,
8080
"resiliency not supported by server, disabling\n");

fs/cifs/smb2ops.c

+32-12
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
581581
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
582582
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
583583
NULL /* no data input */, 0 /* no data input */,
584-
(char **)&out_buf, &ret_data_len);
584+
CIFSMaxBufSize, (char **)&out_buf, &ret_data_len);
585585
if (rc == -EOPNOTSUPP) {
586586
cifs_dbg(FYI,
587587
"server does not support query network interfaces\n");
@@ -1297,7 +1297,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
12971297

12981298
rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
12991299
FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
1300-
NULL, 0 /* no input */,
1300+
NULL, 0 /* no input */, CIFSMaxBufSize,
13011301
(char **)&res_key, &ret_data_len);
13021302

13031303
if (rc) {
@@ -1402,7 +1402,7 @@ smb2_ioctl_query_info(const unsigned int xid,
14021402
rc = SMB2_ioctl_init(tcon, &rqst[1],
14031403
COMPOUND_FID, COMPOUND_FID,
14041404
qi.info_type, true, NULL,
1405-
0);
1405+
0, CIFSMaxBufSize);
14061406
}
14071407
} else if (qi.flags == PASSTHRU_QUERY_INFO) {
14081408
memset(&qi_iov, 0, sizeof(qi_iov));
@@ -1530,8 +1530,8 @@ smb2_copychunk_range(const unsigned int xid,
15301530
rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
15311531
trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
15321532
true /* is_fsctl */, (char *)pcchunk,
1533-
sizeof(struct copychunk_ioctl), (char **)&retbuf,
1534-
&ret_data_len);
1533+
sizeof(struct copychunk_ioctl), CIFSMaxBufSize,
1534+
(char **)&retbuf, &ret_data_len);
15351535
if (rc == 0) {
15361536
if (ret_data_len !=
15371537
sizeof(struct copychunk_ioctl_rsp)) {
@@ -1691,7 +1691,7 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
16911691
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
16921692
cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
16931693
true /* is_fctl */,
1694-
&setsparse, 1, NULL, NULL);
1694+
&setsparse, 1, CIFSMaxBufSize, NULL, NULL);
16951695
if (rc) {
16961696
tcon->broken_sparse_sup = true;
16971697
cifs_dbg(FYI, "set sparse rc = %d\n", rc);
@@ -1764,7 +1764,7 @@ smb2_duplicate_extents(const unsigned int xid,
17641764
true /* is_fsctl */,
17651765
(char *)&dup_ext_buf,
17661766
sizeof(struct duplicate_extents_to_file),
1767-
NULL,
1767+
CIFSMaxBufSize, NULL,
17681768
&ret_data_len);
17691769

17701770
if (ret_data_len > 0)
@@ -1799,14 +1799,16 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
17991799
true /* is_fsctl */,
18001800
(char *)&integr_info,
18011801
sizeof(struct fsctl_set_integrity_information_req),
1802-
NULL,
1802+
CIFSMaxBufSize, NULL,
18031803
&ret_data_len);
18041804

18051805
}
18061806

18071807
/* GMT Token is @GMT-YYYY.MM.DD-HH.MM.SS Unicode which is 48 bytes + null */
18081808
#define GMT_TOKEN_SIZE 50
18091809

1810+
#define MIN_SNAPSHOT_ARRAY_SIZE 16 /* See MS-SMB2 section 3.3.5.15.1 */
1811+
18101812
/*
18111813
* Input buffer contains (empty) struct smb_snapshot array with size filled in
18121814
* For output see struct SRV_SNAPSHOT_ARRAY in MS-SMB2 section 2.2.32.2
@@ -1818,13 +1820,29 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
18181820
char *retbuf = NULL;
18191821
unsigned int ret_data_len = 0;
18201822
int rc;
1823+
u32 max_response_size;
18211824
struct smb_snapshot_array snapshot_in;
18221825

1826+
if (get_user(ret_data_len, (unsigned int __user *)ioc_buf))
1827+
return -EFAULT;
1828+
1829+
/*
1830+
* Note that for snapshot queries that servers like Azure expect that
1831+
* the first query be minimal size (and just used to get the number/size
1832+
* of previous versions) so response size must be specified as EXACTLY
1833+
* sizeof(struct snapshot_array) which is 16 when rounded up to multiple
1834+
* of eight bytes.
1835+
*/
1836+
if (ret_data_len == 0)
1837+
max_response_size = MIN_SNAPSHOT_ARRAY_SIZE;
1838+
else
1839+
max_response_size = CIFSMaxBufSize;
1840+
18231841
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
18241842
cfile->fid.volatile_fid,
18251843
FSCTL_SRV_ENUMERATE_SNAPSHOTS,
18261844
true /* is_fsctl */,
1827-
NULL, 0 /* no input data */,
1845+
NULL, 0 /* no input data */, max_response_size,
18281846
(char **)&retbuf,
18291847
&ret_data_len);
18301848
cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n",
@@ -2302,7 +2320,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
23022320
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
23032321
FSCTL_DFS_GET_REFERRALS,
23042322
true /* is_fsctl */,
2305-
(char *)dfs_req, dfs_req_size,
2323+
(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
23062324
(char **)&dfs_rsp, &dfs_rsp_size);
23072325
} while (rc == -EAGAIN);
23082326

@@ -2656,7 +2674,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
26562674
rc = SMB2_ioctl_init(tcon, &rqst[num++], cfile->fid.persistent_fid,
26572675
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
26582676
true /* is_fctl */, (char *)&fsctl_buf,
2659-
sizeof(struct file_zero_data_information));
2677+
sizeof(struct file_zero_data_information),
2678+
CIFSMaxBufSize);
26602679
if (rc)
26612680
goto zero_range_exit;
26622681

@@ -2733,7 +2752,8 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
27332752
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
27342753
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
27352754
true /* is_fctl */, (char *)&fsctl_buf,
2736-
sizeof(struct file_zero_data_information), NULL, NULL);
2755+
sizeof(struct file_zero_data_information),
2756+
CIFSMaxBufSize, NULL, NULL);
27372757
free_xid(xid);
27382758
return rc;
27392759
}

fs/cifs/smb2pdu.c

+22-13
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,8 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
10021002

10031003
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
10041004
FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */,
1005-
(char *)pneg_inbuf, inbuflen, (char **)&pneg_rsp, &rsplen);
1005+
(char *)pneg_inbuf, inbuflen, CIFSMaxBufSize,
1006+
(char **)&pneg_rsp, &rsplen);
10061007
if (rc == -EOPNOTSUPP) {
10071008
/*
10081009
* Old Windows versions or Netapp SMB server can return
@@ -2478,7 +2479,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
24782479
int
24792480
SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
24802481
u64 persistent_fid, u64 volatile_fid, u32 opcode,
2481-
bool is_fsctl, char *in_data, u32 indatalen)
2482+
bool is_fsctl, char *in_data, u32 indatalen,
2483+
__u32 max_response_size)
24822484
{
24832485
struct smb2_ioctl_req *req;
24842486
struct kvec *iov = rqst->rq_iov;
@@ -2520,16 +2522,21 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
25202522
req->OutputCount = 0; /* MBZ */
25212523

25222524
/*
2523-
* Could increase MaxOutputResponse, but that would require more
2524-
* than one credit. Windows typically sets this smaller, but for some
2525+
* In most cases max_response_size is set to 16K (CIFSMaxBufSize)
2526+
* We Could increase default MaxOutputResponse, but that could require
2527+
* more credits. Windows typically sets this smaller, but for some
25252528
* ioctls it may be useful to allow server to send more. No point
25262529
* limiting what the server can send as long as fits in one credit
2527-
* Unfortunately - we can not handle more than CIFS_MAX_MSG_SIZE
2528-
* (by default, note that it can be overridden to make max larger)
2529-
* in responses (except for read responses which can be bigger.
2530-
* We may want to bump this limit up
2530+
* We can not handle more than CIFS_MAX_BUF_SIZE yet but may want
2531+
* to increase this limit up in the future.
2532+
* Note that for snapshot queries that servers like Azure expect that
2533+
* the first query be minimal size (and just used to get the number/size
2534+
* of previous versions) so response size must be specified as EXACTLY
2535+
* sizeof(struct snapshot_array) which is 16 when rounded up to multiple
2536+
* of eight bytes. Currently that is the only case where we set max
2537+
* response size smaller.
25312538
*/
2532-
req->MaxOutputResponse = cpu_to_le32(CIFSMaxBufSize);
2539+
req->MaxOutputResponse = cpu_to_le32(max_response_size);
25332540

25342541
if (is_fsctl)
25352542
req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
@@ -2550,13 +2557,14 @@ SMB2_ioctl_free(struct smb_rqst *rqst)
25502557
cifs_small_buf_release(rqst->rq_iov[0].iov_base); /* request */
25512558
}
25522559

2560+
25532561
/*
25542562
* SMB2 IOCTL is used for both IOCTLs and FSCTLs
25552563
*/
25562564
int
25572565
SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
25582566
u64 volatile_fid, u32 opcode, bool is_fsctl,
2559-
char *in_data, u32 indatalen,
2567+
char *in_data, u32 indatalen, u32 max_out_data_len,
25602568
char **out_data, u32 *plen /* returned data len */)
25612569
{
25622570
struct smb_rqst rqst;
@@ -2593,8 +2601,8 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
25932601
rqst.rq_iov = iov;
25942602
rqst.rq_nvec = SMB2_IOCTL_IOV_SIZE;
25952603

2596-
rc = SMB2_ioctl_init(tcon, &rqst, persistent_fid, volatile_fid,
2597-
opcode, is_fsctl, in_data, indatalen);
2604+
rc = SMB2_ioctl_init(tcon, &rqst, persistent_fid, volatile_fid, opcode,
2605+
is_fsctl, in_data, indatalen, max_out_data_len);
25982606
if (rc)
25992607
goto ioctl_exit;
26002608

@@ -2672,7 +2680,8 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
26722680
rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
26732681
FSCTL_SET_COMPRESSION, true /* is_fsctl */,
26742682
(char *)&fsctl_input /* data input */,
2675-
2 /* in data len */, &ret_data /* out data */, NULL);
2683+
2 /* in data len */, CIFSMaxBufSize /* max out data */,
2684+
&ret_data /* out data */, NULL);
26762685

26772686
cifs_dbg(FYI, "set compression rc %d\n", rc);
26782687

fs/cifs/smb2proto.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,12 @@ extern int SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
142142
extern void SMB2_open_free(struct smb_rqst *rqst);
143143
extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
144144
u64 persistent_fid, u64 volatile_fid, u32 opcode,
145-
bool is_fsctl, char *in_data, u32 indatalen,
145+
bool is_fsctl, char *in_data, u32 indatalen, u32 maxoutlen,
146146
char **out_data, u32 *plen /* returned data len */);
147147
extern int SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
148148
u64 persistent_fid, u64 volatile_fid, u32 opcode,
149-
bool is_fsctl, char *in_data, u32 indatalen);
149+
bool is_fsctl, char *in_data, u32 indatalen,
150+
__u32 max_response_size);
150151
extern void SMB2_ioctl_free(struct smb_rqst *rqst);
151152
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
152153
u64 persistent_file_id, u64 volatile_file_id);

0 commit comments

Comments
 (0)