diff options
Diffstat (limited to 'block/ll_rw_blk.c')
-rw-r--r-- | block/ll_rw_blk.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 8025d646ab3..de5ba479c22 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1351,11 +1351,22 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, new_segment: if (!sg) sg = sglist; - else + else { + /* + * If the driver previously mapped a shorter + * list, we could see a termination bit + * prematurely unless it fully inits the sg + * table on each mapping. We KNOW that there + * must be more entries here or the driver + * would be buggy, so force clear the + * termination bit to avoid doing a full + * sg_init_table() in drivers for each command. + */ + sg->page_link &= ~0x02; sg = sg_next(sg); + } - memset(sg, 0, sizeof(*sg)); - sg->page = bvec->bv_page; + sg_set_page(sg, bvec->bv_page); sg->length = nbytes; sg->offset = bvec->bv_offset; nsegs++; @@ -1363,6 +1374,9 @@ new_segment: bvprv = bvec; } /* segments in rq */ + if (sg) + __sg_mark_end(sg); + return nsegs; } |