[SCSI] block: fix the partial mappings with struct rq_map_data
This fixes bio_copy_user_iov to properly handle the partial mappings with struct rq_map_data (which only sg uses for now but st and osst will shortly). It adds the offset member to struct rq_map_data and changes blk_rq_map_user to update it so that bio_copy_user_iov can add an appropriate page frame via bio_add_pc_page(). Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Acked-by: Jens Axboe <jens.axboe@oracle.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
Родитель
e623ddb4e9
Коммит
56c451f4b5
|
@ -150,6 +150,9 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
|
||||||
bio = rq->bio;
|
bio = rq->bio;
|
||||||
bytes_read += ret;
|
bytes_read += ret;
|
||||||
ubuf += ret;
|
ubuf += ret;
|
||||||
|
|
||||||
|
if (map_data)
|
||||||
|
map_data->offset += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bio_flagged(bio, BIO_USER_MAPPED))
|
if (!bio_flagged(bio, BIO_USER_MAPPED))
|
||||||
|
|
|
@ -1669,6 +1669,7 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
|
||||||
md->pages = req_schp->pages;
|
md->pages = req_schp->pages;
|
||||||
md->page_order = req_schp->page_order;
|
md->page_order = req_schp->page_order;
|
||||||
md->nr_entries = req_schp->k_use_sg;
|
md->nr_entries = req_schp->k_use_sg;
|
||||||
|
md->offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iov_count)
|
if (iov_count)
|
||||||
|
|
12
fs/bio.c
12
fs/bio.c
|
@ -788,6 +788,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
|
||||||
int i, ret;
|
int i, ret;
|
||||||
int nr_pages = 0;
|
int nr_pages = 0;
|
||||||
unsigned int len = 0;
|
unsigned int len = 0;
|
||||||
|
unsigned int offset = map_data ? map_data->offset & ~PAGE_MASK : 0;
|
||||||
|
|
||||||
for (i = 0; i < iov_count; i++) {
|
for (i = 0; i < iov_count; i++) {
|
||||||
unsigned long uaddr;
|
unsigned long uaddr;
|
||||||
|
@ -814,12 +815,16 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
|
||||||
bio->bi_rw |= (!write_to_vm << BIO_RW);
|
bio->bi_rw |= (!write_to_vm << BIO_RW);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
i = 0;
|
|
||||||
if (map_data)
|
if (map_data) {
|
||||||
nr_pages = 1 << map_data->page_order;
|
nr_pages = 1 << map_data->page_order;
|
||||||
|
i = map_data->offset / PAGE_SIZE;
|
||||||
|
}
|
||||||
while (len) {
|
while (len) {
|
||||||
unsigned int bytes = PAGE_SIZE;
|
unsigned int bytes = PAGE_SIZE;
|
||||||
|
|
||||||
|
bytes -= offset;
|
||||||
|
|
||||||
if (bytes > len)
|
if (bytes > len)
|
||||||
bytes = len;
|
bytes = len;
|
||||||
|
|
||||||
|
@ -841,10 +846,11 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes)
|
if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
len -= bytes;
|
len -= bytes;
|
||||||
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
@ -690,6 +690,7 @@ struct rq_map_data {
|
||||||
struct page **pages;
|
struct page **pages;
|
||||||
int page_order;
|
int page_order;
|
||||||
int nr_entries;
|
int nr_entries;
|
||||||
|
unsigned long offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct req_iterator {
|
struct req_iterator {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче