Commit fe768d51 authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French
Browse files

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: default avatarPavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent c4b8f657
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -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,
+6 −3
Original line number Original line Diff line number Diff line
@@ -2126,9 +2126,12 @@ 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);
			if (!is_retryable_error(rc))
				rc = -EBADF;
				rc = -EBADF;
		} else {
		} else {
			wdata2->pid = wdata2->cfile->pid;
			wdata2->pid = wdata2->cfile->pid;
+61 −29
Original line number Original line Diff line number Diff line
@@ -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 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
				/* 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,12 +1914,13 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,


	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);
		spin_lock(&tcon->open_file_lock);
			list_move_tail(&inv_file->flist,
		list_move_tail(&inv_file->flist, &cifs_inode->openFileList);
					&cifs_inode->openFileList);
		spin_unlock(&tcon->open_file_lock);
		spin_unlock(&tcon->open_file_lock);
		cifsFileInfo_put(inv_file);
		cifsFileInfo_put(inv_file);
		++refind;
		++refind;
@@ -1920,9 +1928,21 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
		spin_lock(&tcon->open_file_lock);
		spin_lock(&tcon->open_file_lock);
		goto refind_writable;
		goto refind_writable;
	}
	}

	return rc;
}
}


	return NULL;
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,8 +1990,11 @@ 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);
		if (!is_retryable_error(rc))
			rc = -EIO;
			rc = -EIO;
	}
	}


@@ -2144,11 +2167,16 @@ static int cifs_writepages(struct address_space *mapping,
		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,7 +2217,11 @@ static int cifs_writepages(struct address_space *mapping,
		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",
				 get_file_rc);
			if (is_retryable_error(get_file_rc))
				rc = get_file_rc;
			else
				rc = -EBADF;
				rc = -EBADF;
		} else
		} else
			rc = wdata_send_pages(wdata, nr_pages, mapping, wbc);
			rc = wdata_send_pages(wdata, nr_pages, mapping, wbc);