Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 145f47c7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '5.1-rc3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb3 fixes from Steve French:
 "Four smb3 fixes for stable:

   - fix an open path where we had an unitialized structure

   - fix for snapshot (previous version) enumeration

   - allow reconnect timeout on handles to be configurable to better
     handle network or server crash

   - correctly handle lack of file_all_info structure"

* tag '5.1-rc3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: a smb2_validate_and_copy_iov failure does not mean the handle is invalid.
  SMB3: Allow persistent handle timeout to be configurable on mount
  smb3: Fix enumerating snapshots to Azure
  cifs: fix kref underflow in close_shroot()
parents 8ed86627 4811e309
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -559,6 +559,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
			tcon->ses->server->echo_interval / HZ);
	if (tcon->snapshot_time)
		seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
	if (tcon->handle_timeout)
		seq_printf(s, ",handletimeout=%u", tcon->handle_timeout);
	/* convert actimeo and display it in seconds */
	seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);

+8 −0
Original line number Diff line number Diff line
@@ -59,6 +59,12 @@
 */
#define CIFS_MAX_ACTIMEO (1 << 30)

/*
 * Max persistent and resilient handle timeout (milliseconds).
 * Windows durable max was 960000 (16 minutes)
 */
#define SMB3_MAX_HANDLE_TIMEOUT 960000

/*
 * MAX_REQ is the maximum number of requests that WE will send
 * on one socket concurrently.
@@ -586,6 +592,7 @@ struct smb_vol {
	struct nls_table *local_nls;
	unsigned int echo_interval; /* echo interval in secs */
	__u64 snapshot_time; /* needed for timewarp tokens */
	__u32 handle_timeout; /* persistent and durable handle timeout in ms */
	unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
};

