Skip to content

Commit

Permalink
block: move the padding adjustment to blk_rq_map_sg
Browse files Browse the repository at this point in the history
blk_rq_map_user adjusts bi_size of the last bio. It breaks the rule
that req->data_len (the true data length) is equal to sum(bio). It
broke the scsi command completion code.

commit e97a294 was introduced to fix
the above issue. However, the partial completion code doesn't work
with it. The commit is also a layer violation (scsi mid-layer should
not know about the block layer's padding).

This patch moves the padding adjustment to blk_rq_map_sg (suggested by
James). The padding works like the drain buffer. This patch breaks the
rule that req->data_len is equal to sum(sg), however, the drain buffer
already broke it. So this patch just restores the rule that
req->data_len is equal to sub(bio) without breaking anything new.

Now when a low level driver needs padding, blk_rq_map_user and
blk_rq_map_user_iov guarantee there's enough room for padding.
blk_rq_map_sg can safely extend the last entry of a scatter list.

blk_rq_map_sg must extend the last entry of a scatter list only for a
request that got through bio_copy_user_iov. This patches introduces
new REQ_COPY_USER flag.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: Tejun Heo <htejun@gmail.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
  • Loading branch information
fujita authored and Jens Axboe committed Apr 21, 2008
1 parent afdc1a7 commit f18573a
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 20 deletions.
24 changes: 5 additions & 19 deletions block/blk-map.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,25 +141,8 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
ubuf += ret;
}

/*
* __blk_rq_map_user() copies the buffers if starting address
* or length isn't aligned to dma_pad_mask. As the copied
* buffer is always page aligned, we know that there's enough
* room for padding. Extend the last bio and update
* rq->data_len accordingly.
*
* On unmap, bio_uncopy_user() will use unmodified
* bio_map_data pointed to by bio->bi_private.
*/
if (len & q->dma_pad_mask) {
unsigned int pad_len = (q->dma_pad_mask & ~len) + 1;
struct bio *tail = rq->biotail;

tail->bi_io_vec[tail->bi_vcnt - 1].bv_len += pad_len;
tail->bi_size += pad_len;

rq->extra_len += pad_len;
}
if (!bio_flagged(bio, BIO_USER_MAPPED))
rq->cmd_flags |= REQ_COPY_USER;

rq->buffer = rq->data = NULL;
return 0;
Expand Down Expand Up @@ -224,6 +207,9 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
return -EINVAL;
}

if (!bio_flagged(bio, BIO_USER_MAPPED))
rq->cmd_flags |= REQ_COPY_USER;

bio_get(bio);
blk_rq_bio_prep(q, rq, bio);
rq->buffer = rq->data = NULL;
Expand Down
9 changes: 9 additions & 0 deletions block/blk-merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,15 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
bvprv = bvec;
} /* segments in rq */


if (unlikely(rq->cmd_flags & REQ_COPY_USER) &&
(rq->data_len & q->dma_pad_mask)) {
unsigned int pad_len = (q->dma_pad_mask & ~rq->data_len) + 1;

sg->length += pad_len;
rq->extra_len += pad_len;
}

if (q->dma_drain_size && q->dma_drain_needed(rq)) {
if (rq->cmd_flags & REQ_RW)
memset(q->dma_drain_buffer, 0, q->dma_drain_size);
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
"Notifying upper driver of completion "
"(result %x)\n", cmd->result));

good_bytes = scsi_bufflen(cmd) + cmd->request->extra_len;
good_bytes = scsi_bufflen(cmd);
if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
drv = scsi_cmd_to_driver(cmd);
if (drv->done)
Expand Down
2 changes: 2 additions & 0 deletions include/linux/blkdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ enum rq_flag_bits {
__REQ_RW_SYNC, /* request is sync (O_DIRECT) */
__REQ_ALLOCED, /* request came from our alloc pool */
__REQ_RW_META, /* metadata io request */
__REQ_COPY_USER, /* contains copies of user pages */
__REQ_NR_BITS, /* stops here */
};

Expand All @@ -133,6 +134,7 @@ enum rq_flag_bits {
#define REQ_RW_SYNC (1 << __REQ_RW_SYNC)
#define REQ_ALLOCED (1 << __REQ_ALLOCED)
#define REQ_RW_META (1 << __REQ_RW_META)
#define REQ_COPY_USER (1 << __REQ_COPY_USER)

#define BLK_MAX_CDB 16

Expand Down

0 comments on commit f18573a

Please sign in to comment.