Commit d8848eef authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull cifs fixes from Steve French:
 "Minor cleanup and fixes, one for stable, four rdma (smbdirect)
  related. Also adds SEEK_HOLE support"

* tag '5.2-rc-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: add support for SEEK_DATA and SEEK_HOLE
  Fixed https://bugzilla.kernel.org/show_bug.cgi?id=202935 allow write on the same file
  cifs: Allocate memory for all iovs in smb2_ioctl
  cifs: Don't match port on SMBDirect transport
  cifs:smbd Use the correct DMA direction when sending data
  cifs:smbd When reconnecting to server, call smbd_destroy() after all MIDs have been called
  cifs: use the right include for signal_pending()
  smb3: trivial cleanup to smb2ops.c
  cifs: cleanup smb2ops.c and normalize strings
  smb3: display session id in debug data
parents 1ba3b5dc dece44e3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -380,6 +380,8 @@ skip_rdma:
				atomic_read(&server->in_send),
				atomic_read(&server->num_waiters));
#endif
			/* dump session id helpful for use with network trace */
			seq_printf(m, " SessionId: 0x%llx", ses->Suid);
			if (ses->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA)
				seq_puts(m, " encrypted");
			if (ses->sign)
+9 −5
Original line number Diff line number Diff line
@@ -878,6 +878,9 @@ out:

static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
{
	struct cifsFileInfo *cfile = file->private_data;
	struct cifs_tcon *tcon;

	/*
	 * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate
	 * the cached file length
@@ -909,6 +912,12 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
		if (rc < 0)
			return (loff_t)rc;
	}
	if (cfile && cfile->tlink) {
		tcon = tlink_tcon(cfile->tlink);
		if (tcon->ses->server->ops->llseek)
			return tcon->ses->server->ops->llseek(file, tcon,
							      offset, whence);
	}
	return generic_file_llseek(file, offset, whence);
}

@@ -1070,11 +1079,6 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,

	cifs_dbg(FYI, "copychunk range\n");

	if (src_inode == target_inode) {
		rc = -EINVAL;
		goto out;
	}

	if (!src_file->private_data || !dst_file->private_data) {
		rc = -EBADF;
		cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
+2 −0
Original line number Diff line number Diff line
@@ -497,6 +497,8 @@ struct smb_version_operations {
	/* version specific fiemap implementation */
	int (*fiemap)(struct cifs_tcon *tcon, struct cifsFileInfo *,
		      struct fiemap_extent_info *, u64, u64);
	/* version specific llseek implementation */
	loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int);
};

struct smb_version_values {
+24 −17
Original line number Diff line number Diff line
@@ -528,6 +528,21 @@ cifs_reconnect(struct TCP_Server_Info *server)
	/* do not want to be sending data on a socket we are freeing */
	cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
	mutex_lock(&server->srv_mutex);
	if (server->ssocket) {
		cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
			 server->ssocket->state, server->ssocket->flags);
		kernel_sock_shutdown(server->ssocket, SHUT_WR);
		cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n",
			 server->ssocket->state, server->ssocket->flags);
		sock_release(server->ssocket);
		server->ssocket = NULL;
	}
	server->sequence_number = 0;
	server->session_estab = false;
	kfree(server->session_key.response);
	server->session_key.response = NULL;
	server->session_key.len = 0;
	server->lstrp = jiffies;

	/* mark submitted MIDs for retry and issue callback */
	INIT_LIST_HEAD(&retry_list);
@@ -540,6 +555,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
		list_move(&mid_entry->qhead, &retry_list);
	}
	spin_unlock(&GlobalMid_Lock);
	mutex_unlock(&server->srv_mutex);

	cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
	list_for_each_safe(tmp, tmp2, &retry_list) {
@@ -548,24 +564,11 @@ cifs_reconnect(struct TCP_Server_Info *server)
		mid_entry->callback(mid_entry);
	}

	if (server->ssocket) {
		cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
			 server->ssocket->state, server->ssocket->flags);
		kernel_sock_shutdown(server->ssocket, SHUT_WR);
		cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n",
			 server->ssocket->state, server->ssocket->flags);
		sock_release(server->ssocket);
		server->ssocket = NULL;
	} else if (cifs_rdma_enabled(server))
	if (cifs_rdma_enabled(server)) {
		mutex_lock(&server->srv_mutex);
		smbd_destroy(server);
	server->sequence_number = 0;
	server->session_estab = false;
	kfree(server->session_key.response);
	server->session_key.response = NULL;
	server->session_key.len = 0;
	server->lstrp = jiffies;

		mutex_unlock(&server->srv_mutex);
	}

	do {
		try_to_freeze();
@@ -2443,6 +2446,10 @@ match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
{
	__be16 port, *sport;

	/* SMBDirect manages its own ports, don't match it here */
	if (server->rdma)
		return true;

	switch (addr->sa_family) {
	case AF_INET:
		sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
+111 −23
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 *  SMB2 version specific operations
 *
@@ -282,7 +283,7 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
	__u64 wire_mid = le64_to_cpu(shdr->MessageId);

	if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
		cifs_dbg(VFS, "encrypted frame parsing not supported yet");
		cifs_dbg(VFS, "Encrypted frame parsing not supported yet\n");
		return NULL;
	}

@@ -324,6 +325,7 @@ static int
smb2_negotiate(const unsigned int xid, struct cifs_ses *ses)
{
	int rc;

	ses->server->CurrentMid = 0;
	rc = SMB2_negotiate(xid, ses);
	/* BB we probably don't need to retry with modern servers */
@@ -789,8 +791,6 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
		SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
	else
		close_shroot(&tcon->crfid);

	return;
}

static void
@@ -818,7 +818,6 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
	SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
			FS_DEVICE_INFORMATION);
	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
	return;
}

