提交 ce950499 编写于 作者: P Pavel Shilovsky 提交者: Xie XiuQi

CIFS: Fix error paths in writeback code

CIFS: Fix leaking locked VFS cache pages in writeback retry

mainline inclusion
from mainline-v5.0-rc2
commit 9a66396f1857cc1de06f4f4771797315e1a4ea56
category: bugfix
bugzilla: 12058
CVE: NA

-------------------------------------------------

This patch aims to address writeback code problems related to error
paths. In particular it respects EINTR and related error codes and
stores and returns the first error occurred during writeback.
Signed-off-by: NPavel Shilovsky <pshilov@microsoft.com>
Acked-by: NJeff Layton <jlayton@kernel.org>
Signed-off-by: NSteve French <stfrench@microsoft.com>
Signed-off-by: NZhangXiaoxu <zhangxiaoxu5@huawei.com>
Reviewed-by: Nzhengbin <zhengbin13@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 08c0cf5a
...@@ -1562,6 +1562,25 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, ...@@ -1562,6 +1562,25 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
kfree(param); kfree(param);
} }
static inline bool is_interrupt_error(int error)
{
switch (error) {
case -EINTR:
case -ERESTARTSYS:
case -ERESTARTNOHAND:
case -ERESTARTNOINTR:
return true;
}
return false;
}
static inline bool is_retryable_error(int error)
{
if (is_interrupt_error(error) || error == -EAGAIN)
return true;
return false;
}
#define MID_FREE 0 #define MID_FREE 0
#define MID_REQUEST_ALLOCATED 1 #define MID_REQUEST_ALLOCATED 1
#define MID_REQUEST_SUBMITTED 2 #define MID_REQUEST_SUBMITTED 2
......
...@@ -2042,7 +2042,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) ...@@ -2042,7 +2042,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
for (j = 0; j < nr_pages; j++) { for (j = 0; j < nr_pages; j++) {
unlock_page(wdata2->pages[j]); unlock_page(wdata2->pages[j]);
if (rc != 0 && rc != -EAGAIN) { if (rc != 0 && !is_retryable_error(rc)) {
SetPageError(wdata2->pages[j]); SetPageError(wdata2->pages[j]);
end_page_writeback(wdata2->pages[j]); end_page_writeback(wdata2->pages[j]);
put_page(wdata2->pages[j]); put_page(wdata2->pages[j]);
...@@ -2051,7 +2051,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) ...@@ -2051,7 +2051,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
if (rc) { if (rc) {
kref_put(&wdata2->refcount, cifs_writedata_release); kref_put(&wdata2->refcount, cifs_writedata_release);
if (rc == -EAGAIN) if (is_retryable_error(rc))
continue; continue;
break; break;
} }
...@@ -2060,7 +2060,8 @@ cifs_writev_requeue(struct cifs_writedata *wdata) ...@@ -2060,7 +2060,8 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
i += nr_pages; i += nr_pages;
} while (i < wdata->nr_pages); } while (i < wdata->nr_pages);
mapping_set_error(inode->i_mapping, rc); if (rc != 0 && !is_retryable_error(rc))
mapping_set_error(inode->i_mapping, rc);
kref_put(&wdata->refcount, cifs_writedata_release); kref_put(&wdata->refcount, cifs_writedata_release);
} }
......
...@@ -730,7 +730,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) ...@@ -730,7 +730,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
if (can_flush) { if (can_flush) {
rc = filemap_write_and_wait(inode->i_mapping); rc = filemap_write_and_wait(inode->i_mapping);
mapping_set_error(inode->i_mapping, rc); if (!is_interrupt_error(rc))
mapping_set_error(inode->i_mapping, rc);
if (tcon->unix_ext) if (tcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode, full_path, rc = cifs_get_inode_info_unix(&inode, full_path,
...@@ -2118,6 +2119,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2118,6 +2119,7 @@ static int cifs_writepages(struct address_space *mapping,
pgoff_t end, index; pgoff_t end, index;
struct cifs_writedata *wdata; struct cifs_writedata *wdata;
int rc = 0; int rc = 0;
int saved_rc = 0;
unsigned int xid; unsigned int xid;
/* /*
...@@ -2146,8 +2148,10 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2146,8 +2148,10 @@ static int cifs_writepages(struct address_space *mapping,
rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize,
&wsize, &credits); &wsize, &credits);
if (rc) if (rc != 0) {
done = true;
break; break;
}
tofind = min((wsize / PAGE_SIZE) - 1, end - index) + 1; tofind = min((wsize / PAGE_SIZE) - 1, end - index) + 1;
...@@ -2155,6 +2159,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2155,6 +2159,7 @@ static int cifs_writepages(struct address_space *mapping,
&found_pages); &found_pages);
if (!wdata) { if (!wdata) {
rc = -ENOMEM; rc = -ENOMEM;
done = true;
add_credits_and_wake_if(server, credits, 0); add_credits_and_wake_if(server, credits, 0);
break; break;
} }
...@@ -2183,7 +2188,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2183,7 +2188,7 @@ static int cifs_writepages(struct address_space *mapping,
if (rc != 0) { if (rc != 0) {
add_credits_and_wake_if(server, wdata->credits, 0); add_credits_and_wake_if(server, wdata->credits, 0);
for (i = 0; i < nr_pages; ++i) { for (i = 0; i < nr_pages; ++i) {
if (rc == -EAGAIN) if (is_retryable_error(rc))
redirty_page_for_writepage(wbc, redirty_page_for_writepage(wbc,
wdata->pages[i]); wdata->pages[i]);
else else
...@@ -2191,7 +2196,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2191,7 +2196,7 @@ static int cifs_writepages(struct address_space *mapping,
end_page_writeback(wdata->pages[i]); end_page_writeback(wdata->pages[i]);
put_page(wdata->pages[i]); put_page(wdata->pages[i]);
} }
if (rc != -EAGAIN) if (!is_retryable_error(rc))
mapping_set_error(mapping, rc); mapping_set_error(mapping, rc);
} }
kref_put(&wdata->refcount, cifs_writedata_release); kref_put(&wdata->refcount, cifs_writedata_release);
...@@ -2201,6 +2206,15 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2201,6 +2206,15 @@ static int cifs_writepages(struct address_space *mapping,
continue; continue;
} }
/* Return immediately if we received a signal during writing */
if (is_interrupt_error(rc)) {
done = true;
break;
}
if (rc != 0 && saved_rc == 0)
saved_rc = rc;
wbc->nr_to_write -= nr_pages; wbc->nr_to_write -= nr_pages;
if (wbc->nr_to_write <= 0) if (wbc->nr_to_write <= 0)
done = true; done = true;
...@@ -2218,6 +2232,9 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2218,6 +2232,9 @@ static int cifs_writepages(struct address_space *mapping,
goto retry; goto retry;
} }
if (saved_rc != 0)
rc = saved_rc;
if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
mapping->writeback_index = index; mapping->writeback_index = index;
...@@ -2250,8 +2267,8 @@ cifs_writepage_locked(struct page *page, struct writeback_control *wbc) ...@@ -2250,8 +2267,8 @@ cifs_writepage_locked(struct page *page, struct writeback_control *wbc)
set_page_writeback(page); set_page_writeback(page);
retry_write: retry_write:
rc = cifs_partialpagewrite(page, 0, PAGE_SIZE); rc = cifs_partialpagewrite(page, 0, PAGE_SIZE);
if (rc == -EAGAIN) { if (is_retryable_error(rc)) {
if (wbc->sync_mode == WB_SYNC_ALL) if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
goto retry_write; goto retry_write;
redirty_page_for_writepage(wbc, page); redirty_page_for_writepage(wbc, page);
} else if (rc != 0) { } else if (rc != 0) {
......
...@@ -2250,6 +2250,11 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) ...@@ -2250,6 +2250,11 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
* the flush returns error? * the flush returns error?
*/ */
rc = filemap_write_and_wait(inode->i_mapping); rc = filemap_write_and_wait(inode->i_mapping);
if (is_interrupt_error(rc)) {
rc = -ERESTARTSYS;
goto out;
}
mapping_set_error(inode->i_mapping, rc); mapping_set_error(inode->i_mapping, rc);
rc = 0; rc = 0;
...@@ -2393,6 +2398,11 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2393,6 +2398,11 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
* the flush returns error? * the flush returns error?
*/ */
rc = filemap_write_and_wait(inode->i_mapping); rc = filemap_write_and_wait(inode->i_mapping);
if (is_interrupt_error(rc)) {
rc = -ERESTARTSYS;
goto cifs_setattr_exit;
}
mapping_set_error(inode->i_mapping, rc); mapping_set_error(inode->i_mapping, rc);
rc = 0; rc = 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册