Re: nvme blk_update_request IO error is seen on stable kernel 5.4.41.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

Gentle reminder.

Thanks,
Dakshaja



On Thursday, May 05/21/20, 2020 at 19:36:42 +0530, Dakshaja Uppalapati wrote:
> Hi all,
> 
> Issue which is reported in https://lore.kernel.org/linux-nvme/CH2PR12MB40050ACF
> 2C0DC7439355ED3FDD270@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/T/#r8cfc80b26f0cd
> 1cde41879a68fd6a71186e9594c is also seen on stable kernel 5.4.41. 
> In upstream issue is fixed with commit b716e6889c95f64b.
> For stable 5.4 kernel it doesn’t apply clean and needs pulling in the following
> commits. 
> 
> commit 2cb6963a16e9e114486decf591af7cb2d69cb154
> Author: Christoph Hellwig <hch@xxxxxx>
> Date:   Wed Oct 23 10:35:41 2019 -0600
> 
> commit 6f86f2c9d94d55c4d3a6f1ffbc2e1115b5cb38a8
> Author: Christoph Hellwig <hch@xxxxxx>
> Date:   Wed Oct 23 10:35:42 2019 -0600
> 
> commit 59ef0eaa7741c3543f98220cc132c61bf0230bce
> Author: Christoph Hellwig <hch@xxxxxx>
> Date:   Wed Oct 23 10:35:43 2019 -0600
> 
> commit e9061c397839eea34207668bfedce0a6c18c5015
> Author: Christoph Hellwig <hch@xxxxxx>
> Date:   Wed Oct 23 10:35:44 2019 -0600
> 
> commit b716e6889c95f64ba32af492461f6cc9341f3f05
> Author: Sagi Grimberg <sagi@xxxxxxxxxxx>
> Date:   Sun Jan 26 23:23:28 2020 -0800
> 
> I tried a patch by including only necessary parts of the commits e9061c397839, 
> 59ef0eaa7741 and b716e6889c95. PFA.
> 
> With the attached patch, issue is not seen.
> 
> Please let me know on how to fix it in stable, can all above 5 changes be 
> cleanly pushed  or if  attached shorter version can be pushed?
> 
> Thanks,
> Dakshaja.
> 

> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
> index 57a4062cb..47bee01d3 100644
> --- a/drivers/nvme/target/core.c
> +++ b/drivers/nvme/target/core.c
> @@ -931,16 +931,35 @@ void nvmet_req_uninit(struct nvmet_req *req)
>  }
>  EXPORT_SYMBOL_GPL(nvmet_req_uninit);
>  
> -void nvmet_req_execute(struct nvmet_req *req)
> +bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len)
>  {
> -	if (unlikely(req->data_len != req->transfer_len)) {
> +	if (unlikely(data_len != req->transfer_len)) {
>  		req->error_loc = offsetof(struct nvme_common_command, dptr);
>  		nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR);
> -	} else
> -		req->execute(req);
> +		return false;
> +	}
> +	return true;
> +}
> +EXPORT_SYMBOL_GPL(nvmet_check_data_len);
> +
> +void nvmet_req_execute(struct nvmet_req *req)
> +{
> +	req->execute(req);
>  }
>  EXPORT_SYMBOL_GPL(nvmet_req_execute);
>  
> +bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len)
> +{
> +       if (unlikely(data_len > req->transfer_len)) {
> +               req->error_loc = offsetof(struct nvme_common_command, dptr);
> +               nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR);
> +               return false;
> +       }
> +
> +       return true;
> +}
> +
> +
>  int nvmet_req_alloc_sgl(struct nvmet_req *req)
>  {
>  	struct pci_dev *p2p_dev = NULL;
> diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
> index 32008d851..498efb062 100644
> --- a/drivers/nvme/target/io-cmd-bdev.c
> +++ b/drivers/nvme/target/io-cmd-bdev.c
> @@ -150,6 +150,10 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
>  	sector_t sector;
>  	int op, op_flags = 0, i;
>  
> +	if (!nvmet_check_data_len(req, nvmet_rw_len(req)))
> +        	return;
> +
> +
>  	if (!req->sg_cnt) {
>  		nvmet_req_complete(req, 0);
>  		return;
> @@ -207,6 +211,8 @@ static void nvmet_bdev_execute_flush(struct nvmet_req *req)
>  {
>  	struct bio *bio = &req->b.inline_bio;
>  
> +	if (!nvmet_check_data_len(req, 0))
> +		return;
>  	bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
>  	bio_set_dev(bio, req->ns->bdev);
>  	bio->bi_private = req;
> @@ -274,6 +280,9 @@ static void nvmet_bdev_execute_discard(struct nvmet_req *req)
>  
>  static void nvmet_bdev_execute_dsm(struct nvmet_req *req)
>  {
> +	if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req)))
> +                return;
> +
>  	switch (le32_to_cpu(req->cmd->dsm.attributes)) {
>  	case NVME_DSMGMT_AD:
>  		nvmet_bdev_execute_discard(req);
> @@ -295,6 +304,8 @@ static void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req)
>  	sector_t nr_sector;
>  	int ret;
>  
> +	if (!nvmet_check_data_len(req, 0))
> +        	return;
>  	sector = le64_to_cpu(write_zeroes->slba) <<
>  		(req->ns->blksize_shift - 9);
>  	nr_sector = (((sector_t)le16_to_cpu(write_zeroes->length) + 1) <<
> @@ -319,20 +330,15 @@ u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req)
>  	case nvme_cmd_read:
>  	case nvme_cmd_write:
>  		req->execute = nvmet_bdev_execute_rw;
> -		req->data_len = nvmet_rw_len(req);
>  		return 0;
>  	case nvme_cmd_flush:
>  		req->execute = nvmet_bdev_execute_flush;
> -		req->data_len = 0;
>  		return 0;
>  	case nvme_cmd_dsm:
>  		req->execute = nvmet_bdev_execute_dsm;
> -		req->data_len = (le32_to_cpu(cmd->dsm.nr) + 1) *
> -			sizeof(struct nvme_dsm_range);
>  		return 0;
>  	case nvme_cmd_write_zeroes:
>  		req->execute = nvmet_bdev_execute_write_zeroes;
> -		req->data_len = 0;
>  		return 0;
>  	default:
>  		pr_err("unhandled cmd %d on qid %d\n", cmd->common.opcode,
> diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
> index 05453f5d1..34fc0c04d 100644
> --- a/drivers/nvme/target/io-cmd-file.c
> +++ b/drivers/nvme/target/io-cmd-file.c
> @@ -232,6 +232,9 @@ static void nvmet_file_execute_rw(struct nvmet_req *req)
>  {
>  	ssize_t nr_bvec = req->sg_cnt;
>  
> +	if (!nvmet_check_data_len(req, nvmet_rw_len(req)))
> +		return;
> +
>  	if (!req->sg_cnt || !nr_bvec) {
>  		nvmet_req_complete(req, 0);
>  		return;
> @@ -273,6 +276,8 @@ static void nvmet_file_flush_work(struct work_struct *w)
>  
>  static void nvmet_file_execute_flush(struct nvmet_req *req)
>  {
> +	if (!nvmet_check_data_len(req, 0))
> +		return;
>  	INIT_WORK(&req->f.work, nvmet_file_flush_work);
>  	schedule_work(&req->f.work);
>  }
> @@ -331,6 +336,9 @@ static void nvmet_file_dsm_work(struct work_struct *w)
>  
>  static void nvmet_file_execute_dsm(struct nvmet_req *req)
>  {
> +	if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req)))
> +                return;
> +
>  	INIT_WORK(&req->f.work, nvmet_file_dsm_work);
>  	schedule_work(&req->f.work);
>  }
> @@ -359,6 +367,8 @@ static void nvmet_file_write_zeroes_work(struct work_struct *w)
>  
>  static void nvmet_file_execute_write_zeroes(struct nvmet_req *req)
>  {
> +	if (!nvmet_check_data_len(req, 0))
> +	        return;
>  	INIT_WORK(&req->f.work, nvmet_file_write_zeroes_work);
>  	schedule_work(&req->f.work);
>  }
> @@ -371,20 +381,15 @@ u16 nvmet_file_parse_io_cmd(struct nvmet_req *req)
>  	case nvme_cmd_read:
>  	case nvme_cmd_write:
>  		req->execute = nvmet_file_execute_rw;
> -		req->data_len = nvmet_rw_len(req);
>  		return 0;
>  	case nvme_cmd_flush:
>  		req->execute = nvmet_file_execute_flush;
> -		req->data_len = 0;
>  		return 0;
>  	case nvme_cmd_dsm:
>  		req->execute = nvmet_file_execute_dsm;
> -		req->data_len = (le32_to_cpu(cmd->dsm.nr) + 1) *
> -			sizeof(struct nvme_dsm_range);
>  		return 0;
>  	case nvme_cmd_write_zeroes:
>  		req->execute = nvmet_file_execute_write_zeroes;
> -		req->data_len = 0;
>  		return 0;
>  	default:
>  		pr_err("unhandled cmd for file ns %d on qid %d\n",
> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
> index c51f8dd01..a8a7744d8 100644
> --- a/drivers/nvme/target/nvmet.h
> +++ b/drivers/nvme/target/nvmet.h
> @@ -375,7 +375,9 @@ u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req);
>  bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
>  		struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops);
>  void nvmet_req_uninit(struct nvmet_req *req);
> +bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len);
>  void nvmet_req_execute(struct nvmet_req *req);
> +bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len);
>  void nvmet_req_complete(struct nvmet_req *req, u16 status);
>  int nvmet_req_alloc_sgl(struct nvmet_req *req);
>  void nvmet_req_free_sgl(struct nvmet_req *req);
> @@ -495,6 +497,12 @@ static inline u32 nvmet_rw_len(struct nvmet_req *req)
>  			req->ns->blksize_shift;
>  }
>  
> +static inline u32 nvmet_dsm_len(struct nvmet_req *req)
> +{
> +        return (le32_to_cpu(req->cmd->dsm.nr) + 1) *
> +                sizeof(struct nvme_dsm_range);
> +}
> +
>  u16 errno_to_nvme_status(struct nvmet_req *req, int errno);
>  
>  /* Convert a 32-bit number to a 16-bit 0's based number */




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux