Skip to content

Commit

Permalink
CIFS: Fix leaking locked VFS cache pages in writeback retry
Browse files Browse the repository at this point in the history
If we don't find a writable file handle when retrying writepages
we break of the loop and do not unlock and put pages neither from
wdata2 nor from the original wdata. Fix this by walking through
all the remaining pages and cleanup them properly.

Cc: <[email protected]>
Signed-off-by: Pavel Shilovsky <[email protected]>
Signed-off-by: Steve French <[email protected]>
  • Loading branch information
piastry authored and Steve French committed Mar 5, 2019
1 parent 1c163f4 commit 165df9a
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -2125,12 +2125,13 @@ cifs_writev_requeue(struct cifs_writedata *wdata)

wdata2->cfile = find_writable_file(CIFS_I(inode), false);
if (!wdata2->cfile) {
cifs_dbg(VFS, "No writable handles for inode\n");
cifs_dbg(VFS, "No writable handle to retry writepages\n");
rc = -EBADF;
break;
} else {
wdata2->pid = wdata2->cfile->pid;
rc = server->ops->async_writev(wdata2,
cifs_writedata_release);
}
wdata2->pid = wdata2->cfile->pid;
rc = server->ops->async_writev(wdata2, cifs_writedata_release);

for (j = 0; j < nr_pages; j++) {
unlock_page(wdata2->pages[j]);
Expand All @@ -2145,13 +2146,21 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
kref_put(&wdata2->refcount, cifs_writedata_release);
if (is_retryable_error(rc))
continue;
i += nr_pages;
break;
}

rest_len -= cur_len;
i += nr_pages;
} while (i < wdata->nr_pages);

/* cleanup remaining pages from the original wdata */
for (; i < wdata->nr_pages; i++) {
SetPageError(wdata->pages[i]);
end_page_writeback(wdata->pages[i]);
put_page(wdata->pages[i]);
}

if (rc != 0 && !is_retryable_error(rc))
mapping_set_error(inode->i_mapping, rc);
kref_put(&wdata->refcount, cifs_writedata_release);
Expand Down

0 comments on commit 165df9a

Please sign in to comment.