static int
@@ -906,9 +905,8 @@ 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 (name_len == 0) {
		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");
@@ -1161,6 +1159,7 @@ static void
smb2_clear_stats(struct cifs_tcon *tcon)
{
	int i;

	for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
		atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0);
		atomic_set(&tcon->stats.smb2_stats.smb2_com_failed[i], 0);
@@ -1529,7 +1528,7 @@ smb2_copychunk_range(const unsigned int xid,
	if (pcchunk == NULL)
		return -ENOMEM;

	cifs_dbg(FYI, "in smb2_copychunk_range - about to call request res key\n");
	cifs_dbg(FYI, "%s: about to call request res key\n", __func__);
	/* Request a key from the server to identify the source of the copy */
	rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink),
				srcfile->fid.persistent_fid,
@@ -1649,6 +1648,7 @@ static unsigned int
smb2_read_data_offset(char *buf)
{
	struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;

	return rsp->DataOffset;
}

@@ -1777,7 +1777,7 @@ smb2_duplicate_extents(const unsigned int xid,
	dup_ext_buf.SourceFileOffset = cpu_to_le64(src_off);
	dup_ext_buf.TargetFileOffset = cpu_to_le64(dest_off);
	dup_ext_buf.ByteCount = cpu_to_le64(len);
	cifs_dbg(FYI, "duplicate extents: src off %lld dst off %lld len %lld",
	cifs_dbg(FYI, "Duplicate extents: src off %lld dst off %lld len %lld\n",
		src_off, dest_off, len);

	rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
@@ -1794,7 +1794,7 @@ smb2_duplicate_extents(const unsigned int xid,
			&ret_data_len);

	if (ret_data_len > 0)
		cifs_dbg(FYI, "non-zero response length in duplicate extents");
		cifs_dbg(FYI, "Non-zero response length in duplicate extents\n");

duplicate_extents_out:
	return rc;
@@ -2306,7 +2306,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
	struct get_dfs_referral_rsp *dfs_rsp = NULL;
	u32 dfs_req_size = 0, dfs_rsp_size = 0;

	cifs_dbg(FYI, "smb2_get_dfs_refer path <%s>\n", search_name);
	cifs_dbg(FYI, "%s: path: %s\n", __func__, search_name);

	/*
	 * Try to use the IPC tcon, otherwise just use any
@@ -2360,7 +2360,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,

	if (rc) {
		if ((rc != -ENOENT) && (rc != -EOPNOTSUPP))
			cifs_dbg(VFS, "ioctl error in smb2_get_dfs_refer rc=%d\n", rc);
			cifs_dbg(VFS, "ioctl error in %s rc=%d\n", __func__, rc);
		goto out;
	}

@@ -2369,7 +2369,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
				 nls_codepage, remap, search_name,
				 true /* is_unicode */);
	if (rc) {
		cifs_dbg(VFS, "parse error in smb2_get_dfs_refer rc=%d\n", rc);
		cifs_dbg(VFS, "parse error in %s rc=%d\n", __func__, rc);
		goto out;
	}

@@ -2759,7 +2759,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
			return rc;
		}

	cifs_dbg(FYI, "offset %lld len %lld", offset, len);
	cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);

	fsctl_buf.FileOffset = cpu_to_le64(offset);
	fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
@@ -2816,7 +2816,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
		return rc;
	}

	cifs_dbg(FYI, "offset %lld len %lld", offset, len);
	cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);

	fsctl_buf.FileOffset = cpu_to_le64(offset);
	fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
@@ -2922,6 +2922,90 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
	return rc;
}

