Skip to content

Commit

Permalink
nfs: disallow duplicate pages in pgio page vectors
Browse files Browse the repository at this point in the history
Adjacent requests that share the same page are allowed, but should only
use one entry in the page vector. This avoids overruning the page
vector - it is sized based on how many bytes there are, not by
request count.

This fixes issues that manifest as "Redzone overwritten" bugs (the
vector overrun) and hangs waiting on page read / write, as it waits on
the same page more than once.

This also adds bounds checking to the page vector with a graceful failure
(WARN_ON_ONCE and pgio error returned to application).

Reported-by: Toralf Förster <[email protected]>
Signed-off-by: Weston Andros Adamson <[email protected]>
Signed-off-by: Trond Myklebust <[email protected]>
  • Loading branch information
westonandrosadamson authored and trondmypd committed Aug 22, 2014
1 parent 7c3af97 commit bba5c18
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions fs/nfs/pagelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,23 +724,35 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr)
{
struct nfs_page *req;
struct page **pages;
struct page **pages,
*last_page;
struct list_head *head = &desc->pg_list;
struct nfs_commit_info cinfo;
unsigned int pagecount;
unsigned int pagecount, pageused;

pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count);
if (!nfs_pgarray_set(&hdr->page_array, pagecount))
return nfs_pgio_error(desc, hdr);

nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq);
pages = hdr->page_array.pagevec;
last_page = NULL;
pageused = 0;
while (!list_empty(head)) {
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &hdr->pages);
*pages++ = req->wb_page;

if (WARN_ON_ONCE(pageused >= pagecount))
return nfs_pgio_error(desc, hdr);

if (!last_page || last_page != req->wb_page) {
*pages++ = last_page = req->wb_page;
pageused++;
}
}
if (WARN_ON_ONCE(pageused != pagecount))
return nfs_pgio_error(desc, hdr);

if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
(desc->pg_moreio || nfs_reqs_to_commit(&cinfo)))
Expand Down

0 comments on commit bba5c18

Please sign in to comment.