@@ -1058,6 +1065,7 @@ struct cifs_tcon {
	__u32 vol_serial_number;
	__le64 vol_create_time;
	__u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
	__u32 handle_timeout; /* persistent and durable handle timeout in ms */
	__u32 ss_flags;		/* sector size flags */
	__u32 perf_sector_size; /* best sector size for perf */
	__u32 max_chunks;
+29 −1
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ enum {
	Opt_cruid, Opt_gid, Opt_file_mode,
	Opt_dirmode, Opt_port,
	Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
	Opt_echo_interval, Opt_max_credits,
	Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
	Opt_snapshot,

	/* Mount options which take string value */
@@ -208,6 +208,7 @@ static const match_table_t cifs_mount_option_tokens = {
	{ Opt_rsize, "rsize=%s" },
	{ Opt_wsize, "wsize=%s" },
	{ Opt_actimeo, "actimeo=%s" },
	{ Opt_handletimeout, "handletimeout=%s" },
	{ Opt_echo_interval, "echo_interval=%s" },
	{ Opt_max_credits, "max_credits=%s" },
	{ Opt_snapshot, "snapshot=%s" },
@@ -1619,6 +1620,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,

	vol->actimeo = CIFS_DEF_ACTIMEO;

	/* Most clients set timeout to 0, allows server to use its default */
	vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */

	/* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */
	vol->ops = &smb30_operations;
	vol->vals = &smbdefault_values;
@@ -2017,6 +2021,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
				goto cifs_parse_mount_err;
			}
			break;
		case Opt_handletimeout:
			if (get_option_ul(args, &option)) {
				cifs_dbg(VFS, "%s: Invalid handletimeout value\n",
					 __func__);
				goto cifs_parse_mount_err;
			}
			vol->handle_timeout = option;
			if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) {
				cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n");
				goto cifs_parse_mount_err;
			}
			break;
		case Opt_echo_interval:
			if (get_option_ul(args, &option)) {
				cifs_dbg(VFS, "%s: Invalid echo interval value\n",
@@ -3183,6 +3199,8 @@ static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
		return 0;
	if (tcon->snapshot_time != volume_info->snapshot_time)
		return 0;
	if (tcon->handle_timeout != volume_info->handle_timeout)
		return 0;
	return 1;
}

@@ -3297,6 +3315,16 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
			tcon->snapshot_time = volume_info->snapshot_time;
	}

	if (volume_info->handle_timeout) {
		if (ses->server->vals->protocol_id == 0) {
			cifs_dbg(VFS,
			     "Use SMB2.1 or later for handle timeout option\n");
			rc = -EOPNOTSUPP;
			goto out_fail;
		} else
			tcon->handle_timeout = volume_info->handle_timeout;
	}

	tcon->ses = ses;
	if (volume_info->password) {
		tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
+4 −2
Original line number Diff line number Diff line
@@ -68,13 +68,15 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,


	 if (oparms->tcon->use_resilient) {
		nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
		/* default timeout is 0, servers pick default (120 seconds) */
		nr_ioctl_req.Timeout =
			cpu_to_le32(oparms->tcon->handle_timeout);
		nr_ioctl_req.Reserved = 0;
		rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
			fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY,
			true /* is_fsctl */,
			(char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
			NULL, NULL /* no return info */);
			CIFSMaxBufSize, NULL, NULL /* no return info */);
		if (rc == -EOPNOTSUPP) {
			cifs_dbg(VFS,
			     "resiliency not supported by server, disabling\n");
+42 −26
Original line number Diff line number Diff line
@@ -581,7 +581,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
	rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
			FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
			NULL /* no data input */, 0 /* no data input */,
			(char **)&out_buf, &ret_data_len);
			CIFSMaxBufSize, (char **)&out_buf, &ret_data_len);
	if (rc == -EOPNOTSUPP) {
		cifs_dbg(FYI,
			 "server does not support query network interfaces\n");
@@ -717,31 +717,27 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
	oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId);
#endif /* CIFS_DEBUG2 */

	if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
		oplock = smb2_parse_lease_state(server, o_rsp,
						&oparms.fid->epoch,
						oparms.fid->lease_key);
	else
		goto oshr_exit;


	memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid));
	tcon->crfid.tcon = tcon;
	tcon->crfid.is_valid = true;
	kref_init(&tcon->crfid.refcount);
	kref_get(&tcon->crfid.refcount);

	if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
		kref_get(&tcon->crfid.refcount);
		oplock = smb2_parse_lease_state(server, o_rsp,
						&oparms.fid->epoch,
						oparms.fid->lease_key);
	} else
		goto oshr_exit;

	qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
	if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info))
		goto oshr_exit;
	rc = smb2_validate_and_copy_iov(
	if (!smb2_validate_and_copy_iov(
				le16_to_cpu(qi_rsp->OutputBufferOffset),
				sizeof(struct smb2_file_all_info),
				&rsp_iov[1], sizeof(struct smb2_file_all_info),
				(char *)&tcon->crfid.file_all_info);
	if (rc)
		goto oshr_exit;
				(char *)&tcon->crfid.file_all_info))
		tcon->crfid.file_all_info_is_valid = 1;

 oshr_exit:
