Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e36a5d6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
parents 9bd062d9 a98ee8c1
Loading
Loading
Loading
Loading
+56 −21
Original line number Diff line number Diff line
@@ -1475,7 +1475,11 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
	cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
		 page, pos, copied));

	if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
	if (PageChecked(page)) {
		if (copied == len)
			SetPageUptodate(page);
		ClearPageChecked(page);
	} else if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
		SetPageUptodate(page);

	if (!PageUptodate(page)) {
@@ -2062,39 +2066,70 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping,
{
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
	loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
	loff_t page_start = pos & PAGE_MASK;
	loff_t i_size;
	struct page *page;
	int rc = 0;

	cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));

	*pagep = __grab_cache_page(mapping, index);
	if (!*pagep)
		return -ENOMEM;

	if (PageUptodate(*pagep))
		return 0;
	page = __grab_cache_page(mapping, index);
	if (!page) {
		rc = -ENOMEM;
		goto out;
	}

	/* If we are writing a full page it will be up to date,
	   no need to read from the server */
	if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE)
		return 0;
	if (PageUptodate(page))
		goto out;

	if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
		int rc;
	/*
	 * If we write a full page it will be up to date, no need to read from
	 * the server. If the write is short, we'll end up doing a sync write
	 * instead.
	 */
	if (len == PAGE_CACHE_SIZE)
		goto out;

		/* might as well read a page, it is fast enough */
		rc = cifs_readpage_worker(file, *pagep, &offset);
	/*
	 * optimize away the read when we have an oplock, and we're not
	 * expecting to use any of the data we'd be reading in. That
	 * is, when the page lies beyond the EOF, or straddles the EOF
	 * and the write will cover all of the existing data.
	 */
	if (CIFS_I(mapping->host)->clientCanCacheRead) {
		i_size = i_size_read(mapping->host);
		if (page_start >= i_size ||
		    (offset == 0 && (pos + len) >= i_size)) {
			zero_user_segments(page, 0, offset,
					   offset + len,
					   PAGE_CACHE_SIZE);
			/*
			 * PageChecked means that the parts of the page
			 * to which we're not writing are considered up
			 * to date. Once the data is copied to the
			 * page, it can be set uptodate.
			 */
			SetPageChecked(page);
			goto out;
		}
	}

		/* we do not need to pass errors back
		   e.g. if we do not have read access to the file
		   because cifs_write_end will attempt synchronous writes
		   -- shaggy */
	if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
		/*
		 * might as well read a page, it is fast enough. If we get
		 * an error, we don't need to return it. cifs_write_end will
		 * do a sync write instead since PG_uptodate isn't set.
		 */
		cifs_readpage_worker(file, page, &page_start);
	} else {
		/* we could try using another file handle if there is one -
		   but how would we lock it to prevent close of that handle
		   racing with this read? In any case
		   this will be written out by write_end so is fine */
	}

	return 0;
out:
	*pagep = page;
	return rc;
}

const struct address_space_operations cifs_addr_ops = {