mirror of https://gitee.com/openkylin/linux.git
CIFS: Fix error paths in writeback code
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: Pavel Shilovsky <pshilov@microsoft.com> Acked-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
ee258d7915
commit
9a66396f18
|
@ -1575,6 +1575,25 @@ static inline void free_dfs_info_array(struct dfs_info3_param *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_REQUEST_ALLOCATED 1
|
||||
#define MID_REQUEST_SUBMITTED 2
|
||||
|
|
|
@ -2123,7 +2123,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
|
|||
|
||||
for (j = 0; j < nr_pages; j++) {
|
||||
unlock_page(wdata2->pages[j]);
|
||||
if (rc != 0 && rc != -EAGAIN) {
|
||||
if (rc != 0 && !is_retryable_error(rc)) {
|
||||
SetPageError(wdata2->pages[j]);
|
||||
end_page_writeback(wdata2->pages[j]);
|
||||
put_page(wdata2->pages[j]);
|
||||
|
@ -2132,7 +2132,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
|
|||
|
||||
if (rc) {
|
||||
kref_put(&wdata2->refcount, cifs_writedata_release);
|
||||
if (rc == -EAGAIN)
|
||||
if (is_retryable_error(rc))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
@ -2141,7 +2141,8 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
|
|||
i += 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -733,7 +733,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
|
|||
|
||||
if (can_flush) {
|
||||
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)
|
||||
rc = cifs_get_inode_info_unix(&inode, full_path,
|
||||
|
@ -2118,6 +2119,7 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
pgoff_t end, index;
|
||||
struct cifs_writedata *wdata;
|
||||
int rc = 0;
|
||||
int saved_rc = 0;
|
||||
unsigned int xid;
|
||||
|
||||
/*
|
||||
|
@ -2146,8 +2148,10 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
|
||||
rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize,
|
||||
&wsize, &credits);
|
||||
if (rc)
|
||||
if (rc != 0) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
tofind = min((wsize / PAGE_SIZE) - 1, end - index) + 1;
|
||||
|
||||
|
@ -2155,6 +2159,7 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
&found_pages);
|
||||
if (!wdata) {
|
||||
rc = -ENOMEM;
|
||||
done = true;
|
||||
add_credits_and_wake_if(server, credits, 0);
|
||||
break;
|
||||
}
|
||||
|
@ -2183,7 +2188,7 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
if (rc != 0) {
|
||||
add_credits_and_wake_if(server, wdata->credits, 0);
|
||||
for (i = 0; i < nr_pages; ++i) {
|
||||
if (rc == -EAGAIN)
|
||||
if (is_retryable_error(rc))
|
||||
redirty_page_for_writepage(wbc,
|
||||
wdata->pages[i]);
|
||||
else
|
||||
|
@ -2191,7 +2196,7 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
end_page_writeback(wdata->pages[i]);
|
||||
put_page(wdata->pages[i]);
|
||||
}
|
||||
if (rc != -EAGAIN)
|
||||
if (!is_retryable_error(rc))
|
||||
mapping_set_error(mapping, rc);
|
||||
}
|
||||
kref_put(&wdata->refcount, cifs_writedata_release);
|
||||
|
@ -2201,6 +2206,15 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
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;
|
||||
if (wbc->nr_to_write <= 0)
|
||||
done = true;
|
||||
|
@ -2218,6 +2232,9 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
goto retry;
|
||||
}
|
||||
|
||||
if (saved_rc != 0)
|
||||
rc = saved_rc;
|
||||
|
||||
if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
|
||||
mapping->writeback_index = index;
|
||||
|
||||
|
@ -2250,8 +2267,8 @@ cifs_writepage_locked(struct page *page, struct writeback_control *wbc)
|
|||
set_page_writeback(page);
|
||||
retry_write:
|
||||
rc = cifs_partialpagewrite(page, 0, PAGE_SIZE);
|
||||
if (rc == -EAGAIN) {
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
if (is_retryable_error(rc)) {
|
||||
if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
|
||||
goto retry_write;
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
} else if (rc != 0) {
|
||||
|
|
|
@ -2257,6 +2257,11 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
|||
* the flush returns error?
|
||||
*/
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (is_interrupt_error(rc)) {
|
||||
rc = -ERESTARTSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mapping_set_error(inode->i_mapping, rc);
|
||||
rc = 0;
|
||||
|
||||
|
@ -2400,6 +2405,11 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||
* the flush returns error?
|
||||
*/
|
||||
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);
|
||||
rc = 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue