diff mbox series

[24/26] netfs: Remove the old writeback code

Message ID 20240328163424.2781320-25-dhowells@redhat.com (mailing list archive)
State New, archived
Headers show
Series netfs, afs, 9p, cifs: Rework netfs to use ->writepages() to copy to cache | expand

Commit Message

David Howells March 28, 2024, 4:34 p.m. UTC
Remove the old writeback code.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Jeff Layton <jlayton@kernel.org>
cc: Eric Van Hensbergen <ericvh@kernel.org>
cc: Latchesar Ionkov <lucho@ionkov.net>
cc: Dominique Martinet <asmadeus@codewreck.org>
cc: Christian Schoenebeck <linux_oss@crudebyte.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: v9fs@lists.linux.dev
cc: linux-afs@lists.infradead.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/9p/vfs_addr.c          |  34 ---
 fs/afs/write.c            |  40 ---
 fs/netfs/buffered_write.c | 629 --------------------------------------
 fs/netfs/direct_write.c   |   2 +-
 fs/netfs/output.c         | 477 -----------------------------
 5 files changed, 1 insertion(+), 1181 deletions(-)
 delete mode 100644 fs/netfs/output.c

Comments

Jeffrey Layton April 15, 2024, 12:20 p.m. UTC | #1
On Thu, 2024-03-28 at 16:34 +0000, David Howells wrote:
> Remove the old writeback code.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Jeff Layton <jlayton@kernel.org>
> cc: Eric Van Hensbergen <ericvh@kernel.org>
> cc: Latchesar Ionkov <lucho@ionkov.net>
> cc: Dominique Martinet <asmadeus@codewreck.org>
> cc: Christian Schoenebeck <linux_oss@crudebyte.com>
> cc: Marc Dionne <marc.dionne@auristor.com>
> cc: v9fs@lists.linux.dev
> cc: linux-afs@lists.infradead.org
> cc: netfs@lists.linux.dev
> cc: linux-fsdevel@vger.kernel.org
> ---
>  fs/9p/vfs_addr.c          |  34 ---
>  fs/afs/write.c            |  40 ---
>  fs/netfs/buffered_write.c | 629 --------------------------------------
>  fs/netfs/direct_write.c   |   2 +-
>  fs/netfs/output.c         | 477 -----------------------------
>  5 files changed, 1 insertion(+), 1181 deletions(-)
>  delete mode 100644 fs/netfs/output.c
> 
> diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
> index 4845e655bc39..a97ceb105cd8 100644
> --- a/fs/9p/vfs_addr.c
> +++ b/fs/9p/vfs_addr.c
> @@ -60,40 +60,6 @@ static void v9fs_issue_write(struct netfs_io_subrequest *subreq)
>  	netfs_write_subrequest_terminated(subreq, len ?: err, false);
>  }
>  
> -#if 0 // TODO: Remove

#23 and #24 should probably be merged. I don't see any reason to do the
two-step of ifdef'ing out the code and then removing it. Just go for it
at this point in the series.

> -static void v9fs_upload_to_server(struct netfs_io_subrequest *subreq)
> -{
> -	struct p9_fid *fid = subreq->rreq->netfs_priv;
> -	int err, len;
> -
> -	trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
> -	len = p9_client_write(fid, subreq->start, &subreq->io_iter, &err);
> -	netfs_write_subrequest_terminated(subreq, len ?: err, false);
> -}
> -
> -static void v9fs_upload_to_server_worker(struct work_struct *work)
> -{
> -	struct netfs_io_subrequest *subreq =
> -		container_of(work, struct netfs_io_subrequest, work);
> -
> -	v9fs_upload_to_server(subreq);
> -}
> -
> -/*
> - * Set up write requests for a writeback slice.  We need to add a write request
> - * for each write we want to make.
> - */
> -static void v9fs_create_write_requests(struct netfs_io_request *wreq, loff_t start, size_t len)
> -{
> -	struct netfs_io_subrequest *subreq;
> -
> -	subreq = netfs_create_write_request(wreq, NETFS_UPLOAD_TO_SERVER,
> -					    start, len, v9fs_upload_to_server_worker);
> -	if (subreq)
> -		netfs_queue_write_request(subreq);
> -}
> -#endif
> -
>  /**
>   * v9fs_issue_read - Issue a read from 9P
>   * @subreq: The read to make
> diff --git a/fs/afs/write.c b/fs/afs/write.c
> index 0ead204c84cb..6ef7d4cbc008 100644
> --- a/fs/afs/write.c
> +++ b/fs/afs/write.c
> @@ -156,46 +156,6 @@ static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, loff_t
>  	return afs_put_operation(op);
>  }
>  
> -#if 0 // TODO: Remove
> -static void afs_upload_to_server(struct netfs_io_subrequest *subreq)
> -{
> -	struct afs_vnode *vnode = AFS_FS_I(subreq->rreq->inode);
> -	ssize_t ret;
> -
> -	_enter("%x[%x],%zx",
> -	       subreq->rreq->debug_id, subreq->debug_index, subreq->io_iter.count);
> -
> -	trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
> -	ret = afs_store_data(vnode, &subreq->io_iter, subreq->start);
> -	netfs_write_subrequest_terminated(subreq, ret < 0 ? ret : subreq->len,
> -					  false);
> -}
> -
> -static void afs_upload_to_server_worker(struct work_struct *work)
> -{
> -	struct netfs_io_subrequest *subreq =
> -		container_of(work, struct netfs_io_subrequest, work);
> -
> -	afs_upload_to_server(subreq);
> -}
> -
> -/*
> - * Set up write requests for a writeback slice.  We need to add a write request
> - * for each write we want to make.
> - */
> -void afs_create_write_requests(struct netfs_io_request *wreq, loff_t start, size_t len)
> -{
> -	struct netfs_io_subrequest *subreq;
> -
> -	_enter("%x,%llx-%llx", wreq->debug_id, start, start + len);
> -
> -	subreq = netfs_create_write_request(wreq, NETFS_UPLOAD_TO_SERVER,
> -					    start, len, afs_upload_to_server_worker);
> -	if (subreq)
> -		netfs_queue_write_request(subreq);
> -}
> -#endif
> -
>  /*
>   * Writeback calls this when it finds a folio that needs uploading.  This isn't
>   * called if writeback only has copy-to-cache to deal with.
> diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c
> index 945e646cd2db..2da9905abec9 100644
> --- a/fs/netfs/buffered_write.c
> +++ b/fs/netfs/buffered_write.c
> @@ -575,632 +575,3 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr
>  	return ret;
>  }
>  EXPORT_SYMBOL(netfs_page_mkwrite);
> -
> -#if 0 // TODO: Remove
> -/*
> - * Kill all the pages in the given range
> - */
> -static void netfs_kill_pages(struct address_space *mapping,
> -			     loff_t start, loff_t len)
> -{
> -	struct folio *folio;
> -	pgoff_t index = start / PAGE_SIZE;
> -	pgoff_t last = (start + len - 1) / PAGE_SIZE, next;
> -
> -	_enter("%llx-%llx", start, start + len - 1);
> -
> -	do {
> -		_debug("kill %lx (to %lx)", index, last);
> -
> -		folio = filemap_get_folio(mapping, index);
> -		if (IS_ERR(folio)) {
> -			next = index + 1;
> -			continue;
> -		}
> -
> -		next = folio_next_index(folio);
> -
> -		trace_netfs_folio(folio, netfs_folio_trace_kill);
> -		folio_clear_uptodate(folio);
> -		folio_end_writeback(folio);
> -		folio_lock(folio);
> -		generic_error_remove_folio(mapping, folio);
> -		folio_unlock(folio);
> -		folio_put(folio);
> -
> -	} while (index = next, index <= last);
> -
> -	_leave("");
> -}
> -
> -/*
> - * Redirty all the pages in a given range.
> - */
> -static void netfs_redirty_pages(struct address_space *mapping,
> -				loff_t start, loff_t len)
> -{
> -	struct folio *folio;
> -	pgoff_t index = start / PAGE_SIZE;
> -	pgoff_t last = (start + len - 1) / PAGE_SIZE, next;
> -
> -	_enter("%llx-%llx", start, start + len - 1);
> -
> -	do {
> -		_debug("redirty %llx @%llx", len, start);
> -
> -		folio = filemap_get_folio(mapping, index);
> -		if (IS_ERR(folio)) {
> -			next = index + 1;
> -			continue;
> -		}
> -
> -		next = folio_next_index(folio);
> -		trace_netfs_folio(folio, netfs_folio_trace_redirty);
> -		filemap_dirty_folio(mapping, folio);
> -		folio_end_writeback(folio);
> -		folio_put(folio);
> -	} while (index = next, index <= last);
> -
> -	balance_dirty_pages_ratelimited(mapping);
> -
> -	_leave("");
> -}
> -
> -/*
> - * Completion of write to server
> - */
> -static void netfs_pages_written_back(struct netfs_io_request *wreq)
> -{
> -	struct address_space *mapping = wreq->mapping;
> -	struct netfs_folio *finfo;
> -	struct netfs_group *group = NULL;
> -	struct folio *folio;
> -	pgoff_t last;
> -	int gcount = 0;
> -
> -	XA_STATE(xas, &mapping->i_pages, wreq->start / PAGE_SIZE);
> -
> -	_enter("%llx-%llx", wreq->start, wreq->start + wreq->len);
> -
> -	rcu_read_lock();
> -
> -	last = (wreq->start + wreq->len - 1) / PAGE_SIZE;
> -	xas_for_each(&xas, folio, last) {
> -		WARN(!folio_test_writeback(folio),
> -		     "bad %llx @%llx page %lx %lx\n",
> -		     wreq->len, wreq->start, folio->index, last);
> -
> -		if ((finfo = netfs_folio_info(folio))) {
> -			/* Streaming writes cannot be redirtied whilst under
> -			 * writeback, so discard the streaming record.
> -			 */
> -			folio_detach_private(folio);
> -			group = finfo->netfs_group;
> -			gcount++;
> -			trace_netfs_folio(folio, netfs_folio_trace_clear_s);
> -			kfree(finfo);
> -		} else if ((group = netfs_folio_group(folio))) {
> -			/* Need to detach the group pointer if the page didn't
> -			 * get redirtied.  If it has been redirtied, then it
> -			 * must be within the same group.
> -			 */
> -			if (folio_test_dirty(folio)) {
> -				trace_netfs_folio(folio, netfs_folio_trace_redirtied);
> -				goto end_wb;
> -			}
> -			if (folio_trylock(folio)) {
> -				if (!folio_test_dirty(folio)) {
> -					folio_detach_private(folio);
> -					gcount++;
> -					if (group == NETFS_FOLIO_COPY_TO_CACHE)
> -						trace_netfs_folio(folio,
> -								  netfs_folio_trace_end_copy);
> -					else
> -						trace_netfs_folio(folio, netfs_folio_trace_clear_g);
> -				} else {
> -					trace_netfs_folio(folio, netfs_folio_trace_redirtied);
> -				}
> -				folio_unlock(folio);
> -				goto end_wb;
> -			}
> -
> -			xas_pause(&xas);
> -			rcu_read_unlock();
> -			folio_lock(folio);
> -			if (!folio_test_dirty(folio)) {
> -				folio_detach_private(folio);
> -				gcount++;
> -				trace_netfs_folio(folio, netfs_folio_trace_clear_g);
> -			} else {
> -				trace_netfs_folio(folio, netfs_folio_trace_redirtied);
> -			}
> -			folio_unlock(folio);
> -			rcu_read_lock();
> -		} else {
> -			trace_netfs_folio(folio, netfs_folio_trace_clear);
> -		}
> -	end_wb:
> -		xas_advance(&xas, folio_next_index(folio) - 1);
> -		folio_end_writeback(folio);
> -	}
> -
> -	rcu_read_unlock();
> -	netfs_put_group_many(group, gcount);
> -	_leave("");
> -}
> -
> -/*
> - * Deal with the disposition of the folios that are under writeback to close
> - * out the operation.
> - */
> -static void netfs_cleanup_buffered_write(struct netfs_io_request *wreq)
> -{
> -	struct address_space *mapping = wreq->mapping;
> -
> -	_enter("");
> -
> -	switch (wreq->error) {
> -	case 0:
> -		netfs_pages_written_back(wreq);
> -		break;
> -
> -	default:
> -		pr_notice("R=%08x Unexpected error %d\n", wreq->debug_id, wreq->error);
> -		fallthrough;
> -	case -EACCES:
> -	case -EPERM:
> -	case -ENOKEY:
> -	case -EKEYEXPIRED:
> -	case -EKEYREJECTED:
> -	case -EKEYREVOKED:
> -	case -ENETRESET:
> -	case -EDQUOT:
> -	case -ENOSPC:
> -		netfs_redirty_pages(mapping, wreq->start, wreq->len);
> -		break;
> -
> -	case -EROFS:
> -	case -EIO:
> -	case -EREMOTEIO:
> -	case -EFBIG:
> -	case -ENOENT:
> -	case -ENOMEDIUM:
> -	case -ENXIO:
> -		netfs_kill_pages(mapping, wreq->start, wreq->len);
> -		break;
> -	}
> -
> -	if (wreq->error)
> -		mapping_set_error(mapping, wreq->error);
> -	if (wreq->netfs_ops->done)
> -		wreq->netfs_ops->done(wreq);
> -}
> -
> -/*
> - * Extend the region to be written back to include subsequent contiguously
> - * dirty pages if possible, but don't sleep while doing so.
> - *
> - * If this page holds new content, then we can include filler zeros in the
> - * writeback.
> - */
> -static void netfs_extend_writeback(struct address_space *mapping,
> -				   struct netfs_group *group,
> -				   struct xa_state *xas,
> -				   long *_count,
> -				   loff_t start,
> -				   loff_t max_len,
> -				   size_t *_len,
> -				   size_t *_top)
> -{
> -	struct netfs_folio *finfo;
> -	struct folio_batch fbatch;
> -	struct folio *folio;
> -	unsigned int i;
> -	pgoff_t index = (start + *_len) / PAGE_SIZE;
> -	size_t len;
> -	void *priv;
> -	bool stop = true;
> -
> -	folio_batch_init(&fbatch);
> -
> -	do {
> -		/* Firstly, we gather up a batch of contiguous dirty pages
> -		 * under the RCU read lock - but we can't clear the dirty flags
> -		 * there if any of those pages are mapped.
> -		 */
> -		rcu_read_lock();
> -
> -		xas_for_each(xas, folio, ULONG_MAX) {
> -			stop = true;
> -			if (xas_retry(xas, folio))
> -				continue;
> -			if (xa_is_value(folio))
> -				break;
> -			if (folio->index != index) {
> -				xas_reset(xas);
> -				break;
> -			}
> -
> -			if (!folio_try_get_rcu(folio)) {
> -				xas_reset(xas);
> -				continue;
> -			}
> -
> -			/* Has the folio moved or been split? */
> -			if (unlikely(folio != xas_reload(xas))) {
> -				folio_put(folio);
> -				xas_reset(xas);
> -				break;
> -			}
> -
> -			if (!folio_trylock(folio)) {
> -				folio_put(folio);
> -				xas_reset(xas);
> -				break;
> -			}
> -			if (!folio_test_dirty(folio) ||
> -			    folio_test_writeback(folio)) {
> -				folio_unlock(folio);
> -				folio_put(folio);
> -				xas_reset(xas);
> -				break;
> -			}
> -
> -			stop = false;
> -			len = folio_size(folio);
> -			priv = folio_get_private(folio);
> -			if ((const struct netfs_group *)priv != group) {
> -				stop = true;
> -				finfo = netfs_folio_info(folio);
> -				if (!finfo ||
> -				    finfo->netfs_group != group ||
> -				    finfo->dirty_offset > 0) {
> -					folio_unlock(folio);
> -					folio_put(folio);
> -					xas_reset(xas);
> -					break;
> -				}
> -				len = finfo->dirty_len;
> -			}
> -
> -			*_top += folio_size(folio);
> -			index += folio_nr_pages(folio);
> -			*_count -= folio_nr_pages(folio);
> -			*_len += len;
> -			if (*_len >= max_len || *_count <= 0)
> -				stop = true;
> -
> -			if (!folio_batch_add(&fbatch, folio))
> -				break;
> -			if (stop)
> -				break;
> -		}
> -
> -		xas_pause(xas);
> -		rcu_read_unlock();
> -
> -		/* Now, if we obtained any folios, we can shift them to being
> -		 * writable and mark them for caching.
> -		 */
> -		if (!folio_batch_count(&fbatch))
> -			break;
> -
> -		for (i = 0; i < folio_batch_count(&fbatch); i++) {
> -			folio = fbatch.folios[i];
> -			if (group == NETFS_FOLIO_COPY_TO_CACHE)
> -				trace_netfs_folio(folio, netfs_folio_trace_copy_plus);
> -			else
> -				trace_netfs_folio(folio, netfs_folio_trace_store_plus);
> -
> -			if (!folio_clear_dirty_for_io(folio))
> -				BUG();
> -			folio_start_writeback(folio);
> -			folio_unlock(folio);
> -		}
> -
> -		folio_batch_release(&fbatch);
> -		cond_resched();
> -	} while (!stop);
> -}
> -
> -/*
> - * Synchronously write back the locked page and any subsequent non-locked dirty
> - * pages.
> - */
> -static ssize_t netfs_write_back_from_locked_folio(struct address_space *mapping,
> -						  struct writeback_control *wbc,
> -						  struct netfs_group *group,
> -						  struct xa_state *xas,
> -						  struct folio *folio,
> -						  unsigned long long start,
> -						  unsigned long long end)
> -{
> -	struct netfs_io_request *wreq;
> -	struct netfs_folio *finfo;
> -	struct netfs_inode *ctx = netfs_inode(mapping->host);
> -	unsigned long long i_size = i_size_read(&ctx->inode);
> -	size_t len, max_len;
> -	long count = wbc->nr_to_write;
> -	int ret;
> -
> -	_enter(",%lx,%llx-%llx", folio->index, start, end);
> -
> -	wreq = netfs_alloc_request(mapping, NULL, start, folio_size(folio),
> -				   group == NETFS_FOLIO_COPY_TO_CACHE ?
> -				   NETFS_COPY_TO_CACHE : NETFS_WRITEBACK);
> -	if (IS_ERR(wreq)) {
> -		folio_unlock(folio);
> -		return PTR_ERR(wreq);
> -	}
> -
> -	if (!folio_clear_dirty_for_io(folio))
> -		BUG();
> -	folio_start_writeback(folio);
> -
> -	count -= folio_nr_pages(folio);
> -
> -	/* Find all consecutive lockable dirty pages that have contiguous
> -	 * written regions, stopping when we find a page that is not
> -	 * immediately lockable, is not dirty or is missing, or we reach the
> -	 * end of the range.
> -	 */
> -	if (group == NETFS_FOLIO_COPY_TO_CACHE)
> -		trace_netfs_folio(folio, netfs_folio_trace_copy);
> -	else
> -		trace_netfs_folio(folio, netfs_folio_trace_store);
> -
> -	len = wreq->len;
> -	finfo = netfs_folio_info(folio);
> -	if (finfo) {
> -		start += finfo->dirty_offset;
> -		if (finfo->dirty_offset + finfo->dirty_len != len) {
> -			len = finfo->dirty_len;
> -			goto cant_expand;
> -		}
> -		len = finfo->dirty_len;
> -	}
> -
> -	if (start < i_size) {
> -		/* Trim the write to the EOF; the extra data is ignored.  Also
> -		 * put an upper limit on the size of a single storedata op.
> -		 */
> -		max_len = 65536 * 4096;
> -		max_len = min_t(unsigned long long, max_len, end - start + 1);
> -		max_len = min_t(unsigned long long, max_len, i_size - start);
> -
> -		if (len < max_len)
> -			netfs_extend_writeback(mapping, group, xas, &count, start,
> -					       max_len, &len, &wreq->upper_len);
> -	}
> -
> -cant_expand:
> -	len = min_t(unsigned long long, len, i_size - start);
> -
> -	/* We now have a contiguous set of dirty pages, each with writeback
> -	 * set; the first page is still locked at this point, but all the rest
> -	 * have been unlocked.
> -	 */
> -	folio_unlock(folio);
> -	wreq->start = start;
> -	wreq->len = len;
> -
> -	if (start < i_size) {
> -		_debug("write back %zx @%llx [%llx]", len, start, i_size);
> -
> -		/* Speculatively write to the cache.  We have to fix this up
> -		 * later if the store fails.
> -		 */
> -		wreq->cleanup = netfs_cleanup_buffered_write;
> -
> -		iov_iter_xarray(&wreq->iter, ITER_SOURCE, &mapping->i_pages, start,
> -				wreq->upper_len);
> -		if (group != NETFS_FOLIO_COPY_TO_CACHE) {
> -			__set_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags);
> -			ret = netfs_begin_write(wreq, true, netfs_write_trace_writeback);
> -		} else {
> -			ret = netfs_begin_write(wreq, true, netfs_write_trace_copy_to_cache);
> -		}
> -		if (ret == 0 || ret == -EIOCBQUEUED)
> -			wbc->nr_to_write -= len / PAGE_SIZE;
> -	} else {
> -		_debug("write discard %zx @%llx [%llx]", len, start, i_size);
> -
> -		/* The dirty region was entirely beyond the EOF. */
> -		netfs_pages_written_back(wreq);
> -		ret = 0;
> -	}
> -
> -	netfs_put_request(wreq, false, netfs_rreq_trace_put_return);
> -	_leave(" = 1");
> -	return 1;
> -}
> -
> -/*
> - * Write a region of pages back to the server
> - */
> -static ssize_t netfs_writepages_begin(struct address_space *mapping,
> -				      struct writeback_control *wbc,
> -				      struct netfs_group *group,
> -				      struct xa_state *xas,
> -				      unsigned long long *_start,
> -				      unsigned long long end)
> -{
> -	const struct netfs_folio *finfo;
> -	struct folio *folio;
> -	unsigned long long start = *_start;
> -	ssize_t ret;
> -	void *priv;
> -	int skips = 0;
> -
> -	_enter("%llx,%llx,", start, end);
> -
> -search_again:
> -	/* Find the first dirty page in the group. */
> -	rcu_read_lock();
> -
> -	for (;;) {
> -		folio = xas_find_marked(xas, end / PAGE_SIZE, PAGECACHE_TAG_DIRTY);
> -		if (xas_retry(xas, folio) || xa_is_value(folio))
> -			continue;
> -		if (!folio)
> -			break;
> -
> -		if (!folio_try_get_rcu(folio)) {
> -			xas_reset(xas);
> -			continue;
> -		}
> -
> -		if (unlikely(folio != xas_reload(xas))) {
> -			folio_put(folio);
> -			xas_reset(xas);
> -			continue;
> -		}
> -
> -		/* Skip any dirty folio that's not in the group of interest. */
> -		priv = folio_get_private(folio);
> -		if ((const struct netfs_group *)priv == NETFS_FOLIO_COPY_TO_CACHE) {
> -			group = NETFS_FOLIO_COPY_TO_CACHE;
> -		} else if ((const struct netfs_group *)priv != group) {
> -			finfo = __netfs_folio_info(priv);
> -			if (!finfo || finfo->netfs_group != group) {
> -				folio_put(folio);
> -				continue;
> -			}
> -		}
> -
> -		xas_pause(xas);
> -		break;
> -	}
> -	rcu_read_unlock();
> -	if (!folio)
> -		return 0;
> -
> -	start = folio_pos(folio); /* May regress with THPs */
> -
> -	_debug("wback %lx", folio->index);
> -
> -	/* At this point we hold neither the i_pages lock nor the page lock:
> -	 * the page may be truncated or invalidated (changing page->mapping to
> -	 * NULL), or even swizzled back from swapper_space to tmpfs file
> -	 * mapping
> -	 */
> -lock_again:
> -	if (wbc->sync_mode != WB_SYNC_NONE) {
> -		ret = folio_lock_killable(folio);
> -		if (ret < 0)
> -			return ret;
> -	} else {
> -		if (!folio_trylock(folio))
> -			goto search_again;
> -	}
> -
> -	if (folio->mapping != mapping ||
> -	    !folio_test_dirty(folio)) {
> -		start += folio_size(folio);
> -		folio_unlock(folio);
> -		goto search_again;
> -	}
> -
> -	if (folio_test_writeback(folio)) {
> -		folio_unlock(folio);
> -		if (wbc->sync_mode != WB_SYNC_NONE) {
> -			folio_wait_writeback(folio);
> -			goto lock_again;
> -		}
> -
> -		start += folio_size(folio);
> -		if (wbc->sync_mode == WB_SYNC_NONE) {
> -			if (skips >= 5 || need_resched()) {
> -				ret = 0;
> -				goto out;
> -			}
> -			skips++;
> -		}
> -		goto search_again;
> -	}
> -
> -	ret = netfs_write_back_from_locked_folio(mapping, wbc, group, xas,
> -						 folio, start, end);
> -out:
> -	if (ret > 0)
> -		*_start = start + ret;
> -	_leave(" = %zd [%llx]", ret, *_start);
> -	return ret;
> -}
> -
> -/*
> - * Write a region of pages back to the server
> - */
> -static int netfs_writepages_region(struct address_space *mapping,
> -				   struct writeback_control *wbc,
> -				   struct netfs_group *group,
> -				   unsigned long long *_start,
> -				   unsigned long long end)
> -{
> -	ssize_t ret;
> -
> -	XA_STATE(xas, &mapping->i_pages, *_start / PAGE_SIZE);
> -
> -	do {
> -		ret = netfs_writepages_begin(mapping, wbc, group, &xas,
> -					     _start, end);
> -		if (ret > 0 && wbc->nr_to_write > 0)
> -			cond_resched();
> -	} while (ret > 0 && wbc->nr_to_write > 0);
> -
> -	return ret > 0 ? 0 : ret;
> -}
> -
> -/*
> - * write some of the pending data back to the server
> - */
> -int netfs_writepages(struct address_space *mapping,
> -		     struct writeback_control *wbc)
> -{
> -	struct netfs_group *group = NULL;
> -	loff_t start, end;
> -	int ret;
> -
> -	_enter("");
> -
> -	/* We have to be careful as we can end up racing with setattr()
> -	 * truncating the pagecache since the caller doesn't take a lock here
> -	 * to prevent it.
> -	 */
> -
> -	if (wbc->range_cyclic && mapping->writeback_index) {
> -		start = mapping->writeback_index * PAGE_SIZE;
> -		ret = netfs_writepages_region(mapping, wbc, group,
> -					      &start, LLONG_MAX);
> -		if (ret < 0)
> -			goto out;
> -
> -		if (wbc->nr_to_write <= 0) {
> -			mapping->writeback_index = start / PAGE_SIZE;
> -			goto out;
> -		}
> -
> -		start = 0;
> -		end = mapping->writeback_index * PAGE_SIZE;
> -		mapping->writeback_index = 0;
> -		ret = netfs_writepages_region(mapping, wbc, group, &start, end);
> -		if (ret == 0)
> -			mapping->writeback_index = start / PAGE_SIZE;
> -	} else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) {
> -		start = 0;
> -		ret = netfs_writepages_region(mapping, wbc, group,
> -					      &start, LLONG_MAX);
> -		if (wbc->nr_to_write > 0 && ret == 0)
> -			mapping->writeback_index = start / PAGE_SIZE;
> -	} else {
> -		start = wbc->range_start;
> -		ret = netfs_writepages_region(mapping, wbc, group,
> -					      &start, wbc->range_end);
> -	}
> -
> -out:
> -	_leave(" = %d", ret);
> -	return ret;
> -}
> -EXPORT_SYMBOL(netfs_writepages);
> -#endif
> diff --git a/fs/netfs/direct_write.c b/fs/netfs/direct_write.c
> index 330ba7cb3f10..e4a9cf7cd234 100644
> --- a/fs/netfs/direct_write.c
> +++ b/fs/netfs/direct_write.c
> @@ -37,7 +37,7 @@ static ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov
>  	size_t len = iov_iter_count(iter);
>  	bool async = !is_sync_kiocb(iocb);
>  
> -	_enter("");
> +	_enter("%lx", iov_iter_count(iter));
>  
>  	/* We're going to need a bounce buffer if what we transmit is going to
>  	 * be different in some way to the source buffer, e.g. because it gets
> diff --git a/fs/netfs/output.c b/fs/netfs/output.c
> deleted file mode 100644
> index 85374322f10f..000000000000
> --- a/fs/netfs/output.c
> +++ /dev/null
> @@ -1,477 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/* Network filesystem high-level write support.
> - *
> - * Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
> - * Written by David Howells (dhowells@redhat.com)
> - */
> -
> -#include <linux/fs.h>
> -#include <linux/mm.h>
> -#include <linux/pagemap.h>
> -#include <linux/slab.h>
> -#include <linux/writeback.h>
> -#include <linux/pagevec.h>
> -#include "internal.h"
> -
> -/**
> - * netfs_create_write_request - Create a write operation.
> - * @wreq: The write request this is storing from.
> - * @dest: The destination type
> - * @start: Start of the region this write will modify
> - * @len: Length of the modification
> - * @worker: The worker function to handle the write(s)
> - *
> - * Allocate a write operation, set it up and add it to the list on a write
> - * request.
> - */
> -struct netfs_io_subrequest *netfs_create_write_request(struct netfs_io_request *wreq,
> -						       enum netfs_io_source dest,
> -						       loff_t start, size_t len,
> -						       work_func_t worker)
> -{
> -	struct netfs_io_subrequest *subreq;
> -
> -	subreq = netfs_alloc_subrequest(wreq);
> -	if (subreq) {
> -		INIT_WORK(&subreq->work, worker);
> -		subreq->source	= dest;
> -		subreq->start	= start;
> -		subreq->len	= len;
> -
> -		switch (subreq->source) {
> -		case NETFS_UPLOAD_TO_SERVER:
> -			netfs_stat(&netfs_n_wh_upload);
> -			break;
> -		case NETFS_WRITE_TO_CACHE:
> -			netfs_stat(&netfs_n_wh_write);
> -			break;
> -		default:
> -			BUG();
> -		}
> -
> -		subreq->io_iter = wreq->io_iter;
> -		iov_iter_advance(&subreq->io_iter, subreq->start - wreq->start);
> -		iov_iter_truncate(&subreq->io_iter, subreq->len);
> -
> -		trace_netfs_sreq_ref(wreq->debug_id, subreq->debug_index,
> -				     refcount_read(&subreq->ref),
> -				     netfs_sreq_trace_new);
> -		atomic_inc(&wreq->nr_outstanding);
> -		list_add_tail(&subreq->rreq_link, &wreq->subrequests);
> -		trace_netfs_sreq(subreq, netfs_sreq_trace_prepare);
> -	}
> -
> -	return subreq;
> -}
> -EXPORT_SYMBOL(netfs_create_write_request);
> -
> -/*
> - * Process a completed write request once all the component operations have
> - * been completed.
> - */
> -static void netfs_write_terminated(struct netfs_io_request *wreq, bool was_async)
> -{
> -	struct netfs_io_subrequest *subreq;
> -	struct netfs_inode *ctx = netfs_inode(wreq->inode);
> -	size_t transferred = 0;
> -
> -	_enter("R=%x[]", wreq->debug_id);
> -
> -	trace_netfs_rreq(wreq, netfs_rreq_trace_write_done);
> -
> -	list_for_each_entry(subreq, &wreq->subrequests, rreq_link) {
> -		if (subreq->error || subreq->transferred == 0)
> -			break;
> -		transferred += subreq->transferred;
> -		if (subreq->transferred < subreq->len)
> -			break;
> -	}
> -	wreq->transferred = transferred;
> -
> -	list_for_each_entry(subreq, &wreq->subrequests, rreq_link) {
> -		if (!subreq->error)
> -			continue;
> -		switch (subreq->source) {
> -		case NETFS_UPLOAD_TO_SERVER:
> -			/* Depending on the type of failure, this may prevent
> -			 * writeback completion unless we're in disconnected
> -			 * mode.
> -			 */
> -			if (!wreq->error)
> -				wreq->error = subreq->error;
> -			break;
> -
> -		case NETFS_WRITE_TO_CACHE:
> -			/* Failure doesn't prevent writeback completion unless
> -			 * we're in disconnected mode.
> -			 */
> -			if (subreq->error != -ENOBUFS)
> -				ctx->ops->invalidate_cache(wreq);
> -			break;
> -
> -		default:
> -			WARN_ON_ONCE(1);
> -			if (!wreq->error)
> -				wreq->error = -EIO;
> -			return;
> -		}
> -	}
> -
> -	wreq->cleanup(wreq);
> -
> -	if (wreq->origin == NETFS_DIO_WRITE &&
> -	    wreq->mapping->nrpages) {
> -		pgoff_t first = wreq->start >> PAGE_SHIFT;
> -		pgoff_t last = (wreq->start + wreq->transferred - 1) >> PAGE_SHIFT;
> -		invalidate_inode_pages2_range(wreq->mapping, first, last);
> -	}
> -
> -	if (wreq->origin == NETFS_DIO_WRITE)
> -		inode_dio_end(wreq->inode);
> -
> -	_debug("finished");
> -	trace_netfs_rreq(wreq, netfs_rreq_trace_wake_ip);
> -	clear_bit_unlock(NETFS_RREQ_IN_PROGRESS, &wreq->flags);
> -	wake_up_bit(&wreq->flags, NETFS_RREQ_IN_PROGRESS);
> -
> -	if (wreq->iocb) {
> -		wreq->iocb->ki_pos += transferred;
> -		if (wreq->iocb->ki_complete)
> -			wreq->iocb->ki_complete(
> -				wreq->iocb, wreq->error ? wreq->error : transferred);
> -	}
> -
> -	netfs_clear_subrequests(wreq, was_async);
> -	netfs_put_request(wreq, was_async, netfs_rreq_trace_put_complete);
> -}
> -
> -/*
> - * Deal with the completion of writing the data to the cache.
> - */
> -void netfs_write_subrequest_terminated(void *_op, ssize_t transferred_or_error,
> -				       bool was_async)
> -{
> -	struct netfs_io_subrequest *subreq = _op;
> -	struct netfs_io_request *wreq = subreq->rreq;
> -	unsigned int u;
> -
> -	_enter("%x[%x] %zd", wreq->debug_id, subreq->debug_index, transferred_or_error);
> -
> -	switch (subreq->source) {
> -	case NETFS_UPLOAD_TO_SERVER:
> -		netfs_stat(&netfs_n_wh_upload_done);
> -		break;
> -	case NETFS_WRITE_TO_CACHE:
> -		netfs_stat(&netfs_n_wh_write_done);
> -		break;
> -	case NETFS_INVALID_WRITE:
> -		break;
> -	default:
> -		BUG();
> -	}
> -
> -	if (IS_ERR_VALUE(transferred_or_error)) {
> -		subreq->error = transferred_or_error;
> -		trace_netfs_failure(wreq, subreq, transferred_or_error,
> -				    netfs_fail_write);
> -		goto failed;
> -	}
> -
> -	if (WARN(transferred_or_error > subreq->len - subreq->transferred,
> -		 "Subreq excess write: R%x[%x] %zd > %zu - %zu",
> -		 wreq->debug_id, subreq->debug_index,
> -		 transferred_or_error, subreq->len, subreq->transferred))
> -		transferred_or_error = subreq->len - subreq->transferred;
> -
> -	subreq->error = 0;
> -	subreq->transferred += transferred_or_error;
> -
> -	if (iov_iter_count(&subreq->io_iter) != subreq->len - subreq->transferred)
> -		pr_warn("R=%08x[%u] ITER POST-MISMATCH %zx != %zx-%zx %x\n",
> -			wreq->debug_id, subreq->debug_index,
> -			iov_iter_count(&subreq->io_iter), subreq->len,
> -			subreq->transferred, subreq->io_iter.iter_type);
> -
> -	if (subreq->transferred < subreq->len)
> -		goto incomplete;
> -
> -	__clear_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags);
> -out:
> -	trace_netfs_sreq(subreq, netfs_sreq_trace_terminated);
> -
> -	/* If we decrement nr_outstanding to 0, the ref belongs to us. */
> -	u = atomic_dec_return(&wreq->nr_outstanding);
> -	if (u == 0)
> -		netfs_write_terminated(wreq, was_async);
> -	else if (u == 1)
> -		wake_up_var(&wreq->nr_outstanding);
> -
> -	netfs_put_subrequest(subreq, was_async, netfs_sreq_trace_put_terminated);
> -	return;
> -
> -incomplete:
> -	if (transferred_or_error == 0) {
> -		if (__test_and_set_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags)) {
> -			subreq->error = -ENODATA;
> -			goto failed;
> -		}
> -	} else {
> -		__clear_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags);
> -	}
> -
> -	__set_bit(NETFS_SREQ_SHORT_IO, &subreq->flags);
> -	set_bit(NETFS_RREQ_INCOMPLETE_IO, &wreq->flags);
> -	goto out;
> -
> -failed:
> -	switch (subreq->source) {
> -	case NETFS_WRITE_TO_CACHE:
> -		netfs_stat(&netfs_n_wh_write_failed);
> -		set_bit(NETFS_RREQ_INCOMPLETE_IO, &wreq->flags);
> -		break;
> -	case NETFS_UPLOAD_TO_SERVER:
> -		netfs_stat(&netfs_n_wh_upload_failed);
> -		set_bit(NETFS_RREQ_FAILED, &wreq->flags);
> -		wreq->error = subreq->error;
> -		break;
> -	default:
> -		break;
> -	}
> -	goto out;
> -}
> -EXPORT_SYMBOL(netfs_write_subrequest_terminated);
> -
> -static void netfs_write_to_cache_op(struct netfs_io_subrequest *subreq)
> -{
> -	struct netfs_io_request *wreq = subreq->rreq;
> -	struct netfs_cache_resources *cres = &wreq->cache_resources;
> -
> -	trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
> -
> -	cres->ops->write(cres, subreq->start, &subreq->io_iter,
> -			 netfs_write_subrequest_terminated, subreq);
> -}
> -
> -static void netfs_write_to_cache_op_worker(struct work_struct *work)
> -{
> -	struct netfs_io_subrequest *subreq =
> -		container_of(work, struct netfs_io_subrequest, work);
> -
> -	netfs_write_to_cache_op(subreq);
> -}
> -
> -/**
> - * netfs_queue_write_request - Queue a write request for attention
> - * @subreq: The write request to be queued
> - *
> - * Queue the specified write request for processing by a worker thread.  We
> - * pass the caller's ref on the request to the worker thread.
> - */
> -void netfs_queue_write_request(struct netfs_io_subrequest *subreq)
> -{
> -	if (!queue_work(system_unbound_wq, &subreq->work))
> -		netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_wip);
> -}
> -EXPORT_SYMBOL(netfs_queue_write_request);
> -
> -/*
> - * Set up a op for writing to the cache.
> - */
> -static void netfs_set_up_write_to_cache(struct netfs_io_request *wreq)
> -{
> -	struct netfs_cache_resources *cres = &wreq->cache_resources;
> -	struct netfs_io_subrequest *subreq;
> -	struct netfs_inode *ctx = netfs_inode(wreq->inode);
> -	struct fscache_cookie *cookie = netfs_i_cookie(ctx);
> -	loff_t start = wreq->start;
> -	size_t len = wreq->len;
> -	int ret;
> -
> -	if (!fscache_cookie_enabled(cookie)) {
> -		clear_bit(NETFS_RREQ_WRITE_TO_CACHE, &wreq->flags);
> -		return;
> -	}
> -
> -	_debug("write to cache");
> -	ret = fscache_begin_write_operation(cres, cookie);
> -	if (ret < 0)
> -		return;
> -
> -	ret = cres->ops->prepare_write(cres, &start, &len, wreq->upper_len,
> -				       i_size_read(wreq->inode), true);
> -	if (ret < 0)
> -		return;
> -
> -	subreq = netfs_create_write_request(wreq, NETFS_WRITE_TO_CACHE, start, len,
> -					    netfs_write_to_cache_op_worker);
> -	if (!subreq)
> -		return;
> -
> -	netfs_write_to_cache_op(subreq);
> -}
> -
> -/*
> - * Begin the process of writing out a chunk of data.
> - *
> - * We are given a write request that holds a series of dirty regions and
> - * (partially) covers a sequence of folios, all of which are present.  The
> - * pages must have been marked as writeback as appropriate.
> - *
> - * We need to perform the following steps:
> - *
> - * (1) If encrypting, create an output buffer and encrypt each block of the
> - *     data into it, otherwise the output buffer will point to the original
> - *     folios.
> - *
> - * (2) If the data is to be cached, set up a write op for the entire output
> - *     buffer to the cache, if the cache wants to accept it.
> - *
> - * (3) If the data is to be uploaded (ie. not merely cached):
> - *
> - *     (a) If the data is to be compressed, create a compression buffer and
> - *         compress the data into it.
> - *
> - *     (b) For each destination we want to upload to, set up write ops to write
> - *         to that destination.  We may need multiple writes if the data is not
> - *         contiguous or the span exceeds wsize for a server.
> - */
> -int netfs_begin_write(struct netfs_io_request *wreq, bool may_wait,
> -		      enum netfs_write_trace what)
> -{
> -	struct netfs_inode *ctx = netfs_inode(wreq->inode);
> -
> -	_enter("R=%x %llx-%llx f=%lx",
> -	       wreq->debug_id, wreq->start, wreq->start + wreq->len - 1,
> -	       wreq->flags);
> -
> -	trace_netfs_write(wreq, what);
> -	if (wreq->len == 0 || wreq->iter.count == 0) {
> -		pr_err("Zero-sized write [R=%x]\n", wreq->debug_id);
> -		return -EIO;
> -	}
> -
> -	if (wreq->origin == NETFS_DIO_WRITE)
> -		inode_dio_begin(wreq->inode);
> -
> -	wreq->io_iter = wreq->iter;
> -
> -	/* ->outstanding > 0 carries a ref */
> -	netfs_get_request(wreq, netfs_rreq_trace_get_for_outstanding);
> -	atomic_set(&wreq->nr_outstanding, 1);
> -
> -	/* Start the encryption/compression going.  We can do that in the
> -	 * background whilst we generate a list of write ops that we want to
> -	 * perform.
> -	 */
> -	// TODO: Encrypt or compress the region as appropriate
> -
> -	/* We need to write all of the region to the cache */
> -	if (test_bit(NETFS_RREQ_WRITE_TO_CACHE, &wreq->flags))
> -		netfs_set_up_write_to_cache(wreq);
> -
> -	/* However, we don't necessarily write all of the region to the server.
> -	 * Caching of reads is being managed this way also.
> -	 */
> -	if (test_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags))
> -		ctx->ops->create_write_requests(wreq, wreq->start, wreq->len);
> -
> -	if (atomic_dec_and_test(&wreq->nr_outstanding))
> -		netfs_write_terminated(wreq, false);
> -
> -	if (!may_wait)
> -		return -EIOCBQUEUED;
> -
> -	wait_on_bit(&wreq->flags, NETFS_RREQ_IN_PROGRESS,
> -		    TASK_UNINTERRUPTIBLE);
> -	return wreq->error;
> -}
> -
> -/*
> - * Begin a write operation for writing through the pagecache.
> - */
> -struct netfs_io_request *netfs_begin_writethrough(struct kiocb *iocb, size_t len)
> -{
> -	struct netfs_io_request *wreq;
> -	struct file *file = iocb->ki_filp;
> -
> -	wreq = netfs_alloc_request(file->f_mapping, file, iocb->ki_pos, len,
> -				   NETFS_WRITETHROUGH);
> -	if (IS_ERR(wreq))
> -		return wreq;
> -
> -	trace_netfs_write(wreq, netfs_write_trace_writethrough);
> -
> -	__set_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags);
> -	iov_iter_xarray(&wreq->iter, ITER_SOURCE, &wreq->mapping->i_pages, wreq->start, 0);
> -	wreq->io_iter = wreq->iter;
> -
> -	/* ->outstanding > 0 carries a ref */
> -	netfs_get_request(wreq, netfs_rreq_trace_get_for_outstanding);
> -	atomic_set(&wreq->nr_outstanding, 1);
> -	return wreq;
> -}
> -
> -static void netfs_submit_writethrough(struct netfs_io_request *wreq, bool final)
> -{
> -	struct netfs_inode *ictx = netfs_inode(wreq->inode);
> -	unsigned long long start;
> -	size_t len;
> -
> -	if (!test_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags))
> -		return;
> -
> -	start = wreq->start + wreq->submitted;
> -	len = wreq->iter.count - wreq->submitted;
> -	if (!final) {
> -		len /= wreq->wsize; /* Round to number of maximum packets */
> -		len *= wreq->wsize;
> -	}
> -
> -	ictx->ops->create_write_requests(wreq, start, len);
> -	wreq->submitted += len;
> -}
> -
> -/*
> - * Advance the state of the write operation used when writing through the
> - * pagecache.  Data has been copied into the pagecache that we need to append
> - * to the request.  If we've added more than wsize then we need to create a new
> - * subrequest.
> - */
> -int netfs_advance_writethrough(struct netfs_io_request *wreq, size_t copied, bool to_page_end)
> -{
> -	_enter("ic=%zu sb=%llu ws=%u cp=%zu tp=%u",
> -	       wreq->iter.count, wreq->submitted, wreq->wsize, copied, to_page_end);
> -
> -	wreq->iter.count += copied;
> -	wreq->io_iter.count += copied;
> -	if (to_page_end && wreq->io_iter.count - wreq->submitted >= wreq->wsize)
> -		netfs_submit_writethrough(wreq, false);
> -
> -	return wreq->error;
> -}
> -
> -/*
> - * End a write operation used when writing through the pagecache.
> - */
> -int netfs_end_writethrough(struct netfs_io_request *wreq, struct kiocb *iocb)
> -{
> -	int ret = -EIOCBQUEUED;
> -
> -	_enter("ic=%zu sb=%llu ws=%u",
> -	       wreq->iter.count, wreq->submitted, wreq->wsize);
> -
> -	if (wreq->submitted < wreq->io_iter.count)
> -		netfs_submit_writethrough(wreq, true);
> -
> -	if (atomic_dec_and_test(&wreq->nr_outstanding))
> -		netfs_write_terminated(wreq, false);
> -
> -	if (is_sync_kiocb(iocb)) {
> -		wait_on_bit(&wreq->flags, NETFS_RREQ_IN_PROGRESS,
> -			    TASK_UNINTERRUPTIBLE);
> -		ret = wreq->error;
> -	}
> -
> -	netfs_put_request(wreq, false, netfs_rreq_trace_put_return);
> -	return ret;
> -}
>
David Howells April 17, 2024, 10:36 a.m. UTC | #2
Jeff Layton <jlayton@kernel.org> wrote:

