1
0
Fork 0

CIFS: Return error code when getting file handle for writeback

Now we just return NULL cifsFileInfo pointer in cases we didn't find
or couldn't reopen a file. This hides errors from cifs_reopen_file()
especially retryable errors which should be handled appropriately.
Create new cifs_get_writable_file() routine that returns error codes
from cifs_reopen_file() and use it in the writeback codepath.

Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
hifive-unleashed-5.1
Pavel Shilovsky 2019-01-29 12:15:11 -08:00 committed by Steve French
parent c4b8f657d5
commit fe768d51c8
3 changed files with 70 additions and 32 deletions

View File

@ -134,6 +134,9 @@ extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written); unsigned int bytes_written);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only,
struct cifsFileInfo **ret_file);
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server); extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
extern int decode_negTokenInit(unsigned char *security_blob, int length, extern int decode_negTokenInit(unsigned char *security_blob, int length,

View File

@ -2126,10 +2126,13 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
wdata2->tailsz = tailsz; wdata2->tailsz = tailsz;
wdata2->bytes = cur_len; wdata2->bytes = cur_len;
wdata2->cfile = find_writable_file(CIFS_I(inode), false); rc = cifs_get_writable_file(CIFS_I(inode), false,
&wdata2->cfile);
if (!wdata2->cfile) { if (!wdata2->cfile) {
cifs_dbg(VFS, "No writable handle to retry writepages\n"); cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
rc = -EBADF; rc);
if (!is_retryable_error(rc))
rc = -EBADF;
} else { } else {
wdata2->pid = wdata2->cfile->pid; wdata2->pid = wdata2->cfile->pid;
rc = server->ops->async_writev(wdata2, rc = server->ops->async_writev(wdata2,

View File

@ -1842,24 +1842,30 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
return NULL; return NULL;
} }
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, /* Return -EBADF if no handle is found and general rc otherwise */
bool fsuid_only) int
cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
struct cifsFileInfo **ret_file)
{ {
struct cifsFileInfo *open_file, *inv_file = NULL; struct cifsFileInfo *open_file, *inv_file = NULL;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
bool any_available = false; bool any_available = false;
int rc; int rc = -EBADF;
unsigned int refind = 0; unsigned int refind = 0;
/* Having a null inode here (because mapping->host was set to zero by *ret_file = NULL;
the VFS or MM) should not happen but we had reports of on oops (due to
it being zero) during stress testcases so we need to check for it */ /*
* Having a null inode here (because mapping->host was set to zero by
* the VFS or MM) should not happen but we had reports of on oops (due
* to it being zero) during stress testcases so we need to check for it
*/
if (cifs_inode == NULL) { if (cifs_inode == NULL) {
cifs_dbg(VFS, "Null inode passed to cifs_writeable_file\n"); cifs_dbg(VFS, "Null inode passed to cifs_writeable_file\n");
dump_stack(); dump_stack();
return NULL; return rc;
} }
cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
@ -1873,7 +1879,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
refind_writable: refind_writable:
if (refind > MAX_REOPEN_ATT) { if (refind > MAX_REOPEN_ATT) {
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
return NULL; return rc;
} }
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (!any_available && open_file->pid != current->tgid) if (!any_available && open_file->pid != current->tgid)
@ -1885,7 +1891,8 @@ refind_writable:
/* found a good writable file */ /* found a good writable file */
cifsFileInfo_get(open_file); cifsFileInfo_get(open_file);
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
return open_file; *ret_file = open_file;
return 0;
} else { } else {
if (!inv_file) if (!inv_file)
inv_file = open_file; inv_file = open_file;
@ -1907,22 +1914,35 @@ refind_writable:
if (inv_file) { if (inv_file) {
rc = cifs_reopen_file(inv_file, false); rc = cifs_reopen_file(inv_file, false);
if (!rc) if (!rc) {
return inv_file; *ret_file = inv_file;
else { return 0;
spin_lock(&tcon->open_file_lock);
list_move_tail(&inv_file->flist,
&cifs_inode->openFileList);
spin_unlock(&tcon->open_file_lock);
cifsFileInfo_put(inv_file);
++refind;
inv_file = NULL;
spin_lock(&tcon->open_file_lock);
goto refind_writable;
} }
spin_lock(&tcon->open_file_lock);
list_move_tail(&inv_file->flist, &cifs_inode->openFileList);
spin_unlock(&tcon->open_file_lock);
cifsFileInfo_put(inv_file);
++refind;
inv_file = NULL;
spin_lock(&tcon->open_file_lock);
goto refind_writable;
} }
return NULL; return rc;
}
struct cifsFileInfo *
find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only)
{
struct cifsFileInfo *cfile;
int rc;
rc = cifs_get_writable_file(cifs_inode, fsuid_only, &cfile);
if (rc)
cifs_dbg(FYI, "couldn't find writable handle rc=%d", rc);
return cfile;
} }
static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
@ -1959,8 +1979,8 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
if (mapping->host->i_size - offset < (loff_t)to) if (mapping->host->i_size - offset < (loff_t)to)
to = (unsigned)(mapping->host->i_size - offset); to = (unsigned)(mapping->host->i_size - offset);
open_file = find_writable_file(CIFS_I(mapping->host), false); rc = cifs_get_writable_file(CIFS_I(mapping->host), false, &open_file);
if (open_file) { if (!rc) {
bytes_written = cifs_write(open_file, open_file->pid, bytes_written = cifs_write(open_file, open_file->pid,
write_data, to - from, &offset); write_data, to - from, &offset);
cifsFileInfo_put(open_file); cifsFileInfo_put(open_file);
@ -1970,9 +1990,12 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
rc = 0; rc = 0;
else if (bytes_written < 0) else if (bytes_written < 0)
rc = bytes_written; rc = bytes_written;
else
rc = -EFAULT;
} else { } else {
cifs_dbg(FYI, "No writeable filehandles for inode\n"); cifs_dbg(FYI, "No writable handle for write page rc=%d\n", rc);
rc = -EIO; if (!is_retryable_error(rc))
rc = -EIO;
} }
kunmap(page); kunmap(page);
@ -2144,11 +2167,16 @@ retry:
pgoff_t next = 0, tofind, saved_index = index; pgoff_t next = 0, tofind, saved_index = index;
struct cifs_credits credits_on_stack; struct cifs_credits credits_on_stack;
struct cifs_credits *credits = &credits_on_stack; struct cifs_credits *credits = &credits_on_stack;
int get_file_rc = 0;
if (cfile) if (cfile)
cifsFileInfo_put(cfile); cifsFileInfo_put(cfile);
cfile = find_writable_file(CIFS_I(inode), false); rc = cifs_get_writable_file(CIFS_I(inode), false, &cfile);
/* in case of an error store it to return later */
if (rc)
get_file_rc = rc;
rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize,
&wsize, credits); &wsize, credits);
@ -2189,8 +2217,12 @@ retry:
cfile = NULL; cfile = NULL;
if (!wdata->cfile) { if (!wdata->cfile) {
cifs_dbg(VFS, "No writable handle in writepages\n"); cifs_dbg(VFS, "No writable handle in writepages rc=%d\n",
rc = -EBADF; get_file_rc);
if (is_retryable_error(get_file_rc))
rc = get_file_rc;
else
rc = -EBADF;
} else } else
rc = wdata_send_pages(wdata, nr_pages, mapping, wbc); rc = wdata_send_pages(wdata, nr_pages, mapping, wbc);