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

Commit 442c9ac9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull cifs iovec cleanups from Al Viro.

* 'sendmsg.cifs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  cifs: don't bother with kmap on read_pages side
  cifs_readv_receive: use cifs_read_from_socket()
  cifs: no need to wank with copying and advancing iovec on recvmsg side either
  cifs: quit playing games with draining iovecs
  cifs: merge the hash calculation helpers
parents ba5a2655 71335664
Loading
Loading
Loading
Loading
+54 −43
Original line number Original line Diff line number Diff line
@@ -66,45 +66,15 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
	return 0;
	return 0;
}
}


/*
int __cifs_calc_signature(struct smb_rqst *rqst,
 * Calculate and return the CIFS signature based on the mac key and SMB PDU.
			struct TCP_Server_Info *server, char *signature,
 * The 16 byte signature must be allocated by the caller. Note we only use the
			struct shash_desc *shash)
 * 1st eight bytes and that the smb header signature field on input contains
 * the sequence number before this function is called. Also, this function
 * should be called with the server->srv_mutex held.
 */
static int cifs_calc_signature(struct smb_rqst *rqst,
			struct TCP_Server_Info *server, char *signature)
{
{
	int i;
	int i;
	int rc;
	int rc;
	struct kvec *iov = rqst->rq_iov;
	struct kvec *iov = rqst->rq_iov;
	int n_vec = rqst->rq_nvec;
	int n_vec = rqst->rq_nvec;


	if (iov == NULL || signature == NULL || server == NULL)
		return -EINVAL;

	if (!server->secmech.sdescmd5) {
		rc = cifs_crypto_shash_md5_allocate(server);
		if (rc) {
			cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
			return -1;
		}
	}

	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
		return rc;
	}

	rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
		server->session_key.response, server->session_key.len);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
		return rc;
	}

	for (i = 0; i < n_vec; i++) {
	for (i = 0; i < n_vec; i++) {
		if (iov[i].iov_len == 0)
		if (iov[i].iov_len == 0)
			continue;
			continue;
@@ -117,12 +87,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
		if (i == 0) {
		if (i == 0) {
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
				break; /* nothing to sign or corrupt header */
				break; /* nothing to sign or corrupt header */
			rc =
			rc = crypto_shash_update(shash,
			crypto_shash_update(&server->secmech.sdescmd5->shash,
				iov[i].iov_base + 4, iov[i].iov_len - 4);
				iov[i].iov_base + 4, iov[i].iov_len - 4);
		} else {
		} else {
			rc =
			rc = crypto_shash_update(shash,
			crypto_shash_update(&server->secmech.sdescmd5->shash,
				iov[i].iov_base, iov[i].iov_len);
				iov[i].iov_base, iov[i].iov_len);
		}
		}
		if (rc) {
		if (rc) {
@@ -134,21 +102,64 @@ static int cifs_calc_signature(struct smb_rqst *rqst,


	/* now hash over the rq_pages array */
	/* now hash over the rq_pages array */
	for (i = 0; i < rqst->rq_npages; i++) {
	for (i = 0; i < rqst->rq_npages; i++) {
		struct kvec p_iov;
		void *kaddr = kmap(rqst->rq_pages[i]);
		size_t len = rqst->rq_pagesz;

		if (i == rqst->rq_npages - 1)
			len = rqst->rq_tailsz;

		crypto_shash_update(shash, kaddr, len);


		cifs_rqst_page_to_kvec(rqst, i, &p_iov);
		crypto_shash_update(&server->secmech.sdescmd5->shash,
					p_iov.iov_base, p_iov.iov_len);
		kunmap(rqst->rq_pages[i]);
		kunmap(rqst->rq_pages[i]);
	}
	}


	rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
	rc = crypto_shash_final(shash, signature);
	if (rc)
	if (rc)
		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
		cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);


	return rc;
	return rc;
}
}


/*
 * Calculate and return the CIFS signature based on the mac key and SMB PDU.
 * The 16 byte signature must be allocated by the caller. Note we only use the
 * 1st eight bytes and that the smb header signature field on input contains
 * the sequence number before this function is called. Also, this function
 * should be called with the server->srv_mutex held.
 */
static int cifs_calc_signature(struct smb_rqst *rqst,
			struct TCP_Server_Info *server, char *signature)
{
	int rc;

	if (!rqst->rq_iov || !signature || !server)
		return -EINVAL;

	if (!server->secmech.sdescmd5) {
		rc = cifs_crypto_shash_md5_allocate(server);
		if (rc) {
			cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
			return -1;
		}
	}

	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not init md5\n", __func__);
		return rc;
	}

	rc = crypto_shash_update(&server->secmech.sdescmd5->shash,
		server->session_key.response, server->session_key.len);
	if (rc) {
		cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
		return rc;
	}

	return __cifs_calc_signature(rqst, server, signature,
				     &server->secmech.sdescmd5->shash);
}

/* must be called with server->srv_mutex held */
/* must be called with server->srv_mutex held */
int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
		   __u32 *pexpected_response_sequence_number)
		   __u32 *pexpected_response_sequence_number)
