Message ID | 20200901120006.9545-1-linmiaohe@huawei.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | block: Fix potential page reference leak in __bio_iov_iter_get_pages() | expand |
On Tue, Sep 01, 2020 at 08:00:06AM -0400, Miaohe Lin wrote: > When bio is full, __bio_iov_iter_get_pages() would return error directly > while left page reference still held in pages. Release these references. > Also advance the iov_iter according to what we have done successfully. > > Fixes: 576ed9135489 ("block: use bio_add_page in bio_iov_iter_get_pages") > Signed-off-by: Miaohe Lin <linmiaohe@huawei.com> The WARN_ON means something is fundamentally wrong here. I think a few leaked pages are the least of our problems in this case.
diff --git a/block/bio.c b/block/bio.c index a9931f23d933..e113073958cb 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1023,7 +1023,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) put_page(page); } else { if (WARN_ON_ONCE(bio_full(bio, len))) - return -EINVAL; + goto put_pages; __bio_add_page(bio, page, len, offset); } offset = 0; @@ -1031,6 +1031,19 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) iov_iter_advance(iter, size); return 0; + +put_pages: + /* Advance iov_iter to what we have done yet. */ + iov_iter_advance(iter, size - left); + /* Put the page references still held by pages. */ + for (; left > 0; left -= len, i++) { + struct page *page = pages[i]; + + len = min_t(size_t, PAGE_SIZE - offset, left); + put_page(page); + offset = 0; + } + return -EINVAL; } static int __bio_iov_append_get_pages(struct bio *bio, struct iov_iter *iter)
When bio is full, __bio_iov_iter_get_pages() would return error directly while left page reference still held in pages. Release these references. Also advance the iov_iter according to what we have done successfully. Fixes: 576ed9135489 ("block: use bio_add_page in bio_iov_iter_get_pages") Signed-off-by: Miaohe Lin <linmiaohe@huawei.com> --- block/bio.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)