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

Commit eb0645a8 authored by Dan Williams's avatar Dan Williams Committed by Linus Torvalds
Browse files

async_tx: fix kmap_atomic usage in async_memcpy



Andrew Morton:
	[async_memcpy] is very wrong if both ASYNC_TX_KMAP_DST and
	ASYNC_TX_KMAP_SRC can ever be set.  We'll end up using the same kmap
	slot for both src add dest and we get either corrupted data or a BUG.

Evgeniy Polyakov:
	Btw, shouldn't it always be kmap_atomic() even if flag is not set.
	That pages are usual one returned by alloc_page().

So fix the usage of kmap_atomic and kill the ASYNC_TX_KMAP_DST and
ASYNC_TX_KMAP_SRC flags.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7c6129c6
Loading
Loading
Loading
Loading
+4 −15
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@
 * @offset: offset in pages to start transaction
 * @len: length in bytes
 * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
 *	ASYNC_TX_KMAP_SRC, ASYNC_TX_KMAP_DST
 * @depend_tx: memcpy depends on the result of this transaction
 * @cb_fn: function to call when the memcpy completes
 * @cb_param: parameter to pass to the callback routine
@@ -88,23 +87,13 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
					__FUNCTION__);
		}

		if (flags & ASYNC_TX_KMAP_DST)
		dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;
		else
			dest_buf = page_address(dest) + dest_offset;

		if (flags & ASYNC_TX_KMAP_SRC)
			src_buf = kmap_atomic(src, KM_USER0) + src_offset;
		else
			src_buf = page_address(src) + src_offset;
		src_buf = kmap_atomic(src, KM_USER1) + src_offset;

		memcpy(dest_buf, src_buf, len);

		if (flags & ASYNC_TX_KMAP_DST)
		kunmap_atomic(dest_buf, KM_USER0);

		if (flags & ASYNC_TX_KMAP_SRC)
			kunmap_atomic(src_buf, KM_USER0);
		kunmap_atomic(src_buf, KM_USER1);

		async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
	}
+2 −2
Original line number Diff line number Diff line
@@ -493,12 +493,12 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
			if (frombio)
				tx = async_memcpy(page, bio_page, page_offset,
					b_offset, clen,
					ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_SRC,
					ASYNC_TX_DEP_ACK,
					tx, NULL, NULL);
			else
				tx = async_memcpy(bio_page, page, b_offset,
					page_offset, clen,
					ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_DST,
					ASYNC_TX_DEP_ACK,
					tx, NULL, NULL);
		}
		if (clen < len) /* hit end of page */
+0 −6
Original line number Diff line number Diff line
@@ -51,10 +51,6 @@ struct dma_chan_ref {
 * @ASYNC_TX_ACK: immediately ack the descriptor, precludes setting up a
 * dependency chain
 * @ASYNC_TX_DEP_ACK: ack the dependency descriptor.  Useful for chaining.
 * @ASYNC_TX_KMAP_SRC: if the transaction is to be performed synchronously
 * take an atomic mapping (KM_USER0) on the source page(s)
 * @ASYNC_TX_KMAP_DST: if the transaction is to be performed synchronously
 * take an atomic mapping (KM_USER0) on the dest page(s)
 */
enum async_tx_flags {
	ASYNC_TX_XOR_ZERO_DST	 = (1 << 0),
@@ -62,8 +58,6 @@ enum async_tx_flags {
	ASYNC_TX_ASSUME_COHERENT = (1 << 2),
	ASYNC_TX_ACK		 = (1 << 3),
	ASYNC_TX_DEP_ACK	 = (1 << 4),
	ASYNC_TX_KMAP_SRC	 = (1 << 5),
	ASYNC_TX_KMAP_DST	 = (1 << 6),
};

#ifdef CONFIG_DMA_ENGINE