+0 −2
Original line number Original line Diff line number Diff line
@@ -615,8 +615,6 @@ struct TCP_Server_Info {
	bool	sec_mskerberos;		/* supports legacy MS Kerberos */
	bool	sec_mskerberos;		/* supports legacy MS Kerberos */
	bool	large_buf;		/* is current buffer large? */
	bool	large_buf;		/* is current buffer large? */
	struct delayed_work	echo; /* echo ping workqueue job */
	struct delayed_work	echo; /* echo ping workqueue job */
	struct kvec *iov;	/* reusable kvec array for receives */
	unsigned int nr_iov;	/* number of kvecs in array */
	char	*smallbuf;	/* pointer to current "small" buffer */
	char	*smallbuf;	/* pointer to current "small" buffer */
	char	*bigbuf;	/* pointer to current "big" buffer */
	char	*bigbuf;	/* pointer to current "big" buffer */
	unsigned int total_read; /* total amount of data read in this pass */
	unsigned int total_read; /* total amount of data read in this pass */
+6 −6
Original line number Original line Diff line number Diff line
@@ -37,8 +37,6 @@ extern void cifs_buf_release(void *);
extern struct smb_hdr *cifs_small_buf_get(void);
extern struct smb_hdr *cifs_small_buf_get(void);
extern void cifs_small_buf_release(void *);
extern void cifs_small_buf_release(void *);
extern void free_rsp_buf(int, void *);
extern void free_rsp_buf(int, void *);
extern void cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
					struct kvec *iov);
extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *,
			unsigned int /* length */);
			unsigned int /* length */);
extern unsigned int _get_xid(void);
extern unsigned int _get_xid(void);
@@ -182,9 +180,8 @@ extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
			         unsigned int to_read);
			         unsigned int to_read);
extern int cifs_readv_from_socket(struct TCP_Server_Info *server,
extern int cifs_read_page_from_socket(struct TCP_Server_Info *server,
		struct kvec *iov_orig, unsigned int nr_segs,
				      struct page *page, unsigned int to_read);
		unsigned int to_read);
extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
			       struct cifs_sb_info *cifs_sb);
			       struct cifs_sb_info *cifs_sb);
extern int cifs_match_super(struct super_block *, void *);
extern int cifs_match_super(struct super_block *, void *);
@@ -512,4 +509,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
			   struct cifs_sb_info *cifs_sb,
			   struct cifs_sb_info *cifs_sb,
			   const unsigned char *path, char *pbuf,
			   const unsigned char *path, char *pbuf,
			   unsigned int *pbytes_written);
			   unsigned int *pbytes_written);
int __cifs_calc_signature(struct smb_rqst *rqst,
			struct TCP_Server_Info *server, char *signature,
			struct shash_desc *shash);
#endif			/* _CIFSPROTO_H */
#endif			/* _CIFSPROTO_H */
+4 −7
Original line number Original line Diff line number Diff line
@@ -1447,10 +1447,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
	len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
	len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
							HEADER_SIZE(server) + 1;
							HEADER_SIZE(server) + 1;


	rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1;
	length = cifs_read_from_socket(server,
	rdata->iov.iov_len = len;
				       buf + HEADER_SIZE(server) - 1, len);

	length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
	if (length < 0)
	if (length < 0)
		return length;
		return length;
	server->total_read += length;
	server->total_read += length;
@@ -1502,9 +1500,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
	len = data_offset - server->total_read;
	len = data_offset - server->total_read;
	if (len > 0) {
	if (len > 0) {
		/* read any junk before data into the rest of smallbuf */
		/* read any junk before data into the rest of smallbuf */
		rdata->iov.iov_base = buf + server->total_read;
		length = cifs_read_from_socket(server,
		rdata->iov.iov_len = len;
					       buf + server->total_read, len);
		length = cifs_readv_from_socket(server, &rdata->iov, 1, len);
		if (length < 0)
		if (length < 0)
			return length;
			return length;
		server->total_read += length;
		server->total_read += length;
+35 −92
Original line number Original line Diff line number Diff line
@@ -501,97 +501,32 @@ server_unresponsive(struct TCP_Server_Info *server)
	return false;
	return false;
}
}


/*
static int
 * kvec_array_init - clone a kvec array, and advance into it
cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
 * @new:	pointer to memory for cloned array
 * @iov:	pointer to original array
 * @nr_segs:	number of members in original array
 * @bytes:	number of bytes to advance into the cloned array
 *
 * This function will copy the array provided in iov to a section of memory
 * and advance the specified number of bytes into the new array. It returns
 * the number of segments in the new array. "new" must be at least as big as
 * the original iov array.
 */
