116211268SDavid Howells // SPDX-License-Identifier: GPL-2.0-or-later 216211268SDavid Howells /* Network filesystem high-level buffered read support. 316211268SDavid Howells * 416211268SDavid Howells * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. 516211268SDavid Howells * Written by David Howells (dhowells@redhat.com) 616211268SDavid Howells */ 716211268SDavid Howells 816211268SDavid Howells #include <linux/export.h> 916211268SDavid Howells #include <linux/task_io_accounting_ops.h> 1016211268SDavid Howells #include "internal.h" 1116211268SDavid Howells 1216211268SDavid Howells /* 1316211268SDavid Howells * Unlock the folios in a read operation. We need to set PG_fscache on any 1416211268SDavid Howells * folios we're going to write back before we unlock them. 1516211268SDavid Howells */ 1616211268SDavid Howells void netfs_rreq_unlock_folios(struct netfs_io_request *rreq) 1716211268SDavid Howells { 1816211268SDavid Howells struct netfs_io_subrequest *subreq; 1916211268SDavid Howells struct folio *folio; 2016211268SDavid Howells unsigned int iopos, account = 0; 2116211268SDavid Howells pgoff_t start_page = rreq->start / PAGE_SIZE; 2216211268SDavid Howells pgoff_t last_page = ((rreq->start + rreq->len) / PAGE_SIZE) - 1; 2316211268SDavid Howells bool subreq_failed = false; 2416211268SDavid Howells 2516211268SDavid Howells XA_STATE(xas, &rreq->mapping->i_pages, start_page); 2616211268SDavid Howells 2716211268SDavid Howells if (test_bit(NETFS_RREQ_FAILED, &rreq->flags)) { 2816211268SDavid Howells __clear_bit(NETFS_RREQ_COPY_TO_CACHE, &rreq->flags); 2916211268SDavid Howells list_for_each_entry(subreq, &rreq->subrequests, rreq_link) { 3016211268SDavid Howells __clear_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags); 3116211268SDavid Howells } 3216211268SDavid Howells } 3316211268SDavid Howells 3416211268SDavid Howells /* Walk through the pagecache and the I/O request lists simultaneously. 3516211268SDavid Howells * We may have a mixture of cached and uncached sections and we only 3616211268SDavid Howells * really want to write out the uncached sections. This is slightly 3716211268SDavid Howells * complicated by the possibility that we might have huge pages with a 3816211268SDavid Howells * mixture inside. 3916211268SDavid Howells */ 4016211268SDavid Howells subreq = list_first_entry(&rreq->subrequests, 4116211268SDavid Howells struct netfs_io_subrequest, rreq_link); 4216211268SDavid Howells iopos = 0; 4316211268SDavid Howells subreq_failed = (subreq->error < 0); 4416211268SDavid Howells 4516211268SDavid Howells trace_netfs_rreq(rreq, netfs_rreq_trace_unlock); 4616211268SDavid Howells 4716211268SDavid Howells rcu_read_lock(); 4816211268SDavid Howells xas_for_each(&xas, folio, last_page) { 4916211268SDavid Howells unsigned int pgpos = (folio_index(folio) - start_page) * PAGE_SIZE; 5016211268SDavid Howells unsigned int pgend = pgpos + folio_size(folio); 5116211268SDavid Howells bool pg_failed = false; 5216211268SDavid Howells 5316211268SDavid Howells for (;;) { 5416211268SDavid Howells if (!subreq) { 5516211268SDavid Howells pg_failed = true; 5616211268SDavid Howells break; 5716211268SDavid Howells } 5816211268SDavid Howells if (test_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags)) 5916211268SDavid Howells folio_start_fscache(folio); 6016211268SDavid Howells pg_failed |= subreq_failed; 6116211268SDavid Howells if (pgend < iopos + subreq->len) 6216211268SDavid Howells break; 6316211268SDavid Howells 6416211268SDavid Howells account += subreq->transferred; 6516211268SDavid Howells iopos += subreq->len; 6616211268SDavid Howells if (!list_is_last(&subreq->rreq_link, &rreq->subrequests)) { 6716211268SDavid Howells subreq = list_next_entry(subreq, rreq_link); 6816211268SDavid Howells subreq_failed = (subreq->error < 0); 6916211268SDavid Howells } else { 7016211268SDavid Howells subreq = NULL; 7116211268SDavid Howells subreq_failed = false; 7216211268SDavid Howells } 7316211268SDavid Howells if (pgend == iopos) 7416211268SDavid Howells break; 7516211268SDavid Howells } 7616211268SDavid Howells 7716211268SDavid Howells if (!pg_failed) { 7816211268SDavid Howells flush_dcache_folio(folio); 7916211268SDavid Howells folio_mark_uptodate(folio); 8016211268SDavid Howells } 8116211268SDavid Howells 8216211268SDavid Howells if (!test_bit(NETFS_RREQ_DONT_UNLOCK_FOLIOS, &rreq->flags)) { 8316211268SDavid Howells if (folio_index(folio) == rreq->no_unlock_folio && 8416211268SDavid Howells test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags)) 8516211268SDavid Howells _debug("no unlock"); 8616211268SDavid Howells else 8716211268SDavid Howells folio_unlock(folio); 8816211268SDavid Howells } 8916211268SDavid Howells } 9016211268SDavid Howells rcu_read_unlock(); 9116211268SDavid Howells 9216211268SDavid Howells task_io_account_read(account); 9316211268SDavid Howells if (rreq->netfs_ops->done) 9416211268SDavid Howells rreq->netfs_ops->done(rreq); 9516211268SDavid Howells } 9616211268SDavid Howells 9716211268SDavid Howells static void netfs_cache_expand_readahead(struct netfs_io_request *rreq, 9816211268SDavid Howells loff_t *_start, size_t *_len, loff_t i_size) 9916211268SDavid Howells { 10016211268SDavid Howells struct netfs_cache_resources *cres = &rreq->cache_resources; 10116211268SDavid Howells 10216211268SDavid Howells if (cres->ops && cres->ops->expand_readahead) 10316211268SDavid Howells cres->ops->expand_readahead(cres, _start, _len, i_size); 10416211268SDavid Howells } 10516211268SDavid Howells 10616211268SDavid Howells static void netfs_rreq_expand(struct netfs_io_request *rreq, 10716211268SDavid Howells struct readahead_control *ractl) 10816211268SDavid Howells { 10916211268SDavid Howells /* Give the cache a chance to change the request parameters. The 11016211268SDavid Howells * resultant request must contain the original region. 11116211268SDavid Howells */ 11216211268SDavid Howells netfs_cache_expand_readahead(rreq, &rreq->start, &rreq->len, rreq->i_size); 11316211268SDavid Howells 11416211268SDavid Howells /* Give the netfs a chance to change the request parameters. The 11516211268SDavid Howells * resultant request must contain the original region. 11616211268SDavid Howells */ 11716211268SDavid Howells if (rreq->netfs_ops->expand_readahead) 11816211268SDavid Howells rreq->netfs_ops->expand_readahead(rreq); 11916211268SDavid Howells 12016211268SDavid Howells /* Expand the request if the cache wants it to start earlier. Note 12116211268SDavid Howells * that the expansion may get further extended if the VM wishes to 12216211268SDavid Howells * insert THPs and the preferred start and/or end wind up in the middle 12316211268SDavid Howells * of THPs. 12416211268SDavid Howells * 12516211268SDavid Howells * If this is the case, however, the THP size should be an integer 12616211268SDavid Howells * multiple of the cache granule size, so we get a whole number of 12716211268SDavid Howells * granules to deal with. 12816211268SDavid Howells */ 12916211268SDavid Howells if (rreq->start != readahead_pos(ractl) || 13016211268SDavid Howells rreq->len != readahead_length(ractl)) { 13116211268SDavid Howells readahead_expand(ractl, rreq->start, rreq->len); 13216211268SDavid Howells rreq->start = readahead_pos(ractl); 13316211268SDavid Howells rreq->len = readahead_length(ractl); 13416211268SDavid Howells 13516211268SDavid Howells trace_netfs_read(rreq, readahead_pos(ractl), readahead_length(ractl), 13616211268SDavid Howells netfs_read_trace_expanded); 13716211268SDavid Howells } 13816211268SDavid Howells } 13916211268SDavid Howells 14016211268SDavid Howells /** 14116211268SDavid Howells * netfs_readahead - Helper to manage a read request 14216211268SDavid Howells * @ractl: The description of the readahead request 14316211268SDavid Howells * 14416211268SDavid Howells * Fulfil a readahead request by drawing data from the cache if possible, or 14516211268SDavid Howells * the netfs if not. Space beyond the EOF is zero-filled. Multiple I/O 14616211268SDavid Howells * requests from different sources will get munged together. If necessary, the 14716211268SDavid Howells * readahead window can be expanded in either direction to a more convenient 14816211268SDavid Howells * alighment for RPC efficiency or to make storage in the cache feasible. 14916211268SDavid Howells * 15016211268SDavid Howells * The calling netfs must initialise a netfs context contiguous to the vfs 15116211268SDavid Howells * inode before calling this. 15216211268SDavid Howells * 15316211268SDavid Howells * This is usable whether or not caching is enabled. 15416211268SDavid Howells */ 15516211268SDavid Howells void netfs_readahead(struct readahead_control *ractl) 15616211268SDavid Howells { 15716211268SDavid Howells struct netfs_io_request *rreq; 158*874c8ca1SDavid Howells struct netfs_inode *ctx = netfs_inode(ractl->mapping->host); 15916211268SDavid Howells int ret; 16016211268SDavid Howells 16116211268SDavid Howells _enter("%lx,%x", readahead_index(ractl), readahead_count(ractl)); 16216211268SDavid Howells 16316211268SDavid Howells if (readahead_count(ractl) == 0) 16416211268SDavid Howells return; 16516211268SDavid Howells 16616211268SDavid Howells rreq = netfs_alloc_request(ractl->mapping, ractl->file, 16716211268SDavid Howells readahead_pos(ractl), 16816211268SDavid Howells readahead_length(ractl), 16916211268SDavid Howells NETFS_READAHEAD); 17016211268SDavid Howells if (IS_ERR(rreq)) 17116211268SDavid Howells return; 17216211268SDavid Howells 17316211268SDavid Howells if (ctx->ops->begin_cache_operation) { 17416211268SDavid Howells ret = ctx->ops->begin_cache_operation(rreq); 17516211268SDavid Howells if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) 17616211268SDavid Howells goto cleanup_free; 17716211268SDavid Howells } 17816211268SDavid Howells 17916211268SDavid Howells netfs_stat(&netfs_n_rh_readahead); 18016211268SDavid Howells trace_netfs_read(rreq, readahead_pos(ractl), readahead_length(ractl), 18116211268SDavid Howells netfs_read_trace_readahead); 18216211268SDavid Howells 18316211268SDavid Howells netfs_rreq_expand(rreq, ractl); 18416211268SDavid Howells 18516211268SDavid Howells /* Drop the refs on the folios here rather than in the cache or 18616211268SDavid Howells * filesystem. The locks will be dropped in netfs_rreq_unlock(). 18716211268SDavid Howells */ 18816211268SDavid Howells while (readahead_folio(ractl)) 18916211268SDavid Howells ; 19016211268SDavid Howells 19116211268SDavid Howells netfs_begin_read(rreq, false); 19216211268SDavid Howells return; 19316211268SDavid Howells 19416211268SDavid Howells cleanup_free: 19516211268SDavid Howells netfs_put_request(rreq, false, netfs_rreq_trace_put_failed); 19616211268SDavid Howells return; 19716211268SDavid Howells } 19816211268SDavid Howells EXPORT_SYMBOL(netfs_readahead); 19916211268SDavid Howells 20016211268SDavid Howells /** 2016c62371bSMatthew Wilcox (Oracle) * netfs_read_folio - Helper to manage a read_folio request 20216211268SDavid Howells * @file: The file to read from 2036c62371bSMatthew Wilcox (Oracle) * @folio: The folio to read 20416211268SDavid Howells * 2056c62371bSMatthew Wilcox (Oracle) * Fulfil a read_folio request by drawing data from the cache if 2066c62371bSMatthew Wilcox (Oracle) * possible, or the netfs if not. Space beyond the EOF is zero-filled. 2076c62371bSMatthew Wilcox (Oracle) * Multiple I/O requests from different sources will get munged together. 20816211268SDavid Howells * 20916211268SDavid Howells * The calling netfs must initialise a netfs context contiguous to the vfs 21016211268SDavid Howells * inode before calling this. 21116211268SDavid Howells * 21216211268SDavid Howells * This is usable whether or not caching is enabled. 21316211268SDavid Howells */ 2146c62371bSMatthew Wilcox (Oracle) int netfs_read_folio(struct file *file, struct folio *folio) 21516211268SDavid Howells { 21616211268SDavid Howells struct address_space *mapping = folio_file_mapping(folio); 21716211268SDavid Howells struct netfs_io_request *rreq; 218*874c8ca1SDavid Howells struct netfs_inode *ctx = netfs_inode(mapping->host); 21916211268SDavid Howells int ret; 22016211268SDavid Howells 22116211268SDavid Howells _enter("%lx", folio_index(folio)); 22216211268SDavid Howells 22316211268SDavid Howells rreq = netfs_alloc_request(mapping, file, 22416211268SDavid Howells folio_file_pos(folio), folio_size(folio), 22516211268SDavid Howells NETFS_READPAGE); 22616211268SDavid Howells if (IS_ERR(rreq)) { 22716211268SDavid Howells ret = PTR_ERR(rreq); 22816211268SDavid Howells goto alloc_error; 22916211268SDavid Howells } 23016211268SDavid Howells 23116211268SDavid Howells if (ctx->ops->begin_cache_operation) { 23216211268SDavid Howells ret = ctx->ops->begin_cache_operation(rreq); 23316211268SDavid Howells if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) 23416211268SDavid Howells goto discard; 23516211268SDavid Howells } 23616211268SDavid Howells 23716211268SDavid Howells netfs_stat(&netfs_n_rh_readpage); 23816211268SDavid Howells trace_netfs_read(rreq, rreq->start, rreq->len, netfs_read_trace_readpage); 23916211268SDavid Howells return netfs_begin_read(rreq, true); 24016211268SDavid Howells 24116211268SDavid Howells discard: 24216211268SDavid Howells netfs_put_request(rreq, false, netfs_rreq_trace_put_discard); 24316211268SDavid Howells alloc_error: 24416211268SDavid Howells folio_unlock(folio); 24516211268SDavid Howells return ret; 24616211268SDavid Howells } 2476c62371bSMatthew Wilcox (Oracle) EXPORT_SYMBOL(netfs_read_folio); 24816211268SDavid Howells 24916211268SDavid Howells /* 25016211268SDavid Howells * Prepare a folio for writing without reading first 25116211268SDavid Howells * @folio: The folio being prepared 25216211268SDavid Howells * @pos: starting position for the write 25316211268SDavid Howells * @len: length of write 25416211268SDavid Howells * @always_fill: T if the folio should always be completely filled/cleared 25516211268SDavid Howells * 25616211268SDavid Howells * In some cases, write_begin doesn't need to read at all: 25716211268SDavid Howells * - full folio write 25816211268SDavid Howells * - write that lies in a folio that is completely beyond EOF 25916211268SDavid Howells * - write that covers the folio from start to EOF or beyond it 26016211268SDavid Howells * 26116211268SDavid Howells * If any of these criteria are met, then zero out the unwritten parts 26216211268SDavid Howells * of the folio and return true. Otherwise, return false. 26316211268SDavid Howells */ 26416211268SDavid Howells static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len, 26516211268SDavid Howells bool always_fill) 26616211268SDavid Howells { 26716211268SDavid Howells struct inode *inode = folio_inode(folio); 26816211268SDavid Howells loff_t i_size = i_size_read(inode); 26916211268SDavid Howells size_t offset = offset_in_folio(folio, pos); 27016211268SDavid Howells size_t plen = folio_size(folio); 27116211268SDavid Howells 27216211268SDavid Howells if (unlikely(always_fill)) { 27316211268SDavid Howells if (pos - offset + len <= i_size) 27416211268SDavid Howells return false; /* Page entirely before EOF */ 27516211268SDavid Howells zero_user_segment(&folio->page, 0, plen); 27616211268SDavid Howells folio_mark_uptodate(folio); 27716211268SDavid Howells return true; 27816211268SDavid Howells } 27916211268SDavid Howells 28016211268SDavid Howells /* Full folio write */ 28116211268SDavid Howells if (offset == 0 && len >= plen) 28216211268SDavid Howells return true; 28316211268SDavid Howells 28416211268SDavid Howells /* Page entirely beyond the end of the file */ 28516211268SDavid Howells if (pos - offset >= i_size) 28616211268SDavid Howells goto zero_out; 28716211268SDavid Howells 28816211268SDavid Howells /* Write that covers from the start of the folio to EOF or beyond */ 28916211268SDavid Howells if (offset == 0 && (pos + len) >= i_size) 29016211268SDavid Howells goto zero_out; 29116211268SDavid Howells 29216211268SDavid Howells return false; 29316211268SDavid Howells zero_out: 29416211268SDavid Howells zero_user_segments(&folio->page, 0, offset, offset + len, plen); 29516211268SDavid Howells return true; 29616211268SDavid Howells } 29716211268SDavid Howells 29816211268SDavid Howells /** 29916211268SDavid Howells * netfs_write_begin - Helper to prepare for writing 30016211268SDavid Howells * @file: The file to read from 30116211268SDavid Howells * @mapping: The mapping to read from 30216211268SDavid Howells * @pos: File position at which the write will begin 30316211268SDavid Howells * @len: The length of the write (may extend beyond the end of the folio chosen) 30416211268SDavid Howells * @_folio: Where to put the resultant folio 30516211268SDavid Howells * @_fsdata: Place for the netfs to store a cookie 30616211268SDavid Howells * 30716211268SDavid Howells * Pre-read data for a write-begin request by drawing data from the cache if 30816211268SDavid Howells * possible, or the netfs if not. Space beyond the EOF is zero-filled. 30916211268SDavid Howells * Multiple I/O requests from different sources will get munged together. If 31016211268SDavid Howells * necessary, the readahead window can be expanded in either direction to a 31116211268SDavid Howells * more convenient alighment for RPC efficiency or to make storage in the cache 31216211268SDavid Howells * feasible. 31316211268SDavid Howells * 31416211268SDavid Howells * The calling netfs must provide a table of operations, only one of which, 31516211268SDavid Howells * issue_op, is mandatory. 31616211268SDavid Howells * 31716211268SDavid Howells * The check_write_begin() operation can be provided to check for and flush 31816211268SDavid Howells * conflicting writes once the folio is grabbed and locked. It is passed a 31916211268SDavid Howells * pointer to the fsdata cookie that gets returned to the VM to be passed to 32016211268SDavid Howells * write_end. It is permitted to sleep. It should return 0 if the request 32116211268SDavid Howells * should go ahead; unlock the folio and return -EAGAIN to cause the folio to 32216211268SDavid Howells * be regot; or return an error. 32316211268SDavid Howells * 32416211268SDavid Howells * The calling netfs must initialise a netfs context contiguous to the vfs 32516211268SDavid Howells * inode before calling this. 32616211268SDavid Howells * 32716211268SDavid Howells * This is usable whether or not caching is enabled. 32816211268SDavid Howells */ 32916211268SDavid Howells int netfs_write_begin(struct file *file, struct address_space *mapping, 330de2a9311SMatthew Wilcox (Oracle) loff_t pos, unsigned int len, struct folio **_folio, 331de2a9311SMatthew Wilcox (Oracle) void **_fsdata) 33216211268SDavid Howells { 33316211268SDavid Howells struct netfs_io_request *rreq; 334*874c8ca1SDavid Howells struct netfs_inode *ctx = netfs_inode(file_inode(file )); 33516211268SDavid Howells struct folio *folio; 336236d93c4SMatthew Wilcox (Oracle) unsigned int fgp_flags = FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_STABLE; 33716211268SDavid Howells pgoff_t index = pos >> PAGE_SHIFT; 33816211268SDavid Howells int ret; 33916211268SDavid Howells 34016211268SDavid Howells DEFINE_READAHEAD(ractl, file, NULL, mapping, index); 34116211268SDavid Howells 34216211268SDavid Howells retry: 34316211268SDavid Howells folio = __filemap_get_folio(mapping, index, fgp_flags, 34416211268SDavid Howells mapping_gfp_mask(mapping)); 34516211268SDavid Howells if (!folio) 34616211268SDavid Howells return -ENOMEM; 34716211268SDavid Howells 34816211268SDavid Howells if (ctx->ops->check_write_begin) { 34916211268SDavid Howells /* Allow the netfs (eg. ceph) to flush conflicts. */ 35016211268SDavid Howells ret = ctx->ops->check_write_begin(file, pos, len, folio, _fsdata); 35116211268SDavid Howells if (ret < 0) { 35216211268SDavid Howells trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin); 35316211268SDavid Howells if (ret == -EAGAIN) 35416211268SDavid Howells goto retry; 35516211268SDavid Howells goto error; 35616211268SDavid Howells } 35716211268SDavid Howells } 35816211268SDavid Howells 35916211268SDavid Howells if (folio_test_uptodate(folio)) 36016211268SDavid Howells goto have_folio; 36116211268SDavid Howells 36216211268SDavid Howells /* If the page is beyond the EOF, we want to clear it - unless it's 36316211268SDavid Howells * within the cache granule containing the EOF, in which case we need 36416211268SDavid Howells * to preload the granule. 36516211268SDavid Howells */ 36616211268SDavid Howells if (!netfs_is_cache_enabled(ctx) && 36716211268SDavid Howells netfs_skip_folio_read(folio, pos, len, false)) { 36816211268SDavid Howells netfs_stat(&netfs_n_rh_write_zskip); 36916211268SDavid Howells goto have_folio_no_wait; 37016211268SDavid Howells } 37116211268SDavid Howells 37216211268SDavid Howells rreq = netfs_alloc_request(mapping, file, 37316211268SDavid Howells folio_file_pos(folio), folio_size(folio), 37416211268SDavid Howells NETFS_READ_FOR_WRITE); 37516211268SDavid Howells if (IS_ERR(rreq)) { 37616211268SDavid Howells ret = PTR_ERR(rreq); 37716211268SDavid Howells goto error; 37816211268SDavid Howells } 37916211268SDavid Howells rreq->no_unlock_folio = folio_index(folio); 38016211268SDavid Howells __set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags); 38116211268SDavid Howells 38216211268SDavid Howells if (ctx->ops->begin_cache_operation) { 38316211268SDavid Howells ret = ctx->ops->begin_cache_operation(rreq); 38416211268SDavid Howells if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) 38516211268SDavid Howells goto error_put; 38616211268SDavid Howells } 38716211268SDavid Howells 38816211268SDavid Howells netfs_stat(&netfs_n_rh_write_begin); 38916211268SDavid Howells trace_netfs_read(rreq, pos, len, netfs_read_trace_write_begin); 39016211268SDavid Howells 39116211268SDavid Howells /* Expand the request to meet caching requirements and download 39216211268SDavid Howells * preferences. 39316211268SDavid Howells */ 39416211268SDavid Howells ractl._nr_pages = folio_nr_pages(folio); 39516211268SDavid Howells netfs_rreq_expand(rreq, &ractl); 39616211268SDavid Howells 39716211268SDavid Howells /* We hold the folio locks, so we can drop the references */ 39816211268SDavid Howells folio_get(folio); 39916211268SDavid Howells while (readahead_folio(&ractl)) 40016211268SDavid Howells ; 40116211268SDavid Howells 40216211268SDavid Howells ret = netfs_begin_read(rreq, true); 40316211268SDavid Howells if (ret < 0) 40416211268SDavid Howells goto error; 40516211268SDavid Howells 40616211268SDavid Howells have_folio: 40716211268SDavid Howells ret = folio_wait_fscache_killable(folio); 40816211268SDavid Howells if (ret < 0) 40916211268SDavid Howells goto error; 41016211268SDavid Howells have_folio_no_wait: 41116211268SDavid Howells *_folio = folio; 41216211268SDavid Howells _leave(" = 0"); 41316211268SDavid Howells return 0; 41416211268SDavid Howells 41516211268SDavid Howells error_put: 41616211268SDavid Howells netfs_put_request(rreq, false, netfs_rreq_trace_put_failed); 41716211268SDavid Howells error: 41816211268SDavid Howells folio_unlock(folio); 41916211268SDavid Howells folio_put(folio); 42016211268SDavid Howells _leave(" = %d", ret); 42116211268SDavid Howells return ret; 42216211268SDavid Howells } 42316211268SDavid Howells EXPORT_SYMBOL(netfs_write_begin); 424