[PATCH] splice: fixup writeout path after ->map changes
Since ->map() no longer locks the page, we need to adjust the handling of those pages (and stealing) a little. This now passes full regressions again. Signed-off-by: Jens Axboe <axboe@suse.de>
This commit is contained in:
parent
a4514ebd8e
commit
9e0267c26e
49
fs/splice.c
49
fs/splice.c
@ -50,7 +50,8 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *info,
|
|||||||
struct page *page = buf->page;
|
struct page *page = buf->page;
|
||||||
struct address_space *mapping = page_mapping(page);
|
struct address_space *mapping = page_mapping(page);
|
||||||
|
|
||||||
WARN_ON(!PageLocked(page));
|
lock_page(page);
|
||||||
|
|
||||||
WARN_ON(!PageUptodate(page));
|
WARN_ON(!PageUptodate(page));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -65,8 +66,10 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *info,
|
|||||||
if (PagePrivate(page))
|
if (PagePrivate(page))
|
||||||
try_to_release_page(page, mapping_gfp_mask(mapping));
|
try_to_release_page(page, mapping_gfp_mask(mapping));
|
||||||
|
|
||||||
if (!remove_mapping(mapping, page))
|
if (!remove_mapping(mapping, page)) {
|
||||||
|
unlock_page(page);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
buf->flags |= PIPE_BUF_FLAG_STOLEN | PIPE_BUF_FLAG_LRU;
|
buf->flags |= PIPE_BUF_FLAG_STOLEN | PIPE_BUF_FLAG_LRU;
|
||||||
return 0;
|
return 0;
|
||||||
@ -507,14 +510,12 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
|
|||||||
if (sd->flags & SPLICE_F_MOVE) {
|
if (sd->flags & SPLICE_F_MOVE) {
|
||||||
/*
|
/*
|
||||||
* If steal succeeds, buf->page is now pruned from the vm
|
* If steal succeeds, buf->page is now pruned from the vm
|
||||||
* side (LRU and page cache) and we can reuse it.
|
* side (LRU and page cache) and we can reuse it. The page
|
||||||
|
* will also be looked on successful return.
|
||||||
*/
|
*/
|
||||||
if (buf->ops->steal(info, buf))
|
if (buf->ops->steal(info, buf))
|
||||||
goto find_page;
|
goto find_page;
|
||||||
|
|
||||||
/*
|
|
||||||
* this will also set the page locked
|
|
||||||
*/
|
|
||||||
page = buf->page;
|
page = buf->page;
|
||||||
if (add_to_page_cache(page, mapping, index, gfp_mask))
|
if (add_to_page_cache(page, mapping, index, gfp_mask))
|
||||||
goto find_page;
|
goto find_page;
|
||||||
@ -523,15 +524,27 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
|
|||||||
lru_cache_add(page);
|
lru_cache_add(page);
|
||||||
} else {
|
} else {
|
||||||
find_page:
|
find_page:
|
||||||
ret = -ENOMEM;
|
page = find_lock_page(mapping, index);
|
||||||
page = find_or_create_page(mapping, index, gfp_mask);
|
if (!page) {
|
||||||
if (!page)
|
ret = -ENOMEM;
|
||||||
goto out_nomem;
|
page = page_cache_alloc_cold(mapping);
|
||||||
|
if (unlikely(!page))
|
||||||
|
goto out_nomem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This will also lock the page
|
||||||
|
*/
|
||||||
|
ret = add_to_page_cache_lru(page, mapping, index,
|
||||||
|
gfp_mask);
|
||||||
|
if (unlikely(ret))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the page is uptodate, it is also locked. If it isn't
|
* We get here with the page locked. If the page is also
|
||||||
* uptodate, we can mark it uptodate if we are filling the
|
* uptodate, we don't need to do more. If it isn't, we
|
||||||
* full page. Otherwise we need to read it in first...
|
* may need to bring it in if we are not going to overwrite
|
||||||
|
* the full page.
|
||||||
*/
|
*/
|
||||||
if (!PageUptodate(page)) {
|
if (!PageUptodate(page)) {
|
||||||
if (sd->len < PAGE_CACHE_SIZE) {
|
if (sd->len < PAGE_CACHE_SIZE) {
|
||||||
@ -553,10 +566,8 @@ find_page:
|
|||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
WARN_ON(!PageLocked(page));
|
|
||||||
SetPageUptodate(page);
|
SetPageUptodate(page);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,10 +596,10 @@ find_page:
|
|||||||
mark_page_accessed(page);
|
mark_page_accessed(page);
|
||||||
balance_dirty_pages_ratelimited(mapping);
|
balance_dirty_pages_ratelimited(mapping);
|
||||||
out:
|
out:
|
||||||
if (!(buf->flags & PIPE_BUF_FLAG_STOLEN)) {
|
if (!(buf->flags & PIPE_BUF_FLAG_STOLEN))
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
unlock_page(page);
|
|
||||||
}
|
unlock_page(page);
|
||||||
out_nomem:
|
out_nomem:
|
||||||
buf->ops->unmap(info, buf);
|
buf->ops->unmap(info, buf);
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user