@@ -1299,7 +1295,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,

	rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
			FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
			NULL, 0 /* no input */,
			NULL, 0 /* no input */, CIFSMaxBufSize,
			(char **)&res_key, &ret_data_len);

	if (rc) {
@@ -1404,7 +1400,7 @@ smb2_ioctl_query_info(const unsigned int xid,
			rc = SMB2_ioctl_init(tcon, &rqst[1],
					     COMPOUND_FID, COMPOUND_FID,
					     qi.info_type, true, NULL,
					     0);
					     0, CIFSMaxBufSize);
		}
	} else if (qi.flags == PASSTHRU_QUERY_INFO) {
		memset(&qi_iov, 0, sizeof(qi_iov));
@@ -1532,8 +1528,8 @@ smb2_copychunk_range(const unsigned int xid,
		rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
			trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
			true /* is_fsctl */, (char *)pcchunk,
			sizeof(struct copychunk_ioctl),	(char **)&retbuf,
			&ret_data_len);
			sizeof(struct copychunk_ioctl),	CIFSMaxBufSize,
			(char **)&retbuf, &ret_data_len);
		if (rc == 0) {
			if (ret_data_len !=
					sizeof(struct copychunk_ioctl_rsp)) {
@@ -1693,7 +1689,7 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
	rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
			cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
			true /* is_fctl */,
			&setsparse, 1, NULL, NULL);
			&setsparse, 1, CIFSMaxBufSize, NULL, NULL);
	if (rc) {
		tcon->broken_sparse_sup = true;
		cifs_dbg(FYI, "set sparse rc = %d\n", rc);
@@ -1766,7 +1762,7 @@ smb2_duplicate_extents(const unsigned int xid,
			true /* is_fsctl */,
			(char *)&dup_ext_buf,
			sizeof(struct duplicate_extents_to_file),
			NULL,
			CIFSMaxBufSize, NULL,
			&ret_data_len);

	if (ret_data_len > 0)
@@ -1801,7 +1797,7 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
			true /* is_fsctl */,
			(char *)&integr_info,
			sizeof(struct fsctl_set_integrity_information_req),
			NULL,
			CIFSMaxBufSize, NULL,
			&ret_data_len);

}
@@ -1809,6 +1805,8 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
/* GMT Token is @GMT-YYYY.MM.DD-HH.MM.SS Unicode which is 48 bytes + null */
#define GMT_TOKEN_SIZE 50

#define MIN_SNAPSHOT_ARRAY_SIZE 16 /* See MS-SMB2 section 3.3.5.15.1 */

/*
 * Input buffer contains (empty) struct smb_snapshot array with size filled in
 * For output see struct SRV_SNAPSHOT_ARRAY in MS-SMB2 section 2.2.32.2
@@ -1820,13 +1818,29 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
	char *retbuf = NULL;
	unsigned int ret_data_len = 0;
	int rc;
	u32 max_response_size;
	struct smb_snapshot_array snapshot_in;

	if (get_user(ret_data_len, (unsigned int __user *)ioc_buf))
		return -EFAULT;

	/*
	 * Note that for snapshot queries that servers like Azure expect that
	 * the first query be minimal size (and just used to get the number/size
	 * of previous versions) so response size must be specified as EXACTLY
	 * sizeof(struct snapshot_array) which is 16 when rounded up to multiple
	 * of eight bytes.
	 */
	if (ret_data_len == 0)
		max_response_size = MIN_SNAPSHOT_ARRAY_SIZE;
	else
		max_response_size = CIFSMaxBufSize;

	rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
			cfile->fid.volatile_fid,
			FSCTL_SRV_ENUMERATE_SNAPSHOTS,
			true /* is_fsctl */,
			NULL, 0 /* no input data */,
			NULL, 0 /* no input data */, max_response_size,
			(char **)&retbuf,
			&ret_data_len);
	cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n",
@@ -2304,7 +2318,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
		rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
				FSCTL_DFS_GET_REFERRALS,
				true /* is_fsctl */,
				(char *)dfs_req, dfs_req_size,
				(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
				(char **)&dfs_rsp, &dfs_rsp_size);
	} while (rc == -EAGAIN);

@@ -2658,7 +2672,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
	rc = SMB2_ioctl_init(tcon, &rqst[num++], cfile->fid.persistent_fid,
			     cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
			     true /* is_fctl */, (char *)&fsctl_buf,
			     sizeof(struct file_zero_data_information));
			     sizeof(struct file_zero_data_information),
			     CIFSMaxBufSize);
	if (rc)
		goto zero_range_exit;

@@ -2735,7 +2750,8 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
	rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
			cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
			true /* is_fctl */, (char *)&fsctl_buf,
			sizeof(struct file_zero_data_information), NULL, NULL);
			sizeof(struct file_zero_data_information),
			CIFSMaxBufSize, NULL, NULL);
	free_xid(xid);
	return rc;
}
Loading