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

Commit 38da0f49 authored by Akinobu Mita's avatar Akinobu Mita Committed by Nicholas Bellinger
Browse files

target/file: Fix BUG() when CONFIG_DEBUG_SG=y and DIF protection enabled



When CONFIG_DEBUG_SG=y and DIF protection support enabled, kernel
BUG()s are triggered due to the following two issues:

1) prot_sg is not initialized by sg_init_table().

When CONFIG_DEBUG_SG=y, scatterlist helpers check sg entry has a
correct magic value.

2) vmalloc'ed buffer is passed to sg_set_buf().

sg_set_buf() uses virt_to_page() to convert virtual address to struct
page, but it doesn't work with vmalloc address.  vmalloc_to_page()
should be used instead.  As prot_buf isn't usually too large, so
fix it by allocating prot_buf by kmalloc instead of vmalloc.

Signed-off-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Cc: Sagi Grimberg <sagig@mellanox.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: <stable@vger.kernel.org> # v3.14+
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent dc0fafda
Loading
Loading
Loading
Loading
+8 −7
Original line number Original line Diff line number Diff line
@@ -274,7 +274,7 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
		     se_dev->prot_length;
		     se_dev->prot_length;


	if (!is_write) {
	if (!is_write) {
		fd_prot->prot_buf = vzalloc(prot_size);
		fd_prot->prot_buf = kzalloc(prot_size, GFP_KERNEL);
		if (!fd_prot->prot_buf) {
		if (!fd_prot->prot_buf) {
			pr_err("Unable to allocate fd_prot->prot_buf\n");
			pr_err("Unable to allocate fd_prot->prot_buf\n");
			return -ENOMEM;
			return -ENOMEM;
@@ -286,9 +286,10 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
					   fd_prot->prot_sg_nents, GFP_KERNEL);
					   fd_prot->prot_sg_nents, GFP_KERNEL);
		if (!fd_prot->prot_sg) {
		if (!fd_prot->prot_sg) {
			pr_err("Unable to allocate fd_prot->prot_sg\n");
			pr_err("Unable to allocate fd_prot->prot_sg\n");
			vfree(fd_prot->prot_buf);
			kfree(fd_prot->prot_buf);
			return -ENOMEM;
			return -ENOMEM;
		}
		}
		sg_init_table(fd_prot->prot_sg, fd_prot->prot_sg_nents);
		size = prot_size;
		size = prot_size;


		for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) {
		for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) {
@@ -318,7 +319,7 @@ static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,


	if (is_write || ret < 0) {
	if (is_write || ret < 0) {
		kfree(fd_prot->prot_sg);
		kfree(fd_prot->prot_sg);
		vfree(fd_prot->prot_buf);
		kfree(fd_prot->prot_buf);
	}
	}


	return ret;
	return ret;
@@ -599,11 +600,11 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
						 0, fd_prot.prot_sg, 0);
						 0, fd_prot.prot_sg, 0);
			if (rc) {
			if (rc) {
				kfree(fd_prot.prot_sg);
				kfree(fd_prot.prot_sg);
				vfree(fd_prot.prot_buf);
				kfree(fd_prot.prot_buf);
				return rc;
				return rc;
			}
			}
			kfree(fd_prot.prot_sg);
			kfree(fd_prot.prot_sg);
			vfree(fd_prot.prot_buf);
			kfree(fd_prot.prot_buf);
		}
		}
	} else {
	} else {
		memset(&fd_prot, 0, sizeof(struct fd_prot));
		memset(&fd_prot, 0, sizeof(struct fd_prot));
@@ -619,7 +620,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
						  0, fd_prot.prot_sg, 0);
						  0, fd_prot.prot_sg, 0);
			if (rc) {
			if (rc) {
				kfree(fd_prot.prot_sg);
				kfree(fd_prot.prot_sg);
				vfree(fd_prot.prot_buf);
				kfree(fd_prot.prot_buf);
				return rc;
				return rc;
			}
			}
		}
		}
@@ -655,7 +656,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,


	if (ret < 0) {
	if (ret < 0) {
		kfree(fd_prot.prot_sg);
		kfree(fd_prot.prot_sg);
		vfree(fd_prot.prot_buf);
		kfree(fd_prot.prot_buf);
		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
	}
	}