static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offset, int whence)
{
	struct cifsFileInfo *wrcfile, *cfile = file->private_data;
	struct cifsInodeInfo *cifsi;
	struct inode *inode;
	int rc = 0;
	struct file_allocated_range_buffer in_data, *out_data = NULL;
	u32 out_data_len;
	unsigned int xid;

	if (whence != SEEK_HOLE && whence != SEEK_DATA)
		return generic_file_llseek(file, offset, whence);

	inode = d_inode(cfile->dentry);
	cifsi = CIFS_I(inode);

	if (offset < 0 || offset >= i_size_read(inode))
		return -ENXIO;

	xid = get_xid();
	/*
	 * We need to be sure that all dirty pages are written as they
	 * might fill holes on the server.
	 * Note that we also MUST flush any written pages since at least
	 * some servers (Windows2016) will not reflect recent writes in
	 * QUERY_ALLOCATED_RANGES until SMB2_flush is called.
	 */
	wrcfile = find_writable_file(cifsi, false);
	if (wrcfile) {
		filemap_write_and_wait(inode->i_mapping);
		smb2_flush_file(xid, tcon, &wrcfile->fid);
		cifsFileInfo_put(wrcfile);
	}

	if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) {
		if (whence == SEEK_HOLE)
			offset = i_size_read(inode);
		goto lseek_exit;
	}

	in_data.file_offset = cpu_to_le64(offset);
	in_data.length = cpu_to_le64(i_size_read(inode));

	rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
			cfile->fid.volatile_fid,
			FSCTL_QUERY_ALLOCATED_RANGES, true,
			(char *)&in_data, sizeof(in_data),
			sizeof(struct file_allocated_range_buffer),
			(char **)&out_data, &out_data_len);
	if (rc == -E2BIG)
		rc = 0;
	if (rc)
		goto lseek_exit;

	if (whence == SEEK_HOLE && out_data_len == 0)
		goto lseek_exit;

	if (whence == SEEK_DATA && out_data_len == 0) {
		rc = -ENXIO;
		goto lseek_exit;
	}

	if (out_data_len < sizeof(struct file_allocated_range_buffer)) {
		rc = -EINVAL;
		goto lseek_exit;
	}
	if (whence == SEEK_DATA) {
		offset = le64_to_cpu(out_data->file_offset);
		goto lseek_exit;
	}
	if (offset < le64_to_cpu(out_data->file_offset))
		goto lseek_exit;

	offset = le64_to_cpu(out_data->file_offset) + le64_to_cpu(out_data->length);

 lseek_exit:
	free_xid(xid);
	kfree(out_data);
	if (!rc)
		return vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
	else
		return rc;
}

static int smb3_fiemap(struct cifs_tcon *tcon,
		       struct cifsFileInfo *cfile,
		       struct fiemap_extent_info *fei, u64 start, u64 len)
@@ -3384,7 +3468,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,

	req = aead_request_alloc(tfm, GFP_KERNEL);
	if (!req) {
		cifs_dbg(VFS, "%s: Failed to alloc aead request", __func__);
		cifs_dbg(VFS, "%s: Failed to alloc aead request\n", __func__);
		return -ENOMEM;
	}

@@ -3395,7 +3479,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,

	sg = init_sg(num_rqst, rqst, sign);
	if (!sg) {
		cifs_dbg(VFS, "%s: Failed to init sg", __func__);
		cifs_dbg(VFS, "%s: Failed to init sg\n", __func__);
		rc = -ENOMEM;
		goto free_req;
	}
@@ -3403,7 +3487,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
	iv_len = crypto_aead_ivsize(tfm);
	iv = kzalloc(iv_len, GFP_KERNEL);
	if (!iv) {
		cifs_dbg(VFS, "%s: Failed to alloc IV", __func__);
		cifs_dbg(VFS, "%s: Failed to alloc iv\n", __func__);
		rc = -ENOMEM;
		goto free_sg;
	}
@@ -3511,7 +3595,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
	fill_transform_hdr(tr_hdr, orig_len, old_rq);

	rc = crypt_message(server, num_rqst, new_rq, 1);
	cifs_dbg(FYI, "encrypt message returned %d", rc);
	cifs_dbg(FYI, "Encrypt message returned %d\n", rc);
	if (rc)
		goto err_free;

@@ -3552,7 +3636,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
	rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE;

	rc = crypt_message(server, 1, &rqst, 0);
	cifs_dbg(FYI, "decrypt message returned %d\n", rc);
	cifs_dbg(FYI, "Decrypt message returned %d\n", rc);

	if (rc)
		return rc;
@@ -4166,6 +4250,7 @@ struct smb_version_operations smb20_operations = {
	.ioctl_query_info = smb2_ioctl_query_info,
	.make_node = smb2_make_node,
	.fiemap = smb3_fiemap,
	.llseek = smb3_llseek,
};

struct smb_version_operations smb21_operations = {
@@ -4266,6 +4351,7 @@ struct smb_version_operations smb21_operations = {
	.ioctl_query_info = smb2_ioctl_query_info,
	.make_node = smb2_make_node,
	.fiemap = smb3_fiemap,
	.llseek = smb3_llseek,
};

struct smb_version_operations smb30_operations = {
@@ -4375,6 +4461,7 @@ struct smb_version_operations smb30_operations = {
	.ioctl_query_info = smb2_ioctl_query_info,
	.make_node = smb2_make_node,
	.fiemap = smb3_fiemap,
	.llseek = smb3_llseek,
};

struct smb_version_operations smb311_operations = {
@@ -4485,6 +4572,7 @@ struct smb_version_operations smb311_operations = {
	.ioctl_query_info = smb2_ioctl_query_info,
	.make_node = smb2_make_node,
	.fiemap = smb3_fiemap,
	.llseek = smb3_llseek,
};

struct smb_version_values smb20_values = {
Loading