> #23 and #24 should probably be merged. I don't see any reason to do the
> two-step of ifdef'ing out the code and then removing it. Just go for it
> at this point in the series.

I would prefer to keep the ~500 line patch that's rearranging the plumbing
separate from the ~1200 line patch that just deletes a load of lines to make
the cutover patch easier to review.  I guess that comes down to a matter of
preference.

David
diff mbox series

Patch

diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 4845e655bc39..a97ceb105cd8 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -60,40 +60,6 @@  static void v9fs_issue_write(struct netfs_io_subrequest *subreq)
 	netfs_write_subrequest_terminated(subreq, len ?: err, false);
 }
 
-#if 0 // TODO: Remove
-static void v9fs_upload_to_server(struct netfs_io_subrequest *subreq)
-{
-	struct p9_fid *fid = subreq->rreq->netfs_priv;
-	int err, len;
-
-	trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
-	len = p9_client_write(fid, subreq->start, &subreq->io_iter, &err);
-	netfs_write_subrequest_terminated(subreq, len ?: err, false);
-}
-
-static void v9fs_upload_to_server_worker(struct work_struct *work)
-{
-	struct netfs_io_subrequest *subreq =
-		container_of(work, struct netfs_io_subrequest, work);
-
-	v9fs_upload_to_server(subreq);
-}
-
-/*
- * Set up write requests for a writeback slice.  We need to add a write request
- * for each write we want to make.
- */
-static void v9fs_create_write_requests(struct netfs_io_request *wreq, loff_t start, size_t len)
-{
-	struct netfs_io_subrequest *subreq;
-
-	subreq = netfs_create_write_request(wreq, NETFS_UPLOAD_TO_SERVER,
-					    start, len, v9fs_upload_to_server_worker);
-	if (subreq)
-		netfs_queue_write_request(subreq);
-}
-#endif
-
 /**
  * v9fs_issue_read - Issue a read from 9P
  * @subreq: The read to make
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 0ead204c84cb..6ef7d4cbc008 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -156,46 +156,6 @@  static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, loff_t
 	return afs_put_operation(op);
 }
 
-#if 0 // TODO: Remove
-static void afs_upload_to_server(struct netfs_io_subrequest *subreq)
-{
-	struct afs_vnode *vnode = AFS_FS_I(subreq->rreq->inode);
-	ssize_t ret;
-
-	_enter("%x[%x],%zx",
-	       subreq->rreq->debug_id, subreq->debug_index, subreq->io_iter.count);
-
-	trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
-	ret = afs_store_data(vnode, &subreq->io_iter, subreq->start);
-	netfs_write_subrequest_terminated(subreq, ret < 0 ? ret : subreq->len,
-					  false);
-}
-
-static void afs_upload_to_server_worker(struct work_struct *work)
-{
-	struct netfs_io_subrequest *subreq =
-		container_of(work, struct netfs_io_subrequest, work);
-
-	afs_upload_to_server(subreq);
-}
-
-/*
- * Set up write requests for a writeback slice.  We need to add a write request
- * for each write we want to make.
- */
-void afs_create_write_requests(struct netfs_io_request *wreq, loff_t start, size_t len)
-{
-	struct netfs_io_subrequest *subreq;
-
-	_enter("%x,%llx-%llx", wreq->debug_id, start, start + len);
-
-	subreq = netfs_create_write_request(wreq, NETFS_UPLOAD_TO_SERVER,
-					    start, len, afs_upload_to_server_worker);
-	if (subreq)
-		netfs_queue_write_request(subreq);
-}
-#endif
-
 /*
  * Writeback calls this when it finds a folio that needs uploading.  This isn't
  * called if writeback only has copy-to-cache to deal with.
diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c
index 945e646cd2db..2da9905abec9 100644
--- a/fs/netfs/buffered_write.c
+++ b/fs/netfs/buffered_write.c
@@ -575,632 +575,3 @@  vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr
 	return ret;
 }
 EXPORT_SYMBOL(netfs_page_mkwrite);
-
-#if 0 // TODO: Remove
-/*
- * Kill all the pages in the given range
- */
-static void netfs_kill_pages(struct address_space *mapping,
-			     loff_t start, loff_t len)
-{
-	struct folio *folio;
-	pgoff_t index = start / PAGE_SIZE;
-	pgoff_t last = (start + len - 1) / PAGE_SIZE, next;
-
-	_enter("%llx-%llx", start, start + len - 1);
-
-	do {
-		_debug("kill %lx (to %lx)", index, last);
-
-		folio = filemap_get_folio(mapping, index);
-		if (IS_ERR(folio)) {
-			next = index + 1;
-			continue;
-		}
-
-		next = folio_next_index(folio);
-
-		trace_netfs_folio(folio, netfs_folio_trace_kill);
-		folio_clear_uptodate(folio);
-		folio_end_writeback(folio);
-		folio_lock(folio);
-		generic_error_remove_folio(mapping, folio);
-		folio_unlock(folio);
-		folio_put(folio);
-
-	} while (index = next, index <= last);
-
-	_leave("");
-}
-
-/*
- * Redirty all the pages in a given range.
- */
-static void netfs_redirty_pages(struct address_space *mapping,
-				loff_t start, loff_t len)
-{
-	struct folio *folio;
-	pgoff_t index = start / PAGE_SIZE;
-	pgoff_t last = (start + len - 1) / PAGE_SIZE, next;
-
-	_enter("%llx-%llx", start, start + len - 1);
-
-	do {
-		_debug("redirty %llx @%llx", len, start);
-
-		folio = filemap_get_folio(mapping, index);
-		if (IS_ERR(folio)) {
-			next = index + 1;
-			continue;
-		}
-
-		next = folio_next_index(folio);
-		trace_netfs_folio(folio, netfs_folio_trace_redirty);
-		filemap_dirty_folio(mapping, folio);
-		folio_end_writeback(folio);
-		folio_put(folio);
-	} while (index = next, index <= last);
-
-	balance_dirty_pages_ratelimited(mapping);
-
-	_leave("");
-}
-
-/*
- * Completion of write to server
- */
-static void netfs_pages_written_back(struct netfs_io_request *wreq)
-{
-	struct address_space *mapping = wreq->mapping;
-	struct netfs_folio *finfo;
-	struct netfs_group *group = NULL;
-	struct folio *folio;
-	pgoff_t last;
-	int gcount = 0;
-
-	XA_STATE(xas, &mapping->i_pages, wreq->start / PAGE_SIZE);
-
-	_enter("%llx-%llx", wreq->start, wreq->start + wreq->len);
-
-	rcu_read_lock();
-
-	last = (wreq->start + wreq->len - 1) / PAGE_SIZE;
-	xas_for_each(&xas, folio, last) {
-		WARN(!folio_test_writeback(folio),
-		     "bad %llx @%llx page %lx %lx\n",
-		     wreq->len, wreq->start, folio->index, last);
-
-		if ((finfo = netfs_folio_info(folio))) {
-			/* Streaming writes cannot be redirtied whilst under
-			 * writeback, so discard the streaming record.
-			 */
-			folio_detach_private(folio);
-			group = finfo->netfs_group;
-			gcount++;
-			trace_netfs_folio(folio, netfs_folio_trace_clear_s);
-			kfree(finfo);
-		} else if ((group = netfs_folio_group(folio))) {
-			/* Need to detach the group pointer if the page didn't
-			 * get redirtied.  If it has been redirtied, then it
-			 * must be within the same group.
-			 */
-			if (folio_test_dirty(folio)) {
-				trace_netfs_folio(folio, netfs_folio_trace_redirtied);
-				goto end_wb;
-			}
-			if (folio_trylock(folio)) {
-				if (!folio_test_dirty(folio)) {
-					folio_detach_private(folio);
-					gcount++;
-					if (group == NETFS_FOLIO_COPY_TO_CACHE)
-						trace_netfs_folio(folio,
-								  netfs_folio_trace_end_copy);
-					else
-						trace_netfs_folio(folio, netfs_folio_trace_clear_g);
-				} else {
-					trace_netfs_folio(folio, netfs_folio_trace_redirtied);
-				}
-				folio_unlock(folio);
-				goto end_wb;
-			}
-
-			xas_pause(&xas);
-			rcu_read_unlock();
-			folio_lock(folio);
-			if (!folio_test_dirty(folio)) {
-				folio_detach_private(folio);
-				gcount++;
-				trace_netfs_folio(folio, netfs_folio_trace_clear_g);
-			} else {
-				trace_netfs_folio(folio, netfs_folio_trace_redirtied);
-			}
-			folio_unlock(folio);
-			rcu_read_lock();
-		} else {
-			trace_netfs_folio(folio, netfs_folio_trace_clear);
-		}
-	end_wb:
-		xas_advance(&xas, folio_next_index(folio) - 1);
-		folio_end_writeback(folio);
-	}
-
-	rcu_read_unlock();
-	netfs_put_group_many(group, gcount);
-	_leave("");
-}
-
-/*
- * Deal with the disposition of the folios that are under writeback to close
- * out the operation.
- */
-static void netfs_cleanup_buffered_write(struct netfs_io_request *wreq)
-{
-	struct address_space *mapping = wreq->mapping;
-
-	_enter("");
-
-	switch (wreq->error) {
-	case 0:
-		netfs_pages_written_back(wreq);
-		break;
-
-	default:
-		pr_notice("R=%08x Unexpected error %d\n", wreq->debug_id, wreq->error);
-		fallthrough;
-	case -EACCES:
-	case -EPERM:
-	case -ENOKEY:
-	case -EKEYEXPIRED:
-	case -EKEYREJECTED:
-	case -EKEYREVOKED:
-	case -ENETRESET:
-	case -EDQUOT:
-	case -ENOSPC:
-		netfs_redirty_pages(mapping, wreq->start, wreq->len);
-		break;
-
-	case -EROFS:
-	case -EIO:
-	case -EREMOTEIO:
-	case -EFBIG:
-	case -ENOENT:
-	case -ENOMEDIUM:
-	case -ENXIO:
-		netfs_kill_pages(mapping, wreq->start, wreq->len);
-		break;
-	}
-
-	if (wreq->error)
-		mapping_set_error(mapping, wreq->error);
-	if (wreq->netfs_ops->done)
-		wreq->netfs_ops->done(wreq);
-}
-
-/*
- * Extend the region to be written back to include subsequent contiguously
- * dirty pages if possible, but don't sleep while doing so.
- *
- * If this page holds new content, then we can include filler zeros in the
- * writeback.
- */
-static void netfs_extend_writeback(struct address_space *mapping,
-				   struct netfs_group *group,
-				   struct xa_state *xas,
-				   long *_count,
-				   loff_t start,
-				   loff_t max_len,
-				   size_t *_len,
-				   size_t *_top)
-{
-	struct netfs_folio *finfo;
-	struct folio_batch fbatch;
-	struct folio *folio;
-	unsigned int i;
-	pgoff_t index = (start + *_len) / PAGE_SIZE;
-	size_t len;
-	void *priv;
-	bool stop = true;
-
-	folio_batch_init(&fbatch);
-
-	do {
-		/* Firstly, we gather up a batch of contiguous dirty pages
-		 * under the RCU read lock - but we can't clear the dirty flags
-		 * there if any of those pages are mapped.
-		 */
-		rcu_read_lock();
-
-		xas_for_each(xas, folio, ULONG_MAX) {
-			stop = true;
-			if (xas_retry(xas, folio))
-				continue;
-			if (xa_is_value(folio))
-				break;
-			if (folio->index != index) {
-				xas_reset(xas);
-				break;
-			}
-
-			if (!folio_try_get_rcu(folio)) {
-				xas_reset(xas);
-				continue;
-			}
-
-			/* Has the folio moved or been split? */
-			if (unlikely(folio != xas_reload(xas))) {
-				folio_put(folio);
-				xas_reset(xas);
-				break;
-			}
-
-			if (!folio_trylock(folio)) {
-				folio_put(folio);
-				xas_reset(xas);
-				break;
-			}
-			if (!folio_test_dirty(folio) ||
-			    folio_test_writeback(folio)) {
-				folio_unlock(folio);
-				folio_put(folio);
-				xas_reset(xas);
-				break;
-			}
-
-			stop = false;
-			len = folio_size(folio);
-			priv = folio_get_private(folio);
-			if ((const struct netfs_group *)priv != group) {
-				stop = true;
-				finfo = netfs_folio_info(folio);
-				if (!finfo ||
-				    finfo->netfs_group != group ||
-				    finfo->dirty_offset > 0) {
-					folio_unlock(folio);
-					folio_put(folio);
-					xas_reset(xas);
-					break;
-				}
-				len = finfo->dirty_len;
-			}
-
-			*_top += folio_size(folio);
-			index += folio_nr_pages(folio);
-			*_count -= folio_nr_pages(folio);
-			*_len += len;
-			if (*_len >= max_len || *_count <= 0)
-				stop = true;
-
-			if (!folio_batch_add(&fbatch, folio))
-				break;
-			if (stop)
-				break;
-		}
-
-		xas_pause(xas);
-		rcu_read_unlock();
-
-		/* Now, if we obtained any folios, we can shift them to being
-		 * writable and mark them for caching.
-		 */
-		if (!folio_batch_count(&fbatch))
-			break;
-
-		for (i = 0; i < folio_batch_count(&fbatch); i++) {
-			folio = fbatch.folios[i];
-			if (group == NETFS_FOLIO_COPY_TO_CACHE)
-				trace_netfs_folio(folio, netfs_folio_trace_copy_plus);
-			else
-				trace_netfs_folio(folio, netfs_folio_trace_store_plus);
-
-			if (!folio_clear_dirty_for_io(folio))
-				BUG();
-			folio_start_writeback(folio);
-			folio_unlock(folio);
-		}
-
-		folio_batch_release(&fbatch);
-		cond_resched();
-	} while (!stop);
-}
-
-/*
- * Synchronously write back the locked page and any subsequent non-locked dirty
- * pages.
- */
-static ssize_t netfs_write_back_from_locked_folio(struct address_space *mapping,
-						  struct writeback_control *wbc,
-						  struct netfs_group *group,
-						  struct xa_state *xas,
-						  struct folio *folio,
-						  unsigned long long start,
-						  unsigned long long end)
-{
-	struct netfs_io_request *wreq;
-	struct netfs_folio *finfo;
-	struct netfs_inode *ctx = netfs_inode(mapping->host);
-	unsigned long long i_size = i_size_read(&ctx->inode);
-	size_t len, max_len;
-	long count = wbc->nr_to_write;
-	int ret;
-
-	_enter(",%lx,%llx-%llx", folio->index, start, end);
-
-	wreq = netfs_alloc_request(mapping, NULL, start, folio_size(folio),
-				   group == NETFS_FOLIO_COPY_TO_CACHE ?
-				   NETFS_COPY_TO_CACHE : NETFS_WRITEBACK);
-	if (IS_ERR(wreq)) {
-		folio_unlock(folio);
-		return PTR_ERR(wreq);
-	}
-
-	if (!folio_clear_dirty_for_io(folio))
-		BUG();
-	folio_start_writeback(folio);
-
-	count -= folio_nr_pages(folio);
-
-	/* Find all consecutive lockable dirty pages that have contiguous
-	 * written regions, stopping when we find a page that is not
-	 * immediately lockable, is not dirty or is missing, or we reach the
-	 * end of the range.
-	 */
-	if (group == NETFS_FOLIO_COPY_TO_CACHE)
-		trace_netfs_folio(folio, netfs_folio_trace_copy);
-	else
-		trace_netfs_folio(folio, netfs_folio_trace_store);
-
-	len = wreq->len;
-	finfo = netfs_folio_info(folio);
-	if (finfo) {
-		start += finfo->dirty_offset;
-		if (finfo->dirty_offset + finfo->dirty_len != len) {
-			len = finfo->dirty_len;
-			goto cant_expand;
-		}
-		len = finfo->dirty_len;
-	}
-
-	if (start < i_size) {
-		/* Trim the write to the EOF; the extra data is ignored.  Also
-		 * put an upper limit on the size of a single storedata op.
-		 */
-		max_len = 65536 * 4096;
-		max_len = min_t(unsigned long long, max_len, end - start + 1);
-		max_len = min_t(unsigned long long, max_len, i_size - start);
-
-		if (len < max_len)
-			netfs_extend_writeback(mapping, group, xas, &count, start,
-					       max_len, &len, &wreq->upper_len);
-	}
-
-cant_expand:
-	len = min_t(unsigned long long, len, i_size - start);
-
-	/* We now have a contiguous set of dirty pages, each with writeback
-	 * set; the first page is still locked at this point, but all the rest
-	 * have been unlocked.
-	 */
-	folio_unlock(folio);
-	wreq->start = start;
-	wreq->len = len;
-
-	if (start < i_size) {
-		_debug("write back %zx @%llx [%llx]", len, start, i_size);
-
-		/* Speculatively write to the cache.  We have to fix this up
-		 * later if the store fails.
-		 */
-		wreq->cleanup = netfs_cleanup_buffered_write;
-
-		iov_iter_xarray(&wreq->iter, ITER_SOURCE, &mapping->i_pages, start,
-				wreq->upper_len);
-		if (group != NETFS_FOLIO_COPY_TO_CACHE) {
-			__set_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags);
-			ret = netfs_begin_write(wreq, true, netfs_write_trace_writeback);
-		} else {
-			ret = netfs_begin_write(wreq, true, netfs_write_trace_copy_to_cache);
-		}
-		if (ret == 0 || ret == -EIOCBQUEUED)
-			wbc->nr_to_write -= len / PAGE_SIZE;
-	} else {
-		_debug("write discard %zx @%llx [%llx]", len, start, i_size);
-
-		/* The dirty region was entirely beyond the EOF. */
-		netfs_pages_written_back(wreq);
-		ret = 0;
-	}
-
-	netfs_put_request(wreq, false, netfs_rreq_trace_put_return);
-	_leave(" = 1");
-	return 1;
-}
-
-/*
- * Write a region of pages back to the server
- */
-static ssize_t netfs_writepages_begin(struct address_space *mapping,
-				      struct writeback_control *wbc,
-				      struct netfs_group *group,
-				      struct xa_state *xas,
-				      unsigned long long *_start,
-				      unsigned long long end)
-{
-	const struct netfs_folio *finfo;
-	struct folio *folio;
-	unsigned long long start = *_start;
-	ssize_t ret;
-	void *priv;
-	int skips = 0;
-
-	_enter("%llx,%llx,", start, end);
-
-search_again:
-	/* Find the first dirty page in the group. */
-	rcu_read_lock();
-
-	for (;;) {
-		folio = xas_find_marked(xas, end / PAGE_SIZE, PAGECACHE_TAG_DIRTY);
-		if (xas_retry(xas, folio) || xa_is_value(folio))
-			continue;
-		if (!folio)
-			break;
-
-		if (!folio_try_get_rcu(folio)) {
-			xas_reset(xas);
-			continue;
-		}
-
-		if (unlikely(folio != xas_reload(xas))) {
-			folio_put(folio);
-			xas_reset(xas);
-			continue;
-		}
-
-		/* Skip any dirty folio that's not in the group of interest. */
-		priv = folio_get_private(folio);
-		if ((const struct netfs_group *)priv == NETFS_FOLIO_COPY_TO_CACHE) {
-			group = NETFS_FOLIO_COPY_TO_CACHE;
-		} else if ((const struct netfs_group *)priv != group) {
-			finfo = __netfs_folio_info(priv);
-			if (!finfo || finfo->netfs_group != group) {
-				folio_put(folio);
-				continue;
-			}
-		}
-
-		xas_pause(xas);
-		break;
-	}
-	rcu_read_unlock();
-	if (!folio)
-		return 0;
-
-	start = folio_pos(folio); /* May regress with THPs */
-
-	_debug("wback %lx", folio->index);
-
-	/* At this point we hold neither the i_pages lock nor the page lock:
-	 * the page may be truncated or invalidated (changing page->mapping to
-	 * NULL), or even swizzled back from swapper_space to tmpfs file
-	 * mapping
-	 */
-lock_again:
-	if (wbc->sync_mode != WB_SYNC_NONE) {
-		ret = folio_lock_killable(folio);
-		if (ret < 0)
-			return ret;
-	} else {
-		if (!folio_trylock(folio))
-			goto search_again;
-	}
-
-	if (folio->mapping != mapping ||
-	    !folio_test_dirty(folio)) {
-		start += folio_size(folio);
-		folio_unlock(folio);
-		goto search_again;
-	}
-
-	if (folio_test_writeback(folio)) {
-		folio_unlock(folio);
-		if (wbc->sync_mode != WB_SYNC_NONE) {
-			folio_wait_writeback(folio);
-			goto lock_again;
-		}
-
-		start += folio_size(folio);
-		if (wbc->sync_mode == WB_SYNC_NONE) {
-			if (skips >= 5 || need_resched()) {
-				ret = 0;
-				goto out;
-			}
-			skips++;
-		}
-		goto search_again;
-	}
-
-	ret = netfs_write_back_from_locked_folio(mapping, wbc, group, xas,
-						 folio, start, end);
-out:
-	if (ret > 0)
-		*_start = start + ret;
-	_leave(" = %zd [%llx]", ret, *_start);
-	return ret;
-}
-
-/*
- * Write a region of pages back to the server
- */
-static int netfs_writepages_region(struct address_space *mapping,
-				   struct writeback_control *wbc,
-				   struct netfs_group *group,
-				   unsigned long long *_start,
-				   unsigned long long end)
-{
-	ssize_t ret;
-
-	XA_STATE(xas, &mapping->i_pages, *_start / PAGE_SIZE);
-
-	do {
-		ret = netfs_writepages_begin(mapping, wbc, group, &xas,
-					     _start, end);
-		if (ret > 0 && wbc->nr_to_write > 0)
-			cond_resched();
-	} while (ret > 0 && wbc->nr_to_write > 0);
-
-	return ret > 0 ? 0 : ret;
-}
-
-/*
- * write some of the pending data back to the server
- */
-int netfs_writepages(struct address_space *mapping,
-		     struct writeback_control *wbc)
-{
-	struct netfs_group *group = NULL;
-	loff_t start, end;
-	int ret;
-
-	_enter("");
-
-	/* We have to be careful as we can end up racing with setattr()
-	 * truncating the pagecache since the caller doesn't take a lock here
-	 * to prevent it.
-	 */
-
-	if (wbc->range_cyclic && mapping->writeback_index) {
-		start = mapping->writeback_index * PAGE_SIZE;
-		ret = netfs_writepages_region(mapping, wbc, group,
-					      &start, LLONG_MAX);
-		if (ret < 0)
-			goto out;
-
-		if (wbc->nr_to_write <= 0) {
-			mapping->writeback_index = start / PAGE_SIZE;
-			goto out;
-		}
-
-		start = 0;
-		end = mapping->writeback_index * PAGE_SIZE;
-		mapping->writeback_index = 0;
-		ret = netfs_writepages_region(mapping, wbc, group, &start, end);
-		if (ret == 0)
-			mapping->writeback_index = start / PAGE_SIZE;
-	} else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) {
-		start = 0;
-		ret = netfs_writepages_region(mapping, wbc, group,
-					      &start, LLONG_MAX);
-		if (wbc->nr_to_write > 0 && ret == 0)
-			mapping->writeback_index = start / PAGE_SIZE;
-	} else {
-		start = wbc->range_start;
-		ret = netfs_writepages_region(mapping, wbc, group,
-					      &start, wbc->range_end);
-	}
-
-out:
-	_leave(" = %d", ret);
-	return ret;
-}
-EXPORT_SYMBOL(netfs_writepages);
-#endif
diff --git a/fs/netfs/direct_write.c b/fs/netfs/direct_write.c
index 330ba7cb3f10..e4a9cf7cd234 100644
--- a/fs/netfs/direct_write.c
+++ b/fs/netfs/direct_write.c
@@ -37,7 +37,7 @@  static ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov
 	size_t len = iov_iter_count(iter);
 	bool async = !is_sync_kiocb(iocb);
 
