Skip to content

Commit 608a969

Browse files
ChaitanayaKulkarniChristoph Hellwig
authored andcommitted
nvmet: fix inline bio check for bdev-ns
When handling rw commands, for inline bio case we only consider transfer size. This works well when req->sg_cnt fits into the req->inline_bvec, but it will result in the warning in __bio_add_page() when req->sg_cnt > NVMET_MAX_INLINE_BVEC. Consider an I/O size 32768 and first page is not aligned to the page boundary, then I/O is split in following manner :- [ 2206.256140] nvmet: sg->length 3440 sg->offset 656 [ 2206.256144] nvmet: sg->length 4096 sg->offset 0 [ 2206.256148] nvmet: sg->length 4096 sg->offset 0 [ 2206.256152] nvmet: sg->length 4096 sg->offset 0 [ 2206.256155] nvmet: sg->length 4096 sg->offset 0 [ 2206.256159] nvmet: sg->length 4096 sg->offset 0 [ 2206.256163] nvmet: sg->length 4096 sg->offset 0 [ 2206.256166] nvmet: sg->length 4096 sg->offset 0 [ 2206.256170] nvmet: sg->length 656 sg->offset 0 Now the req->transfer_size == NVMET_MAX_INLINE_DATA_LEN i.e. 32768, but the req->sg_cnt is (9) > NVMET_MAX_INLINE_BIOVEC which is (8). This will result in the following warning message :- nvmet_bdev_execute_rw() bio_add_page() __bio_add_page() WARN_ON_ONCE(bio_full(bio, len)); This scenario is very hard to reproduce on the nvme-loop transport only with rw commands issued with the passthru IOCTL interface from the host application and the data buffer is allocated with the malloc() and not the posix_memalign(). Fixes: 73383ad ("nvmet: don't split large I/Os unconditionally") Signed-off-by: Chaitanya Kulkarni <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 5e1f689 commit 608a969

File tree

2 files changed

+7
-1
lines changed

2 files changed

+7
-1
lines changed

drivers/nvme/target/io-cmd-bdev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
258258

259259
sector = nvmet_lba_to_sect(req->ns, req->cmd->rw.slba);
260260

261-
if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
261+
if (nvmet_use_inline_bvec(req)) {
262262
bio = &req->b.inline_bio;
263263
bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
264264
} else {

drivers/nvme/target/nvmet.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,4 +616,10 @@ static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
616616
return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
617617
}
618618

619+
static inline bool nvmet_use_inline_bvec(struct nvmet_req *req)
620+
{
621+
return req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN &&
622+
req->sg_cnt <= NVMET_MAX_INLINE_BIOVEC;
623+
}
624+
619625
#endif /* _NVMET_H */

0 commit comments

Comments
 (0)