static unsigned int
kvec_array_init(struct kvec *new, struct kvec *iov, unsigned int nr_segs,
		size_t bytes)
{
	size_t base = 0;

	while (bytes || !iov->iov_len) {
		int copy = min(bytes, iov->iov_len);

		bytes -= copy;
		base += copy;
		if (iov->iov_len == base) {
			iov++;
			nr_segs--;
			base = 0;
		}
	}
	memcpy(new, iov, sizeof(*iov) * nr_segs);
	new->iov_base += base;
	new->iov_len -= base;
	return nr_segs;
}

static struct kvec *
get_server_iovec(struct TCP_Server_Info *server, unsigned int nr_segs)
{
	struct kvec *new_iov;

	if (server->iov && nr_segs <= server->nr_iov)
		return server->iov;

	/* not big enough -- allocate a new one and release the old */
	new_iov = kmalloc(sizeof(*new_iov) * nr_segs, GFP_NOFS);
	if (new_iov) {
		kfree(server->iov);
		server->iov = new_iov;
		server->nr_iov = nr_segs;
	}
	return new_iov;
}

int
cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
		       unsigned int nr_segs, unsigned int to_read)
{
{
	int length = 0;
	int length = 0;
	int total_read;
	int total_read;
	unsigned int segs;
	struct msghdr smb_msg;
	struct kvec *iov;

	iov = get_server_iovec(server, nr_segs);
	if (!iov)
		return -ENOMEM;


	smb_msg.msg_control = NULL;
	smb_msg->msg_control = NULL;
	smb_msg.msg_controllen = 0;
	smb_msg->msg_controllen = 0;


	for (total_read = 0; to_read; total_read += length, to_read -= length) {
	for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
		try_to_freeze();
		try_to_freeze();


		if (server_unresponsive(server)) {
		if (server_unresponsive(server))
			total_read = -ECONNABORTED;
			return -ECONNABORTED;
			break;
		}


		segs = kvec_array_init(iov, iov_orig, nr_segs, total_read);
		length = sock_recvmsg(server->ssocket, smb_msg, 0);


		length = kernel_recvmsg(server->ssocket, &smb_msg,
		if (server->tcpStatus == CifsExiting)
					iov, segs, to_read, 0);
			return -ESHUTDOWN;


		if (server->tcpStatus == CifsExiting) {
		if (server->tcpStatus == CifsNeedReconnect) {
			total_read = -ESHUTDOWN;
			break;
		} else if (server->tcpStatus == CifsNeedReconnect) {
			cifs_reconnect(server);
			cifs_reconnect(server);
			total_read = -ECONNABORTED;
			return -ECONNABORTED;
			break;
		}
		} else if (length == -ERESTARTSYS ||

		if (length == -ERESTARTSYS ||
		    length == -EAGAIN ||
		    length == -EAGAIN ||
		    length == -EINTR) {
		    length == -EINTR) {
			/*
			/*
@@ -602,12 +537,12 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig,
			usleep_range(1000, 2000);
			usleep_range(1000, 2000);
			length = 0;
			length = 0;
			continue;
			continue;
		} else if (length <= 0) {
		}
			cifs_dbg(FYI, "Received no data or error: expecting %d\n"

				 "got %d", to_read, length);
		if (length <= 0) {
			cifs_dbg(FYI, "Received no data or error: %d\n", length);
			cifs_reconnect(server);
			cifs_reconnect(server);
			total_read = -ECONNABORTED;
			return -ECONNABORTED;
			break;
		}
		}
	}
	}
	return total_read;
	return total_read;
@@ -617,12 +552,21 @@ int
cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
		      unsigned int to_read)
		      unsigned int to_read)
{
{
	struct kvec iov;
	struct msghdr smb_msg;
	struct kvec iov = {.iov_base = buf, .iov_len = to_read};
	iov_iter_kvec(&smb_msg.msg_iter, READ | ITER_KVEC, &iov, 1, to_read);


	iov.iov_base = buf;
	return cifs_readv_from_socket(server, &smb_msg);
	iov.iov_len = to_read;
}


	return cifs_readv_from_socket(server, &iov, 1, to_read);
int
cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
		      unsigned int to_read)
{
	struct msghdr smb_msg;
	struct bio_vec bv = {.bv_page = page, .bv_len = to_read};
	iov_iter_bvec(&smb_msg.msg_iter, READ | ITER_BVEC, &bv, 1, to_read);
	return cifs_readv_from_socket(server, &smb_msg);
}
}


static bool
static bool
@@ -783,7 +727,6 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
	}
	}


	kfree(server->hostname);
	kfree(server->hostname);
	kfree(server->iov);
	kfree(server);
	kfree(server);


	length = atomic_dec_return(&tcpSesAllocCount);
	length = atomic_dec_return(&tcpSesAllocCount);
Loading