-	_enter("");
+	_enter("%lx", iov_iter_count(iter));
 
 	/* We're going to need a bounce buffer if what we transmit is going to
 	 * be different in some way to the source buffer, e.g. because it gets
diff --git a/fs/netfs/output.c b/fs/netfs/output.c
deleted file mode 100644
index 85374322f10f..000000000000
--- a/fs/netfs/output.c
+++ /dev/null
@@ -1,477 +0,0 @@ 
-// SPDX-License-Identifier: GPL-2.0-only
-/* Network filesystem high-level write support.
- *
- * Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- */
-
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/writeback.h>
-#include <linux/pagevec.h>
-#include "internal.h"
-
-/**
- * netfs_create_write_request - Create a write operation.
- * @wreq: The write request this is storing from.
- * @dest: The destination type
- * @start: Start of the region this write will modify
- * @len: Length of the modification
- * @worker: The worker function to handle the write(s)
- *
- * Allocate a write operation, set it up and add it to the list on a write
- * request.
- */
-struct netfs_io_subrequest *netfs_create_write_request(struct netfs_io_request *wreq,
-						       enum netfs_io_source dest,
-						       loff_t start, size_t len,
-						       work_func_t worker)
-{
-	struct netfs_io_subrequest *subreq;
-
-	subreq = netfs_alloc_subrequest(wreq);
-	if (subreq) {
-		INIT_WORK(&subreq->work, worker);
-		subreq->source	= dest;
-		subreq->start	= start;
-		subreq->len	= len;
-
-		switch (subreq->source) {
-		case NETFS_UPLOAD_TO_SERVER:
-			netfs_stat(&netfs_n_wh_upload);
-			break;
-		case NETFS_WRITE_TO_CACHE:
-			netfs_stat(&netfs_n_wh_write);
-			break;
-		default:
-			BUG();
-		}
-
-		subreq->io_iter = wreq->io_iter;
-		iov_iter_advance(&subreq->io_iter, subreq->start - wreq->start);
-		iov_iter_truncate(&subreq->io_iter, subreq->len);
-
-		trace_netfs_sreq_ref(wreq->debug_id, subreq->debug_index,
-				     refcount_read(&subreq->ref),
-				     netfs_sreq_trace_new);
-		atomic_inc(&wreq->nr_outstanding);
-		list_add_tail(&subreq->rreq_link, &wreq->subrequests);
-		trace_netfs_sreq(subreq, netfs_sreq_trace_prepare);
-	}
-
-	return subreq;
-}
-EXPORT_SYMBOL(netfs_create_write_request);
-
-/*
- * Process a completed write request once all the component operations have
- * been completed.
- */
-static void netfs_write_terminated(struct netfs_io_request *wreq, bool was_async)
-{
-	struct netfs_io_subrequest *subreq;
-	struct netfs_inode *ctx = netfs_inode(wreq->inode);
-	size_t transferred = 0;
-
-	_enter("R=%x[]", wreq->debug_id);
-
-	trace_netfs_rreq(wreq, netfs_rreq_trace_write_done);
-
-	list_for_each_entry(subreq, &wreq->subrequests, rreq_link) {
-		if (subreq->error || subreq->transferred == 0)
-			break;
-		transferred += subreq->transferred;
-		if (subreq->transferred < subreq->len)
-			break;
-	}
-	wreq->transferred = transferred;
-
-	list_for_each_entry(subreq, &wreq->subrequests, rreq_link) {
-		if (!subreq->error)
-			continue;
-		switch (subreq->source) {
-		case NETFS_UPLOAD_TO_SERVER:
-			/* Depending on the type of failure, this may prevent
-			 * writeback completion unless we're in disconnected
-			 * mode.
-			 */
-			if (!wreq->error)
-				wreq->error = subreq->error;
-			break;
-
-		case NETFS_WRITE_TO_CACHE:
-			/* Failure doesn't prevent writeback completion unless
-			 * we're in disconnected mode.
-			 */
-			if (subreq->error != -ENOBUFS)
-				ctx->ops->invalidate_cache(wreq);
-			break;
-
-		default:
-			WARN_ON_ONCE(1);
-			if (!wreq->error)
-				wreq->error = -EIO;
-			return;
-		}
-	}
-
-	wreq->cleanup(wreq);
-
-	if (wreq->origin == NETFS_DIO_WRITE &&
-	    wreq->mapping->nrpages) {
-		pgoff_t first = wreq->start >> PAGE_SHIFT;
-		pgoff_t last = (wreq->start + wreq->transferred - 1) >> PAGE_SHIFT;
-		invalidate_inode_pages2_range(wreq->mapping, first, last);
-	}
-
-	if (wreq->origin == NETFS_DIO_WRITE)
-		inode_dio_end(wreq->inode);
-
-	_debug("finished");
-	trace_netfs_rreq(wreq, netfs_rreq_trace_wake_ip);
-	clear_bit_unlock(NETFS_RREQ_IN_PROGRESS, &wreq->flags);
-	wake_up_bit(&wreq->flags, NETFS_RREQ_IN_PROGRESS);
-
-	if (wreq->iocb) {
-		wreq->iocb->ki_pos += transferred;
-		if (wreq->iocb->ki_complete)
-			wreq->iocb->ki_complete(
-				wreq->iocb, wreq->error ? wreq->error : transferred);
-	}
-
-	netfs_clear_subrequests(wreq, was_async);
-	netfs_put_request(wreq, was_async, netfs_rreq_trace_put_complete);
-}
-
-/*
- * Deal with the completion of writing the data to the cache.
- */
-void netfs_write_subrequest_terminated(void *_op, ssize_t transferred_or_error,
-				       bool was_async)
-{
-	struct netfs_io_subrequest *subreq = _op;
-	struct netfs_io_request *wreq = subreq->rreq;
-	unsigned int u;
-
-	_enter("%x[%x] %zd", wreq->debug_id, subreq->debug_index, transferred_or_error);
-
-	switch (subreq->source) {
-	case NETFS_UPLOAD_TO_SERVER:
-		netfs_stat(&netfs_n_wh_upload_done);
-		break;
-	case NETFS_WRITE_TO_CACHE:
-		netfs_stat(&netfs_n_wh_write_done);
-		break;
-	case NETFS_INVALID_WRITE:
-		break;
-	default:
-		BUG();
-	}
-
-	if (IS_ERR_VALUE(transferred_or_error)) {
-		subreq->error = transferred_or_error;
-		trace_netfs_failure(wreq, subreq, transferred_or_error,
-				    netfs_fail_write);
-		goto failed;
-	}
-
-	if (WARN(transferred_or_error > subreq->len - subreq->transferred,
-		 "Subreq excess write: R%x[%x] %zd > %zu - %zu",
-		 wreq->debug_id, subreq->debug_index,
-		 transferred_or_error, subreq->len, subreq->transferred))
-		transferred_or_error = subreq->len - subreq->transferred;
-
-	subreq->error = 0;
-	subreq->transferred += transferred_or_error;
-
-	if (iov_iter_count(&subreq->io_iter) != subreq->len - subreq->transferred)
-		pr_warn("R=%08x[%u] ITER POST-MISMATCH %zx != %zx-%zx %x\n",
-			wreq->debug_id, subreq->debug_index,
-			iov_iter_count(&subreq->io_iter), subreq->len,
-			subreq->transferred, subreq->io_iter.iter_type);
-
-	if (subreq->transferred < subreq->len)
-		goto incomplete;
-
-	__clear_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags);
-out:
-	trace_netfs_sreq(subreq, netfs_sreq_trace_terminated);
-
-	/* If we decrement nr_outstanding to 0, the ref belongs to us. */
-	u = atomic_dec_return(&wreq->nr_outstanding);
-	if (u == 0)
-		netfs_write_terminated(wreq, was_async);
-	else if (u == 1)
-		wake_up_var(&wreq->nr_outstanding);
-
-	netfs_put_subrequest(subreq, was_async, netfs_sreq_trace_put_terminated);
-	return;
-
-incomplete:
-	if (transferred_or_error == 0) {
-		if (__test_and_set_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags)) {
-			subreq->error = -ENODATA;
-			goto failed;
-		}
-	} else {
-		__clear_bit(NETFS_SREQ_NO_PROGRESS, &subreq->flags);
-	}
-
-	__set_bit(NETFS_SREQ_SHORT_IO, &subreq->flags);
-	set_bit(NETFS_RREQ_INCOMPLETE_IO, &wreq->flags);
-	goto out;
-
-failed:
-	switch (subreq->source) {
-	case NETFS_WRITE_TO_CACHE:
-		netfs_stat(&netfs_n_wh_write_failed);
-		set_bit(NETFS_RREQ_INCOMPLETE_IO, &wreq->flags);
-		break;
-	case NETFS_UPLOAD_TO_SERVER:
-		netfs_stat(&netfs_n_wh_upload_failed);
-		set_bit(NETFS_RREQ_FAILED, &wreq->flags);
-		wreq->error = subreq->error;
-		break;
-	default:
-		break;
-	}
-	goto out;
-}
-EXPORT_SYMBOL(netfs_write_subrequest_terminated);
-
-static void netfs_write_to_cache_op(struct netfs_io_subrequest *subreq)
-{
-	struct netfs_io_request *wreq = subreq->rreq;
-	struct netfs_cache_resources *cres = &wreq->cache_resources;
-
-	trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
-
-	cres->ops->write(cres, subreq->start, &subreq->io_iter,
-			 netfs_write_subrequest_terminated, subreq);
-}
-
-static void netfs_write_to_cache_op_worker(struct work_struct *work)
-{
-	struct netfs_io_subrequest *subreq =
-		container_of(work, struct netfs_io_subrequest, work);
-
-	netfs_write_to_cache_op(subreq);
-}
-
-/**
- * netfs_queue_write_request - Queue a write request for attention
- * @subreq: The write request to be queued
- *
- * Queue the specified write request for processing by a worker thread.  We
- * pass the caller's ref on the request to the worker thread.
- */
-void netfs_queue_write_request(struct netfs_io_subrequest *subreq)
-{
-	if (!queue_work(system_unbound_wq, &subreq->work))
-		netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_wip);
-}
-EXPORT_SYMBOL(netfs_queue_write_request);
-
-/*
- * Set up a op for writing to the cache.
- */
-static void netfs_set_up_write_to_cache(struct netfs_io_request *wreq)
-{
-	struct netfs_cache_resources *cres = &wreq->cache_resources;
-	struct netfs_io_subrequest *subreq;
-	struct netfs_inode *ctx = netfs_inode(wreq->inode);
-	struct fscache_cookie *cookie = netfs_i_cookie(ctx);
-	loff_t start = wreq->start;
-	size_t len = wreq->len;
-	int ret;
-
-	if (!fscache_cookie_enabled(cookie)) {
-		clear_bit(NETFS_RREQ_WRITE_TO_CACHE, &wreq->flags);
-		return;
-	}
-
-	_debug("write to cache");
-	ret = fscache_begin_write_operation(cres, cookie);
-	if (ret < 0)
-		return;
-
-	ret = cres->ops->prepare_write(cres, &start, &len, wreq->upper_len,
-				       i_size_read(wreq->inode), true);
-	if (ret < 0)
-		return;
-
-	subreq = netfs_create_write_request(wreq, NETFS_WRITE_TO_CACHE, start, len,
-					    netfs_write_to_cache_op_worker);
-	if (!subreq)
-		return;
-
-	netfs_write_to_cache_op(subreq);
-}
-
-/*
- * Begin the process of writing out a chunk of data.
- *
- * We are given a write request that holds a series of dirty regions and
- * (partially) covers a sequence of folios, all of which are present.  The
- * pages must have been marked as writeback as appropriate.
- *
- * We need to perform the following steps:
- *
- * (1) If encrypting, create an output buffer and encrypt each block of the
- *     data into it, otherwise the output buffer will point to the original
- *     folios.
- *
- * (2) If the data is to be cached, set up a write op for the entire output
- *     buffer to the cache, if the cache wants to accept it.
- *
- * (3) If the data is to be uploaded (ie. not merely cached):
- *
- *     (a) If the data is to be compressed, create a compression buffer and
- *         compress the data into it.
- *
- *     (b) For each destination we want to upload to, set up write ops to write
- *         to that destination.  We may need multiple writes if the data is not
- *         contiguous or the span exceeds wsize for a server.
- */
-int netfs_begin_write(struct netfs_io_request *wreq, bool may_wait,
-		      enum netfs_write_trace what)
-{
-	struct netfs_inode *ctx = netfs_inode(wreq->inode);
-
-	_enter("R=%x %llx-%llx f=%lx",
-	       wreq->debug_id, wreq->start, wreq->start + wreq->len - 1,
-	       wreq->flags);
-
-	trace_netfs_write(wreq, what);
-	if (wreq->len == 0 || wreq->iter.count == 0) {
-		pr_err("Zero-sized write [R=%x]\n", wreq->debug_id);
-		return -EIO;
-	}
-
-	if (wreq->origin == NETFS_DIO_WRITE)
-		inode_dio_begin(wreq->inode);
-
-	wreq->io_iter = wreq->iter;
-
-	/* ->outstanding > 0 carries a ref */
-	netfs_get_request(wreq, netfs_rreq_trace_get_for_outstanding);
-	atomic_set(&wreq->nr_outstanding, 1);
-
-	/* Start the encryption/compression going.  We can do that in the
-	 * background whilst we generate a list of write ops that we want to
-	 * perform.
-	 */
-	// TODO: Encrypt or compress the region as appropriate
-
-	/* We need to write all of the region to the cache */
-	if (test_bit(NETFS_RREQ_WRITE_TO_CACHE, &wreq->flags))
-		netfs_set_up_write_to_cache(wreq);
-
-	/* However, we don't necessarily write all of the region to the server.
-	 * Caching of reads is being managed this way also.
-	 */
-	if (test_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags))
-		ctx->ops->create_write_requests(wreq, wreq->start, wreq->len);
-
-	if (atomic_dec_and_test(&wreq->nr_outstanding))
-		netfs_write_terminated(wreq, false);
-
-	if (!may_wait)
-		return -EIOCBQUEUED;
-
-	wait_on_bit(&wreq->flags, NETFS_RREQ_IN_PROGRESS,
-		    TASK_UNINTERRUPTIBLE);
-	return wreq->error;
-}
-
-/*
- * Begin a write operation for writing through the pagecache.
- */
-struct netfs_io_request *netfs_begin_writethrough(struct kiocb *iocb, size_t len)
-{
-	struct netfs_io_request *wreq;
-	struct file *file = iocb->ki_filp;
-
-	wreq = netfs_alloc_request(file->f_mapping, file, iocb->ki_pos, len,
-				   NETFS_WRITETHROUGH);
-	if (IS_ERR(wreq))
-		return wreq;
-
-	trace_netfs_write(wreq, netfs_write_trace_writethrough);
-
-	__set_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags);
-	iov_iter_xarray(&wreq->iter, ITER_SOURCE, &wreq->mapping->i_pages, wreq->start, 0);
-	wreq->io_iter = wreq->iter;
-
-	/* ->outstanding > 0 carries a ref */
-	netfs_get_request(wreq, netfs_rreq_trace_get_for_outstanding);
-	atomic_set(&wreq->nr_outstanding, 1);
-	return wreq;
-}
-
-static void netfs_submit_writethrough(struct netfs_io_request *wreq, bool final)
-{
-	struct netfs_inode *ictx = netfs_inode(wreq->inode);
-	unsigned long long start;
-	size_t len;
-
-	if (!test_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags))
-		return;
-
-	start = wreq->start + wreq->submitted;
-	len = wreq->iter.count - wreq->submitted;
-	if (!final) {
-		len /= wreq->wsize; /* Round to number of maximum packets */
-		len *= wreq->wsize;
-	}
-
-	ictx->ops->create_write_requests(wreq, start, len);
-	wreq->submitted += len;
-}
-
-/*
- * Advance the state of the write operation used when writing through the
- * pagecache.  Data has been copied into the pagecache that we need to append
- * to the request.  If we've added more than wsize then we need to create a new
- * subrequest.
- */
-int netfs_advance_writethrough(struct netfs_io_request *wreq, size_t copied, bool to_page_end)
-{
-	_enter("ic=%zu sb=%llu ws=%u cp=%zu tp=%u",
-	       wreq->iter.count, wreq->submitted, wreq->wsize, copied, to_page_end);
-
-	wreq->iter.count += copied;
-	wreq->io_iter.count += copied;
-	if (to_page_end && wreq->io_iter.count - wreq->submitted >= wreq->wsize)
-		netfs_submit_writethrough(wreq, false);
-
-	return wreq->error;
-}
-
-/*
- * End a write operation used when writing through the pagecache.
- */
-int netfs_end_writethrough(struct netfs_io_request *wreq, struct kiocb *iocb)
-{
-	int ret = -EIOCBQUEUED;
-
-	_enter("ic=%zu sb=%llu ws=%u",
-	       wreq->iter.count, wreq->submitted, wreq->wsize);
-
-	if (wreq->submitted < wreq->io_iter.count)
-		netfs_submit_writethrough(wreq, true);
-
-	if (atomic_dec_and_test(&wreq->nr_outstanding))
-		netfs_write_terminated(wreq, false);
-
-	if (is_sync_kiocb(iocb)) {
-		wait_on_bit(&wreq->flags, NETFS_RREQ_IN_PROGRESS,
-			    TASK_UNINTERRUPTIBLE);
-		ret = wreq->error;
-	}
-
-	netfs_put_request(wreq, false, netfs_rreq_trace_put_return);
-	return ret;
-}